'Make pyright/PyCharm recognize arguments set by decorator
I have the following decorator function (simplified version of serialize_request from api-client-pydantic) that is supposed to be used on a function that takes any number of pydantic models as parameters. It initializes those models with the arguments passed to it and then calls the wrapped function with these models as arguments.
def serialize(extra_kwargs: Dict[str, Any] = None) -> Callable:
extra_kw = extra_kwargs or {"by_alias": True, "exclude_none": True}
def decorator(func: Callable) -> Callable:
map_schemas = {}
map_params = {}
parameters = []
for arg_name, arg_type in get_type_hints(func).items():
if arg_name == "return":
continue
map_schemas[arg_name] = arg_type
if inspect.isclass(arg_type) and issubclass(arg_type, BaseModel):
# the model's signature contains only aliases
arg_fields = list(arg_type.__fields__.keys())
arg_params = inspect.signature(arg_type).parameters
map_params[arg_name] = set(list(arg_params.keys()) + arg_fields)
parameters.extend(list(arg_params.values()))
@wraps(func)
def wrap(*args, **kwargs):
if map_schemas:
data, origin_kwargs = {}, {}
for arg_name, arg_type in map_schemas.items():
if inspect.isclass(arg_type) and issubclass(arg_type, BaseModel):
arg_kwargs = {
k: v for k, v in kwargs.items() if k in map_params[arg_name]
}
data[arg_name] = parse_obj_as(arg_type, arg_kwargs).dict(
**extra_kw
)
else:
val = kwargs.get(arg_name)
if val is not None:
origin_kwargs[arg_name] = val
new_kwargs = {**origin_kwargs, **data} or kwargs
return func(*args, **new_kwargs)
return func(*args, **kwargs)
# Override signature
if parameters:
sig = inspect.signature(func)
_self_param = sig.parameters.get("self")
self_param = [_self_param] if _self_param else []
sig = sig.replace(parameters=tuple(self_param + parameters))
wrap.__signature__ = sig # type: ignore
return wrap
return decorator
By overwriting the signature, tools like ipython recognize the new arguments and show them in the pop up help. For example, with the below models and function:
class ModelA(BaseModel):
a: str
b: int
class ModelB(BaseModel):
one: float
two: Optional[str] = None
@serialize()
def foo(model_a: ModelA, model_b: ModelB):
print(model_a)
print(model_b)
But pyright doesn't recognize them and shows an error:
I don't know what PyCharm uses internally, but it also doesn't recognize the new arguments. It doesn't show an error though, it just accepts anything as valid arguments, also none at all:
Now, my question is if there is some way to make pyright/PyCharm and similar tools recognize those "new" arguments set by the decorator and make them behave as though the parameters were set as such on the function directly.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|




