当测试目录包含__init__.py时,为什么导入适用于Python?

时间:2015-06-05 17:32:40

标签: python nose

考虑以下项目结构:

a.py
test/
  test_a.py

使用test_a.py导入模块a

import a

正如预期的那样,在nosetests目录中运行test会导致导入错误:

ERROR: Failure: ImportError (No module named a)

但是,我注意到在__init__.py目录中添加一个空test文件会导致导入与nosetests一起使用(但在使用Python运行test_a.py时则不行)。你能解释一下原因吗?

我了解添加__init__.py会使test成为一个包。但这是否意味着import包含查找中包含包的目录?

2 个答案:

答案 0 :(得分:5)

目录中存在__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和不包含sys.path

注意:它是测试运行者,python test_a.py。这在the second "Note" of this section here中有记录(感谢@davidism)。只要在包含和不包含包结构的情况下运行\(([^)]*?)\) ,您就不会看到任何变化。

答案 1 :(得分:2)

我查看了鼻子模块的源代码,这就是原因。

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的原因是“导入”'工作