Fix awxkit config monkeypatching under pytest 9.2 (#16763)

Use monkeypatch.setitem for awxkit config in tests

awxkit's `config` is a PseudoNamespace, a dict subclass that exposes
its keys as attributes. pytest 9.2.0 changed monkeypatch.setattr to
read the previous value from the target's __dict__ instead of via
getattr, so for a dict-backed namespace it always records the attribute
as "did not exist" and schedules a delattr on undo. Patching the same
key twice (autouse fixture plus test body) then deletes it twice, and
PseudoNamespace.__delattr__ raises KeyError at teardown. This breaks
13 tests in test/cli/test_authentication.py on pytest >= 9.2.0.

monkeypatch.setitem records the old value with dict.get, which sees the
dict-backed storage correctly, so undo restores or removes exactly what
was there on any pytest version. test/api/pages/test_base.py is updated
for the same reason: under 9.2.0 its undo would delete a pre-existing
base_url or credentials value instead of restoring it.


Claude-Session: https://claude.ai/code/session_01SbeYPdRRLaGCk74gJHq9yS

Signed-off-by: Hao Liu <44379968+TheRealHaoLiu@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Hao Liu
2026-10-28 22:27:06 +00:00
committed by GitHub
co-authored by Claude Fable 5.1
parent b6a16ac82a
commit 8565291e43
2 changed files with 9 additions and 9 deletions
+2 -2
View File
@@ -6,8 +6,8 @@ from awxkit.config import config
@pytest.fixture(autouse=True)
def setup_config(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(config, "credentials", {"default": {"username": "foo", "password": "bar"}}, raising=False)
monkeypatch.setattr(config, "base_url", "", raising=False)
monkeypatch.setitem(config, "credentials", {"default": {"username": "foo", "password": "bar"}})
monkeypatch.setitem(config, "base_url", "")
@pytest.fixture
+7 -7
View File
@@ -9,8 +9,8 @@ from awxkit import config
@pytest.fixture(autouse=True)
def reset_config_state(monkeypatch: pytest.MonkeyPatch) -> None:
"""Ensure clean config state for each test to prevent parallel test interference"""
monkeypatch.setattr(config, 'force_basic_auth', False, raising=False)
monkeypatch.setattr(config, 'use_sessions', False, raising=False)
monkeypatch.setitem(config, 'force_basic_auth', False)
monkeypatch.setitem(config, 'use_sessions', False)
# ============================================================================
@@ -47,7 +47,7 @@ def setup_session_auth(cli_args: Optional[List[str]] = None) -> Tuple[CLI, Mock,
def test_basic_auth_enabled(monkeypatch):
"""Test that AWXKIT_FORCE_BASIC_AUTH=true enables Basic authentication"""
cli, mock_root, mock_connection = setup_basic_auth()
monkeypatch.setattr(config, 'force_basic_auth', True)
monkeypatch.setitem(config, 'force_basic_auth', True)
cli.authenticate()
mock_connection.login.assert_called_once_with('testuser', 'testpass')
@@ -58,7 +58,7 @@ def test_basic_auth_enabled(monkeypatch):
def test_session_auth_default(monkeypatch):
"""Test that session auth is used by default (backward compatibility)"""
cli, mock_root, mock_load_session = setup_session_auth()
monkeypatch.setattr(config, 'force_basic_auth', False)
monkeypatch.setitem(config, 'force_basic_auth', False)
cli.authenticate()
mock_root.load_session.assert_called_once()
@@ -71,7 +71,7 @@ def test_aap_gateway_scenario(monkeypatch):
cli, mock_root, mock_connection = setup_basic_auth(
['awx', '--conf.host', 'https://aap-sbx.cambiahealth.com', '--conf.username', 'puretest', '--conf.password', 'testpass']
)
monkeypatch.setattr(config, 'force_basic_auth', True)
monkeypatch.setitem(config, 'force_basic_auth', True)
cli.authenticate()
mock_connection.login.assert_called_once_with('puretest', 'testpass')
@@ -82,7 +82,7 @@ def test_aap_gateway_scenario(monkeypatch):
def test_empty_credentials_error(monkeypatch):
"""Test error handling for explicitly empty credentials"""
cli, mock_root, mock_connection = setup_basic_auth(['awx', '--conf.username', '', '--conf.password', ''])
monkeypatch.setattr(config, 'force_basic_auth', True)
monkeypatch.setitem(config, 'force_basic_auth', True)
with pytest.raises(ValueError, match="Basic authentication requires both username and password"):
cli.authenticate()
@@ -94,7 +94,7 @@ def test_connection_failure(monkeypatch):
"""Test error handling when Basic auth connection fails"""
cli, mock_root, mock_connection = setup_basic_auth()
mock_connection.login.side_effect = Exception("Connection failed")
monkeypatch.setattr(config, 'force_basic_auth', True)
monkeypatch.setitem(config, 'force_basic_auth', True)
with pytest.raises(RuntimeError, match="Basic authentication failed: Connection failed"):
cli.authenticate()