From c22ec9f861091b8ac2944dfcefee0d35c7c467a9 Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 10 Feb 2025 16:27:08 -0500 Subject: [PATCH 1/7] Improve operator.itemgetter generic following mypy 1.11 fix --- .../test_cases/check_SupportsGetItem.py | 30 +++++++++++++++++++ stdlib/operator.pyi | 7 ++--- 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 stdlib/@tests/test_cases/check_SupportsGetItem.py diff --git a/stdlib/@tests/test_cases/check_SupportsGetItem.py b/stdlib/@tests/test_cases/check_SupportsGetItem.py new file mode 100644 index 000000000000..e17b8391415b --- /dev/null +++ b/stdlib/@tests/test_cases/check_SupportsGetItem.py @@ -0,0 +1,30 @@ +from _typeshed import SupportsGetItem +from operator import itemgetter +from collections.abc import Callable +from typing import TypeVar +from _typeshed import SupportsDunderGT, SupportsDunderLT +from collections.abc import Callable +from typing import Any, Tuple, TypeVar, Union + +_T = TypeVar("_T") + + +# This should be equivalent to itemgetter.__call__ +def standalone_call(obj: SupportsGetItem[int, _T]) -> _T: ... + + +# Regression tests for https://github.com/python/mypy/issues/14032 + +test_dict = min({"first": 1, "second": 2}, key=itemgetter(1)) +test_items = min({"first": 1, "second": 2}.items(), key=itemgetter(1)) +test_dict_standalone = min({"first": 1, "second": 2}, key=standalone_call) +test_items_standalone = min({"first": 1, "second": 2}.items(), key=standalone_call) + +expected_type_form_min_param_1: Callable[[Tuple[str, int]], Union[SupportsDunderLT[Any], SupportsDunderGT[Any]]] +revealed_type_itemgetter_call: Callable[[SupportsGetItem[Any, _T]], _T] # pyright: ignore[reportGeneralTypeIssues] + +revealed_type_itemgetter_call = itemgetter(1) +expected_type_form_min_param_1 = itemgetter(1) + +revealed_type_itemgetter_call = standalone_call +expected_type_form_min_param_1 = standalone_call diff --git a/stdlib/operator.pyi b/stdlib/operator.pyi index bc2b5e026617..33268b3b504d 100644 --- a/stdlib/operator.pyi +++ b/stdlib/operator.pyi @@ -203,11 +203,8 @@ class itemgetter(Generic[_T_co]): # __key: _KT_contra in SupportsGetItem seems to be causing variance issues, ie: # TypeVar "_KT_contra@SupportsGetItem" is contravariant # "tuple[int, int]" is incompatible with protocol "SupportsIndex" - # preventing [_T_co, ...] instead of [Any, ...] - # - # A suspected mypy issue prevents using [..., _T] instead of [..., Any] here. - # https://github.com/python/mypy/issues/14032 - def __call__(self, obj: SupportsGetItem[Any, Any]) -> Any: ... + # preventing [_T_co, _T] instead of [Any, _T] + def __call__(self, obj: SupportsGetItem[Any, _T]) -> _T: ... @final class methodcaller: From 36314daa64b723cb097ee10cc19ca7ed34a15623 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 21:31:33 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/@tests/test_cases/check_SupportsGetItem.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/stdlib/@tests/test_cases/check_SupportsGetItem.py b/stdlib/@tests/test_cases/check_SupportsGetItem.py index e17b8391415b..ab40be8daf7e 100644 --- a/stdlib/@tests/test_cases/check_SupportsGetItem.py +++ b/stdlib/@tests/test_cases/check_SupportsGetItem.py @@ -1,9 +1,6 @@ -from _typeshed import SupportsGetItem -from operator import itemgetter -from collections.abc import Callable -from typing import TypeVar -from _typeshed import SupportsDunderGT, SupportsDunderLT +from _typeshed import SupportsDunderGT, SupportsDunderLT, SupportsGetItem from collections.abc import Callable +from operator import itemgetter from typing import Any, Tuple, TypeVar, Union _T = TypeVar("_T") From ee422a8558527e4ff16649509f81e5e9e4d0dc2f Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 10 Feb 2025 16:34:11 -0500 Subject: [PATCH 3/7] Possibly fix six.byte2int entry from stubtest allowlist --- stubs/six/@tests/stubtest_allowlist.txt | 2 -- stubs/six/six/__init__.pyi | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/stubs/six/@tests/stubtest_allowlist.txt b/stubs/six/@tests/stubtest_allowlist.txt index b00e2bf52be9..5c638491dd63 100644 --- a/stubs/six/@tests/stubtest_allowlist.txt +++ b/stubs/six/@tests/stubtest_allowlist.txt @@ -14,8 +14,6 @@ six.get_method_self six.viewitems six.viewkeys six.viewvalues -# Should be `operator.itemgetter[int]`. But a bug in mypy prevents using TypeVar in itemgetter__call__ -six.byte2int # Utils six.Module_six_moves_urllib diff --git a/stubs/six/six/__init__.pyi b/stubs/six/six/__init__.pyi index e5a8fdbaa3c6..95e4d13b2bac 100644 --- a/stubs/six/six/__init__.pyi +++ b/stubs/six/six/__init__.pyi @@ -2,7 +2,7 @@ import builtins import operator import types import unittest -from _typeshed import IdentityFunction, SupportsGetItem, Unused +from _typeshed import IdentityFunction, Unused from builtins import next as next from collections.abc import Callable, ItemsView, Iterable, Iterator as _Iterator, KeysView, Mapping, ValuesView from functools import wraps as wraps @@ -61,8 +61,7 @@ unichr = chr def int2byte(i: int) -> bytes: ... -# Should be `byte2int: operator.itemgetter[int]`. But a bug in mypy prevents using TypeVar in itemgetter.__call__ -def byte2int(obj: SupportsGetItem[int, _T]) -> _T: ... +byte2int: operator.itemgetter[int] indexbytes = operator.getitem iterbytes = iter From 11bded322624980ba5c173867d0b3a45619ebe23 Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 10 Feb 2025 16:35:40 -0500 Subject: [PATCH 4/7] remove extra space --- stubs/six/six/__init__.pyi | 1 - 1 file changed, 1 deletion(-) diff --git a/stubs/six/six/__init__.pyi b/stubs/six/six/__init__.pyi index 95e4d13b2bac..b2a140f403b4 100644 --- a/stubs/six/six/__init__.pyi +++ b/stubs/six/six/__init__.pyi @@ -62,7 +62,6 @@ unichr = chr def int2byte(i: int) -> bytes: ... byte2int: operator.itemgetter[int] - indexbytes = operator.getitem iterbytes = iter From 8ce6cfb2bf112af3526085e1a6a392cdbad1327a Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 10 Feb 2025 17:21:11 -0500 Subject: [PATCH 5/7] Add from __future__ import annotations --- stdlib/@tests/test_cases/check_SupportsGetItem.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stdlib/@tests/test_cases/check_SupportsGetItem.py b/stdlib/@tests/test_cases/check_SupportsGetItem.py index ab40be8daf7e..1e0c9da15032 100644 --- a/stdlib/@tests/test_cases/check_SupportsGetItem.py +++ b/stdlib/@tests/test_cases/check_SupportsGetItem.py @@ -1,7 +1,9 @@ +from __future__ import annotations + from _typeshed import SupportsDunderGT, SupportsDunderLT, SupportsGetItem from collections.abc import Callable from operator import itemgetter -from typing import Any, Tuple, TypeVar, Union +from typing import Any, TypeVar _T = TypeVar("_T") @@ -17,7 +19,7 @@ def standalone_call(obj: SupportsGetItem[int, _T]) -> _T: ... test_dict_standalone = min({"first": 1, "second": 2}, key=standalone_call) test_items_standalone = min({"first": 1, "second": 2}.items(), key=standalone_call) -expected_type_form_min_param_1: Callable[[Tuple[str, int]], Union[SupportsDunderLT[Any], SupportsDunderGT[Any]]] +expected_type_form_min_param_1: Callable[[tuple[str, int]], SupportsDunderLT[Any] | SupportsDunderGT[Any]] revealed_type_itemgetter_call: Callable[[SupportsGetItem[Any, _T]], _T] # pyright: ignore[reportGeneralTypeIssues] revealed_type_itemgetter_call = itemgetter(1) From ad8f4d18d388270dcab1a28b7d8e5ba03ed8528d Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 10 Feb 2025 18:11:52 -0500 Subject: [PATCH 6/7] clearer, more relevant tests --- .../test_cases/check_SupportsGetItem.py | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/stdlib/@tests/test_cases/check_SupportsGetItem.py b/stdlib/@tests/test_cases/check_SupportsGetItem.py index 1e0c9da15032..7f3e8898b983 100644 --- a/stdlib/@tests/test_cases/check_SupportsGetItem.py +++ b/stdlib/@tests/test_cases/check_SupportsGetItem.py @@ -3,27 +3,34 @@ from _typeshed import SupportsDunderGT, SupportsDunderLT, SupportsGetItem from collections.abc import Callable from operator import itemgetter -from typing import Any, TypeVar +from typing import Any, TypeVar, assert_type _T = TypeVar("_T") -# This should be equivalent to itemgetter.__call__ -def standalone_call(obj: SupportsGetItem[int, _T]) -> _T: ... +# This should be equivalent to itemgetter().__call__ +def standalone_call(obj: SupportsGetItem[Any, _T]) -> _T: ... -# Regression tests for https://github.com/python/mypy/issues/14032 - -test_dict = min({"first": 1, "second": 2}, key=itemgetter(1)) -test_items = min({"first": 1, "second": 2}.items(), key=itemgetter(1)) -test_dict_standalone = min({"first": 1, "second": 2}, key=standalone_call) -test_items_standalone = min({"first": 1, "second": 2}.items(), key=standalone_call) +# Expected type of itemgetter(1).__call__ +expected_type_itemgetter_call: Callable[[SupportsGetItem[int, _T]], _T] # pyright: ignore[reportGeneralTypeIssues] -expected_type_form_min_param_1: Callable[[tuple[str, int]], SupportsDunderLT[Any] | SupportsDunderGT[Any]] -revealed_type_itemgetter_call: Callable[[SupportsGetItem[Any, _T]], _T] # pyright: ignore[reportGeneralTypeIssues] +# Expecting itemgetter(1) to be assignable to this +# based on the example below: min({"first": 1, "second": 2}.items(), key=itemgetter(1)) +expected_assignable_to: Callable[[tuple[str, int]], SupportsDunderLT[Any] | SupportsDunderGT[Any]] -revealed_type_itemgetter_call = itemgetter(1) -expected_type_form_min_param_1 = itemgetter(1) -revealed_type_itemgetter_call = standalone_call -expected_type_form_min_param_1 = standalone_call +# Regression tests for https://github.com/python/mypy/issues/14032 +assert_type(itemgetter("")({"first": 1, "second": 2}), int) +assert_type(min({"first": 1, "second": 2}, key=itemgetter(1)), str) +assert_type(min({"first": 1, "second": 2}.items(), key=itemgetter(1)), tuple[str, int]) +assert_type(standalone_call({"first": 1, "second": 2}), int) +assert_type(min({"first": 1, "second": 2}, key=standalone_call), str) +assert_type(min({"first": 1, "second": 2}.items(), key=standalone_call), tuple[str, int]) + +expected_itemgetter_call_type = itemgetter(1).__call__ +expected_itemgetter_call_type = itemgetter(1) +expected_assignable_to = itemgetter(1) + +expected_itemgetter_call_type = standalone_call +expected_assignable_to = standalone_call From 6662f2287a7b103d2c3d26b6793ccdca226f5bec Mon Sep 17 00:00:00 2001 From: Avasam Date: Mon, 10 Feb 2025 18:14:15 -0500 Subject: [PATCH 7/7] Additional comments --- stdlib/@tests/test_cases/check_SupportsGetItem.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/@tests/test_cases/check_SupportsGetItem.py b/stdlib/@tests/test_cases/check_SupportsGetItem.py index 7f3e8898b983..5319665a6be3 100644 --- a/stdlib/@tests/test_cases/check_SupportsGetItem.py +++ b/stdlib/@tests/test_cases/check_SupportsGetItem.py @@ -17,6 +17,7 @@ def standalone_call(obj: SupportsGetItem[Any, _T]) -> _T: ... # Expecting itemgetter(1) to be assignable to this # based on the example below: min({"first": 1, "second": 2}.items(), key=itemgetter(1)) +# That example and assigning to this variable are what failed in https://github.com/python/mypy/issues/14032 expected_assignable_to: Callable[[tuple[str, int]], SupportsDunderLT[Any] | SupportsDunderGT[Any]]