Skip to content

Instantly share code, notes, and snippets.

@jathanism
Created December 13, 2012 16:00
Show Gist options
  • Save jathanism/4277417 to your computer and use it in GitHub Desktop.
Save jathanism/4277417 to your computer and use it in GitHub Desktop.
A decorator to inject a namespace into a function's internal global namespace, and then clean it up when you're done. It can be used with or without an argument.
from functools import wraps
framework_namespace = {'api_key':"This is the api_key"}
def inject_namespace(fn=None, namespace=None):
"""
Inject a dictionary into the global namespace of the wrapped function
and then clean it up afterward. Hacktastic!
Credit: http://stackoverflow.com/a/3910211/194311
"""
if namespace is None:
namespace = {}
def real_decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
# Determine which names in framework namespace collide
preexistent = [n for n in namespace if n in fn.func_globals]
nonexistent = [n for n in namespace if n not in preexistent]
# Save any preexisting name's values
fn.globals_save = dict((n, fn.func_globals[n]) for n in preexistent)
# Temporarily inject namespace
fn.func_globals.update(namespace)
retval = fn(*args, **kwargs) # Call ``fn`` and save ``retval``
# Cleanup namespace to remove names that didn't exist
for name in nonexistent:
del fn.func_globals[name]
# Restore the values of any names that collided
fn.func_globals.update(fn.globals_save)
return retval
return wrapper
# Wrap the wrapped function in the real decorator if it's callable
if callable(fn):
return real_decorator(fn)
return real_decorator
# Works with or without arguments. If you dont' specify ``namespace``, then the
# default is used.
#@inject_namespace
@inject_namespace(namespace=framework_namespace)
def func(x, y):
"""Docstring"""
print 'inside func()', locals()
try:
print 'API KEY', api_key
except NameError:
print 'NO API KEY FOUND'
return x + y
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment