setuptoolsテストはインポートエラーを隠します。より良い情報を得るには?
-
10-07-2019 - |
質問
python setuptoolsでは、python setup.py testがテストスイートを実行します。ただし、テストスイートでインポートエラーが発生した場合、取得する唯一のエラーメッセージは、テストクラスが見つからないことを訴えるAttributeErrorです。より詳細なエラーメッセージを取得する方法があるので、テストスイートを修正できますか?
次の例を使用して、自分自身について詳しく説明します。 fooというパッケージがあり、pasterで新たに作成されたとします。次に、テストを追加します
./foo
./foo/__init__.py
./foo/tests
./foo/tests/__init__.py
./foo/tests/mytest.py
./setup.cfg
./setup.py
今、mytest.pyに次のコードが含まれているとします
import unittest
class MyTestClass(unittest.TestCase):
def testFoo(self):
self.assertEqual(1,1)
これは動作します。ただし、存在しないモジュールをインポートしようとすると
import unittest
import frombiz
class MyTestClass(unittest.TestCase):
def testFoo(self):
self.assertEqual(1,1)
これは私が取得したエラーです
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'
つまり、失敗したインポートへの参照はありません。
解決
問題は、 __ import __()
の最初の引数がモジュールでなければならないことです。ドットで区切られた名前のオブジェクトに到達する必要がある場合、どの部分がモジュールであり、何がモジュールではないのかはわかりません。 module.subname
オブジェクトを取得する1つの方法は、最初にサブモジュールとしてインポートを試み、失敗した場合は getattr(module、subname)
を unittest として使用することですcode>は。これにより、
ImportError
ではなく AttributeError
が表示される場合があります。これを行う別の方法は、最初に getattr(module、subname)
を試行し、失敗した場合にのみインポートを試行することです。この方法の方が優れているわけではありません。 AttributeError
がより適切な場合に、 ImportError
が表示されることがあります。
この場合、おそらく最良の unittest
は、インポートと属性のルックアップの両方が失敗したという独自の例外を発生させることです。この問題のバグレポートを送信してください。
他のヒント
nose を使用します。コードを変更する必要はありません。ただやる:
$ pip install nose
$ nosetests
ImportErrorがある場合、それが表示されます:
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
配布(setuptools以降のsetuptoolsのフォーク)でコードを試すこともできますあまり積極的に維持されていません)。何か違うことができるかどうかはわかりませんが、一見の価値はあります。
ここでの問題は、unittestモジュールが実行しないトレースバックを慎重に検査しない限り、Python ImportErrorが実際にエラーが発生したモジュールを通知しないことです。 unittestモジュールでも、実行に使用するツールに関係なく、同じ問題が発生します。
&quot; nose&quot;を試してみてください。パッケージ-setuptoolsプラグインが含まれているため、setuptoolsのデフォルトのテストファインダーを使用する代わりに、setup.pyに追加してテストの検索とインポートを行うことができます。正しく思い出せば、unittestとは異なる方法でテストコードをロードし、この場合により良いエラーメッセージを提供できる可能性があります。たとえそうでなくても、おそらくユニットテストよりも鼻に追加する方が簡単でしょう!