Skip to content

Commit

Permalink
Merge pull request #4285 from kchmck/fix-4046
Browse files Browse the repository at this point in the history
Fix problems with running tests in package `__init__` files (#4046)
  • Loading branch information
nicoddemus committed Nov 2, 2018
2 parents 48f52b1 + 5197354 commit 21725e9
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 20 deletions.
1 change: 1 addition & 0 deletions changelog/4046.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix problems with running tests in package ``__init__.py`` files.
29 changes: 19 additions & 10 deletions src/_pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,15 +281,6 @@ def pytest_ignore_collect(path, config):
if _in_venv(path) and not allow_in_venv:
return True

# Skip duplicate paths.
keepduplicates = config.getoption("keepduplicates")
duplicate_paths = config.pluginmanager._duplicatepaths
if not keepduplicates:
if path in duplicate_paths:
return True
else:
duplicate_paths.add(path)

return False


Expand Down Expand Up @@ -551,14 +542,32 @@ def _collect(self, arg):
col = root._collectfile(argpath)
if col:
self._node_cache[argpath] = col
for y in self.matchnodes(col, names):
m = self.matchnodes(col, names)
# If __init__.py was the only file requested, then the matched node will be
# the corresponding Package, and the first yielded item will be the __init__
# Module itself, so just use that. If this special case isn't taken, then all
# the files in the package will be yielded.
if argpath.basename == "__init__.py":
yield next(m[0].collect())
return
for y in m:
yield y

def _collectfile(self, path):
ihook = self.gethookproxy(path)
if not self.isinitpath(path):
if ihook.pytest_ignore_collect(path=path, config=self.config):
return ()

# Skip duplicate paths.
keepduplicates = self.config.getoption("keepduplicates")
if not keepduplicates:
duplicate_paths = self.config.pluginmanager._duplicatepaths
if path in duplicate_paths:
return ()
else:
duplicate_paths.add(path)

return ihook.pytest_collect_file(path=path, parent=self)

def _recurse(self, path):
Expand Down
9 changes: 0 additions & 9 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,15 +553,6 @@ def isinitpath(self, path):
return path in self.session._initialpaths

def collect(self):
# XXX: HACK!
# Before starting to collect any files from this package we need
# to cleanup the duplicate paths added by the session's collect().
# Proper fix is to not track these as duplicates in the first place.
for path in list(self.session.config.pluginmanager._duplicatepaths):
# if path.parts()[:len(self.fspath.dirpath().parts())] == self.fspath.dirpath().parts():
if path.dirname.startswith(self.name):
self.session.config.pluginmanager._duplicatepaths.remove(path)

this_path = self.fspath.dirpath()
init_module = this_path.join("__init__.py")
if init_module.check(file=1) and path_matches_patterns(
Expand Down
15 changes: 15 additions & 0 deletions testing/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,21 @@ def test_collect_init_tests(testdir):
"*<Function 'test_foo'>",
]
)
result = testdir.runpytest("./tests", "--collect-only")
result.stdout.fnmatch_lines(
[
"*<Module '__init__.py'>",
"*<Function 'test_init'>",
"*<Module 'test_foo.py'>",
"*<Function 'test_foo'>",
]
)
result = testdir.runpytest("./tests/test_foo.py", "--collect-only")
result.stdout.fnmatch_lines(["*<Module 'test_foo.py'>", "*<Function 'test_foo'>"])
assert "test_init" not in result.stdout.str()
result = testdir.runpytest("./tests/__init__.py", "--collect-only")
result.stdout.fnmatch_lines(["*<Module '__init__.py'>", "*<Function 'test_init'>"])
assert "test_foo" not in result.stdout.str()


def test_collect_invalid_signature_message(testdir):
Expand Down
2 changes: 1 addition & 1 deletion testing/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ class TestY(TestX):
started = reprec.getcalls("pytest_collectstart")
finished = reprec.getreports("pytest_collectreport")
assert len(started) == len(finished)
assert len(started) == 7 # XXX extra TopCollector
assert len(started) == 8
colfail = [x for x in finished if x.failed]
assert len(colfail) == 1

Expand Down

0 comments on commit 21725e9

Please sign in to comment.