From d65f300988be1b1cfc0a98254da4aa8c75fe45e2 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 25 Oct 2018 20:03:14 +0200 Subject: [PATCH 1/5] Move handling of duplicate files This removes the hack added in https://github.com/pytest-dev/pytest/pull/3802. Adjusts test: - it appears to not have been changed to 7 intentionally. - removes XXX comment, likely not relevant anymore since 6dac7743. --- src/_pytest/main.py | 19 ++++++++++--------- src/_pytest/python.py | 9 --------- testing/test_session.py | 2 +- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index f27270f26..7e5d096a5 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -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 @@ -559,6 +550,16 @@ class Session(nodes.FSCollector): 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): diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 58f95034d..414eabec6 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -552,15 +552,6 @@ class Package(Module): 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( diff --git a/testing/test_session.py b/testing/test_session.py index 6225a2c0d..c1785b916 100644 --- a/testing/test_session.py +++ b/testing/test_session.py @@ -219,7 +219,7 @@ class TestNewSession(SessionTests): 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 From 70976b04be195b6ae6fc9a74811429148479a83c Mon Sep 17 00:00:00 2001 From: Mick Koch Date: Wed, 31 Oct 2018 14:18:12 -0400 Subject: [PATCH 2/5] Add test for __init__.py collection with package directory as argument --- testing/test_collection.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/testing/test_collection.py b/testing/test_collection.py index 7f6791dae..58f4afb38 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -957,6 +957,15 @@ def test_collect_init_tests(testdir): "*", ] ) + result = testdir.runpytest("./tests", "--collect-only") + result.stdout.fnmatch_lines( + [ + "*", + "*", + "*", + "*", + ] + ) def test_collect_invalid_signature_message(testdir): From 320e41b142f14e5b864131e30f4c18bdf29199c6 Mon Sep 17 00:00:00 2001 From: Mick Koch Date: Thu, 1 Nov 2018 08:20:01 -0400 Subject: [PATCH 3/5] Add failing test for __init__.py also including other package files --- testing/test_collection.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testing/test_collection.py b/testing/test_collection.py index 58f4afb38..06f8d40ee 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -966,6 +966,12 @@ def test_collect_init_tests(testdir): "*", ] ) + result = testdir.runpytest("./tests/test_foo.py", "--collect-only") + result.stdout.fnmatch_lines(["*", "*"]) + assert "test_init" not in result.stdout.str() + result = testdir.runpytest("./tests/__init__.py", "--collect-only") + result.stdout.fnmatch_lines(["*", "*"]) + assert "test_foo" not in result.stdout.str() def test_collect_invalid_signature_message(testdir): From 5ac4eff09b8514a5b46bdff464605a60051abc83 Mon Sep 17 00:00:00 2001 From: Mick Koch Date: Thu, 1 Nov 2018 08:20:57 -0400 Subject: [PATCH 4/5] Fix __init__.py as argument also including other package files --- src/_pytest/main.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 7e5d096a5..2bb405081 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -542,7 +542,15 @@ class Session(nodes.FSCollector): 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): From 51973543754b0f1149fcf36298bb47e82ccc9ead Mon Sep 17 00:00:00 2001 From: Mick Koch Date: Thu, 1 Nov 2018 08:51:51 -0400 Subject: [PATCH 5/5] Add changelog entry --- changelog/4046.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/4046.bugfix.rst diff --git a/changelog/4046.bugfix.rst b/changelog/4046.bugfix.rst new file mode 100644 index 000000000..2b0da70cd --- /dev/null +++ b/changelog/4046.bugfix.rst @@ -0,0 +1 @@ +Fix problems with running tests in package ``__init__.py`` files.