Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pow doesn't infer types when variables are used #16635

Closed
GatienBouyer opened this issue Dec 8, 2023 · 10 comments
Closed

Pow doesn't infer types when variables are used #16635

GatienBouyer opened this issue Dec 8, 2023 · 10 comments
Labels
bug mypy got something wrong

Comments

@GatienBouyer
Copy link

Bug Report

I would expect that using variables to hold my values doesn't lose the resulting type.

Sample code:

my_wanted_int = 2 ** 3
reveal_type(my_wanted_int) # = int

my_2 = 2
my_3 = 3
reveal_type(my_2) # = int
reveal_type(my_3) # = int
star_result2 = my_2 ** my_3
reveal_type(star_result2) # = Any

Actual Behavior

$ mypy -V
mypy 1.7.1 (compiled: yes)
$ mypy -c "
my_wanted_int = 2 ** 3
reveal_type(my_wanted_int) # = int

my_2 = 2
my_3 = 3
reveal_type(my_2) # = int
reveal_type(my_3) # = int
star_result2 = my_2 ** my_3
reveal_type(star_result2) # = Any instead of int
"
<string>:3: note: Revealed type is "builtins.int"
<string>:7: note: Revealed type is "builtins.int"
<string>:8: note: Revealed type is "builtins.int"
<string>:10: note: Revealed type is "Any"
Success: no issues found in 1 source file

Here is the example in the mypy playground:
https://mypy-play.net/?mypy=latest&python=3.11&gist=e53d4334e01415845108453985c8f88f

Your Environment

  • Mypy version used: 1.7.1
  • Python version used: 3.11
@GatienBouyer GatienBouyer added the bug mypy got something wrong label Dec 8, 2023
@GatienBouyer
Copy link
Author

Possible linked issue: #7621

@ikonst
Copy link
Contributor

ikonst commented Dec 8, 2023

Curiously in testTypeshedSensitivePlugins this expectation is encoded:

reveal_type(a**b)
...
int_pow.py:9: note: Revealed type is "Any"

I'd think it should be typed float | int rather than Any...

@JelleZijlstra
Copy link
Member

@ikonst see https://github.com/python/typeshed/blob/ad5ec921e0c0da471867996fc85b94a3e7d83ecf/stdlib/builtins.pyi#L294 for why it's this way.

@GatienBouyer the explanation for what you're seeing is that if you put the value in a variable, mypy infers the type as just int, so it takes the Any path from above. But if you use the value directly, mypy knows the value is exactly 2 or 3, enabling it to use the overload for positive or negative integers that enables it to infer the value as int.

@AlexWaygood
Copy link
Member

I'd think it should be typed float | int rather than Any...

@ikonst, I tried that two years ago, and this is the mypy_primer report! python/typeshed#6287 (comment)

@GatienBouyer
Copy link
Author

GatienBouyer commented Dec 8, 2023

Indeed, when variables are used, the parameters are of type int, whereas the explicit values are of type _PositiveInt.

However, is there no other way to define positive integers? In a way that enables me to type my variables correctly, so I have the correct type inferred for the result.

_PositiveInteger: TypeAlias = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

The following would be typed Any even if the value is explicitly positive.

x = pow(2, 100)
reveal_type(x) # = Any

There seems to be no way to have a large _PositiveInteger inside my code base, I can't import it to type my variables as _PositiveInteger.

# from mypy.typeshed.stubs.[etc.] import _PositiveInteger # no way to import it
_PositiveInteger = int # to demonstrate the code below
my_2: _PositiveInteger = 2
my_3: _PositiveInteger = 3
would_be_int = pow(my_2, my_3)

My main driver here is to improve my Any ratio in the reports produced by mypy, especially the cobertura and html ones.

@AlexWaygood
Copy link
Member

However is there no other way to define positive integers

not really :/

@ikonst
Copy link
Contributor

ikonst commented Dec 8, 2023

Ahh, I see, e.g. existing code in https://github.com/Yelp/paasta/blob/master/paasta_tools/utils.py:

def calculate_tail_lines(verbose_level: int) -> int:
    if verbose_level <= 1:
        return 0
    else:
        return 10 ** (verbose_level - 1)

Nobody says you can't call calculate_tail_lines(0) in which case the int type will be wrong, but I suppose they carefully pass verbose_level > 0 and making that change would be a false positive for them.

@GatienBouyer
Copy link
Author

As already discussed in python/typeshed#7737 (comment) and in python/typeshed#6287 (comment), mypy has no way to distinguish between positive and negative integers. Until further change on this topic occurs, I close this issue.

@GatienBouyer
Copy link
Author

I add this reference for completeness.
The original discussion: python/typeshed#2271

@erictraut
Copy link

I'll note that pyright doesn't have a problem with the original code sample in this issue. That's because pyright narrows to literal types on assignment, whereas mypy does not. Perhaps this is something mypy maintainers would consider changing.

Code sample in pyright playground

my_wanted_int = 2**3
reveal_type(my_wanted_int)  # int

my_2 = 2
my_3 = 3
reveal_type(my_2)  # (mypy: int, pyright: Literal[2])
reveal_type(my_3)  # (mypy: int, pyright: Literal[3])
star_result2 = my_2**my_3
reveal_type(star_result2)  # (mypy: Any, pyright: int)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

5 participants