diff --git a/pyproject.toml b/pyproject.toml index fa3befac8..47af90b2c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -149,5 +149,5 @@ extra-standard-library = [ known-first-party = ["parse_metadata", "utils"] [tool.typeshed] -pyright_version = "1.1.350" +pyright_version = "1.1.354" oldest_supported_python = "3.8" diff --git a/requirements-tests.txt b/requirements-tests.txt index 2dc611b3c..5d8a62dd7 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -7,7 +7,7 @@ flake8-noqa==1.4.0 # must match .pre-commit-config.yaml flake8-pyi==24.3.0 # must match .pre-commit-config.yaml mypy==1.9.0 pre-commit-hooks==4.5.0 # must match .pre-commit-config.yaml -pytype==2024.2.27; platform_system != "Windows" and python_version < "3.12" +pytype==2024.3.11; platform_system != "Windows" and python_version < "3.12" ruff==0.3.0 # must match .pre-commit-config.yaml # Libraries used by our various scripts. diff --git a/scripts/stubsabot.py b/scripts/stubsabot.py index 64c6c475c..d66018c0b 100644 --- a/scripts/stubsabot.py +++ b/scripts/stubsabot.py @@ -473,7 +473,7 @@ async def determine_action(stub_path: Path, session: aiohttp.ClientSession) -> U relevant_version = obsolete_since.version if obsolete_since else latest_version - project_urls = pypi_info.info["project_urls"] or {} + project_urls: dict[str, str] = pypi_info.info["project_urls"] or {} maybe_links: dict[str, str | None] = { "Release": f"{pypi_info.pypi_root}/{relevant_version}", "Homepage": project_urls.get("Homepage"), diff --git a/stdlib/collections/__init__.pyi b/stdlib/collections/__init__.pyi index 262b2840e..1d23ecd66 100644 --- a/stdlib/collections/__init__.pyi +++ b/stdlib/collections/__init__.pyi @@ -137,8 +137,10 @@ class UserList(MutableSequence[_T]): def copy(self) -> Self: ... def __copy__(self) -> Self: ... def count(self, item: _T) -> int: ... - # All arguments are passed to `list.index` at runtime, so the signature should be kept in line with `list.index`. - def index(self, item: _T, __start: SupportsIndex = 0, __stop: SupportsIndex = sys.maxsize) -> int: ... + # The runtime signature is "item, *args", and the arguments are then passed + # to `list.index`. In order to give more precise types, we pretend that the + # `item` argument is positional-only. + def index(self, item: _T, start: SupportsIndex = 0, stop: SupportsIndex = sys.maxsize, /) -> int: ... # All arguments are passed to `list.sort` at runtime, so the signature should be kept in line with `list.sort`. @overload def sort(self: UserList[SupportsRichComparisonT], *, key: None = None, reverse: bool = False) -> None: ... @@ -459,7 +461,11 @@ class ChainMap(MutableMapping[_KT, _VT]): # All arguments to `fromkeys` are passed to `dict.fromkeys` at runtime, so the signature should be kept in line with `dict.fromkeys`. @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T], __value: None = None) -> ChainMap[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_T]) -> ChainMap[_T, Any | None]: ... + @classmethod + @overload + # Special-case None: the user probably wants to add non-None values later. + def fromkeys(cls, iterable: Iterable[_T], value: None, /) -> ChainMap[_T, Any | None]: ... @classmethod @overload def fromkeys(cls, iterable: Iterable[_T], value: _S, /) -> ChainMap[_T, _S]: ... diff --git a/stdlib/dataclasses.pyi b/stdlib/dataclasses.pyi index a3f288ceb..00e0d31d0 100644 --- a/stdlib/dataclasses.pyi +++ b/stdlib/dataclasses.pyi @@ -227,16 +227,18 @@ if sys.version_info >= (3, 9): else: class _InitVarMeta(type): # Not used, instead `InitVar.__class_getitem__` is called. - def __getitem__(self, params: Any) -> InitVar[Any]: ... + # pyright ignore is needed because pyright (not unreasonably) thinks this + # is an invalid use of InitVar. + def __getitem__(self, params: Any) -> InitVar[Any]: ... # pyright: ignore class InitVar(Generic[_T], metaclass=_InitVarMeta): type: Type[_T] def __init__(self, type: Type[_T]) -> None: ... if sys.version_info >= (3, 9): @overload - def __class_getitem__(cls, type: Type[_T]) -> InitVar[_T]: ... + def __class_getitem__(cls, type: Type[_T]) -> InitVar[_T]: ... # pyright: ignore @overload - def __class_getitem__(cls, type: Any) -> InitVar[Any]: ... + def __class_getitem__(cls, type: Any) -> InitVar[Any]: ... # pyright: ignore if sys.version_info >= (3, 12): def make_dataclass( diff --git a/stubs/gevent/@tests/stubtest_allowlist.txt b/stubs/gevent/@tests/stubtest_allowlist.txt index aa6d08101..c35927487 100644 --- a/stubs/gevent/@tests/stubtest_allowlist.txt +++ b/stubs/gevent/@tests/stubtest_allowlist.txt @@ -217,3 +217,8 @@ gevent.events.IPeriodicMonitorThreadStartedEvent # internal use module for some complex protocols used across different modules # so there wasn't really a great place for them gevent._types + +# The first parameter is technically positional-or-keyword but there's no +# useful way to use it as a keyword argument; we mark it positional-only. +gevent.pool.GroupMappingMixin.imap +gevent.pool.GroupMappingMixin.imap_unordered diff --git a/stubs/gevent/gevent/pool.pyi b/stubs/gevent/gevent/pool.pyi index 76996403f..ffda74704 100644 --- a/stubs/gevent/gevent/pool.pyi +++ b/stubs/gevent/gevent/pool.pyi @@ -47,18 +47,19 @@ class GroupMappingMixin: self, func: Callable[[_T], _S], iterable: Iterable[_T], callback: Callable[[list[_S]], object] | None = None ) -> Greenlet[..., list[_S]]: ... @overload - def imap(self, func: Callable[[_T1], _S], __iter1: Iterable[_T1], *, maxsize: int | None = None) -> IMap[[_T1], _S]: ... + def imap(self, func: Callable[[_T1], _S], iter1: Iterable[_T1], /, *, maxsize: int | None = None) -> IMap[[_T1], _S]: ... @overload def imap( - self, func: Callable[[_T1, _T2], _S], __iter1: Iterable[_T1], __iter2: Iterable[_T2], *, maxsize: int | None = None + self, func: Callable[[_T1, _T2], _S], iter1: Iterable[_T1], iter2: Iterable[_T2], /, *, maxsize: int | None = None ) -> IMap[[_T1, _T2], _S]: ... @overload def imap( self, func: Callable[[_T1, _T2, _T3], _S], - __iter1: Iterable[_T1], - __iter2: Iterable[_T2], - __iter3: Iterable[_T3], + iter1: Iterable[_T1], + iter2: Iterable[_T2], + iter3: Iterable[_T3], + /, *, maxsize: int | None = None, ) -> IMap[[_T1, _T2, _T3], _S]: ... @@ -66,10 +67,11 @@ class GroupMappingMixin: def imap( self, func: Callable[[_T1, _T2, _T3, _T4], _S], - __iter1: Iterable[_T1], - __iter2: Iterable[_T2], - __iter3: Iterable[_T3], - __iter4: Iterable[_T4], + iter1: Iterable[_T1], + iter2: Iterable[_T2], + iter3: Iterable[_T3], + iter4: Iterable[_T4], + /, *, maxsize: int | None = None, ) -> IMap[[_T1, _T2, _T3, _T4], _S]: ... @@ -77,11 +79,12 @@ class GroupMappingMixin: def imap( self, func: Callable[[_T1, _T2, _T3, _T4, _T5], _S], - __iter1: Iterable[_T1], - __iter2: Iterable[_T2], - __iter3: Iterable[_T3], - __iter4: Iterable[_T4], - __iter5: Iterable[_T5], + iter1: Iterable[_T1], + iter2: Iterable[_T2], + iter3: Iterable[_T3], + iter4: Iterable[_T4], + iter5: Iterable[_T5], + /, *, maxsize: int | None = None, ) -> IMap[[_T1, _T2, _T3, _T4, _T5], _S]: ... @@ -89,30 +92,32 @@ class GroupMappingMixin: def imap( self, func: Callable[_P, _S], - __iter1: Iterable[Any], - __iter2: Iterable[Any], - __iter3: Iterable[Any], - __iter4: Iterable[Any], - __iter5: Iterable[Any], - __iter6: Iterable[Any], + iter1: Iterable[Any], + iter2: Iterable[Any], + iter3: Iterable[Any], + iter4: Iterable[Any], + iter5: Iterable[Any], + iter6: Iterable[Any], + /, *iterables: Iterable[Any], maxsize: int | None = None, ) -> IMap[_P, _S]: ... @overload def imap_unordered( - self, func: Callable[[_T1], _S], __iter1: Iterable[_T1], *, maxsize: int | None = None + self, func: Callable[[_T1], _S], iter1: Iterable[_T1], /, *, maxsize: int | None = None ) -> IMapUnordered[[_T1], _S]: ... @overload def imap_unordered( - self, func: Callable[[_T1, _T2], _S], __iter1: Iterable[_T1], __iter2: Iterable[_T2], *, maxsize: int | None = None + self, func: Callable[[_T1, _T2], _S], iter1: Iterable[_T1], iter2: Iterable[_T2], /, *, maxsize: int | None = None ) -> IMapUnordered[[_T1, _T2], _S]: ... @overload def imap_unordered( self, func: Callable[[_T1, _T2, _T3], _S], - __iter1: Iterable[_T1], - __iter2: Iterable[_T2], - __iter3: Iterable[_T3], + iter1: Iterable[_T1], + iter2: Iterable[_T2], + iter3: Iterable[_T3], + /, *, maxsize: int | None = None, ) -> IMapUnordered[[_T1, _T2, _T3], _S]: ... @@ -120,10 +125,11 @@ class GroupMappingMixin: def imap_unordered( self, func: Callable[[_T1, _T2, _T3, _T4], _S], - __iter1: Iterable[_T1], - __iter2: Iterable[_T2], - __iter3: Iterable[_T3], - __iter4: Iterable[_T4], + iter1: Iterable[_T1], + iter2: Iterable[_T2], + iter3: Iterable[_T3], + iter4: Iterable[_T4], + /, *, maxsize: int | None = None, ) -> IMapUnordered[[_T1, _T2, _T3, _T4], _S]: ... @@ -131,11 +137,12 @@ class GroupMappingMixin: def imap_unordered( self, func: Callable[[_T1, _T2, _T3, _T4, _T5], _S], - __iter1: Iterable[_T1], - __iter2: Iterable[_T2], - __iter3: Iterable[_T3], - __iter4: Iterable[_T4], - __iter5: Iterable[_T5], + iter1: Iterable[_T1], + iter2: Iterable[_T2], + iter3: Iterable[_T3], + iter4: Iterable[_T4], + iter5: Iterable[_T5], + /, *, maxsize: int | None = None, ) -> IMapUnordered[[_T1, _T2, _T3, _T4, _T5], _S]: ... @@ -143,12 +150,13 @@ class GroupMappingMixin: def imap_unordered( self, func: Callable[_P, _S], - __iter1: Iterable[Any], - __iter2: Iterable[Any], - __iter3: Iterable[Any], - __iter4: Iterable[Any], - __iter5: Iterable[Any], - __iter6: Iterable[Any], + iter1: Iterable[Any], + iter2: Iterable[Any], + iter3: Iterable[Any], + iter4: Iterable[Any], + iter5: Iterable[Any], + iter6: Iterable[Any], + /, *iterables: Iterable[Any], maxsize: int | None = None, ) -> IMapUnordered[_P, _S]: ... diff --git a/stubs/gevent/gevent/resolver/cares.pyi b/stubs/gevent/gevent/resolver/cares.pyi index 3ee97d59d..b8f3546bf 100644 --- a/stubs/gevent/gevent/resolver/cares.pyi +++ b/stubs/gevent/gevent/resolver/cares.pyi @@ -18,7 +18,7 @@ if sys.platform != "win32": class ares_host_result(tuple[str, list[str], list[str]]): family: int - def __new__(cls, family: int, __hostname: str, __aliases: list[str], __addr_list: list[str]) -> Self: ... + def __new__(cls, family: int, hostname: str, aliases: list[str], addr_list: list[str], /) -> Self: ... class channel: @property diff --git a/tests/stubtest_allowlists/py310.txt b/tests/stubtest_allowlists/py310.txt index d1da8be09..104d8c3ee 100644 --- a/tests/stubtest_allowlists/py310.txt +++ b/tests/stubtest_allowlists/py310.txt @@ -4,6 +4,7 @@ asyncio.base_events.BaseEventLoop.subprocess_exec # BaseEventLoop adds several p builtins.float.__setformat__ # Internal method for CPython test suite builtins.property.__set_name__ # Doesn't actually exist bz2.BZ2Decompressor.__init__ # function does not accept parameters but C signature is set +collections\.UserList\.index # ignoring pos-or-keyword parameter configparser.ParsingError.filename contextlib.AbstractAsyncContextManager.__class_getitem__ contextlib.AbstractContextManager.__class_getitem__ diff --git a/tests/stubtest_allowlists/py311.txt b/tests/stubtest_allowlists/py311.txt index 46dd1b781..72c7e5c2a 100644 --- a/tests/stubtest_allowlists/py311.txt +++ b/tests/stubtest_allowlists/py311.txt @@ -8,6 +8,7 @@ _csv.Writer bz2.BZ2Decompressor.__init__ # function does not accept parameters but C signature is set configparser.LegacyInterpolation.__init__ configparser.ParsingError.filename +collections\.UserList\.index # ignoring pos-or-keyword parameter enum.Enum.__init__ enum.Enum._generate_next_value_ # Not strictly speaking a staticmethod on 3.11, but it acts like one: diff --git a/tests/stubtest_allowlists/py312.txt b/tests/stubtest_allowlists/py312.txt index 79ab47dc1..a995294df 100644 --- a/tests/stubtest_allowlists/py312.txt +++ b/tests/stubtest_allowlists/py312.txt @@ -63,6 +63,7 @@ _weakref.ProxyType.__reversed__ # Doesn't really exist argparse._MutuallyExclusiveGroup.add_mutually_exclusive_group # deprecated, forwards arguments to super ast.ImportFrom.level # None on the class, but never None on instances builtins.property.__set_name__ # Doesn't actually exist +collections\.UserList\.index # ignoring pos-or-keyword parameter dataclasses.KW_ONLY # white lies around defaults enum.auto.__init__ # The stub for enum.auto is nothing like the implementation enum.auto.value # The stub for enum.auto is nothing like the implementation diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index 442f8ee8e..46a162aa9 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -24,8 +24,8 @@ asyncio.base_events.BaseEventLoop.subprocess_exec # BaseEventLoop adds several p asyncio.Future.__init__ # Usually initialized from c object asyncio.futures.Future.__init__ # Usually initialized from c object builtins.dict.get -collections.ChainMap.fromkeys # Runtime has *args which can really only be one argument -collections.UserList.sort # Runtime has *args but will error if any are supplied +collections\.ChainMap\.fromkeys # https://github.com/python/mypy/issues/17023 +collections\.UserList\.sort # Runtime has *args but will error if any are supplied configparser.SectionProxy.__getattr__ # SectionProxy can have arbitrary attributes when custom converters are used # SectionProxy get functions are set in __init__ configparser.SectionProxy.getboolean