python: change `pytest pkg/__init__.py` to only collect the `__init__.py` Module
Previously it would collect the entire package, but this is not what users expect. Refs #3749 Fixes #8976 Fixes #9263 Fixes #9313
This commit is contained in:
		
							parent
							
								
									2870157234
								
							
						
					
					
						commit
						c8b1790ee7
					
				|  | @ -0,0 +1,5 @@ | |||
| Running `pytest pkg/__init__.py` now collects the `pkg/__init__.py` file (module) only. | ||||
| Previously, it collected the entire `pkg` package, including other test files in the directory, but excluding tests in the `__init__.py` file itself | ||||
| (unless :confval:`python_files` was changed to allow `__init__.py` file). | ||||
| 
 | ||||
| To collect the entire package, specify just the directory: `pytest pkg`. | ||||
|  | @ -467,12 +467,26 @@ The ``yield_fixture`` function/decorator | |||
| It has been so for a very long time, so can be search/replaced safely. | ||||
| 
 | ||||
| 
 | ||||
| Removed Features | ||||
| ---------------- | ||||
| Removed Features and Breaking Changes | ||||
| ------------------------------------- | ||||
| 
 | ||||
| As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after | ||||
| an appropriate period of deprecation has passed. | ||||
| 
 | ||||
| Some breaking changes which could not be deprecated are also listed. | ||||
| 
 | ||||
| 
 | ||||
| Collecting ``__init__.py`` files no longer collects package | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| 
 | ||||
| .. versionremoved:: 8.0 | ||||
| 
 | ||||
| Running `pytest pkg/__init__.py` now collects the `pkg/__init__.py` file (module) only. | ||||
| Previously, it collected the entire `pkg` package, including other test files in the directory, but excluding tests in the `__init__.py` file itself | ||||
| (unless :confval:`python_files` was changed to allow `__init__.py` file). | ||||
| 
 | ||||
| To collect the entire package, specify just the directory: `pytest pkg`. | ||||
| 
 | ||||
| 
 | ||||
| The ``pytest.collect`` module | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  |  | |||
|  | @ -736,7 +736,9 @@ class Package(Module): | |||
|         this_path = self.path.parent | ||||
| 
 | ||||
|         # Always collect the __init__ first. | ||||
|         if path_matches_patterns(self.path, self.config.getini("python_files")): | ||||
|         if self.session.isinitpath(self.path) or path_matches_patterns( | ||||
|             self.path, self.config.getini("python_files") | ||||
|         ): | ||||
|             yield Module.from_parent(self, path=self.path) | ||||
| 
 | ||||
|         pkg_prefixes: Set[Path] = set() | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| def test_init(): | ||||
|     pass | ||||
|  | @ -1,2 +1,2 @@ | |||
| def test(): | ||||
| def test_foo(): | ||||
|     pass | ||||
|  |  | |||
|  | @ -1420,10 +1420,15 @@ def test_package_collection_infinite_recursion(pytester: Pytester) -> None: | |||
| 
 | ||||
| 
 | ||||
| def test_package_collection_init_given_as_argument(pytester: Pytester) -> None: | ||||
|     """Regression test for #3749""" | ||||
|     """Regression test for #3749, #8976, #9263, #9313. | ||||
| 
 | ||||
|     Specifying an __init__.py file directly should collect only the __init__.py | ||||
|     Module, not the entire package. | ||||
|     """ | ||||
|     p = pytester.copy_example("collect/package_init_given_as_arg") | ||||
|     result = pytester.runpytest(p / "pkg" / "__init__.py") | ||||
|     result.stdout.fnmatch_lines(["*1 passed*"]) | ||||
|     items, hookrecorder = pytester.inline_genitems(p / "pkg" / "__init__.py") | ||||
|     assert len(items) == 1 | ||||
|     assert items[0].name == "test_init" | ||||
| 
 | ||||
| 
 | ||||
| def test_package_with_modules(pytester: Pytester) -> None: | ||||
|  |  | |||
|  | @ -1392,19 +1392,27 @@ def test_collect_pkg_init_and_file_in_args(pytester: Pytester) -> None: | |||
|     p = subdir.joinpath("test_file.py") | ||||
|     p.write_text("def test_file(): pass", encoding="utf-8") | ||||
| 
 | ||||
