Skip to content

Instantly share code, notes, and snippets.

@wbolster
Created October 4, 2020 19:41
Show Gist options
  • Save wbolster/29b8252fef3862f38d3d7b3daecc2224 to your computer and use it in GitHub Desktop.
Save wbolster/29b8252fef3862f38d3d7b3daecc2224 to your computer and use it in GitHub Desktop.
Dirty tricks to automatically inject keyword arguments from the caller's scope
"""
Dirty tricks to automatically inject keyword arguments from the caller's scope.
"""
import functools
import inspect
import sys
def auto_inject_kwargs(f):
"""
Decorator to automatically inject missing keyword arguments.
The values are looked up by inspecting the caller's local variables of the
same name.
"""
signature = inspect.getfullargspec(f)
injectable_kwargs = set(signature.kwonlyargs)
if signature.kwonlydefaults is not None:
injectable_kwargs.difference_update(signature.kwonlydefaults.keys())
@functools.wraps(f)
def wrapper(*args, **kwargs):
missing_kwarg_names = injectable_kwargs.difference(kwargs.keys())
frame = sys._getframe(1)
for name in missing_kwarg_names:
if name in frame.f_locals:
kwargs[name] = frame.f_locals[name]
return f(*args, **kwargs)
return wrapper
def test_auto_inject_kwargs():
@auto_inject_kwargs
def foo(a, *, b, c, d=4):
return (a, b, c, d)
c = 3 # Should be used b/c not present in call below.
d = 5 # Should not be used b/c default value.
actual = foo(1, b=2)
expected = (1, 2, 3, 4)
assert actual == expected
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment