From 2b80cdf75e05869145e2de5a54fab5abaed8682a Mon Sep 17 00:00:00 2001 From: rwbarton Date: Sun, 1 May 2016 09:50:01 -0700 Subject: [PATCH] Use overloading rather than Union for MutableMapping.update (#174) See https://github.com/python/mypy/issues/1430 for motivation. --- stdlib/2.7/__builtin__.pyi | 6 ++++-- stdlib/2.7/collections.pyi | 7 ++++--- stdlib/2.7/typing.pyi | 6 ++++-- stdlib/3/builtins.pyi | 6 ++++-- stdlib/3/collections/__init__.pyi | 7 ++++--- stdlib/3/typing.pyi | 16 ++++++++++++++-- 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/stdlib/2.7/__builtin__.pyi b/stdlib/2.7/__builtin__.pyi index 480298f8f..3944416fb 100644 --- a/stdlib/2.7/__builtin__.pyi +++ b/stdlib/2.7/__builtin__.pyi @@ -531,8 +531,10 @@ class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): def pop(self, k: _KT, default: _VT = ...) -> _VT: ... def popitem(self) -> Tuple[_KT, _VT]: ... def setdefault(self, k: _KT, default: _VT = ...) -> _VT: ... - def update(self, m: Union[Mapping[_KT, _VT], - Iterable[Tuple[_KT, _VT]]]) -> None: ... + @overload + def update(self, m: Mapping[_KT, _VT]) -> None: ... + @overload + def update(self, m: Iterable[Tuple[_KT, _VT]]) -> None: ... def keys(self) -> List[_KT]: ... def values(self) -> List[_VT]: ... def items(self) -> List[Tuple[_KT, _VT]]: ... diff --git a/stdlib/2.7/collections.pyi b/stdlib/2.7/collections.pyi index 69f13677a..0d7182e8f 100644 --- a/stdlib/2.7/collections.pyi +++ b/stdlib/2.7/collections.pyi @@ -63,9 +63,10 @@ class Counter(Dict[_T, int], Generic[_T]): # it's included so that the signature is compatible with # Dict.update. Not sure if we should use '# type: ignore' instead # and omit the type from the union. - def update(self, m: Union[Mapping[_T, int], - Iterable[Tuple[_T, int]], - Iterable[_T]]) -> None: ... + @overload + def update(self, m: Mapping[_T, int]) -> None: ... + @overload + def update(self, m: Union[Iterable[_T], Iterable[Tuple[_T, int]]]) -> None: ... class OrderedDict(Dict[_KT, _VT], Generic[_KT, _VT]): def popitem(self, last: bool = ...) -> Tuple[_KT, _VT]: ... diff --git a/stdlib/2.7/typing.pyi b/stdlib/2.7/typing.pyi index 3d2e5cefd..77873df63 100644 --- a/stdlib/2.7/typing.pyi +++ b/stdlib/2.7/typing.pyi @@ -179,8 +179,10 @@ class MutableMapping(Mapping[_KT, _VT], Generic[_KT, _VT]): def pop(self, k: _KT, default: _VT = ...) -> _VT: ... def popitem(self) -> Tuple[_KT, _VT]: ... def setdefault(self, k: _KT, default: _VT = ...) -> _VT: ... - def update(self, m: Union[Mapping[_KT, _VT], - Iterable[Tuple[_KT, _VT]]]) -> None: ... + @overload + def update(self, m: Mapping[_KT, _VT]) -> None: ... + @overload + def update(self, m: Iterable[Tuple[_KT, _VT]]) -> None: ... Text = unicode diff --git a/stdlib/3/builtins.pyi b/stdlib/3/builtins.pyi index fc9d82b6e..f7e8562e1 100644 --- a/stdlib/3/builtins.pyi +++ b/stdlib/3/builtins.pyi @@ -506,8 +506,10 @@ class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): def pop(self, k: _KT, default: _VT = None) -> _VT: ... def popitem(self) -> Tuple[_KT, _VT]: ... def setdefault(self, k: _KT, default: _VT = None) -> _VT: ... - def update(self, m: Union[Mapping[_KT, _VT], - Iterable[Tuple[_KT, _VT]]]) -> None: ... + @overload + def update(self, m: Mapping[_KT, _VT]) -> None: ... + @overload + def update(self, m: Iterable[Tuple[_KT, _VT]]) -> None: ... def keys(self) -> KeysView[_KT]: ... def values(self) -> ValuesView[_VT]: ... def items(self) -> ItemsView[_KT, _VT]: ... diff --git a/stdlib/3/collections/__init__.pyi b/stdlib/3/collections/__init__.pyi index 4939e9268..fcf3b2f59 100644 --- a/stdlib/3/collections/__init__.pyi +++ b/stdlib/3/collections/__init__.pyi @@ -102,9 +102,10 @@ class Counter(Dict[_T, int], Generic[_T]): # it's included so that the signature is compatible with # Dict.update. Not sure if we should use '# type: ignore' instead # and omit the type from the union. - def update(self, m: Union[Mapping[_T, int], - Iterable[Tuple[_T, int]], - Iterable[_T]]) -> None: ... + @overload + def update(self, m: Mapping[_T, int]) -> None: ... + @overload + def update(self, m: Union[Iterable[_T], Iterable[Tuple[_T, int]]]) -> None: ... class OrderedDict(Dict[_KT, _VT], Generic[_KT, _VT]): def popitem(self, last: bool = ...) -> Tuple[_KT, _VT]: ... diff --git a/stdlib/3/typing.pyi b/stdlib/3/typing.pyi index 80da6cb1c..8bb760673 100644 --- a/stdlib/3/typing.pyi +++ b/stdlib/3/typing.pyi @@ -236,8 +236,20 @@ class MutableMapping(Mapping[_KT, _VT], Generic[_KT, _VT]): def pop(self, k: _KT, default: _VT = ...) -> _VT: ... def popitem(self) -> Tuple[_KT, _VT]: ... def setdefault(self, k: _KT, default: _VT = ...) -> _VT: ... - def update(self, m: Union[Mapping[_KT, _VT], - Iterable[Tuple[_KT, _VT]]]) -> None: ... + # 'update' used to take a Union, but using overloading is better. + # The second overloaded type here is a bit too general, because + # Mapping[Tuple[_KT, _VT], W] is a subclass of Iterable[Tuple[_KT, _VT]], + # but will always have the behavior of the first overloaded type + # at runtime, leading to keys of a mix of types _KT and Tuple[_KT, _VT]. + # We don't currently have any way of forcing all Mappings to use + # the first overload, but by using overloading rather than a Union, + # mypy will commit to using the first overload when the argument is + # known to be a Mapping with unknown type parameters, which is closer + # to the behavior we want. See mypy issue #1430. + @overload + def update(self, m: Mapping[_KT, _VT]) -> None: ... + @overload + def update(self, m: Iterable[Tuple[_KT, _VT]]) -> None: ... Text = str