在本地导入点名包以进行单元测试

时间:2015-08-31 18:43:25

标签: python python-import

我正在尝试开发和测试包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

是否可以这样做?

1 个答案:

答案 0 :(得分:1)

如果您希望foo被视为一个包,则需要在__init__.py目录下直接有foo,它可以为空,但文件需要在那里。否则Python不会将foo视为一个包,你不能这样做 -

import foo.bar

如评论中所述 -

  

无论如何我不希望foo成为一个包,我希望foo.bar成为包。

这不是直接可能的,因为除非import foo.bar是Python包(或下面解释的命名空间包),否则不能foo

此处唯一的另一种选择是使用 -

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,而无需在__init__.py内定义foo 1}}。

这在 - PEP 0420中有很好的解释,根据规范,python包/模块(来自3.3 +)的新的编码过程是 -

  

在导入处理期间,导入机制将继续迭代父路径中的每个目录,就像在Python 3.2中一样。在寻找名为“foo”的模块或包时,对于父路径中的每个目录:

     
      
  • 如果找到<directory>/foo/__init__.py,则会导入并返回常规包。
  •   
  • 如果没有,但找到<directory>/foo.{py,pyc,so,pyd},则会导入并返回模块。扩展名的确切列表因平台而异,是否指定了-O标志。这里的清单具有代表性。
  •   
  • 如果没有,但找到<directory>/foo并且是目录,则会记录该目录,并继续扫描父路径中的下一个目录。
  •   
  • 否则,扫描将继续执行父路径中的下一个目录。
  •   
     

如果扫描完成而未返回模块或包,并且至少记录了一个目录,则会创建命名空间包。新的命名空间包:

     
      
  • __path__属性设置为扫描期间找到并记录的可迭代路径字符串。
  •   
  • 没有__file__属性。
  •