For testing things that query the environment (e.g., os.getenv
, sys.version
, etc.), it's often more convenient to make the queries lie than to actually fake up the environment. Here's a context manager that does this for one os.getenv
call at a time:
from __future__ import with_statement
from contextlib import contextmanager
import os
@contextmanager
def fake_env(**fakes):
'''fakes is a dict mapping variables to their values. In the
fake_env context, os.getenv calls try to return out of the fakes
dict whenever possible before querying the actual environment.
'''
global os
original = os.getenv
def dummy(var):
try: return fakes[var]
except KeyError: return original(var)
os.getenv = dummy
yield
os.getenv = original
if __name__ == '__main__':
print os.getenv('HOME')
with fake_env(HOME='here'):
print os.getenv('HOME')
print os.getenv('HOME')
But this only works for os.getenv
and the syntax gets a bit clunky if I allow for functions with multiple arguments. I guess between ast
and code
/exec
/eval
I could extend it to take the function to override as a parameter, but not cleanly. Also, I would then be on my way to Greenspun's Tenth. Is there a better way?