|     # NOTE: without "-o python_files=*.py" this collects test_file.py twice. | ||||
|     # This changed/broke with "Add package scoped fixtures #2283" (2b1410895) | ||||
|     # initially (causing a RecursionError). | ||||
|     result = pytester.runpytest("-v", str(init), str(p)) | ||||
|     # Just the package directory, the __init__.py module is filtered out. | ||||
|     result = pytester.runpytest("-v", subdir) | ||||
|     result.stdout.fnmatch_lines( | ||||
|         [ | ||||
|             "sub/test_file.py::test_file PASSED*", | ||||
|             "*1 passed in*", | ||||
|         ] | ||||
|     ) | ||||
| 
 | ||||
|     # But it's included if specified directly. | ||||
|     result = pytester.runpytest("-v", init, p) | ||||
|     result.stdout.fnmatch_lines( | ||||
|         [ | ||||
|             "sub/__init__.py::test_init PASSED*", | ||||
|             "sub/test_file.py::test_file PASSED*", | ||||
|             "*2 passed in*", | ||||
|         ] | ||||
|     ) | ||||
| 
 | ||||
|     result = pytester.runpytest("-v", "-o", "python_files=*.py", str(init), str(p)) | ||||
|     # Or if the pattern allows it. | ||||
|     result = pytester.runpytest("-v", "-o", "python_files=*.py", subdir) | ||||
|     result.stdout.fnmatch_lines( | ||||
|         [ | ||||
|             "sub/__init__.py::test_init PASSED*", | ||||
|  | @ -1419,10 +1427,13 @@ def test_collect_pkg_init_only(pytester: Pytester) -> None: | |||
|     init = subdir.joinpath("__init__.py") | ||||
|     init.write_text("def test_init(): pass", encoding="utf-8") | ||||
| 
 | ||||
|     result = pytester.runpytest(str(init)) | ||||
|     result = pytester.runpytest(subdir) | ||||
|     result.stdout.fnmatch_lines(["*no tests ran in*"]) | ||||
| 
 | ||||
|     result = pytester.runpytest("-v", "-o", "python_files=*.py", str(init)) | ||||
|     result = pytester.runpytest("-v", init) | ||||
|     result.stdout.fnmatch_lines(["sub/__init__.py::test_init PASSED*", "*1 passed in*"]) | ||||
| 
 | ||||
|     result = pytester.runpytest("-v", "-o", "python_files=*.py", subdir) | ||||
|     result.stdout.fnmatch_lines(["sub/__init__.py::test_init PASSED*", "*1 passed in*"]) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -114,7 +114,7 @@ class TestDoctests: | |||
|         reprec.assertoutcome(failed=1) | ||||
| 
 | ||||
|     def test_importmode(self, pytester: Pytester): | ||||
|         p = pytester.makepyfile( | ||||
|         pytester.makepyfile( | ||||
|             **{ | ||||
|                 "namespacepkg/innerpkg/__init__.py": "", | ||||
|                 "namespacepkg/innerpkg/a.py": """ | ||||
|  | @ -132,7 +132,7 @@ class TestDoctests: | |||
|                 """, | ||||
|             } | ||||
|         ) | ||||
|         reprec = pytester.inline_run(p, "--doctest-modules", "--import-mode=importlib") | ||||
|         reprec = pytester.inline_run("--doctest-modules", "--import-mode=importlib") | ||||
|         reprec.assertoutcome(passed=1) | ||||
| 
 | ||||
|     def test_new_pattern(self, pytester: Pytester): | ||||
|  |  | |||
|  | @ -504,7 +504,7 @@ def test_nose_setup_skipped_if_non_callable(pytester: Pytester) -> None: | |||
|             pass | ||||
|         """, | ||||
|     ) | ||||
|     result = pytester.runpytest(p, "-p", "nose") | ||||
|     result = pytester.runpytest(p.parent, "-p", "nose") | ||||
|     assert result.ret == 0 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue