-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Pyright doesn't respect the Python numbers hierarchy #1575
Description
Describe the bug
When using abstract types from numbers, Pyright doesn't recognize either literals (1.1) or primitive types (float) as compatible with the abstract bases like Number, Integral, etc.
To Reproduce
import numbers
a: numbers.Number = 0 + 1j
# ~~~~~~
# Expression of type "complex" cannot be assigned to declared type "Number"
# "complex" is incompatible with "Number"
print(isinstance(a, numbers.Number))
# True
b: numbers.Real = 1.1
# ~~~
# Expression of type "float" cannot be assigned to declared type "Real"
# "float" is incompatible with "Real"
print(isinstance(b, numbers.Real))
# True
c: numbers.Integral = 3
# ~
# Expression of type "Literal[3]" cannot be assigned to declared type "Integral"
# "Literal[3]" is incompatible with "Integral"
print(isinstance(c, numbers.Integral))
# TrueExpected behavior
None of these statements would be type errors.
VS Code extension or command-line
VS Code extension, v1.1.117
Additional context
I'm not totally sure that this is pyright's fault—I don't really understand how abc and typing interact, and whether an abstract base class implicitly supports structural subtype-checking, or whether only explicit subclasses of Protocol support that. Maybe the solution here is actually some change to numbers in the standard library (or some additional stubs in typeshed).
Though this might seem extremely pedantic, using types from numbers can be handy when you don't know (and don't care) if you'll be getting a Python type, or a scalar from NumPy. Union[int, float] (correctly) rejects NumPy scalars. That said, of course the checker can't statically know if a NumPy scalar is Real vs Integral, so Number is probably the only practical type to use in that case.