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
bpo-44975: [typing] Support issubclass for ClassVar data members #27883
base: main
Are you sure you want to change the base?
bpo-44975: [typing] Support issubclass for ClassVar data members #27883
Conversation
|
CC @uriyyo please take a look. Thank you. |
| @@ -1396,8 +1396,15 @@ def _get_protocol_attrs(cls): | |||
|
|
|||
|
|
|||
| def _is_callable_members_only(cls): | |||
| attr_names = _get_protocol_attrs(cls) | |||
| annotations = getattr(cls, '__annotations__', {}) | |||
What about using typing.get_type_hints to resolve annotations for a class?
It will allow having ClassVar annotated as str:
@runtime_checkable
class P(Protocol):
x: 'ClassVar[int]' = 1| annotations = getattr(cls, '__annotations__', {}) | |
| annotations = get_type_hints(cls) |
Good question! I'd considered that too but decided against it for two main reasons:
get_type_hintsis slowget_type_hintswon't work with forward references/ PEP 563 ifClassVaris not defined in the caller's namespace
Consider the following:
# foo.py
from __future__ import annotations
from typing import *
@runtime_checkable
class X(Protocol):
x: ClassVar[int] = 1
y: SomeUndeclaredType = None# bar.py
from .foo import X
class Y: ...
# Error! get_type_hints cannot resolve 'ClassVar' and 'SomeUndeclaredType'
issubclass(X, Y)Nonetheless, your suggestion has reminded me of a basic workaround for string annotations. Thanks.
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
|
|
||
| class C: pass | ||
|
|
||
| class D: |
Let's also add a case with the same class prop, but different value. Example:
class E:
x = 2Because right now all names / values always match. It is not clear whether value is a part of the protocol or not.
| class D: | ||
| x = 1 | ||
| self.assertNotIsSubclass(C, P) | ||
| self.assertIsSubclass(D, P) |
One more case that is not covered: same name, different type.
class F:
x = 'a'It should not pass, but maybe ClassVar wrapper might break / change that.
| x = 1 | ||
| self.assertNotIsSubclass(C, P) | ||
| self.assertIsSubclass(D, P) | ||
|
|
Let's also test these classes:
class G:
x: ClassVar[int] = 1class H:
x: 'ClassVar[int]' = 1| @@ -1394,10 +1394,24 @@ def _get_protocol_attrs(cls): | |||
| attrs.add(attr) | |||
| return attrs | |||
|
|
|||
| _classvar_prefixes = ("typing.ClassVar[", "t.ClassVar[", "ClassVar[") | |||
What about raw ClassVar annotation with generic argument?
https://bugs.python.org/issue44975
The text was updated successfully, but these errors were encountered: