From dccf1f9e333f3482a15105ab33c722872305b96f Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sun, 26 Apr 2026 17:40:46 +0200 Subject: [PATCH] Reset marker config during unconfigure --- CHANGELOG.md | 3 +++ src/_pytask/mark/__init__.py | 6 ++++++ tests/test_mark.py | 21 +++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cffc86b..8f08448e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ releases are available on [PyPI](https://pypi.org/project/pytask) and ## Unreleased +- [#868](https://github.com/pytask-dev/pytask/pull/868) resets the global marker + configuration during unconfigure so `--strict-markers` no longer leaks into later + marker access in the same process. - [#837](https://github.com/pytask-dev/pytask/pull/837) skips incremental live rendering on non-interactive output while preserving the final build table and live-manager lifecycle. diff --git a/src/_pytask/mark/__init__.py b/src/_pytask/mark/__init__.py index 03e23dd9..8864d0f1 100644 --- a/src/_pytask/mark/__init__.py +++ b/src/_pytask/mark/__init__.py @@ -111,6 +111,12 @@ def pytask_parse_config(config: dict[str, Any]) -> None: MARK_GEN.config = config +@hookimpl +def pytask_unconfigure() -> None: + """Reset marker state after pytask is done.""" + MARK_GEN.config = None + + @hookimpl def pytask_post_parse(config: dict[str, Any]) -> None: config["markers"] = parse_markers(config["markers"]) diff --git a/tests/test_mark.py b/tests/test_mark.py index 83d629bd..794d64e5 100644 --- a/tests/test_mark.py +++ b/tests/test_mark.py @@ -355,6 +355,27 @@ def task_write_text(): ... assert "Unknown pytask.mark.unknown" in result.output +@pytest.mark.filterwarnings("ignore:Unknown pytask\\.mark\\.foo") +def test_strict_markers_do_not_leak_after_unconfigure(runner, tmp_path): + source = """ + from pytask import mark + + @mark.unknown + def task_write_text(): ... + """ + tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) + result = runner.invoke(cli, [tmp_path.as_posix(), "--strict-markers"]) + assert result.exit_code == ExitCode.COLLECTION_FAILED + + # If the strict config leaked through MARK_GEN.config, this unknown marker would + # raise instead of warning and returning a MarkDecorator. + md = pytask.mark.foo(1, "2", three=3) + + assert md.name == "foo" + assert md.args == (1, "2") + assert md.kwargs == {"three": 3} + + @pytest.mark.parametrize("name", ["parametrize", "depends_on", "produces", "task"]) def test_error_with_deprecated_markers(runner, tmp_path, name): source = f"""