当测试目录包含 __init__.py 时,为什么导入与 Python nose 一起工作?

Why does import work with Python nose when test directory contains __init__.py?

考虑以下项目结构:

a.py
test/
  test_a.py

with test_a.py 导入模块 a:

import a

不出所料,运行ning noseteststest 目录中导致导入错误:

ERROR: Failure: ImportError (No module named a)

但是,我注意到在 test 目录中添加一个空的 __init__.py 文件可以使导入与 nosetests 一起工作(但当您 运行 test_a.py 和 Python)。你能解释一下为什么吗?

我知道添加 __init__.py 会使 test 成为一个包。但是是不是意味着import在查找中包含了包含包的目录呢?

目录中 __init__.py 文件的存在将 test 从普通的旧目录转换为 python package。这对 sys.path 有影响。

像这样修改您的 test_a.py 模块:

import sys

def test_thing():
    for i, p in enumerate(sys.path):
        print i, p

try:
    import a
except ImportError:
    print('caught import error')

然后从测试目录尝试 运行 nosetests -s,其中有和没有 __init__.py

: 是测试运行器munges sys.path。这记录在 the second "Note" of this section here 中(感谢@davidism)。仅通过 运行 python test_a.py 有或没有包结构,你不会看到任何变化。

我查看了 nose 模块的源代码,原因如下。

def importFromPath(self, path, fqname):
    """Import a dotted-name package whose tail is at path. In other words,
    given foo.bar and path/to/foo/bar.py, import foo from path/to/foo then
    bar from path/to/foo/bar, returning bar.
    """
    # find the base dir of the package
    path_parts = os.path.normpath(os.path.abspath(path)).split(os.sep)
    name_parts = fqname.split('.')
    if path_parts[-1] == '__init__.py':
        path_parts.pop()
    path_parts = path_parts[:-(len(name_parts))]
    dir_path = os.sep.join(path_parts)
    # then import fqname starting from that dir
    return self.importFromDir(dir_path, fqname)

def importFromDir(self, dir, fqname):
    """Import a module *only* from path, ignoring sys.path and
    reloading if the version in sys.modules is not the one we want.
    """
    dir = os.path.normpath(os.path.abspath(dir))

在您的情况下,当从 importFromPath 调用 importFromDir 时,'dir' 是 __init__.py 目录的上一级目录。所以这就是为什么将 __init__.py 添加到您的测试中会使 'import a' 工作