8000 Ensures overloads are ordered from narrow to broad (#2138) · python/typeshed@97d9f2e · GitHub
[go: up one dir, main page]

Skip to content

Commit 97d9f2e

Browse files
Michael0x2aJelleZijlstra
authored andcommitted
Ensures overloads are ordered from narrow to broad (#2138)
This commit reorders any overloads where the first overload was "shadowing" the second, preventing it from ever being matched by type checkers that work by selecting the first matching overload alternative. For example, the first overload alternative below is strictly broader then the second, preventing it from ever being selected: class Parent: pass class Child(Parent): pass @overload def foo(x: *int) -> Parent: ... @overload def foo(x: int, y: int) -> Child: ... The correct thing to do is to either delete the second overload or rearrange them to look like this: @overload def foo(x: int, y: int) -> Child: ... @overload def foo(x: *int) -> Parent: ... Rationale: I'm currently [working on a proposal][0] that would amend PEP 484 to (a) mandate type checkers check overloads in order and (b) prohibit overloads where an earlier alternative completely shadows a later one. [0]: python/typing#253 (comment) This would prohibit overloads that look like the example below, where the first alternative completely shadows the second. I figured it would be a good idea to make these changes ahead of time: if my proposal is accepted, it'd make the transition smoother. If not, this is hopefully a relatively harmless change. Note: I think some of these overloads could be simplified (e.g. `reversed(...)`), but I mostly stuck with rearranging them in case I was wrong. The only overload I actually changed was `hmac.compare_digest` -- I believe the Python 2 version actually accepts unicode.
1 parent d5929ad commit 97d9f2e

File tree

10 files changed

+66
-68
lines changed

10 files changed

+66
-68
lines changed

stdlib/2/__builtin__.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,9 +863,9 @@ def reduce(function: Callable[[_T, _T], _T], iterable: Iterable[_T]) -> _T: ...
863863

864864
def reload(module: Any) -> Any: ...
865865
@overload
866-
def reversed(object: Reversible[_T]) -> Iterator[_T]: ...
867-
@overload
868866
def reversed(object: Sequence[_T]) -> Iterator[_T]: ...
867+
@overload
868+
def reversed(object: Reversible[_T]) -> Iterator[_T]: ...
869869
def repr(o: object) -> str: ...
870870
@overload
871871
def round(number: float) -> float: ...

stdlib/2/builtins.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,9 +863,9 @@ def reduce(function: Callable[[_T, _T], _T], iterable: Iterable[_T]) -> _T: ...
863863

864864
def reload(module: Any) -> Any: ...
865865
@overload
866-
def reversed(object: Reversible[_T]) -> Iterator[_T]: ...
867-
@overload
868866
def reversed(object: Sequence[_T]) -> Iterator[_T]: ...
867+
@overload
868+
def reversed(object: Reversible[_T]) -> Iterator[_T]: ...
869869
def repr(o: object) -> str: ...
870870
@overload
871871
def round(number: float) -> float: ...

stdlib/2/os/__init__.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,9 @@ def renames(old: _PathType, new: _PathType) -> None: ...
219219
def rmdir(path: _PathType) -> None: ...
220220
def stat(path: _PathType) -> Any: ...
221221
@overload
222-
def stat_float_times(newvalue: bool = ...) -> None: ...
223-
@overload
224222
def stat_float_times() -> bool: ...
223+
@overload
224+
def stat_float_times(newvalue: bool) -> None: ...
225225
def statvfs(path: _PathType) -> _StatVFS: ... # Unix only
226226
def symlink(source: _PathType, link_name: _PathType) -> None: ...
227227
def unlink(path: _PathType) -> None: ...

stdlib/2/os/path.pyi

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,13 @@ if sys.version_info < (3, 0):
123123
@overload
124124
def join(__p1: bytes, *p: bytes) -> bytes: ...
125125
@overload
126-
def join(__p1: Text, *p: _PathType) -> Text: ...
127-
@overload
128-
def join(__p1: bytes, __p2: Text, *p: _PathType) -> Text: ...
126+
def join(__p1: bytes, __p2: bytes, __p3: bytes, __p4: Text, *p: _PathType) -> Text: ...
129127
@overload
130128
def join(__p1: bytes, __p2: bytes, __p3: Text, *p: _PathType) -> Text: ...
131129
@overload
132-
def join(__p1: bytes, __p2: bytes, __p3: bytes, __p4: Text, *p: _PathType) -> Text: ...
130+
def join(__p1: bytes, __p2: Text, *p: _PathType) -> Text: ...
131+
@overload
132+
def join(__p1: Text, *p: _PathType) -> Text: ...
133133
elif sys.version_info >= (3, 6):
134134
# Mypy complains that the signatures overlap (same for relpath below), but things seem to behave correctly anyway.
135135
@overload

stdlib/2and3/hmac.pyi

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Stubs for hmac
22

3-
from typing import Any, Callable, Optional, Union, overload
3+
from typing import Any, Callable, Optional, Union, overload, AnyStr
44
from types import ModuleType
55
import sys
66

@@ -29,12 +29,10 @@ class HMAC:
2929
def hexdigest(self) -> str: ...
3030
def copy(self) -> HMAC: ...
3131

32-
@overload
33-
def compare_digest(a: str, b: str) -> bool: ...
34-
@overload
35-
def compare_digest(a: bytes, b: bytes) -> bool: ...
3632
@overload
3733
def compare_digest(a: bytearray, b: bytearray) -> bool: ...
34+
@overload
35+
def compare_digest(a: AnyStr, b: AnyStr) -> bool: ...
3836

3937
if sys.version_info >= (3, 7):
4038
def digest(key: _B, msg: _B, digest: str) -> bytes: ...

stdlib/2and3/sysconfig.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
from typing import overload, Any, Dict, IO, List, Optional, Tuple, Union
44

5-
@overload
6-
def get_config_vars(*args: str) -> List[Any]: ...
75
@overload
86
def get_config_vars() -> Dict[str, Any]: ...
7+
@overload
8+
def get_config_vars(*args: str) -> List[Any]: ...
99
def get_config_var(name: str) -> Optional[str]: ...
1010
def get_scheme_names() -> Tuple[str, ...]: ...
1111
def get_path_names() -> Tuple[str, ...]: ...

stdlib/3/builtins.pyi

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -816,9 +816,9 @@ def eval(source: Union[str, bytes, CodeType], globals: Optional[Dict[str, Any]]
816816
def exec(object: Union[str, bytes, CodeType], globals: Optional[Dict[str, Any]] = ..., locals: Optional[Mapping[str, Any]] = ...) -> Any: ...
817817
def exit(code: Any = ...) -> NoReturn: ...
818818
@overload
819-
def filter(function: Callable[[_T], Any], iterable: Iterable[_T]) -> Iterator[_T]: ...
820-
@overload
821819
def filter(function: None, iterable: Iterable[Optional[_T]]) -> Iterator[_T]: ...
820+
@overload
821+
def filter(function: Callable[[_T], Any], iterable: Iterable[_T]) -> Iterator[_T]: ...
822822
def format(o: object, format_spec: str = ...) -> str: ...
823823
def getattr(o: Any, name: str, default: Any = ...) -> Any: ...
824824
def globals() -> Dict[str, Any]: ...
@@ -908,9 +908,9 @@ def pow(x: float, y: float) -> float: ...
908908
def pow(x: float, y: float, z: float) -> float: ...
909909
def quit(code: Optional[int] = ...) -> None: ...
910910
@overload
911-
def reversed(object: Reversible[_T]) -> Iterator[_T]: ...
912-
@overload
913911
def reversed(object: Sequence[_T]) -> Iterator[_T]: ...
912+
@overload
913+
def reversed(object: Reversible[_T]) -> Iterator[_T]: ...
914914
def repr(o: object) -> str: ...
915915
@overload
916916
def round(number: float) -> int: ...

stdlib/3/typing.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,10 @@ class BinaryIO(IO[bytes]):
434434
# TODO peek?
435435
@overload
436436
@abstractmethod
437-
def write(self, s: bytes) -> int: ...
437+
def write(self, s: bytearray) -> int: ...
438438
@overload
439439
@abstractmethod
440-
def write(self, s: bytearray) -> int: ...
440+
def write(self, s: bytes) -> int: ...
441441

442442
@abstractmethod
443443
def __enter__(self) -> BinaryIO: ...

stdlib/3/urllib/parse.pyi

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,12 @@ def urlsplit(url: str, scheme: str = ..., allow_fragments: bool = ...) -> SplitR
137137
@overload
138138
def urlsplit(url: bytes, scheme: bytes = ..., allow_fragments: bool = ...) -> SplitResultBytes: ...
139139

140-
@overload
141-
def urlunparse(components: Sequence[AnyStr]) -> AnyStr: ...
142140
@overload
143141
def urlunparse(components: Tuple[AnyStr, AnyStr, AnyStr, AnyStr, AnyStr, AnyStr]) -> AnyStr: ...
144-
145142
@overload
146-
def urlunsplit(components: Sequence[AnyStr]) -> AnyStr: ...
143+
def urlunparse(components: Sequence[AnyStr]) -> AnyStr: ...
144+
147145
@overload
148146
def urlunsplit(components: Tuple[AnyStr, AnyStr, AnyStr, AnyStr, AnyStr]) -> AnyStr: ...
147+
@overload
148+
def urlunsplit(components: Sequence[AnyStr]) -> AnyStr: ...

third_party/2and3/attr/__init__.pyi

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,21 @@ class Attribute(Generic[_T]):
6969
# attr(validator=<some callable>) -> Whatever the callable expects.
7070
# This makes this type of assignments possible:
7171
# x: int = attr(8)
72-
72+
#
73+
# This form catches explicit None or no default but with no other arguments returns Any.
74+
@overload
75+
def attrib(default: None = ...,
76+
validator: None = ...,
77+
repr: bool = ...,
78+
cmp: bool = ...,
79+
hash: Optional[bool] = ...,
80+
init: bool = ...,
81+
convert: None = ...,
82+
metadata: Optional[Mapping[Any, Any]] = ...,
83+
type: None = ...,
84+
converter: None = ...,
85+
factory: None = ...,
86+
) -> Any: ...
7387
# This form catches an explicit None or no default and infers the type from the other arguments.
7488
@overload
7589
def attrib(default: None = ...,
@@ -98,20 +112,6 @@ def attrib(default: _T,
98112
converter: Optional[_ConverterType[_T]] = ...,
99113
factory: Optional[Callable[[], _T]] = ...,
100114
) -> _T: ...
101-
# This form catches explicit None or no default but with no other arguments returns Any.
102-
@overload
103-
def attrib(default: None = ...,
104-
validator: None = ...,
105-
repr: bool = ...,
106-
cmp: bool = ...,
107-
hash: Optional[bool] = ...,
108-
init: bool = ...,
109-
convert: None = ...,
110-
metadata: Optional[Mapping[Any, Any]] = ...,
111-
type: None = ...,
112-
converter: None = ...,
113-
factory: None = ...,
114-
) -> Any: ...
115115
# This form covers type=non-Type: e.g. forward references (str), Any
116116
@overload
117117
def attrib(default: Optional[_T] = ...,
@@ -216,6 +216,19 @@ def get_run_validators() -> bool: ...
216216
# dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)
217217

218218

219+
@overload
220+
def ib(default: None = ...,
221+
validator: None = ...,
222+
repr: bool = ...,
223+
cmp: bool = ...,
224+
hash: Optional[bool] = ...,
225+
init: bool = ...,
226+
convert: None = ...,
227+
metadata: Optional[Mapping[Any, Any]] = ...,
228+
type: None = ...,
229+
converter: None = ...,
230+
factory: None = ...,
231+
) -> Any: ...
219232
@overload
220233
def ib(default: None = ...,
221234
validator: Optional[_ValidatorArgType[_T]] = ...,
@@ -243,19 +256,6 @@ def ib(default: _T,
243256
factory: Optional[Callable[[], _T]] = ...,
244257
) -> _T: ...
245258
@overload
246-
def ib(default: None = ...,
247-
validator: None = ...,
248-
repr: bool = ...,
249-
cmp: bool = ...,
250-
hash: Optional[bool] = ...,
251-
init: bool = ...,
252-
convert: None = ...,
253-
metadata: Optional[Mapping[Any, Any]] = ...,
254-
type: None = ...,
255-
converter: None = ...,
256-
factory: None = ...,
257-
) -> Any: ...
258-
@overload
259259
def ib(default: Optional[_T] = ...,
260260
validator: Optional[_ValidatorArgType[_T]] = ...,
261261
repr: bool = ...,
@@ -270,6 +270,19 @@ def ib(default: Optional[_T] = ...,
270270
) -> Any: ...
271271

272272
@overload
273+
def attr(default: None = ...,
274+
validator: None = ...,
275+
repr: bool = ...,
276+
cmp: bool = ...,
277+
hash: Optional[bool] = ...,
278+
init: bool = ...,
279+
convert: None = ...,
280+
metadata: Optional[Mapping[Any, Any]] = ...,
281+
type: None = ...,
282+
converter: None = ...,
283+
factory: None = ...,
284+
) -> Any: ...
285+
@overload
273286
def attr(default: None = ...,
274287
validator: Optional[_ValidatorArgType[_T]] = ...,
275288
repr: bool = ...,
@@ -296,19 +309,6 @@ def attr(default: _T,
296309
factory: Optional[Callable[[], _T]] = ...,
297310
) -> _T: ...
298311
@overload
299-
def attr(default: None = ...,
300-
validator: None = ...,
301-
repr: bool = ...,
302-
cmp: bool = ...,
303-
hash: Optional[bool] = ...,
304-
init: bool = ...,
305-
convert: None = ...,
306-
metadata: Optional[Mapping[Any, Any]] = ...,
307-
type: None = ...,
308-
converter: None = ...,
309-
factory: None = ...,
310-
) -> Any: ...
311-
@overload
312312
def attr(default: Optional[_T] = ...,
313313
validator: Optional[_ValidatorArgType[_T]] = ...,
314314
repr: bool = ...,

0 commit comments

Comments
 (0)
0