Django测试运行器在Ubuntu上的virtualenv失败

Gra*_*yne 14 python django ubuntu virtualenv python-unittest

我一直在努力解决在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?
Run Code Online (Sandbox Code Playgroud)

并且错误的完整堆栈跟踪是:

  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?
Run Code Online (Sandbox Code Playgroud)

测试用例在开发环境中运行良好,当从源分发工具包安装到MAcOS开发主机上的新virtualenv环境时,它们也运行良好.但是当我在Ubuntu 14.04主机上将相同的软件包安装到新的virtualenv时,测试运行器会因上述消息而失败.

我创建的一个管理实用程序出现了问题,它调用了一些函数django-admin(以及其他一些东西).

Web搜索显示有关virtualenv和posix兼容性的错误的报告,这些错误最近(2013/14)在Ubuntu发行版中通过local在虚拟环境中创建目录而得到解决,该目录又包含也可从顶层访问的目录的符号链接虚拟环境目录.错误消息中显示的路径对应于这些别名目录路径.

(我将此作为一个问题发布,因此我可以发布结果并从我的调查中回答,希望它对其他人有用.因此,我不打算详细描述我的特定软件设置. )

Mar*_*oni 32

我有完全相同的问题,无法弄清楚发生了什么.最后这是一个愚蠢的事情:

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

my_app/
    __init__.py
    tests.py
    tests/
        __init__.py
       test_foo.py
Run Code Online (Sandbox Code Playgroud)

通过在同一文件夹中同时包含"tests.py"模块和"tests"包来生成问题.

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

希望能帮助到你.

  • 很好......让我头疼:) (4认同)

Gra*_*yne 5

简短的回答

我的代码中的修复是用于os.path.realpath获取已安装的包路径的规范化版本,并在调用该django-admin实用程序的命令行上传递此值.在我看来,它看起来像这样:

approot = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
Run Code Online (Sandbox Code Playgroud)

和:

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())
Run Code Online (Sandbox Code Playgroud)

(其中ChangeCurrentDir是一个上下文处理程序,它使用指定的当前工作目录运行附带的代码).

更多细节

一些进一步的实验表明,我可以通过战略接替的"修复"的问题os.path.abspath与os.path.realpath在Python和/或Django的库代码.

我发现的核心问题是:

/usr/lib/python2.7/unittest/loader.py
Run Code Online (Sandbox Code Playgroud)

特别:

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 ...
Run Code Online (Sandbox Code Playgroud)

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))
Run Code Online (Sandbox Code Playgroud)

如果我if用这个替换语句:

        if os.path.realpath(realpath).lower() != fullpath_noext.lower():
Run Code Online (Sandbox Code Playgroud)

一切都很开心.这确认了它是符号链接别名问题,因为它 os.path.realpath()解析了基础路径的任何符号链接.但这不是可安装软件包的解决方案,因为它涉及修改底层Python安装.因此,在探究了潜在的问题之后,我需要一些更易于攻击的东西.

下一个停靠点是Django测试运行器库,它安装在虚拟环境中.

<base-env>/local/lib/python2.7/site-packages/django/test/runner.py
Run Code Online (Sandbox Code Playgroud)

特别是,关注堆栈跟踪的这一部分:

  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)
Run Code Online (Sandbox Code Playgroud)

挖掘这段代码,我能够确定问题与label参数有关,默认为'.'(即当前目录).这里没有明显的简单修复,但它表明问题可能与运行时使用的当前目录和/或路径有关django-admin.这导致了上述解决方案(可能有点过分 - 我不确定--pythonpath=是否需要该选项,但它对我有用).