From b2ce3eb68097b0c763a003b9b3a9a478603c5525 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Thu, 18 Dec 2025 09:46:02 -0500 Subject: [PATCH 1/3] feat(testing): auto-clean the user's test env Inspiration: https://github.com/canonical/craft-application/pull/980#discussion_r2628068357 --- craft_application/pytest_plugin.py | 26 ++++++++++++++++++++++++-- docs/reference/changelog.rst | 7 +++++++ docs/reference/pytest-plugin.rst | 2 ++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/craft_application/pytest_plugin.py b/craft_application/pytest_plugin.py index 052631a58..240b132a1 100644 --- a/craft_application/pytest_plugin.py +++ b/craft_application/pytest_plugin.py @@ -25,6 +25,7 @@ from craft_parts import callbacks from craft_application import util +from craft_application._const import CRAFT_DEBUG_ENV from craft_application.util import platforms if TYPE_CHECKING: @@ -33,6 +34,27 @@ from pyfakefs.fake_filesystem import FakeFilesystem +@pytest.fixture(autouse=True, scope="session") +def reset_craft_environment() -> Iterator[None]: + """Reset any relevant environment variables during testing. + + This clears any ``CRAFT_*`` or ``SNAP_*`` environment variables that are set + in the environment. To keep an environment variable while running tests for + debugging purposes, put its name in the environment variable + ``CRAFT_DEBUG_KEEP_ENV_VARS``, which is a comma-separated list of variables. + """ + keep_vars = set(os.environ.get("CRAFT_DEBUG_KEEP_ENV_VARS", "").split()) + keep_vars.add(CRAFT_DEBUG_ENV) # We separately set CRAFT_DEBUG. + + with pytest.MonkeyPatch.context() as monkeypatch: + for var in os.environ: + if var in keep_vars: + continue + if var.startswith(("CRAFT_", "SNAP_")): + monkeypatch.delenv(var, raising=False) + yield + + @pytest.fixture(autouse=True, scope="session") def debug_mode() -> None: """Ensure that the application is in debug mode, raising exceptions from run(). @@ -40,7 +62,7 @@ def debug_mode() -> None: This fixture is automatically used. To disable debug mode for specific tests, use the :py:func:`production_mode` fixture. """ - os.environ["CRAFT_DEBUG"] = "1" + os.environ[CRAFT_DEBUG_ENV] = "1" @pytest.fixture @@ -51,7 +73,7 @@ def production_mode(monkeypatch: pytest.MonkeyPatch) -> None: It should only be used if the application needs to test behaviour that differs between debug mode and production mode. """ - monkeypatch.setenv("CRAFT_DEBUG", "0") + monkeypatch.setenv(CRAFT_DEBUG_ENV, "0") @pytest.fixture diff --git a/docs/reference/changelog.rst b/docs/reference/changelog.rst index 2c3f4fcac..bd38e60cc 100644 --- a/docs/reference/changelog.rst +++ b/docs/reference/changelog.rst @@ -24,6 +24,13 @@ Application - If a lifecycle command is run with ``--destructive-mode``, but without root, a warning will be emitted about potentially unexpected behavior. +Pytest plugin +============= + +- The pytest plugin now includes an auto-used + :py:func:`~craft_application.pytest_plugin.reset_craft_environment` fixture to prevent + relevant externally-set environment variables from causing test failures. + For a complete list of commits, check out the `6.1.0`_ release on GitHub. 6.0.1 (2025-11-19) diff --git a/docs/reference/pytest-plugin.rst b/docs/reference/pytest-plugin.rst index 743352147..bc1d95f49 100644 --- a/docs/reference/pytest-plugin.rst +++ b/docs/reference/pytest-plugin.rst @@ -31,6 +31,8 @@ Some fixtures are automatically enabled for tests, changing the default behaviou applications during the testing process. Each auto-use fixture changes the default behaviour of Craft Application during testing. +.. autofunction:: reset_craft_environment + .. autofunction:: debug_mode .. autofunction:: _reset_craft_parts_callbacks From de8f1a0697a9c77cf1af7bd7a9122ee3bbc79fd5 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Thu, 18 Dec 2025 10:48:36 -0500 Subject: [PATCH 2/3] fix: pr suggestion --- craft_application/pytest_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/craft_application/pytest_plugin.py b/craft_application/pytest_plugin.py index 240b132a1..b296afc74 100644 --- a/craft_application/pytest_plugin.py +++ b/craft_application/pytest_plugin.py @@ -50,7 +50,7 @@ def reset_craft_environment() -> Iterator[None]: for var in os.environ: if var in keep_vars: continue - if var.startswith(("CRAFT_", "SNAP_")): + if var.startswith(("CRAFT_", "SNAP_")) or var == "SNAP": monkeypatch.delenv(var, raising=False) yield From b3cd875aec74d5f52a186ac6df8ff90b1aef7240 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Thu, 18 Dec 2025 14:07:07 -0500 Subject: [PATCH 3/3] fix: Update craft_application/pytest_plugin.py Co-authored-by: Imani Pelton Signed-off-by: Alex Lowe --- craft_application/pytest_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/craft_application/pytest_plugin.py b/craft_application/pytest_plugin.py index b296afc74..8f4c45410 100644 --- a/craft_application/pytest_plugin.py +++ b/craft_application/pytest_plugin.py @@ -43,7 +43,7 @@ def reset_craft_environment() -> Iterator[None]: debugging purposes, put its name in the environment variable ``CRAFT_DEBUG_KEEP_ENV_VARS``, which is a comma-separated list of variables. """ - keep_vars = set(os.environ.get("CRAFT_DEBUG_KEEP_ENV_VARS", "").split()) + keep_vars = set(os.environ.get("CRAFT_DEBUG_KEEP_ENV_VARS", "").split(",")) keep_vars.add(CRAFT_DEBUG_ENV) # We separately set CRAFT_DEBUG. with pytest.MonkeyPatch.context() as monkeypatch: