Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=Nonecreated_at=<Date2021-09-24.13:44:07.559>labels= ['type-bug', 'library', '3.9', '3.10', '3.11']
title='Top / function argument level ClassVar should not be allowed during `get_type_hints()`'updated_at=<Date2021-09-26.17:09:09.780>user='https://github.com/sobolevn'
# contents of `ex.py`fromtypingimportClassVara: ClassVar[int] =1defb(c: ClassVar[int]): ...
And then:
Module: python -c 'import ex; from typing import get_type_hints; print(get_type_hints(ex))'
Function argument: python -c 'import ex; from typing import get_type_hints; print(get_type_hints(ex.b))'
It should not be allowed. Currently, the same with from __future__ import annotations does correctly raise TypeError: typing.ClassVar[int] is not valid as type argument
Hm. IMO it is up to static type checkers to reject bad use of types. The runtime should be relaxed so type checkers can develop new features assigning new semantics to such constructs.
This makes get_type_hints quite opinionated and backwards incompatible. The first line the docs says "This is often the same as obj.annotations".
I also agree with Guido. FYI, we've tried to reduce usage of _type_check in new features since version 3.10. We've found that they make typing_extensions operability with typing worse. For example, the whole of PEP-612 in typing_extensions required lots of hacks to work with typing's Callable.
If you're really vouching for this change. We probably need a 2 major version deprecation period (with warnings telling the user their current type hints are invalid) *plus* asking typing-sig/python-dev if the runtime type hints users will be affected. See PEP-387 for more info.
On the other hand, we now have a less-opinionated alternative to get_type_hints with inspect.get_annotations, but it can't do as much (like resolving ForwardRef).
Just to bring in some context for this discussion: #28279
We have dicussed in the PR above that current implementation depends on existing of __future__ import of annotations.
With from __future__ import annotations:
Top level class var will be raise TypeError
Final and ClassVar function arguments will raise TypeError
Annotations like x: 1 will raise TypeError: Forward references must evaluate to types. Got 1.
Without from __future import annotationsit accepts all the cases above.
I share two opposite views on this change:
By adding the same _type_check logic we can reduce the inconsitency between two versions. It would be easier for users to migrate from one version to another.
By adding this feature, we would more aggresively force some specific semantics for builtin types. Which can possibly be problematic, for example I've tried to add Final annotations to function arguments in my own type checker. It is something current semantics does not support. Moreover, it can cause incompatibility to existing users.
My opinion is that consitency is more important here. Because I received quite a lot of bug reports from users involving different behavior with / without __future__ import of annotations.
But, I understand that it is not up to me to decide :)
By adding the same _type_check logic we can reduce the inconsistency between two versions. It would be easier for users to migrate from one version to another.
That's definitely a plus. But please consider this hypothetical scenario:
Let's say some typing code has _type_check in 3.8
In 3.12, we decide to give type hinting with ints (like x: 1) some meaning (this has been proposed before in typing-sig).
The new construct arrives in 3.12. We backport to typing_extensions, which must support 3.8's typing module.
Now the new addition to 3.12 typing_extensions doesn't work with 3.8 typing because of _type_check, and we need to hack around it.
The hacks may eventually lead to real behavioral inconsistencies between typing_extensions and typing.
Stricter runtime type checking makes growing the typing syntax harder. For the newer types, we try to defer checking to 3rd-party libraries.
Because I received quite a lot of bug reports from users involving different behavior with / without __future__ import of annotations.
Your perspective as a runtime typing library dev is very valuable. Thank you for your feedback! IMO, from __future__ import annotations becoming the default in 3.11 is still undecided. It was yanked from 3.10 for breaking pydantic and FastAPI, and I doubt it will land in 3.11 for the same reasons. It seems the current consensus is to use that import for code with purely static typing, and not use it with runtime typing libraries.
The consensus on this issue is that stricter runtime type-checking in get_type_hints (at least for ClassVar, probably also in general) would be undesirable, and the linked PR has been closed. I am therefore closing this issue.
Activity
sobolevn commented on Sep 24, 2021
This code currently does not raise any issues:
And then:
It should not be allowed. Currently, the same with from __future__ import annotations does correctly raise TypeError: typing.ClassVar[int] is not valid as type argument
Related: #28279
I will send a PR with the fix shortly.
gvanrossum commented on Sep 25, 2021
Hm. IMO it is up to static type checkers to reject bad use of types. The runtime should be relaxed so type checkers can develop new features assigning new semantics to such constructs.
Fidget-Spinner commented on Sep 25, 2021
This makes get_type_hints quite opinionated and backwards incompatible. The first line the docs says "This is often the same as obj.annotations".
I also agree with Guido. FYI, we've tried to reduce usage of _type_check in new features since version 3.10. We've found that they make typing_extensions operability with typing worse. For example, the whole of PEP-612 in typing_extensions required lots of hacks to work with typing's Callable.
If you're really vouching for this change. We probably need a 2 major version deprecation period (with warnings telling the user their current type hints are invalid) *plus* asking typing-sig/python-dev if the runtime type hints users will be affected. See PEP-387 for more info.
On the other hand, we now have a less-opinionated alternative to get_type_hints with inspect.get_annotations, but it can't do as much (like resolving ForwardRef).
sobolevn commented on Sep 25, 2021
Just to bring in some context for this discussion: #28279
We have dicussed in the PR above that current implementation depends on existing of __future__ import of annotations.
With from __future__ import annotations:
Without from __future import annotationsit accepts all the cases above.
I share two opposite views on this change:
My opinion is that consitency is more important here. Because I received quite a lot of bug reports from users involving different behavior with / without __future__ import of annotations.
But, I understand that it is not up to me to decide :)
Fidget-Spinner commented on Sep 25, 2021
That's definitely a plus. But please consider this hypothetical scenario:
If this sounds familiar, that's because something similar has already happened! Callable and Generic had too strict checking in typing (requiring Callable's args to be a tuple of types always) before 3.10. So typing_extensions doesn't support the full PEP-612 syntax :( https://github.com/python/typing/tree/master/typing_extensions#other-notes-and-limitations.
Stricter runtime type checking makes growing the typing syntax harder. For the newer types, we try to defer checking to 3rd-party libraries.
Your perspective as a runtime typing library dev is very valuable. Thank you for your feedback! IMO, from __future__ import annotations becoming the default in 3.11 is still undecided. It was yanked from 3.10 for breaking pydantic and FastAPI, and I doubt it will land in 3.11 for the same reasons. It seems the current consensus is to use that import for code with purely static typing, and not use it with runtime typing libraries.
sobolevn commented on Sep 25, 2021
Thank you, Ken Jin! Very clear explanation!
Is it an official position? Or just a common usage pattern?
What can we do to make this more widely known?
Maybe we can formulate something like "When to use: raw, string, future annotations" in the typing docs (https://docs.python.org/3/library/typing.html)?
ambv commented on Sep 26, 2021
No, we need to decide what will happen to PEP-563 and PEP-649 in Python 3.11.
AlexWaygood commented on Apr 14, 2022
The consensus on this issue is that stricter runtime type-checking in get_type_hints (at least for ClassVar, probably also in general) would be undesirable, and the linked PR has been closed. I am therefore closing this issue.