Skip to content

Conversation

@p-sawicki
Copy link
Collaborator

For decorated functions, a FuncDecl is constructed during compilation from another FuncDecl but some attributes are not copied. One of those is is_coroutine which is used to determine whether the function will be replaced in the module dictionary by a CPyFunction object.

The CPyFunction object is needed for introspection functions to work so without it, inspect.iscoroutinefunction(fn) returns False for decorated async functions. This causes incorrect behavior when the inspect function is used in a decorator, for example:

F = TypeVar("F", bound=Callable[..., Any])

def wrap(fn: F) -> F:
    if inspect.iscoroutinefunction(fn):
        @wraps(fn)
        async def wrapper_async(*args) -> Any:
            return await fn(*args) + await fn(*args)

        return cast(F, wrapper_async)

    @wraps(fn)
    def wrapper(*args) -> Any:
        return fn(*args) + fn(*args)

    return cast(F, wrapper)

@wrap
async def wrapped_async(val: int) -> int:
    return val

In existing test cases this did not come up because the decorators would unconditionally wrap an async function with another async function. Checking iscoroutinefunction of the wrapped function would check the wrapper instead, for which a CPyFunction object was generated correctly. But during execution of wrap, the actual wrapped function is checked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant