Skip to content

Commit de6f2c0

Browse files
committed
Collect tests from __init__.py files if they match 'python_files'
Fix #3773
1 parent be4b359 commit de6f2c0

File tree

7 files changed

+37
-5
lines changed

7 files changed

+37
-5
lines changed

changelog/3773.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix collection of tests from ``__init__.py`` files if they match the ``python_files`` configuration option.

src/_pytest/pytester.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,9 @@ def copy_example(self, name=None):
672672
example_path.copy(result)
673673
return result
674674
else:
675-
raise LookupError("example is not found as a file or directory")
675+
raise LookupError(
676+
'example "{}" is not found as a file or directory'.format(example_path)
677+
)
676678

677679
Session = Session
678680

src/_pytest/python.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,15 +201,19 @@ def pytest_collect_file(path, parent):
201201
ext = path.ext
202202
if ext == ".py":
203203
if not parent.session.isinitpath(path):
204-
for pat in parent.config.getini("python_files") + ["__init__.py"]:
205-
if path.fnmatch(pat):
206-
break
207-
else:
204+
if not path_matches_patterns(
205+
path, parent.config.getini("python_files") + ["__init__.py"]
206+
):
208207
return
209208
ihook = parent.session.gethookproxy(path)
210209
return ihook.pytest_pycollect_makemodule(path=path, parent=parent)
211210

212211

212+
def path_matches_patterns(path, patterns):
213+
"""Returns True if the given py.path.local matches one of the patterns in the list of globs given"""
214+
return any(path.fnmatch(pattern) for pattern in patterns)
215+
216+
213217
def pytest_pycollect_makemodule(path, parent):
214218
if path.basename == "__init__.py":
215219
return Package(path, parent)
@@ -590,6 +594,11 @@ def collect(self):
590594
self.session.config.pluginmanager._duplicatepaths.remove(path)
591595

592596
this_path = self.fspath.dirpath()
597+
init_module = this_path.join("__init__.py")
598+
if init_module.check(file=1) and path_matches_patterns(
599+
init_module, self.config.getini("python_files")
600+
):
601+
yield Module(init_module, self)
593602
pkg_prefixes = set()
594603
for path in this_path.visit(rec=self._recurse, bf=True, sort=True):
595604
# we will visit our own __init__.py file, in which case we skip it
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[pytest]
2+
python_files = *.py
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def test_init():
2+
pass
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def test_foo():
2+
pass

testing/test_collection.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,3 +938,17 @@ def fix():
938938
"*1 passed, 1 error*",
939939
]
940940
)
941+
942+
943+
def test_collect_init_tests(testdir):
944+
"""Check that we collect files from __init__.py files when they patch the 'python_files' (#3773)"""
945+
p = testdir.copy_example("collect/collect_init_tests")
946+
result = testdir.runpytest(p, "--collect-only")
947+
result.stdout.fnmatch_lines(
948+
[
949+
"*<Module '__init__.py'>",
950+
"*<Function 'test_init'>",
951+
"*<Module 'test_foo.py'>",
952+
"*<Function 'test_foo'>",
953+
]
954+
)

0 commit comments

Comments
 (0)