[Python] Type hints lost when a decorator is wrapped as a classmethod?

Discussão em 'Python' iniciado por Stack, Dezembro 18, 2024.

  1. Stack

    Stack Membro Participativo

    Consider the following code:

    from typing import Any, Callable, Coroutine

    class Cache[**P, R]:
    @classmethod
    def decorate(cls, **params):
    def decorator(f: Callable[P, Coroutine[Any, Any, R]]) -> Callable[P, Coroutine[Any, Any, R]]:
    return f # in the real world, we instantiate a Cache here
    return decorator

    @Cache.decorate()
    async def some_function(i: int) -> int:
    return i + 1

    cached_function = Cache.decorate()(some_function)


    If I ask pyright the type of Cache.decorate before the @classmethod wrapper (inspecting the word decorate in the above code), it returns:

    (method) def decorate(
    cls: type[Self@Cache[P@Cache, R@Cache]],
    **params: Unknown
    ) -> ((f: ((**P@Cache) -> (Coroutine[Any, Any, R@Cache])) -> ((**P@Cache) -> Coroutine[Any, Any, R@Cache]))


    That looks to me like it understands that P (the argument types) and R (the return types) are plumbed through correctly.

    However, if I ask it to introspect Cache.decorate in the context where it's being used as a decorator, it returns:

    (method) def decorate(**params: Unknown) -> ((f: ((...) -> Coroutine[Any, Any, Unknown])) -> ((...) -> Coroutine[Any, Any, Unknown]))


    ...which is to say, the relationship between input types and output types has been entirely discarded!

    Continue reading...

Compartilhe esta Página