Skip to content

Commit 6eee1c4

Browse files
authored
test,fix: Force pytest to exit zero when no tests are collected (#221)
* fix: Prevent pytest from exiting non-zero when there are no changed samples pytest considers a failure to collect any tests as an error to be investigated. In the context of "only running pytest tests for changed samples", we'd expect this to happen somewhat commonly. This PR makes pytest exit OK when no tests were collected if this plugin is active. * docs: Fix docstrings
1 parent 473b69a commit 6eee1c4

File tree

1 file changed

+27
-4
lines changed
  • .infra/pytest_plugins/changed_samples/src/pytest_changed_samples

1 file changed

+27
-4
lines changed

.infra/pytest_plugins/changed_samples/src/pytest_changed_samples/plugin.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
PR_CHANGES_OPTION = "--changed-samples-only-from"
1414

1515

16+
def is_plugin_active(config: pytest.Config) -> bool:
17+
"""Return whether any of the plugin provided options were provided on commandline."""
18+
return get_diff_paths_function(config) is not None
19+
20+
1621
def pytest_addoption(parser: pytest.Parser) -> None:
1722
parser.addoption(
1823
WORKING_TREE_CHANGES_OPTION,
@@ -42,10 +47,18 @@ def pytest_configure(config: pytest.Config) -> None:
4247

4348
@pytest.hookimpl(hookwrapper=True)
4449
def pytest_collection(session: pytest.Session) -> None:
50+
"""Set up path filtering based on git diff."""
4551
config = session.config
4652
diff_path_trie = Trie()
4753

48-
for p in get_diff_paths_function(config)():
54+
paths_filter = get_diff_paths_function(config)
55+
56+
if paths_filter is None:
57+
# Exit early if there's no path filter
58+
yield
59+
return
60+
61+
for p in paths_filter():
4962
diff_path_trie.insert(p.parts)
5063

5164
config.stash[DIFF_PATH_TRIE_KEY] = diff_path_trie
@@ -56,8 +69,9 @@ def pytest_collection(session: pytest.Session) -> None:
5669

5770

5871
def pytest_ignore_collect(collection_path: Path, config: pytest.Config) -> Optional[bool]:
72+
"""Ignore paths that were not touched by the current git diff."""
5973
if DIFF_PATH_TRIE_KEY not in config.stash:
60-
# Occures when calling `pytest --fixtures`
74+
# Occurs when calling `pytest --fixtures`
6175
return None
6276

6377
diff_path_trie = config.stash[DIFF_PATH_TRIE_KEY]
@@ -72,7 +86,16 @@ def pytest_ignore_collect(collection_path: Path, config: pytest.Config) -> Optio
7286
return (not diff_path_trie.is_prefix(ignore_dir.resolve().parts)) or None
7387

7488

75-
def get_diff_paths_function(config: pytest.Config) -> Callable[[], Iterable[Path]]:
89+
@pytest.hookimpl(trylast=True)
90+
def pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None:
91+
if not is_plugin_active(session.config):
92+
return
93+
94+
if exitstatus == pytest.ExitCode.NO_TESTS_COLLECTED:
95+
session.exitstatus = pytest.ExitCode.OK
96+
97+
98+
def get_diff_paths_function(config: pytest.Config) -> Optional[Callable[[], Iterable[Path]]]:
7699
"""Get the function that returns paths present in a diff specfied by cmdline arguments
77100
78101
:param pytest.Config config: The pytest config
@@ -87,7 +110,7 @@ def get_diff_paths_function(config: pytest.Config) -> Callable[[], Iterable[Path
87110
if ref := config.getoption(opt_var(PR_CHANGES_OPTION)):
88111
return lambda: get_branch_diff_paths(ref)
89112

90-
return lambda: ()
113+
return None
91114

92115

93116
def opt_var(s: str) -> str:

0 commit comments

Comments
 (0)