-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Decorator infers Never when using protocols #18877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
If I'm not mistaken, what you're doing is not supposed to work: import logging
import time
from typing import Generic, Protocol, ParamSpec, TypeVar
class Loggable(Protocol):
logger: logging.Logger
P = ParamSpec("P")
T = TypeVar("T", covariant=True)
S = TypeVar("S", contravariant=True, bound="Loggable")
class TimedFunc(Protocol, Generic[P, T, S]):
def __call__(_self, self: S, *args: P.args, **kwargs: P.kwargs) -> T:
...
def timer(func: TimedFunc[P, T, S]) -> TimedFunc[P, T, S]:
def wrapper(self: S, *args: P.args, **kwargs: P.kwargs) -> T:
self.logger.info(f"{func} - Start {time.time()}")
resp = func(self, *args, **kwargs)
self.logger.info(f"{func} - End {time.time()}")
return resp
return wrapper
class Foo:
def __init__(self) -> None:
self.logger = logging.getLogger()
@timer
def bar(self, value: str) -> str:
return value |
Thanks! That gets past the first error. Now I'm encountering an issue where from typing import *
S = TypeVar("S", contravariant=True)
class FooLike(Protocol, Generic[S]):
def __call__(_self, self: S, k: str) -> str:
...
def decorator(f: FooLike[S]) -> FooLike[S]:
return f
class Base:
def foo(self, k: str) -> str:
return "base"
class Child(Base):
@decorator
def foo(self, k: str) -> str:
return "child"
(My actual code makes the args + return type generic like |
Oh, and that's because from typing import Protocol, TypeVar
S = TypeVar("S", contravariant=True)
class FooLike(Protocol[S]):
def __call__(_self, self: S, k: str) -> str:
...
class A:
foo: FooLike['A']
A().foo('') # E: Missing positional argument "k" in call to "__call__" of "FooLike" [call-arg] \
# E: Argument 1 to "__call__" of "FooLike" has incompatible type "str"; expected "A" [arg-type]
How about this? import logging
import time
from collections.abc import Callable
from typing import Concatenate, Protocol, ParamSpec, TypeVar
class Loggable(Protocol):
logger: logging.Logger
P = ParamSpec("P")
T = TypeVar("T", covariant=True)
S = TypeVar("S", contravariant=True, bound="Loggable")
class TimedFunc(Protocol[P, T, S]):
def __call__(_self, self: S, *args: P.args, **kwargs: P.kwargs) -> T:
...
def timer(func: TimedFunc[P, T, S]) -> Callable[Concatenate[S, P], T]:
def wrapper(self: S, /, *args: P.args, **kwargs: P.kwargs) -> T:
self.logger.info(f"{func} - Start {time.time()}")
resp = func(self, *args, **kwargs)
self.logger.info(f"{func} - End {time.time()}")
return resp
return wrapper
class Foo:
def __init__(self) -> None:
self.logger = logging.getLogger()
@timer
def bar(self, value: str) -> str:
return value
Foo().bar('') Yes, there's some asymmetry in the definition, but it should work as long as you're fine with # snip
class Base:
def __init__(self) -> None:
self.logger = logging.getLogger()
def bar(self, value: str) -> str:
return ""
class Derived(Base):
@timer
def bar(self, value: str) -> str:
return value (it probably shouldn't as it violates LSP and |
As this doesn't appear to be a |
That seems to work @sterliakov, thanks a ton! (Sorry for the late response, got sick) |
I'm trying to add types to a decorator that can be used on methods in classes containing a
database_store
property. The decorator logs the start/end time to the instance's database_store.For simplicity, I'll just use a
logging.Logger
here. (mypy playground)This results in an error
It works if I hardcode
self: Foo
instead ofself: Loggable
.Other things I tried
Concatenate[Loggable, P]
, but with--strict
, this forcesself
to be a positional argument, and I don't want to update all the methods to dodef foo(self, /, ...)
.Possibly related
Self
andself
are not bound until after class definition, becomingAny
/Never
when passed through a decorator #16554The text was updated successfully, but these errors were encountered: