Can attributes named exactly like their type lead to issues?
From https://github.com/python/typeshed/pull/11085#discussion_r1412902472
I am not sure this is safe in all type checkers, since some may understand this as a forward reference. I'd prefer to keep the alias.
CC @JelleZijlstra
Can the following code lead to problems?
class A: ...
class B:
A: A
Or should we do:
from typing_extensions import TypeAlias
class A: ...
_A: TypeAlias = A
class B:
A: _A
If it is deemed safe, then this issue can be closed. Otherwise, it would be a good candidate for flake8-pyi.
Note that this is different than the following case, which is caught by checkers (at least by pyright):
class Foo:
Bar: type
def bar(self, Bar: Bar) -> None: ... # Variable not allowed in type expression (reportGeneralTypeIssues)
class A: ...
class B:
A: A
reveal_type(B.A)
mypy 1.7.1 (compiled: yes)
$ mypy foo.py
foo.py:6: note: Revealed type is "foo.A"
Success: no issues found in 1 source file
$ pytype --version
2023.11.29
$ pytype foo.py
[...]
File "/home/srittau/Projekte/typeshed/foo.py", line 6, in <module>: A [reveal-type]
[...]
pylance:
(Please ignore pylance's broken locale settings.)
LGTM for the type checkers we actively support.
It's worth noting that the ambiguity only exists in pyi files (and in a regular file with a from __future__ import annotations import), since in either case the declarations are order-independent and could potentially be inferred by the type checker in any arbitrary order.
Realistically it's not going to be completely arbitrary, but it's also difficult to prove that it's never an issue, especially with potential future revisions to the logic, but it's also probably in the type checker's best interest to detect this case, since it could otherwise result in A infinitely waiting on itself to finish inference and if you could deadlock a type checker this easily, then it's not very robust, but it may decide to report an error when it detects this case, rather than look for the symbol in an outer scope.
Python’s type hinting system allows you to specify the expected type of a variable or an attribute. In your example, class B has an attribute A that is expected to be of type A. This is perfectly valid Python code.
However, some type checkers might interpret A: A as a forward reference, i.e., they might think that A is referring to a type that has not been defined yet. This is because Python’s type hinting system supports forward references, where you can refer to a type that is defined later in the code.
The alternative approach you mentioned, using TypeAlias, is a way to avoid this potential confusion. By creating an alias for the type A, you ensure that there’s no ambiguity in the type hint.
While the Python language allows attributes to be named like their types, it can potentially lead to confusion or unexpected behavior with some type checkers. Using a type alias can help avoid these issues. It’s always a good idea to consider the clarity and readability of your code, especially when working with advanced features like type hinting.
What I'm getting from this discussion is that, it doesn't hurt, but also we probably shouldn't go out of our way to "cleanup" any instance of this in existing typeshed code that could result in 1 less TypeAlias. (if the opinion changes, feel free to reopen).
I'll close this issue since there is nothing actionable.