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

Add explanation if argument type is incompatible because of a "numbers" type #15137

Merged
merged 5 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions mypy/messages.py
Original file line number Diff line number Diff line change
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")
JukkaL marked this conversation as resolved.
Show resolved Hide resolved
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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