Rendering updated type information on function with return type changed by decorator #663
-
I have a kinda weird and very specific case here: my decorator strips out the second element of the tuple returned by the function, and leaves only the first, like this: def decorator(
func: Callable[_PS, tuple[_RT, Any]],
) -> Callable[_PS, _RT]:
@wraps(func)
def wrapper(*args: _PS.args, **kwargs: _PS.kwargs) -> _RT:
ret_val, extra_val = func(*args, **kwargs)
# do something with extra val
return ret_val
# Explicitly add the information that this wrapper
# strips out the second return element from `func`
# add as `str` as I'm using `from __future__ import annotations`
wrapper.__annotations__["return"] = get_type_hints(func)["return"].__args__[0].__name__
return wrapper Inspecting my annotations after a function has been decorated shows that it has been correctly patched: @decorator
def my_func(a: int) -> tuple[int, int]:
return (1, 2)
my_func # <function __main__.my_func(a: 'int') -> 'int'> yet my documentation still shows the original TIA! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
Relates to #162, as it seems it's using the |
Beta Was this translation helpful? Give feedback.
-
At the time #162 was open, we were still using pytkdocs (dynamic analysis) and not Griffe (hybrid static/dynamic analysis) to load data from Python code. So the answers in #162 aren't relevant anymore. What happens in your case is that Griffe by default uses static analysis to read the signature of the function, but this signature is actually changed dynamically by the decorator. Griffe is not able to follow such dynamic changes statically. So you'd have to force dynamic analysis on this particular object, or on the whole package. In the first case, you could draw inspiration from this example. In the second case, you'd have to wait for us to implement an option to force inspection 🙂 |
Beta Was this translation helpful? Give feedback.
-
Great, this will probably make do. Thank you very very much @pawamoy! |
Beta Was this translation helpful? Give feedback.
At the time #162 was open, we were still using pytkdocs (dynamic analysis) and not Griffe (hybrid static/dynamic analysis) to load data from Python code. So the answers in #162 aren't relevant anymore.
What happens in your case is that Griffe by default uses static analysis to read the signature of the function, but this signature is actually changed dynamically by the decorator. Griffe is not able to follow such dynamic changes statically. So you'd have to force dynamic analysis on this particular object, or on the whole package. In the first case, you could draw inspiration from this example. In the second case, you'd have to wait for us to implement an option to force inspection 🙂