typeshed icon indicating copy to clipboard operation
typeshed copied to clipboard

Can attributes named exactly like their type lead to issues?

Open Avasam opened this issue 2 years ago • 3 comments

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)

Avasam avatar Dec 06 '23 22:12 Avasam

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:

pylance

(Please ignore pylance's broken locale settings.)

LGTM for the type checkers we actively support.

srittau avatar Dec 07 '23 10:12 srittau

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.

Daverball avatar Dec 10 '23 22:12 Daverball

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.

karimbaidar avatar Dec 29 '23 14:12 karimbaidar

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.

Avasam avatar Mar 14 '24 19:03 Avasam