Description
Bug description
Consider the following class:
class Foo:
def __init__(self) -> None:
self.val: str | int = "1"
def bar(self) -> None:
self.val = "2"
pass
pyreverse will infer the type of Foo.val
to be "str | int, str", which is incorrect as the second assignment does not actually modify the type and "str" is a more specific type than the union "str | int".
Additionally, if the class is modified to look like this:
class Foo:
def __init__(self) -> None:
self.val: list[str] = []
def bar(self) -> None:
self.val = []
pass
pyrverse will infer the type to be "list[str] | list", which should also be incorrect because assigning an empty list here doesn't mean that suddenly the type is list[Any].
I think fixing this issue should look at 3 different steps:
- type hints should have precedence over inferred types: it should not be the responsibility of pyreverse to type check the code, so if type hints are provided, it should be assumed those are correct. This also allows users to get a consistent behaviour by just fixing the type hints in their code
- if a type hint is read from the init, it should have precedence over other calls, since again, type checkers will consider other calls to be an error
- failing the two points above, types should be aggregated and consistent: "str | int, str" should be just "str | int" and the order should be consistent across runs (in my testing, I sometimes got "str | int, str", and other times "str, str | int".
Configuration
No response
Command used
pyreverse repro.py
Pylint output
parsing repro.py
### Expected behavior
As explained in the description, the type inferred for the `val` attribute should be `str | int` in the first case and `list[str]` in the second case.
### Pylint version
```shell
pyreverse is included in pylint:
pylint 2.17.4
astroid 2.15.6
Python 3.11.4 (main, Jun 7 2023, 12:45:49) [GCC 9.4.0]
OS / Environment
No response
Additional dependencies
No response
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment