Skip to content

Commit 4d8ee11

Browse files
authored
Add more return types to the numbers module (#11353)
1 parent 587e75f commit 4d8ee11

File tree

1 file changed

+71
-47
lines changed

1 file changed

+71
-47
lines changed

stdlib/numbers.pyi

Lines changed: 71 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,154 @@
11
# Note: these stubs are incomplete. The more complex type
22
# signatures are currently omitted.
3+
#
4+
# Use SupportsComplex, SupportsFloat and SupportsIndex for return types in this module
5+
# rather than `numbers.Complex`, `numbers.Real` and `numbers.Integral`,
6+
# to avoid an excessive number of `type: ignore`s in subclasses of these ABCs
7+
# (since type checkers don't see `complex` as a subtype of `numbers.Complex`,
8+
# nor `float` as a subtype of `numbers.Real`, etc.)
39

10+
import sys
411
from _typeshed import Incomplete
512
from abc import ABCMeta, abstractmethod
6-
from typing import SupportsFloat, overload
13+
from typing import Literal, SupportsFloat, SupportsIndex, overload
14+
from typing_extensions import TypeAlias
15+
16+
if sys.version_info >= (3, 11):
17+
from typing import SupportsComplex as _SupportsComplex
18+
else:
19+
# builtins.complex didn't have a __complex__ method on older Pythons
20+
import typing
21+
22+
_SupportsComplex: TypeAlias = typing.SupportsComplex | complex
723

824
__all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
925

1026
class Number(metaclass=ABCMeta):
1127
@abstractmethod
1228
def __hash__(self) -> int: ...
1329

30+
# See comment at the top of the file
31+
# for why some of these return types are purposefully vague
1432
class Complex(Number):
1533
@abstractmethod
1634
def __complex__(self) -> complex: ...
1735
def __bool__(self) -> bool: ...
1836
@property
1937
@abstractmethod
20-
def real(self): ...
38+
def real(self) -> SupportsFloat: ...
2139
@property
2240
@abstractmethod
23-
def imag(self): ...
41+
def imag(self) -> SupportsFloat: ...
2442
@abstractmethod
25-
def __add__(self, other): ...
43+
def __add__(self, other) -> _SupportsComplex: ...
2644
@abstractmethod
27-
def __radd__(self, other): ...
45+
def __radd__(self, other) -> _SupportsComplex: ...
2846
@abstractmethod
29-
def __neg__(self): ...
47+
def __neg__(self) -> _SupportsComplex: ...
3048
@abstractmethod
31-
def __pos__(self): ...
32-
def __sub__(self, other): ...
33-
def __rsub__(self, other): ...
49+
def __pos__(self) -> _SupportsComplex: ...
50+
def __sub__(self, other) -> _SupportsComplex: ...
51+
def __rsub__(self, other) -> _SupportsComplex: ...
3452
@abstractmethod
35-
def __mul__(self, other): ...
53+
def __mul__(self, other) -> _SupportsComplex: ...
3654
@abstractmethod
37-
def __rmul__(self, other): ...
55+
def __rmul__(self, other) -> _SupportsComplex: ...
3856
@abstractmethod
39-
def __truediv__(self, other): ...
57+
def __truediv__(self, other) -> _SupportsComplex: ...
4058
@abstractmethod
41-
def __rtruediv__(self, other): ...
59+
def __rtruediv__(self, other) -> _SupportsComplex: ...
4260
@abstractmethod
43-
def __pow__(self, exponent): ...
61+
def __pow__(self, exponent) -> _SupportsComplex: ...
4462
@abstractmethod
45-
def __rpow__(self, base): ...
63+
def __rpow__(self, base) -> _SupportsComplex: ...
4664
@abstractmethod
47-
def __abs__(self) -> Real: ...
65+
def __abs__(self) -> SupportsFloat: ...
4866
@abstractmethod
49-
def conjugate(self): ...
67+
def conjugate(self) -> _SupportsComplex: ...
5068
@abstractmethod
5169
def __eq__(self, other: object) -> bool: ...
5270

71+
# See comment at the top of the file
72+
# for why some of these return types are purposefully vague
5373
class Real(Complex, SupportsFloat):
5474
@abstractmethod
5575
def __float__(self) -> float: ...
5676
@abstractmethod
57-
def __trunc__(self) -> int: ...
77+
def __trunc__(self) -> SupportsIndex: ...
5878
@abstractmethod
59-
def __floor__(self) -> int: ...
79+
def __floor__(self) -> SupportsIndex: ...
6080
@abstractmethod
61-
def __ceil__(self) -> int: ...
81+
def __ceil__(self) -> SupportsIndex: ...
6282
@abstractmethod
6383
@overload
64-
def __round__(self, ndigits: None = None) -> int: ...
84+
def __round__(self, ndigits: None = None) -> SupportsIndex: ...
6585
@abstractmethod
6686
@overload
67-
def __round__(self, ndigits: int): ...
68-
def __divmod__(self, other): ...
69-
def __rdivmod__(self, other): ...
87+
def __round__(self, ndigits: int) -> SupportsFloat: ...
88+
def __divmod__(self, other) -> tuple[SupportsFloat, SupportsFloat]: ...
89+
def __rdivmod__(self, other) -> tuple[SupportsFloat, SupportsFloat]: ...
7090
@abstractmethod
71-
def __floordiv__(self, other) -> int: ...
91+
def __floordiv__(self, other) -> SupportsFloat: ...
7292
@abstractmethod
73-
def __rfloordiv__(self, other) -> int: ...
93+
def __rfloordiv__(self, other) -> SupportsFloat: ...
7494
@abstractmethod
75-
def __mod__(self, other): ...
95+
def __mod__(self, other) -> SupportsFloat: ...
7696
@abstractmethod
77-
def __rmod__(self, other): ...
97+
def __rmod__(self, other) -> SupportsFloat: ...
7898
@abstractmethod
7999
def __lt__(self, other) -> bool: ...
80100
@abstractmethod
81101
def __le__(self, other) -> bool: ...
82102
def __complex__(self) -> complex: ...
83103
@property
84-
def real(self): ...
104+
def real(self) -> SupportsFloat: ...
85105
@property
86-
def imag(self): ...
87-
def conjugate(self): ...
106+
def imag(self) -> Literal[0]: ...
107+
def conjugate(self) -> SupportsFloat: ... # type: ignore[override]
88108

109+
# See comment at the top of the file
110+
# for why some of these return types are purposefully vague
89111
class Rational(Real):
90112
@property
91113
@abstractmethod
92-
def numerator(self) -> int: ...
114+
def numerator(self) -> SupportsIndex: ...
93115
@property
94116
@abstractmethod
95-
def denominator(self) -> int: ...
117+
def denominator(self) -> SupportsIndex: ...
96118
def __float__(self) -> float: ...
97119

120+
# See comment at the top of the file
121+
# for why some of these return types are purposefully vague
98122
class Integral(Rational):
99123
@abstractmethod
100124
def __int__(self) -> int: ...
101125
def __index__(self) -> int: ...
102126
@abstractmethod
103-
def __pow__(self, exponent, modulus: Incomplete | None = None): ...
127+
def __pow__(self, exponent, modulus: Incomplete | None = None) -> SupportsIndex: ... # type: ignore[override]
104128
@abstractmethod
105-
def __lshift__(self, other): ...
129+
def __lshift__(self, other) -> SupportsIndex: ...
106130
@abstractmethod
107-
def __rlshift__(self, other): ...
131+
def __rlshift__(self, other) -> SupportsIndex: ...
108132
@abstractmethod
109-
def __rshift__(self, other): ...
133+
def __rshift__(self, other) -> SupportsIndex: ...
110134
@abstractmethod
111-
def __rrshift__(self, other): ...
135+
def __rrshift__(self, other) -> SupportsIndex: ...
112136
@abstractmethod
113-
def __and__(self, other): ...
137+
def __and__(self, other) -> SupportsIndex: ...
114138
@abstractmethod
115-
def __rand__(self, other): ...
139+
def __rand__(self, other) -> SupportsIndex: ...
116140
@abstractmethod
117-
def __xor__(self, other): ...
141+
def __xor__(self, other) -> SupportsIndex: ...
118142
@abstractmethod
119-
def __rxor__(self, other): ...
143+
def __rxor__(self, other) -> SupportsIndex: ...
120144
@abstractmethod
121-
def __or__(self, other): ...
145+
def __or__(self, other) -> SupportsIndex: ...
122146
@abstractmethod
123-
def __ror__(self, other): ...
147+
def __ror__(self, other) -> SupportsIndex: ...
124148
@abstractmethod
125-
def __invert__(self): ...
149+
def __invert__(self) -> SupportsIndex: ...
126150
def __float__(self) -> float: ...
127151
@property
128-
def numerator(self) -> int: ...
152+
def numerator(self) -> SupportsIndex: ...
129153
@property
130-
def denominator(self) -> int: ...
154+
def denominator(self) -> Literal[1]: ...

0 commit comments

Comments
 (0)