本地导入点名包进行单元测试
Importing a dotted-name package locally for unit testing
我正在尝试开发和测试一个包 foo.bar。我有以下目录布局:
myproject
setup.py (for package foo.bar)
foo
bar
__init__.py
...
tests
main.py
test_something.py
在 test_something.py 中,我想导入 foo.bar 的本地副本,最好只使用 'import foo.bar'。
在 main.py 我有:
import os
import sys
sys.path.append(
os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import test_something
但是,我得到一个错误:
File "./tests/main.py", line 22, in <module>
import test_something
File "/myproject/tests/test_something.py", line 28, in <module>
import foo.bar
ImportError: No module named bar
可以这样做吗?
如果想让foo
被认为是一个包,需要在foo
目录下直接有一个__init__.py
,可以为空,但是文件需要那里。否则 Python 不会将 foo
视为一个包,你不能做 -
import foo.bar
正如评论中所说 -
In any event I don't want foo to be a package, I want foo.bar to be the package.
这不是直接可能的,因为,除非 foo
是一个 Python 包(或下面解释的命名空间包),否则您不能执行 import foo.bar
。
此处唯一的其他选择是使用 -
将 foo
文件夹直接添加到 sys.path
sys.path.append(
os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'foo')))
然后您必须将其导入为 -
import bar
如果你使用的是 Python 3.3 + ,那么你可以使用 namespace packages
,并且你可以导入 foo.bar
而无需定义foo
.
里面的 __init__.py
这在 - PEP 0420 中有很好的解释,根据规范,python packages/modules(从 3.3 + 开始)的新加载过程是 -
During import processing, the import machinery will continue to iterate over each directory in the parent path as it does in Python 3.2. While looking for a module or package named "foo", for each directory in the parent path:
- If
<directory>/foo/__init__.py
is found, a regular package is imported and returned.
- If not, but
<directory>/foo.{py,pyc,so,pyd}
is found, a module is imported and returned. The exact list of extension varies by platform and whether the -O flag is specified. The list here is representative.
- If not, but
<directory>/foo
is found and is a directory, it is recorded and the scan continues with the next directory in the parent path.
- Otherwise the scan continues with the next directory in the parent path.
If the scan completes without returning a module or package, and at least one directory was recorded, then a namespace package is created. The new namespace package:
- Has a
__path__
attribute set to an iterable of the path strings that were found and recorded during the scan.
- Does not have a
__file__
attribute.
我正在尝试开发和测试一个包 foo.bar。我有以下目录布局:
myproject
setup.py (for package foo.bar)
foo
bar
__init__.py
...
tests
main.py
test_something.py
在 test_something.py 中,我想导入 foo.bar 的本地副本,最好只使用 'import foo.bar'。
在 main.py 我有:
import os
import sys
sys.path.append(
os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import test_something
但是,我得到一个错误:
File "./tests/main.py", line 22, in <module>
import test_something
File "/myproject/tests/test_something.py", line 28, in <module>
import foo.bar
ImportError: No module named bar
可以这样做吗?
如果想让foo
被认为是一个包,需要在foo
目录下直接有一个__init__.py
,可以为空,但是文件需要那里。否则 Python 不会将 foo
视为一个包,你不能做 -
import foo.bar
正如评论中所说 -
In any event I don't want foo to be a package, I want foo.bar to be the package.
这不是直接可能的,因为,除非 foo
是一个 Python 包(或下面解释的命名空间包),否则您不能执行 import foo.bar
。
此处唯一的其他选择是使用 -
将foo
文件夹直接添加到 sys.path
sys.path.append(
os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'foo')))
然后您必须将其导入为 -
import bar
如果你使用的是 Python 3.3 + ,那么你可以使用 namespace packages
,并且你可以导入 foo.bar
而无需定义foo
.
__init__.py
这在 - PEP 0420 中有很好的解释,根据规范,python packages/modules(从 3.3 + 开始)的新加载过程是 -
During import processing, the import machinery will continue to iterate over each directory in the parent path as it does in Python 3.2. While looking for a module or package named "foo", for each directory in the parent path:
- If
<directory>/foo/__init__.py
is found, a regular package is imported and returned.- If not, but
<directory>/foo.{py,pyc,so,pyd}
is found, a module is imported and returned. The exact list of extension varies by platform and whether the -O flag is specified. The list here is representative.- If not, but
<directory>/foo
is found and is a directory, it is recorded and the scan continues with the next directory in the parent path.- Otherwise the scan continues with the next directory in the parent path.
If the scan completes without returning a module or package, and at least one directory was recorded, then a namespace package is created. The new namespace package:
- Has a
__path__
attribute set to an iterable of the path strings that were found and recorded during the scan.- Does not have a
__file__
attribute.