Skip to content

Protocols don't support descriptors #5481

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

Closed
ilevkivskyi opened this issue Aug 14, 2018 · 6 comments · Fixed by #18943
Closed

Protocols don't support descriptors #5481

ilevkivskyi opened this issue Aug 14, 2018 · 6 comments · Fixed by #18943
Labels

Comments

@ilevkivskyi
Copy link
Member

ilevkivskyi commented Aug 14, 2018

Consider this code:

class Descr:
    def __get__(self, inst: Any, owner: Any) -> int: ...

class Proto(Protocol):
    x: int

class C:
    x = Descr()

a: Proto = C()

I think it should be allowed. This can be done by simply re-using the logic in analyze_member_access in checkmember.py, see also #5136.

@bryanforbes
Copy link
Contributor

This will be fixed when #3832 is complete

@ilevkivskyi
Copy link
Member Author

This appeared again in dropbox/sqlalchemy-stubs#134

@ckarnell
Copy link
Contributor

Can you tell me exactly where in the code the duplication is happening WRT Protocols, so I can try to piece together some understanding and look into fixing it? I'm looking myself but it's not immediately obvious, and I'm unfamiliar with the codebase.

@ilevkivskyi
Copy link
Member Author

Just to set realistic expectations: it is unlikely anyone beyond core team can fix this. But anyway, the problematic logic duplication is between is_protocol_implementation()/find_member() in subtypes.py and analyze_instance_member_access() in checkmember.py.

@ckarnell
Copy link
Contributor

Got it, makes sense. I might take a peek anyway just out of curiosity.

@sobolevn
Copy link
Member

This was raised once again in django-stubs repo: typeddjango/django-stubs#651

cdce8p pushed a commit to cdce8p/mypy that referenced this issue May 31, 2025
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 <hauntsaninja@gmail.com>
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants