Skip to content

Commit 796bdc2

Browse files
authored
Improve accuracy of six byte index methods (#9117)
1 parent 0ac98f6 commit 796bdc2

File tree

6 files changed

+41
-20
lines changed

6 files changed

+41
-20
lines changed

stdlib/_operator.pyi

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
2-
from collections.abc import Callable, Container, Iterable, Mapping, MutableMapping, MutableSequence, Sequence
2+
from _typeshed import SupportsGetItem
3+
from collections.abc import Callable, Container, Iterable, MutableMapping, MutableSequence, Sequence
34
from typing import Any, AnyStr, Generic, Protocol, SupportsAbs, TypeVar, overload
45
from typing_extensions import ParamSpec, SupportsIndex, TypeAlias, final
56

@@ -77,11 +78,9 @@ def delitem(__a: MutableSequence[Any], __b: slice) -> None: ...
7778
@overload
7879
def delitem(__a: MutableMapping[_K, Any], __b: _K) -> None: ...
7980
@overload
80-
def getitem(__a: Sequence[_T], __b: SupportsIndex) -> _T: ...
81-
@overload
8281
def getitem(__a: Sequence[_T], __b: slice) -> Sequence[_T]: ...
8382
@overload
84-
def getitem(__a: Mapping[_K, _V], __b: _K) -> _V: ...
83+
def getitem(__a: SupportsGetItem[_K, _V], __b: _K) -> _V: ...
8584
def indexOf(__a: Iterable[_T], __b: _T) -> int: ...
8685
@overload
8786
def setitem(__a: MutableSequence[_T], __b: SupportsIndex, __c: _T) -> None: ...
@@ -106,17 +105,30 @@ class attrgetter(Generic[_T_co]):
106105

107106
@final
108107
class itemgetter(Generic[_T_co]):
108+
# mypy lacks support for PEP 646 https://github.com/python/mypy/issues/12280
109+
# So we have to define all of these overloads to simulate unpacking the arguments
109110
@overload
110-
def __new__(cls, item: Any) -> itemgetter[Any]: ...
111+
def __new__(cls, item: _T_co) -> itemgetter[_T_co]: ...
111112
@overload
112-
def __new__(cls, item: Any, __item2: Any) -> itemgetter[tuple[Any, Any]]: ...
113+
def __new__(cls, item: _T_co, __item2: _T_co) -> itemgetter[tuple[_T_co, _T_co]]: ...
113114
@overload
114-
def __new__(cls, item: Any, __item2: Any, __item3: Any) -> itemgetter[tuple[Any, Any, Any]]: ...
115+
def __new__(cls, item: _T_co, __item2: _T_co, __item3: _T_co) -> itemgetter[tuple[_T_co, _T_co, _T_co]]: ...
115116
@overload
116-
def __new__(cls, item: Any, __item2: Any, __item3: Any, __item4: Any) -> itemgetter[tuple[Any, Any, Any, Any]]: ...
117+
def __new__(
118+
cls, item: _T_co, __item2: _T_co, __item3: _T_co, __item4: _T_co
119+
) -> itemgetter[tuple[_T_co, _T_co, _T_co, _T_co]]: ...
117120
@overload
118-
def __new__(cls, item: Any, *items: Any) -> itemgetter[tuple[Any, ...]]: ...
119-
def __call__(self, obj: Any) -> _T_co: ...
121+
def __new__(
122+
cls, item: _T_co, __item2: _T_co, __item3: _T_co, __item4: _T_co, *items: _T_co
123+
) -> itemgetter[tuple[_T_co, ...]]: ...
124+
# __key: _KT_contra in SupportsGetItem seems to be causing variance issues, ie:
125+
# TypeVar "_KT_contra@SupportsGetItem" is contravariant
126+
# "tuple[int, int]" is incompatible with protocol "SupportsIndex"
127+
# preventing [_T_co, ...] instead of [Any, ...]
128+
#
129+
# A suspected mypy issue prevents using [..., _T] instead of [..., Any] here.
130+
# https://github.com/python/mypy/issues/14032
131+
def __call__(self, obj: SupportsGetItem[Any, Any]) -> Any: ...
120132

121133
@final
122134
class methodcaller:

stdlib/_typeshed/__init__.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class SupportsKeysAndGetItem(Protocol[_KT, _VT_co]):
119119

120120
# stable
121121
class SupportsGetItem(Protocol[_KT_contra, _VT_co]):
122-
def __contains__(self, __x: object) -> bool: ...
122+
def __contains__(self, __x: Any) -> bool: ...
123123
def __getitem__(self, __key: _KT_contra) -> _VT_co: ...
124124

125125
# stable

stdlib/mmap.pyi

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ class mmap(Iterable[int], Sized):
6767
def __setitem__(self, __index: int, __object: int) -> None: ...
6868
@overload
6969
def __setitem__(self, __index: slice, __object: ReadableBuffer) -> None: ...
70-
# Doesn't actually exist, but the object is actually iterable because it has __getitem__ and
71-
# __len__, so we claim that there is also an __iter__ to help type checkers.
70+
# Doesn't actually exist, but the object actually supports "in" because it has __getitem__,
71+
# so we claim that there is also a __contains__ to help type checkers.
72+
def __contains__(self, __o: object) -> bool: ...
73+
# Doesn't actually exist, but the object is actually iterable because it has __getitem__ and __len__,
74+
# so we claim that there is also an __iter__ to help type checkers.
7275
def __iter__(self) -> Iterator[int]: ...
7376
def __enter__(self: Self) -> Self: ...
7477
def __exit__(self, *args: object) -> None: ...

stubs/six/@tests/stubtest_allowlist.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ six.create_bound_method.__defaults__
88
six.moves.*
99

1010
# Implemented using "operator" functions in the implementation
11-
six.byte2int
12-
six.indexbytes
1311
six.get_function_closure
1412
six.get_function_code
1513
six.get_function_defaults
@@ -19,6 +17,8 @@ six.get_method_self
1917
six.viewitems
2018
six.viewkeys
2119
six.viewvalues
20+
# Should be `operator.itemgetter[int]`. But a bug in mypy prevents using TypeVar in itemgetter__call__
21+
six.byte2int
2222

2323
# Unclear problems
2424
six.callable

stubs/six/six/__init__.pyi

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import builtins
2+
import operator
23
import types
34
import unittest
4-
from _typeshed import IdentityFunction
5+
from _typeshed import IdentityFunction, SupportsGetItem
56
from builtins import next as next
67
from collections.abc import Callable, ItemsView, Iterable, Iterator as _Iterator, KeysView, Mapping, ValuesView
78
from functools import wraps as wraps
@@ -11,7 +12,7 @@ from re import Pattern
1112
from typing import Any, AnyStr, NoReturn, TypeVar, overload
1213
from typing_extensions import Literal
1314

14-
from . import moves as moves
15+
from six import moves as moves
1516

1617
_T = TypeVar("_T")
1718
_K = TypeVar("_K")
@@ -63,9 +64,13 @@ def u(s: str) -> str: ...
6364
unichr = chr
6465

6566
def int2byte(i: int) -> bytes: ...
66-
def byte2int(bs: bytes) -> int: ...
67-
def indexbytes(buf: bytes, i: int) -> int: ...
68-
def iterbytes(buf: bytes) -> _Iterator[int]: ...
67+
68+
# Should be `byte2int: operator.itemgetter[int]`. But a bug in mypy prevents using TypeVar in itemgetter__call__
69+
def byte2int(obj: SupportsGetItem[int, _T]) -> _T: ...
70+
71+
indexbytes = operator.getitem
72+
iterbytes = iter
73+
6974
def assertCountEqual(self: unittest.TestCase, first: Iterable[_T], second: Iterable[_T], msg: str | None = ...) -> None: ...
7075
@overload
7176
def assertRaisesRegex(self: unittest.TestCase, msg: str | None = ...) -> Any: ...

tests/stubtest_allowlists/py3_common.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ wsgiref.handlers.BaseHandler.status
615615
# These would ideally be special-cased by type checkers; see https://github.com/python/mypy/issues/2220
616616
ctypes.Array.__iter__
617617
mmap.mmap.__iter__
618+
mmap.mmap.__contains__
618619
xml.etree.ElementTree.Element.__iter__
619620
xml.etree.cElementTree.Element.__iter__
620621
typing.IO.__iter__ # See https://github.com/python/typeshed/commit/97bc450acd60c1bcdafef3ce8fbe3b95a9c0cac3

0 commit comments

Comments
 (0)