Created
October 4, 2020 19:41
-
-
Save wbolster/29b8252fef3862f38d3d7b3daecc2224 to your computer and use it in GitHub Desktop.
Dirty tricks to automatically inject keyword arguments from the caller's scope
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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