I have a class method of the form:
def _cool_method(arg1, arg2, **kwargs):
<do pre-processing stuff>
super()._cool_method(**flattened_kwargs)
where I want flattened_kwargs
to be a dict
like:
flattened_kwargs = {
"arg1": value,
"arg2" value,
"kwargs_key1": value,
"kwargs_key2": {"nestedarg1": value, "nestedarg2": value}
"kwargs_key3": value,
}
I need to pass a single kwargs dict
to the super call after some processing in the child method.
I have managed to figure out how to flatten the input signature into a single dict
using locals()
:
attrs = locals().copy()
attrs.pop("kwargs")
attrs.update(kwargs)
I would now like to convert this to a helper function to call in a number of child class methods. However, the above code assumes that I know the name of **kwargs
as defined by the method signature. I would like to inspect this from the child method so that I don't need to hardcode an assumed key into the pop()
call.
I understand that in Python 3.6 I should be using inspect and have managed to get this far:
def _get_signature_kwargs_key(f):
keys = [k for k, v in signature(f).parameters.items() if v.kind == v.VAR_KEYWORD]
return keys[0] if len(keys) == 1 else None
def flatten_signature_args(f, loc):
kwargs_name = _get_signature_kwargs_key(f)
attributes = loc.copy()
# cater for method calls from classes, which include unwanted metadata
for meta in ['__class__', 'self']:
try:
del attributes[meta]
except KeyError:
pass
attributes.pop(kwargs_name)
attributes.update(loc[kwargs_name])
return attributes
For obvious reasons, the assumption of VAR_KEYWORD
uniqueness appears reasonable. However, is there a better approach to extracting this from the signature, or perhaps a better approach to my requirement for flattening the overall signature?
I'm also having to do a hack to remove meta keys when calling a class method, or it fails when I pass self._cool_method
as the input function.
Solved with:
def get_signature_locals(f, loc):]
return {k: v for k, v in loc.items() if k in signature(f).parameters}
def get_signature_kwargs_key(f):
keys = [k for k, v in signature(f).parameters.items() if v.kind == v.VAR_KEYWORD]
try:
return keys.pop()
except IndexError:
return None
def flatten_signature_kwargs(func, loc):
kwargs_name = get_signature_kwargs_key(func)
attributes = get_signature_locals(func, loc)
if kwargs_name:
attributes.pop(kwargs_name)
attributes.update(loc[kwargs_name])
return attributes