From bcad8d2a467919c21b99eda27d862d1fd8db3b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Tue, 14 Jul 2026 12:07:37 +0200 Subject: [PATCH] Replace the use of private `monkeypatch` fixture API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the use of private `monkeypatch` API with the standard invocations to fix compatibility with pytest 9.1, as well as to make the tests more reliable in the future. The previous code operated on `monkeypatch` fixture internals to trigger clearing environment variables expected by tests at the beginning of tests, and reverting any changes made by the tests. However, this does not seem strictly valid, and it actually lead to tests making wrong assumptions. For example, `test_disable_dotenv_from_env` relied on a previous test unsetting `FOO` in the environment, and failed if `FOO` was set while it was run alone. The new logic uses public API only: it cleans up the standard set of environment variables for every test, and additionally cleans up variables specifically used by dotenv tests. With this approach, it is entirely possible for a test to leave the environment "dirty"; however, that's fine since other tests need to clean up the environment anyway to account for user-set environment variables. Fixes #6071 Signed-off-by: Michał Górny --- CHANGES.rst | 1 + tests/conftest.py | 43 +++++++++++++------------------------------ tests/test_cli.py | 8 ++++---- 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 232b144a5c..723af0729f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -28,6 +28,7 @@ Unreleased it's disabled in config. Previously, only disabling worked. :issue:`5916` - ``Flask.select_jinja_autoescape`` uses case-insensitive comparison instead of only lower case file extensions. :pr:`6012` +- Fix compatibility with pytest-9.1 by removing use of private API. :issue:`6071` Version 3.1.3 diff --git a/tests/conftest.py b/tests/conftest.py index 0414b9e22f..e7fad0f861 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,43 +2,26 @@ import sys import pytest -from _pytest import monkeypatch from flask import Flask from flask.globals import app_ctx as _app_ctx -@pytest.fixture(scope="session", autouse=True) -def _standard_os_environ(): - """Set up ``os.environ`` at the start of the test session to have - standard values. Returns a list of operations that is used by - :func:`._reset_os_environ` after each test. - """ - mp = monkeypatch.MonkeyPatch() - out = ( - (os.environ, "FLASK_ENV_FILE", monkeypatch.notset), - (os.environ, "FLASK_APP", monkeypatch.notset), - (os.environ, "FLASK_DEBUG", monkeypatch.notset), - (os.environ, "FLASK_RUN_FROM_CLI", monkeypatch.notset), - (os.environ, "WERKZEUG_RUN_MAIN", monkeypatch.notset), - ) - - for _, key, value in out: - if value is monkeypatch.notset: - mp.delenv(key, False) - else: - mp.setenv(key, value) - - yield out - mp.undo() - - @pytest.fixture(autouse=True) -def _reset_os_environ(monkeypatch, _standard_os_environ): - """Reset ``os.environ`` to the standard environ after each test, - in case a test changed something without cleaning up. +def _standard_os_environ(monkeypatch): + """Set up ``os.environ`` at the start of every test to have + standard values. """ - monkeypatch._setitem.extend(_standard_os_environ) + for key in ( + "FLASK_ENV_FILE", + "FLASK_APP", + "FLASK_DEBUG", + "FLASK_RUN_FROM_CLI", + "WERKZEUG_RUN_MAIN", + ): + monkeypatch.delenv(key, False) + + yield @pytest.fixture diff --git a/tests/test_cli.py b/tests/test_cli.py index 2a34088bd5..f3b9a8504d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -11,7 +11,6 @@ import click import pytest -from _pytest.monkeypatch import notset from click.testing import CliRunner from flask import Blueprint @@ -535,9 +534,8 @@ def dotenv_not_available(): @need_dotenv def test_load_dotenv(monkeypatch): - # can't use monkeypatch.delitem since the keys don't exist yet for item in ("FOO", "BAR", "SPAM", "HAM"): - monkeypatch._setitem.append((os.environ, item, notset)) + monkeypatch.delenv(item, False) monkeypatch.setenv("EGGS", "3") monkeypatch.chdir(test_path) @@ -560,7 +558,7 @@ def test_load_dotenv(monkeypatch): @need_dotenv def test_dotenv_path(monkeypatch): for item in ("FOO", "BAR", "EGGS"): - monkeypatch._setitem.append((os.environ, item, notset)) + monkeypatch.delenv(item, False) load_dotenv(test_path / ".flaskenv") assert Path.cwd() == cwd @@ -568,6 +566,7 @@ def test_dotenv_path(monkeypatch): def test_dotenv_optional(monkeypatch): + monkeypatch.delenv("FOO", False) monkeypatch.setitem(sys.modules, "dotenv", None) monkeypatch.chdir(test_path) load_dotenv() @@ -576,6 +575,7 @@ def test_dotenv_optional(monkeypatch): @need_dotenv def test_disable_dotenv_from_env(monkeypatch, runner): + monkeypatch.delenv("FOO", False) monkeypatch.chdir(test_path) monkeypatch.setitem(os.environ, "FLASK_SKIP_DOTENV", "1") runner.invoke(FlaskGroup())