Skip to content

Commit 3d35a27

Browse files
authored
Merge pull request #3019 from MaxFreedomPollard/fix-switchenv-env-snapshot
misc: Snapshot the environment when a switchenv is entered
2 parents 33c3b12 + 6c439c3 commit 3d35a27

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

‎devito/parameters.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,14 @@ class switchenv(SwitchDecorator):
295295
the context manager, so should be used cautiously.
296296
"""
297297
def __init__(self, params):
298-
self.previous = dict(os.environ)
299298
self.params = params
299+
self.previous = {}
300300

301301
def __enter__(self):
302+
# Snapshot the environment upon entering, not upon construction, since the
303+
# same object is reused across entries, most notably as a decorator
304+
self.previous = dict(os.environ)
305+
302306
# Prevent having multiple conflicting device vars, e.g
303307
# switching CUDA_VISIBLE_DEVICES but having NVIDIA_VISIBLE_DEVICES set.
304308
from devito.arch.archinfo import device_vars

‎tests/test_tools.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,33 @@ def test_switchenv():
344344

345345
# Make sure the switchenv does not persist to verify switchenv works as intended
346346
assert dict(os.environ) == previous_environ
347+
348+
349+
def test_switchenv_reuse():
350+
# Save previous environment
351+
previous_environ = dict(os.environ)
352+
353+
try:
354+
# A switchenv is constructed once, when the decorator is applied, and then
355+
# reused on every call of the decorated function
356+
@switchenv({'TEST_VAR': 'foo'})
357+
def foo():
358+
return os.environ['TEST_VAR']
359+
360+
# Set after the decorator has been applied, so it is not visible to an
361+
# environment snapshot taken at construction time
362+
os.environ['TEST_VAR_LATE'] = 'bar'
363+
364+
assert foo() == 'foo'
365+
assert os.environ.get('TEST_VAR') is None
366+
assert os.environ['TEST_VAR_LATE'] == 'bar'
367+
368+
# Same story for a switchenv reused as a context manager
369+
cm = switchenv({'TEST_VAR': 'foo'})
370+
os.environ['TEST_VAR_LATER'] = 'baz'
371+
with cm:
372+
assert os.environ['TEST_VAR'] == 'foo'
373+
assert os.environ['TEST_VAR_LATER'] == 'baz'
374+
finally:
375+
os.environ.clear()
376+
os.environ.update(previous_environ)

0 commit comments

Comments
 (0)