google / pytype

A static type analyzer for Python code
https://google.github.io/pytype
Other
4.76k stars 277 forks source link

None return annotation sometimes turned into Any depending on the order in which functions are analyzed #1123

Open JohanSchott opened 2 years ago

JohanSchott commented 2 years ago

Please consider two identical functions test_func and a_test_func, except for the function names.

from typing import Union
import random

def return_none_or_int() -> Union[int, None]:
    i = random.randint(0, 1)
    return i if i == 1 else None

def test_func() -> None:
    x = return_none_or_int()
    reveal_type(x)

    i = random.randint(0, 1)
    reveal_type(i)
    y = i if i == 1 else None
    reveal_type(y)

def a_test_func() -> None:
    x = return_none_or_int()
    reveal_type(x)

    i = random.randint(0, 1)
    reveal_type(i)
    y = i if i == 1 else None
    reveal_type(y)

pytype for this code reports

line 11, in test_func: Union[Any, int] [reveal-type]
line 14, in test_func: int [reveal-type]
line 16, in test_func: Optional[int] [reveal-type]
line 21, in a_test_func: Optional[int] [reveal-type]
line 24, in a_test_func: int [reveal-type]
line 26, in a_test_func: Optional[int] [reveal-type]

I expected the first reveal_type (on line 11) to say Optional[int] and to be the same as the output from the forth reveal_type. Somehow it seems that having "test" in the beginning of a function name leads to unexpected types.

I'm using pytype 2022.2.8 and Python 3.8.10.

(mypy reports the expected Union[builtins.int, None] at the first reveal_type. )

rchen152 commented 2 years ago

Hmm, I don't think the issue has anything to do specifically with the "test" in the function name; I see the same problem if I change the function names from test_func and a_test_func to z_func and a_func. pytype sorts methods by name before analyzing them, so it seems what's going on is that the None type is correctly preserved in functions that are analyzed before the function that returns the None but turned into Any in functions analyzed after the function that returns the None.