2009-11-30 6 views
7

In python setuptools, python setup.py test esegue la suite di test. Tuttavia, se ho un errore di importazione nella mia suite di test, l'unico messaggio di errore che ottengo è un AttributeError che lamenta la mancanza della mia classe di test. C'è un modo per ottenere un messaggio di errore più dettagliato, quindi posso sistemare la suite di test?test di setuptools nasconde errori di importazione. Come avere informazioni migliori?

Mi spiegherò meglio con il seguente esempio. Supponiamo di avere un pacchetto chiamato foo, creato di nuovo con paster. Ho quindi aggiungere il test

./foo 
./foo/__init__.py 
./foo/tests 
./foo/tests/__init__.py 
./foo/tests/mytest.py 
./setup.cfg 
./setup.py 

Ora, supponiamo che mytest.py contiene il seguente codice

import unittest 
class MyTestClass(unittest.TestCase): 
    def testFoo(self): 
     self.assertEqual(1,1) 

Questo funziona. Tuttavia, se si tenta di importare un modulo non inesistente

import unittest 
import frombiz 
class MyTestClass(unittest.TestCase): 
    def testFoo(self): 
     self.assertEqual(1,1) 

Questo è l'errore che ottengo

Traceback (most recent call last): 
    File "setup.py", line 26, in <module> 
    test_suite = "foo.tests" 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/distutils/core.py", line 152, in setup 
    dist.run_commands() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/distutils/dist.py", line 975, in run_commands 
    self.run_command(cmd) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/distutils/dist.py", line 995, in run_command 
    cmd_obj.run() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/setuptools/command/test.py", line 121, in run 
    self.with_project_on_sys_path(self.run_tests) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/setuptools/command/test.py", line 101, in with_project_on_sys_path 
    func() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/setuptools/command/test.py", line 130, in run_tests 
    testLoader = loader_class() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 816, in __init__ 
    self.parseArgs(argv) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 843, in parseArgs 
    self.createTests() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 849, in createTests 
    self.module) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 613, in loadTestsFromNames 
    suites = [self.loadTestsFromName(name, module) for name in names] 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 587, in loadTestsFromName 
    return self.loadTestsFromModule(obj) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/setuptools/command/test.py", line 34, in loadTestsFromModule 
    tests.append(self.loadTestsFromName(submodule)) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 584, in loadTestsFromName 
    parent, obj = obj, getattr(obj, part) 
AttributeError: 'module' object has no attribute 'mytest' 

In altre parole, non c'è alcun riferimento alle importazioni fallito.

+1

La mia ipotesi è che non c'è alcun modo per ottenere ciò che si vuole senza modificare il codice sorgente di setuptool. – codeape

+0

@codeape - e buona fortuna con quello.:-) –

risposta

1

Il problema è che il primo argomento di __import__() deve essere il modulo. Quando hai bisogno di raggiungere qualche oggetto con il nome puntato non sai mai quale parte è modulo e cosa no. L'unico modo per ottenere l'oggetto module.subname è provare a importarlo prima come sottomodulo e quando fallisce usare getattr(module, subname), come fa unittest. Questo a volte ti darà AttributeError invece di ImportError. Un altro modo per farlo è provare prima lo getattr(module, subname) e solo quando fallisce, prova ad importare. In questo modo non è migliore: a volte ti darà ImportError quando più appropriato sarebbe AttributeError.

Probabilmente il migliore unittest può fare in questo caso è di sollevare la propria eccezione dicendo che sia l'importazione che la ricerca degli attributi hanno avuto esito negativo. Prova a inviare una segnalazione di bug per questo problema.

+1

È stato registrato un bug? –

0

Si consiglia inoltre di provare il codice con Distribute (un fork di setuptools poiché setuptools non viene mantenuto molto attivamente). Non so se farà qualcosa di diverso, ma ne vale la pena.

+0

distribuire 0.6.24 ha lo stesso problema. –

0

Il problema è che un oggetto Python ImportError non indica quale modulo si è effettivamente verificato l'errore, a meno che non si ispezioni attentamente il traceback, cosa che il modulo non più valido non esegue. Avrai lo stesso problema con il modulo unittest, indipendentemente dallo strumento che usi per eseguirlo.

Si consiglia di provare il pacchetto "nose" - ha un plugin setuptools, quindi è possibile aggiungerlo a setup.py e lasciarlo trovare e importare i test, invece di usare il test finder predefinito di setuptools. Se ricordo correttamente, carica il codice di test in un modo diverso rispetto a unittest e potrebbe essere in grado di fornire un messaggio di errore migliore in questo caso. E anche se così non fosse, sarebbe probabilmente più facile ottenerlo aggiunto al naso che a unittest!

3

Utilizzare nose. Non dovrebbe essere necessaria alcuna modifica al codice. Basta fare:

$ pip install nose 
$ nosetests 

Se c'è un ImportError, si vede:

ERROR: Failure: ImportError (cannot import name MyModel) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/home/garyvdm/bwreport/ve/lib/python3.2/site-packages/nose/failure.py", line 37, in runTest 
    raise self.exc_class(self.exc_val).with_traceback(self.tb) 
    File "/home/garyvdm/bwreport/ve/lib/python3.2/site-packages/nose/loader.py", line 390, in loadTestsFromName 
    addr.filename, addr.module) 
    File "/home/garyvdm/bwreport/ve/lib/python3.2/site-packages/nose/importer.py", line 39, in importFromPath 
    return self.importFromDir(dir_path, fqname) 
    File "/home/garyvdm/bwreport/ve/lib/python3.2/site-packages/nose/importer.py", line 86, in importFromDir 
    mod = load_module(part_fqname, fh, filename, desc) 
    File "/home/garyvdm/bwreport/bwreport/daemon/__init__.py", line 11, in <module> 
    from bwreport.models import (
ImportError: cannot import name MyModel 
+0

La versione di nose di Python3 mi ha fornito un errore esplicito sui problemi di importazione invece di Vago AttributeError come nella domanda originale. Bello! – mlt

+1

Dovrebbe essere 'nosetests' – dvim

+0

@Martynas modificato – Aliostad

Problemi correlati