`py.test` and `__init__.py` files

10

我原以为py.test在某种意义上是“独立的”,它会将test_*.py文件“按原样”处理,并且只引入这些文件中指定的模块,而不考虑任何周围的文件。但看起来我错了。下面是我与py.test的对话:

$ ls
__init__.py    test_pytest.py
$ cat __init__.py 
$ cat test_pytest.py 
def test_pytest():
    assert True
$ py.test test_pytest.py 
========================================================= test session starts ==========================================================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 0 items / 1 errors 

================================================================ ERRORS ================================================================
___________________________________________________ ERROR collecting test_pytest.py ____________________________________________________
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/py-1.4.5-py2.7.egg/py/_path/local.py:529: in pyimport
>           mod = __import__(modname, None, None, ['__doc__'])
E           ImportError: No module named test_pytest
======================================================= 1 error in 0.01 seconds ========================================================
$ rm __init__.py 
$ py.test test_pytest.py 
========================================================= test session starts ==========================================================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 1 items 

test_pytest.py .

======================================================= 1 passed in 0.01 seconds =======================================================
$ 

如何让py.test正常工作并仍然拥有__init__.py文件?

更新

在评论中,Holger Krekel问道,父目录的名称是什么。结果发现只有在具有特定父目录名称时(例如与已安装的包之一的名称相同,如distutils),才能复现上述错误。请参见此处:

~/test_min 
$ tree
.
└── distutils
    ├── __init__.py
    └── test_pytest.py

1 directory, 2 files
~/test_min 
$ cat distutils/__init__.py 
~/test_min 
$ cat distutils/test_pytest.py 
def test_pytest():
    assert True
~/test_min 
$ py.test distutils/test_pytest.py 
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 0 items / 1 errors 

=============================== ERRORS ===============================
_____________ ERROR collecting distutils/test_pytest.py ______________
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/py-1.4.5-py2.7.egg/py/_path/local.py:529: in pyimport
>           mod = __import__(modname, None, None, ['__doc__'])
E           ImportError: No module named test_pytest
====================== 1 error in 0.01 seconds =======================
~/test_min 
$ rm distutils/__init__.py 
~/test_min 
$ py.test distutils/test_pytest.py 
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 1 items 

distutils/test_pytest.py .

====================== 1 passed in 0.01 seconds ======================
~/test_min 
$ touch __init__.py
~/test_min 
$ ls
__init__.py distutils
~/test_min 
$ touch distutils/__init__.py
~/test_min 
$ py.test distutils/test_pytest.py 
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 1 items 

distutils/test_pytest.py .

====================== 1 passed in 0.02 seconds ======================
~/test_min 
$ rm __init__.py 
~/test_min 
$ py.test distutils/test_pytest.py 
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 0 items / 1 errors 

=============================== ERRORS ===============================
_____________ ERROR collecting distutils/test_pytest.py ______________
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/py-1.4.5-py2.7.egg/py/_path/local.py:529: in pyimport
>           mod = __import__(modname, None, None, ['__doc__'])
E           ImportError: No module named test_pytest
====================== 1 error in 0.01 seconds =======================
~/test_min 
$ mv distutils foobar
~/test_min 
$ py.test foobar/test_pytest.py 
======================== test session starts =========================
platform darwin -- Python 2.7.2 -- pytest-2.1.3
collected 1 items 

foobar/test_pytest.py .

====================== 1 passed in 0.01 seconds ======================
~/test_min 
$ 

希望这些额外的信息能帮到您。

1
听起来你可能遇到了 Python 包系统的副作用。 - Chris Morgan
如果你包含__init__.py文件并且只输入... $ py.test会发生什么? - jcfollower
看起来在 http://pytest.org/latest/goodpractises.html#package-name 底部可能有关于你的问题的提示。 - jcfollower
就我所知,我在1.3.4版本中没有看到过这种行为。然而,我已经更新到2.2.0版本来尝试一下,但是得到了相同的错误输出。 - jcollado
1
父目录的名称是什么(包含__init__.py文件的那个)?在包含代码的更高级别目录中,是否还涉及其他__init__.py文件? - hpk42
3个回答

17
看起来像是 py.test 使用 py._path.pyimport 来打开你的文件。如果在该目录中存在 __init__.py 文件,它会将你的文件视为一个模块,否则它会打开这个文件。长话短说,删除 __init__.py 或将你的测试放在项目代码之外的另一个目录中(<---好主意)。 https://py.readthedocs.io/en/latest/path.html#py._path.local.LocalPath.pyimport

1
我授予您赏金,以免自动将其授予tito,因为他的答案是不正确的。虽然,我希望在不改变文件结构的情况下解决这个问题。 - Vladimir Keleshev

7
我强烈建议您将目录重命名为不叫做“distutils”的名称。为什么?因为您正在覆盖现有的模块。 当脚本中出现“import distutils”或“from distutils import *”(来自其他导入或您自己的Python文件)时,它会优先选择您的目录而不是系统目录。 如果模块distutils在之前已经被加载过,则不会加载您的distutils,因为该符号已经存在于global()中。 将该目录重命名(例如tests)将比尝试与py.test / Python内部进行斗争更加简单。

distutils只是一个重现错误的示例。我有自己模块的问题,它有不同的名称。 - Vladimir Keleshev
1
好的,最后一个问题。当您在'.'上添加__init__.py时,'.'目录的名称也被视为模块名称。在您的情况下是什么呢?(还要注意一点,即使通过查看您的测试,我不认为您会遇到这个错误,但不要忘记关于pyc生成的事情,当删除py时,pyc仍然存在并且可导入。) - tito
如果你是指当我执行$ touch __init__.py时?就像你可以从上面的那一行看到的那样,在~/test_min目录中完成了。而且,正如你可以从tree命令中看到的那样,我没有任何pyc文件。 - Vladimir Keleshev

4
你可以告诉pytest忽略特定的文件或glob模式,如此处所述。在您的项目根目录中放置一个conftest.py文件,列出您想要pytest忽略的文件即可:

However, many projects will have a setup.py which they don’t want to be imported. Moreover, there may files only importable by a specific python version. For such cases you can dynamically define files to be ignored by listing them in a conftest.py file:

 # content of conftest.py
 import sys

 collect_ignore = ["setup.py"]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接