-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Decorated function makes type-check fail if done inside of method from the class #9266
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
I didn't follow everything yet (it takes me a while) but does the same thing happen if you use a digger ale instead of '_'? IIRC there's a special case for that somewhere. (But I may very well be wrong, sorry.) |
Changing |
minimal example:
uncommenting |
@Akuli Thanks for the translation. :-) This feels like it’s because mypy doesn’t have the proper type for a decorated method when it checks the init body. Definitely a bug, not simple to fix, so use the workaround of putting the check after the class. |
putting the check after the class requires creating an instance of the class just for the check |
Actually, I ended up doing a different approach (using a class decorator to check the type instead of using the So, while the issue persists, I already found another workaround where things work for me. Just for reference, I'm using the
|
Actually, sorry, that doesn't work as I expected... I'm still checking for a usable workaround. |
You could put the check after the class inside Or you could add a dummy method at the end of the class with the check on |
I did another simpler approach with class decorators which seems to work:
it requires to define one method for each interface, but I think that's a bit better than having it at the end or out of the class. |
But if class decorators were implemented properly that would give |
I agree it's not ideal... do you see any other way to have such a typecheck as a class decorator (with the current set of features from Mypy)? -- if possible I'd really like to have this close to the start of the class (as a class decorator or |
Is there a reason your class can't just inherit from the protocol? IIUC PEP 554 says that should be possible. |
I could, but it doesn't give me type errors if I forget to implement something. i.e.:
|
It would complain if the methods were abstract in the Protocol class. |
I still couldn't get MyPy to complain with the code below... It only seems to complain if I call some function expecting
|
try adding |
Yes, I know it'll error if I try to instance or try to call some method, but the whole point is that I want to type-check some class to conform to some interface without having to create an instance or do some declaration at the end of the class (like what would happen when you implement some java interface). |
I'm confused. Why would you create classes without ever instantiating them (and getting the error)? |
Oh, I would instance it and get the error somewhere, but the error would likely only appear in some test case (if I'm doing a library for others) or some other place where I'm using that class (which may be very far apart from the class implementation), whereas I'd like to have such an error close to the class declaration/name (near the actual Is this such an odd case? (Personally, I find it a bit odd to have protocols and not being able to know if a class implementation conforms to it in the class implementation itself, but maybe my views on how typing should work are too biased from java interfaces) |
I would say practicality beats purity. You still get the name of the class in the error message and even a list of missing methods. |
But then it's not much better than doing it in runtime if I have to look somewhere else -- just to note, I actually do have such a decorator that checks the class during runtime and gives the error at the class declaration: https://github.com/fabioz/pyvmmonitor-core/blob/master/pyvmmonitor_core/interface.py#L220, or I could use ABCs, but I thought type-checking would allow me to get the error earlier... it's definitely one of the selling points for me ;). |
Fixes python#18024 Fixes python#18706 Fixes python#17734 Fixes python#15097 Fixes python#14814 Fixes python#14806 Fixes python#14259 Fixes python#13041 Fixes python#11993 Fixes python#9585 Fixes python#9266 Fixes python#9202 Fixes python#5481 This is a fourth "major" PR toward python#7724. This is one is watershed/crux of the whole series (but to set correct expectations, there are almost a dozen smaller follow-up/clean-up PRs in the pipeline). The core of the idea is to set current type-checker as part of the global state. There are however some details: * There are cases where we call `is_subtype()` before type-checking. For now, I fall back to old logic in this cases. In follow up PRs we may switch to using type-checker instances before type checking phase (this requires some care). * This increases typeops import cycle by a few modules, but unfortunately this is inevitable. * This PR increases potential for infinite recursion in protocols. To mitigate I add: one legitimate fix for `__call__`, and one temporary hack for `freshen_all_functions_type_vars` (to reduce performance impact). * Finally I change semantics for method access on class objects to match the one in old `find_member()`. Now we will expand type by instance, so we have something like this: ```python class B(Generic[T]): def foo(self, x: T) -> T: ... class C(B[str]): ... reveal_type(C.foo) # def (self: B[str], x: str) -> str ``` FWIW, I am not even 100% sure this is correct, it seems to me we _may_ keep the method generic. But in any case what we do currently is definitely wrong (we infer a _non-generic_ `def (x: T) -> T`). --------- Co-authored-by: hauntsaninja <[email protected]> Co-authored-by: Shantanu <[email protected]>
Uh oh!
There was an error while loading. Please reload this page.
I believe this is a bug (explanation below).
I expected to be able to statically check a case by checking whether
self
matches a given protocol (with thecheck_implements
below).This seems to work, but if the method is decorated (with the
implements
as shown in the code below) it doesn't validate properly that a method return type is wrong.i.e.: in the code below I expected that the
_: IFoo = check_implements(self)
line gives an error because the protocol declaration expects abool
return, whereas the method implementation says it returns astr
.I think this is a bug because the same type-check later on says that the implementation doesn't conform to the protocol if done outside of the class -- as
_: IFoo = check_implements(Foo())
, so, it does something on__init__
and a different thing if out of the__init__
. Besides, it works if the function is not decorated.Note: even if I do
_: IFoo = check_implements(Foo())
in the__init__
it doesn't validate properly (so, it doesn't seem related toself
-- and it works as expected if the function is not decorated).The text was updated successfully, but these errors were encountered: