Skip to content

Commit e52b7f8

Browse files
committed
fix(util): tolerate deleted temporary environment variables
When a `patch_env()` body deletes a variable that was initially absent, cleanup raises `KeyError` and can mask an exception from the body. Use `os.environ.pop(name, None)` to restore absence idempotently while preserving restoration of existing values. Add 18 regression cases for absent, empty and populated original values, keep/replace/delete body mutations and normal/exceptional exits. The focused CLI-backend tests changed from 2 failed and 16 passed to 18 passed. Ruff lint/format and `git diff --check` passed. The full suite was not run because its required `GixPython` Windows wheel was unavailable. Agent-Model: unknown
1 parent 8e919a4 commit e52b7f8

2 files changed

Lines changed: 40 additions & 1 deletion

File tree

‎git/util.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def patch_env(name: str, value: str) -> Generator[None, None, None]:
175175
yield
176176
finally:
177177
if old_value is None:
178-
del os.environ[name]
178+
os.environ.pop(name, None)
179179
else:
180180
os.environ[name] = old_value
181181

‎test/test_patch_env.py‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Regression tests for temporary environment variable changes."""
2+
3+
import os
4+
5+
import pytest
6+
7+
from git.util import patch_env
8+
9+
10+
@pytest.mark.parametrize("original", [None, "", "original"])
11+
@pytest.mark.parametrize("change", ["keep", "replace", "delete"])
12+
@pytest.mark.parametrize("raise_error", [False, True])
13+
def test_patch_env_restores_original_state(monkeypatch, original, change, raise_error):
14+
name = "GITPYTHON_TEST_PATCH_ENV"
15+
if original is None:
16+
monkeypatch.delenv(name, raising=False)
17+
else:
18+
monkeypatch.setenv(name, original)
19+
20+
def change_environment():
21+
with patch_env(name, "temporary"):
22+
assert os.environ[name] == "temporary"
23+
if change == "replace":
24+
os.environ[name] = "changed"
25+
elif change == "delete":
26+
del os.environ[name]
27+
if raise_error:
28+
raise RuntimeError("context body failed")
29+
30+
if raise_error:
31+
with pytest.raises(RuntimeError, match="context body failed"):
32+
change_environment()
33+
else:
34+
change_environment()
35+
36+
if original is None:
37+
assert name not in os.environ
38+
else:
39+
assert os.environ[name] == original

0 commit comments

Comments
 (0)