I am building a library that automatically discovers remote API endpoints and populates an object with methods corresponding to the inferred endpoints. The dynamically created methods have the following structure:
def proxy(*args, **kwds):
# 1. Validate arguments: Do arguments match remote API?
# 2. Forward call to remote API
# 3. Parse and return response
pass
This works so far. However, I would like to set the method signature shown with help(proxy)
dynamically. It would increase the user interface greatly if users can see the inferred signatures directly and also use tab-completion for keyword arguments. Is there a way to decorate, annotate, or otherwise manipulate the function to achieve this?
The difference to Dynamically define functions with varying signature is that I only what to change the signature from the caller perspective. The definition of the method should be with *args
and **kwds
.
Poking around the source of the inspect
module, I realized that the information in __signature__
is honored. Therefore, one can create a new, more informative signature dynamically as follows
from inspect import Signature, Parameter
def proxy(*args, **kwds):
pass
user_param = Parameter("user", kind=Parameter.POSITIONAL_OR_KEYWORD)
comment_param = Parameter("comment", kind=Parameter.POSITIONAL_OR_KEYWORD)
sig = Signature([user_param, comment_param])
proxy.__signature__ = sig
proxy.__doc__ = "Post a new comment as given user"
proxy.__name__ = "post_comment"
Calling help(proxy)
will show
post_comment(user, comment)
Post a new comment as given user
and tab-completion suggests user=
or comment=
.
Please note, that the new signature is not enforced. Calling proxy(no_such_argument="hello")
will not raise a TypeError
, so the validation of the signature still needs to take place inside the proxy function.