Most decorators preserve a function’s outward signature and coroutine status, so runtime introspection reports the same results as for the undecorated function. Sometimes a decorator must change that shape by adding or removing parameters, altering return annotations, or converting between synchronous and asynchronous calling conventions. The wrapper body can implement the behavior, but downstream tools rely on runtime introspection to decide how to call or treat the function. wrapt addresses this by replacing an older adapter approach with a standalone with_signature decorator and adding mark_as_sync and mark_as_async to control calling-convention introspection. Convenience bridges like async_to_sync and sync_to_async combine bridging with marking. Runtime introspection differs from static type checking, which uses source-level type hints and separate mechanisms, so these runtime fixes do not generally satisfy static type checkers.
"Most decorators leave the function's outward shape alone. The same parameters go in, the same return type comes out, and inspect.signature and inspect.iscoroutinefunction give the same answers they would have given for the undecorated function. Sometimes you want a decorator that actively changes that shape. Adds or removes a parameter. Changes the return annotation. Turns a sync function into something that should be awaited, or runs an async function to completion so it can be called from sync code."
"The mechanics of doing the work in the wrapper body are usually straightforward. The harder part is making sure that downstream tools, which decide how to call or treat the function based on what introspection tells them, see the shape of the wrapper rather than the shape of the wrapped target. wrapt has had a partial answer to this for a long time via the adapter argument on @wrapt.decorator."
"The 2.2.0 release replaced that with a cleaner standalone with_signature decorator and added a new piece, mark_as_sync / mark_as_async, for the calling-convention side that the existing API did not address at all. There are also a couple of convenience bridges, async_to_sync and sync_to_async, that do the bridging and the marking together for the common cases."
"When this post talks about introspection, it means runtime introspection. Specifically, the answers given by inspect.signature, inspect.iscoroutinefunction, inspect.isasyncgenfunction, inspect.isgeneratorfunction and their friends, computed from the function object after the program has started running. This is distinct from static type checking. mypy and pyright work from source-level type hints before the program runs and rely on different mechanisms ( typing.ParamSpec, typing.Concatenate, properly annotated wrapper signatures and so on)."
Read at Grahamdumpleton
Unable to calculate read time
Collection
[
|
...
]