当测试目录包含 __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 nosetests
在 test
目录中导致导入错误:
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' 工作
考虑以下项目结构:
a.py
test/
test_a.py
with test_a.py
导入模块 a
:
import a
不出所料,运行ning nosetests
在 test
目录中导致导入错误:
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' 工作