Skip to content

Commit

Permalink
Add explanation if argument type is incompatible because of a "number…
Browse files Browse the repository at this point in the history
…s" type (#15137)

Types from `numbers` aren't really supported in any useful way. Make it
more explicit, since this is surprising.

Work on #3186.
  • Loading branch information
JukkaL committed Apr 26, 2023
1 parent 0dafc47 commit 0c6e18a
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
20 changes: 20 additions & 0 deletions mypy/messages.py
Expand Up @@ -137,6 +137,14 @@
"typing._SpecialForm": "typing-medium.pyi",
}

UNSUPPORTED_NUMBERS_TYPES: Final = {
"numbers.Number",
"numbers.Complex",
"numbers.Real",
"numbers.Rational",
"numbers.Integral",
}


class MessageBuilder:
"""Helper class for reporting type checker error messages with parameters.
Expand Down Expand Up @@ -792,6 +800,7 @@ def incompatible_argument(
for type in get_proper_types(expected_types):
if isinstance(arg_type, Instance) and isinstance(type, Instance):
notes = append_invariance_notes(notes, arg_type, type)
notes = append_numbers_notes(notes, arg_type, type)
object_type = get_proper_type(object_type)
if isinstance(object_type, TypedDictType):
code = codes.TYPEDDICT_ITEM
Expand Down Expand Up @@ -2992,6 +3001,17 @@ def append_invariance_notes(
return notes


def append_numbers_notes(
notes: list[str], arg_type: Instance, expected_type: Instance
) -> list[str]:
"""Explain if an unsupported type from "numbers" is used in a subtype check."""
if expected_type.type.fullname in UNSUPPORTED_NUMBERS_TYPES:
notes.append('Types from "numbers" aren\'t supported for static type checking')
notes.append("See https://peps.python.org/pep-0484/#the-numeric-tower")
notes.append("Consider using a protocol instead, such as typing.SupportsFloat")
return notes


def make_inferred_type_note(
context: Context, subtype: Type, supertype: Type, supertype_str: str
) -> str:
Expand Down
33 changes: 33 additions & 0 deletions test-data/unit/check-classes.test
Expand Up @@ -7826,3 +7826,36 @@ class D:
# and that's what matters.
a, b = self.f() # E: "C" has no attribute "__iter__" (not iterable)
[builtins fixtures/tuple.pyi]

[case testUsingNumbersType]
from numbers import Number, Complex, Real, Rational, Integral

def f1(x: Number) -> None: pass
f1(1) # E: Argument 1 to "f1" has incompatible type "int"; expected "Number" \
# N: Types from "numbers" aren't supported for static type checking \
# N: See https://peps.python.org/pep-0484/#the-numeric-tower \
# N: Consider using a protocol instead, such as typing.SupportsFloat

def f2(x: Complex) -> None: pass
f2(1) # E: Argument 1 to "f2" has incompatible type "int"; expected "Complex" \
# N: Types from "numbers" aren't supported for static type checking \
# N: See https://peps.python.org/pep-0484/#the-numeric-tower \
# N: Consider using a protocol instead, such as typing.SupportsFloat

def f3(x: Real) -> None: pass
f3(1) # E: Argument 1 to "f3" has incompatible type "int"; expected "Real" \
# N: Types from "numbers" aren't supported for static type checking \
# N: See https://peps.python.org/pep-0484/#the-numeric-tower \
# N: Consider using a protocol instead, such as typing.SupportsFloat

def f4(x: Rational) -> None: pass
f4(1) # E: Argument 1 to "f4" has incompatible type "int"; expected "Rational" \
# N: Types from "numbers" aren't supported for static type checking \
# N: See https://peps.python.org/pep-0484/#the-numeric-tower \
# N: Consider using a protocol instead, such as typing.SupportsFloat

def f5(x: Integral) -> None: pass
f5(1) # E: Argument 1 to "f5" has incompatible type "int"; expected "Integral" \
# N: Types from "numbers" aren't supported for static type checking \
# N: See https://peps.python.org/pep-0484/#the-numeric-tower \
# N: Consider using a protocol instead, such as typing.SupportsFloat
10 changes: 10 additions & 0 deletions test-data/unit/lib-stub/numbers.pyi
@@ -0,0 +1,10 @@
# Test fixture for numbers
#
# The numbers module isn't properly supported, but we want to test that mypy
# can tell that it doesn't work as expected.

class Number: pass
class Complex: pass
class Real: pass
class Rational: pass
class Integral: pass

0 comments on commit 0c6e18a

Please sign in to comment.