Djangotesting运行器在Ubuntu上的virtualenv失败

我一直在努力解决安装在Ubuntu 14.04上的Python virtualenv中的Djangotesting运行器的问题。 同样的软件在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? 

testing用例在开发环境中运行良好,并且在从源代码发行包安装到MAcOS开发主机上的新virtualenv环境中时也可以正常运行。 但是,当我将相同的软件包安装到Ubuntu 14.04主机上的新virtualenv中时,testing运行器将失败并显示以上消息。

问题出现在我创build的pipe理实用程序中,调用django-admin (以及其他一些东西)的一些function。

networkingsearch揭示了virtualenv和posix兼容性错误的报告,最近在Ubuntu发行版中已经解决了这个问题(2013/14),方法是在虚拟环境中创build一个local目录,该目录又包含到顶级目录的符号链接,级别的虚拟环境目录。 错误消息中显示的path对应于这些别名目录path。

(我把这个post作为一个问题发布,所以我可以把结果和答案从我的调查中发布出来,希望对其他人有所帮助,因此我并不想详细描述我的特定软件设置。 )

我有完全相同的问题,不知道发生了什么事情。 最后这是一个愚蠢的事情:

我有一个类似于这个布局:

 my_app/ __init__.py tests.py tests/ __init__.py test_foo.py 

这个问题是由同一个文件夹中同时包含一个“tests.py”模块和一个“tests”包产生的。

只是删除“tests.py”文件解决了我的问题。

希望能帮助到你。

简短的回答

在我的代码中的修复是使用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是一个上下文处理程序,用指定的当前工作目录运行附带的代码)。

更多细节

一些进一步的实验表明,我可以通过在Python和/或Django库代码中用os.path.realpath替代os.path.abspath来“修复”问题。

我发现的核心问题是:

 /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=选项是必要的,但它是为我工作)。