GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — bpo-44975: [typing] Support issubclass for ClassVar data members by Fidget-Spinner · Pull Request #27883 · python/cpython Conversation
|
|
CC @uriyyo please take a look. Thank you. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM💫
I have few minor questions
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| def _is_callable_members_only(cls): | ||
| attr_names = _get_protocol_attrs(cls) | ||
| annotations = getattr(cls, '__annotations__', {}) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
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) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Good question! I'd considered that too but decided against it for two main reasons:
get_type_hints is slowget_type_hints won't work with forward references/ PEP 563 if ClassVar is not defined in the caller's namespaceConsider 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.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM💫
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Co-authored-by: Łukasz Langa <[email protected]>
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
👍
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| class C: pass | ||
|
|
||
| class D: |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Let's also add a case with the same class prop, but different value. Example:
class E: x = 2
Because right now all names / values always match. It is not clear whether value is a part of the protocol or not.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Agreed.
It is not clear whether value is a part of the protocol or not.
It shouldn't be. IMO, we should only care about the "shape". Trying to runtime-check the value is difficult and should be left to third-party libs to do.
Nevermind, I changed my mind. Let's do it!
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
| x = 1 | ||
| self.assertNotIsSubclass(C, P) | ||
| self.assertIsSubclass(D, P) | ||
|
|
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Let's also test these classes:
class G: x: ClassVar[int] = 1
class H: x: 'ClassVar[int]' = 1
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
These aren't testing more code paths, the code doesn't look at the annotations of the first class argument in issubclass.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
TODO: Docs need updating. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| instance_attr = getattr(instance, attr_name, None) | ||
| if (instance_attr is not None | ||
| and attr is not None | ||
| and type(instance_attr) != type(attr)): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
This is incorrect. Consider this example:
class P(Protocol): x: ClassVar[object] = object() class Y: x: ClassVar[object] = 1
Y implements protocol P, but your code rejects it. There are also problems with None here that could produce an incorrect result.
I'd recommend removing this whole check, and just checking that the attribute exists. Full runtime type checking is hard and the standard library shouldn't try to do it.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@Fidget-Spinner are you still interested in this PR? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@JelleZijlstra hmm not really. I'm not too inclined on runtime checking in the standard library. IMO it's something we should leave to expert 3rd party libs. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
See #89138 -- maybe we should just abandon this? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.