我一直在为Ubuntu 14.04上的Python virtualenv中安装的Django测试运行器遇到问题。相同的软件可以在MacOS上正常运行,我认为在早期版本的Ubuntu上也可以。
失败消息是:
ImportError: '<test>' module incorrectly imported from '<base-env>/local/lib/python2.7/site-packages/<package-dir>'. Expected '<base-env>/lib/python2.7/site-packages/<package-dir>'. Is this module globally installed?
错误的完整堆栈跟踪为:
Traceback (most recent call last):
File "/home/annalist/anenv/bin/django-admin", line 11, in <module>
sys.exit(execute_from_command_line())
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
utility.execute()
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 377, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 50, in run_from_argv
super(Command, self).run_from_argv(argv)
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **options.__dict__)
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 71, in execute
super(Command, self).execute(*args, **options)
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/core/management/base.py", line 338, in execute
output = self.handle(*args, **options)
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 88, in handle
failures = test_runner.run_tests(test_labels)
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/test/runner.py", line 147, in run_tests
suite = self.build_suite(test_labels, extra_tests)
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/test/runner.py", line 96, in build_suite
tests = self.test_loader.discover(start_dir=label, **kwargs)
File "/usr/lib/python2.7/unittest/loader.py", line 206, in discover
tests = list(self._find_tests(start_dir, pattern))
File "/usr/lib/python2.7/unittest/loader.py", line 287, in _find_tests
for test in self._find_tests(full_path, pattern):
File "/usr/lib/python2.7/unittest/loader.py", line 287, in _find_tests
for test in self._find_tests(full_path, pattern):
File "/usr/lib/python2.7/unittest/loader.py", line 267, in _find_tests
raise ImportError(msg % (mod_name, module_dir, expected_dir))
ImportError: 'test_entity' module incorrectly imported from '/home/annalist/anenv/local/lib/python2.7/site-packages/annalist_root/annalist/tests'. Expected '/home/annalist/anenv/lib/python2.7/site-packages/annalist_root/annalist/tests'. Is this module globally installed?
测试用例在开发环境中运行良好,并且从源分发工具包安装到MAcOS开发主机上的新virtualenv环境中时,它们也运行良好。但是,当我在Ubuntu 14.04主机上将相同的软件包安装到新的virtualenv中时,测试运行程序失败并显示以上消息。
问题出现在我创建的管理实用程序中,该实用程序调用的某些功能django-admin
(以及其他一些功能)。
网络搜索显示了具有virtualenv和posix兼容性的bug的报告,这些报告已在Ubuntu发行版中相对较近地解决(2013/14),方法是local
在虚拟环境中创建目录,该目录又包含指向目录的符号链接,这些目录也可以从顶层访问虚拟环境目录。错误消息中显示的路径与这些别名目录路径相对应。
(我将其发布为问题,以便我可以发布调查结果和答案,以期对其他人有用。因此,我不打算详细说明我的特定软件设置。 )
我的代码中的修补程序os.path.realpath
用于获取安装的软件包路径的规范化版本,并在调用该django-admin
实用程序的命令行上传递此值。就我而言,它看起来像这样:
approot = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
和:
with ChangeCurrentDir(approot):
subprocess_command = (
"django-admin test --pythonpath=%s --settings=%s --top-level-directory=%s"%
(approot, settings_module_name, approot)
)
status = subprocess.call(subprocess_command.split())
(其中ChangeCurrentDir
是一个上下文处理程序,用于使用指定的当前工作目录运行随附的代码)。
一些进一步的实验表明,我可以“修复”的战略接替的问题os.path.abspath
与os.path.realpath
在Python和/或Django的库代码。
我发现的核心问题是:
/usr/lib/python2.7/unittest/loader.py
具体来说:
File "/usr/lib/python2.7/unittest/loader.py", line 267, in _find_tests
raise ImportError(msg % (mod_name, module_dir, expected_dir))
ImportError: 'test_entity' module incorrectly imported from ...
loader.py
导致此问题的令人讨厌的代码是:
if realpath.lower() != fullpath_noext.lower():
module_dir = os.path.dirname(realpath)
mod_name = os.path.splitext(os.path.basename(full_path))[0]
expected_dir = os.path.dirname(full_path)
msg = ("%r module incorrectly imported from %r. Expected %r. "
"Is this module globally installed?")
raise ImportError(msg % (mod_name, module_dir, expected_dir))
如果我将此if
语句替换为:
if os.path.realpath(realpath).lower() != fullpath_noext.lower():
然后一切都快乐。这可以确认这是一个符号链接别名问题,因为它os.path.realpath()
可以解析到基础路径的所有符号链接。但这不是可安装软件包的解决方案,因为它涉及修改基础Python安装。因此,在探究了根本问题之后,我需要一些更容易受到攻击的东西。
下一个调用端口是Django测试运行器库,该库安装在虚拟环境中。
<base-env>/local/lib/python2.7/site-packages/django/test/runner.py
特别要注意的是堆栈跟踪的这一部分:
File "/home/annalist/anenv/local/lib/python2.7/site-packages/django/test/runner.py", line 96, in build_suite
tests = self.test_loader.discover(start_dir=label, **kwargs)
浏览此代码,我能够确定问题与label
参数有关,该参数默认为'.'
(即当前目录)。这里没有简单的解决方法,但是这表明问题可能与运行时使用的当前目录和/或路径有关django-admin
。这导致了上述解决方案(可能是过大的解决方案-我不确定--pythonpath=
是否需要该选项,但它对我有用。)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句