From 655a58931dae6fe01c4490611869a48956f7629f Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 17:56:00 +0000 Subject: [PATCH 01/13] Improve `sys` stubs --- stdlib/sys.pyi | 242 +++++++++++++++++++++------- tests/stubtest_allowlists/py310.txt | 1 - tests/stubtest_allowlists/py38.txt | 1 - tests/stubtest_allowlists/py39.txt | 1 - 4 files changed, 183 insertions(+), 62 deletions(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index cb1545711d69..66a76fd722cf 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -1,14 +1,29 @@ import sys -from _typeshed import structseq from builtins import object as _object from importlib.abc import PathEntryFinder from importlib.machinery import ModuleSpec from io import TextIOWrapper from types import FrameType, ModuleType, TracebackType -from typing import Any, AsyncGenerator, Callable, NoReturn, Optional, Protocol, Sequence, TextIO, Type, TypeVar, Union, overload +from typing import ( + Any, + AsyncGenerator, + Callable, + Generic, + Iterable, + NoReturn, + Optional, + Protocol, + Sequence, + TextIO, + Type, + TypeVar, + Union, + overload, +) from typing_extensions import Literal, final _T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) # The following type alias are stub-only and do not exist during runtime _ExcInfo = tuple[Type[BaseException], BaseException, TracebackType] @@ -74,49 +89,142 @@ if sys.platform == "win32": winver: str _xoptions: dict[Any, Any] +# Similar to _typeshed.structseq, but unlike most other `structseq` classes in the stdlib, +# the `n_fields` ClassVar attributes in the sys-module structseq classes are read-only. +class _sys_structseq: + @property + def n_fields(self) -> int: ... + @property + def n_sequence_fields(self) -> int: ... + @property + def n_unnamed_fields(self) -> int: ... + +class _immutable_structseq(_sys_structseq, Generic[_T_co]): + def __new__(cls: Type[_T], sequence: Iterable[_T_co], dict: dict[str, Any] = ...) -> _T: ... + +class _uninstantiable_structseq(_sys_structseq): + # type ignore because mypy doesn't like __new__ returning NoReturn + def __new__(cls, *args: Any, **kwargs: Any) -> NoReturn: ... # type: ignore[misc] + flags: _flags -class _flags: - debug: int - division_warning: int - inspect: int - interactive: int - optimize: int - dont_write_bytecode: int - no_user_site: int - no_site: int - ignore_environment: int - verbose: int - bytes_warning: int - quiet: int - hash_randomization: int - if sys.version_info >= (3, 7): - dev_mode: int - utf8_mode: int +if sys.version_info >= (3, 7): + @final + class _flags( + _uninstantiable_structseq, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int, int] + ): + @property + def debug(self) -> int: ... + @property + def inspect(self) -> int: ... + @property + def interactive(self) -> int: ... + @property + def optimize(self) -> int: ... + @property + def dont_write_bytecode(self) -> int: ... + @property + def no_user_site(self) -> int: ... + @property + def no_site(self) -> int: ... + @property + def ignore_environment(self) -> int: ... + @property + def verbose(self) -> int: ... + @property + def bytes_warning(self) -> int: ... + @property + def quiet(self) -> int: ... + @property + def hash_randomization(self) -> int: ... + @property + def isolated(self) -> int: ... + @property + def dev_mode(self) -> bool: ... + @property + def utf8_mode(self) -> int: ... + @property + def warn_default_encoding(self) -> int: ... # undocumented + +else: + @final + class _flags(_uninstantiable_structseq, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int]): + @property + def debug(self) -> int: ... + @property + def inspect(self) -> int: ... + @property + def interactive(self) -> int: ... + @property + def optimize(self) -> int: ... + @property + def dont_write_bytecode(self) -> int: ... + @property + def no_user_site(self) -> int: ... + @property + def no_site(self) -> int: ... + @property + def ignore_environment(self) -> int: ... + @property + def verbose(self) -> int: ... + @property + def bytes_warning(self) -> int: ... + @property + def quiet(self) -> int: ... + @property + def hash_randomization(self) -> int: ... + @property + def isolated(self) -> int: ... float_info: _float_info -class _float_info: - epsilon: float # DBL_EPSILON - dig: int # DBL_DIG - mant_dig: int # DBL_MANT_DIG - max: float # DBL_MAX - max_exp: int # DBL_MAX_EXP - max_10_exp: int # DBL_MAX_10_EXP - min: float # DBL_MIN - min_exp: int # DBL_MIN_EXP - min_10_exp: int # DBL_MIN_10_EXP - radix: int # FLT_RADIX - rounds: int # FLT_ROUNDS +@final +class _float_info(_immutable_structseq[float], tuple[float, int, int, float, int, int, float, int, int, int, int]): + @property + def max(self) -> float: ... # DBL_MAX + @property + def max_exp(self) -> int: ... # DBL_MAX_EXP + @property + def max_10_exp(self) -> int: ... # DBL_MAX_10_EXP + @property + def min(self) -> float: ... # DBL_MIN + @property + def min_exp(self) -> int: ... # DBL_MIN_EXP + @property + def min_10_exp(self) -> int: ... # DBL_MIN_10_EXP + @property + def dig(self) -> int: ... # DBL_DIG + @property + def mant_dig(self) -> int: ... # DBL_MANT_DIG + @property + def epsilon(self) -> float: ... # DBL_EPSILON + @property + def radix(self) -> int: ... # FLT_RADIX + @property + def rounds(self) -> int: ... # FLT_ROUNDS hash_info: _hash_info -class _hash_info: - width: int - modulus: int - inf: int - nan: int - imag: int +@final +class _hash_info(_immutable_structseq[Any | int], tuple[int, int, int, int, int, str, int, int, int]): + @property + def width(self) -> int: ... + @property + def modulus(self) -> int: ... + @property + def inf(self) -> int: ... + @property + def nan(self) -> int: ... + @property + def imag(self) -> int: ... + @property + def algorithm(self) -> str: ... + @property + def hash_bits(self) -> int: ... + @property + def seed_bits(self) -> int: ... + @property + def cutoff(self) -> int: ... implementation: _implementation @@ -125,16 +233,18 @@ class _implementation: version: _version_info hexversion: int cache_tag: str - _multiarch: str int_info: _int_info -class _int_info: - bits_per_digit: int - sizeof_digit: int +@final +class _int_info(_immutable_structseq[int], tuple[int, int]): + @property + def bits_per_digit(self) -> int: ... + @property + def sizeof_digit(self) -> int: ... @final -class _version_info(structseq[Any | int], tuple[int, int, int, str, int]): +class _version_info(_uninstantiable_structseq, tuple[int, int, int, str, int]): @property def major(self) -> int: ... @property @@ -185,19 +295,30 @@ _TraceFunc = Callable[[FrameType, str, Any], Optional[Callable[[FrameType, str, def gettrace() -> _TraceFunc | None: ... def settrace(tracefunc: _TraceFunc | None) -> None: ... -class _WinVersion(tuple[int, int, int, int, str, int, int, int, int, tuple[int, int, int]]): - major: int - minor: int - build: int - platform: int - service_pack: str - service_pack_minor: int - service_pack_major: int - suite_mast: int - product_type: int - platform_version: tuple[int, int, int] - if sys.platform == "win32": + # A tuple of length 5, even though it has more than 5 attributes. + @final + class _WinVersion(_uninstantiable_structseq, tuple[int, int, int, int, str]): + @property + def major(self) -> int: ... + @property + def minor(self) -> int: ... + @property + def build(self) -> int: ... + @property + def platform(self) -> int: ... + @property + def service_pack(self) -> str: ... + @property + def service_pack_minor(self) -> int: ... + @property + def service_pack_major(self) -> int: ... + @property + def suite_mast(self) -> int: ... + @property + def product_type(self) -> int: ... + @property + def platform_version(self) -> tuple[int, int, int]: ... def getwindowsversion() -> _WinVersion: ... def intern(__string: str) -> str: ... @@ -220,21 +341,24 @@ if sys.version_info < (3, 9): if sys.version_info >= (3, 8): # not exported by sys - class UnraisableHookArgs: + class _UnraisableHookArgs: exc_type: Type[BaseException] exc_value: BaseException | None exc_traceback: TracebackType | None err_msg: str | None object: _object | None - unraisablehook: Callable[[UnraisableHookArgs], Any] + unraisablehook: Callable[[_UnraisableHookArgs], Any] def addaudithook(hook: Callable[[str, tuple[Any, ...]], Any]) -> None: ... def audit(__event: str, *args: Any) -> None: ... _AsyncgenHook = Optional[Callable[[AsyncGenerator[Any, Any]], None]] -class _asyncgen_hooks(tuple[_AsyncgenHook, _AsyncgenHook]): - firstiter: _AsyncgenHook - finalizer: _AsyncgenHook +@final +class _asyncgen_hooks(_immutable_structseq[_AsyncgenHook], tuple[_AsyncgenHook, _AsyncgenHook]): + @property + def firstiter(self) -> _AsyncgenHook: ... + @property + def finalizer(self) -> _AsyncgenHook: ... def get_asyncgen_hooks() -> _asyncgen_hooks: ... def set_asyncgen_hooks(firstiter: _AsyncgenHook = ..., finalizer: _AsyncgenHook = ...) -> None: ... diff --git a/tests/stubtest_allowlists/py310.txt b/tests/stubtest_allowlists/py310.txt index 390ca296106c..f77d9d227c88 100644 --- a/tests/stubtest_allowlists/py310.txt +++ b/tests/stubtest_allowlists/py310.txt @@ -66,7 +66,6 @@ re.Pattern.scanner # Undocumented and not useful. #6405 ssl.PROTOCOL_SSLv3 # Depends on ssl compilation ssl.RAND_egd # Depends on openssl compilation symtable.SymbolTable.has_exec -sys.UnraisableHookArgs # Not exported from sys types.ClassMethodDescriptorType.__get__ types.CodeType.replace # stubtest thinks default values are None but None doesn't work at runtime types.GenericAlias.__getattr__ diff --git a/tests/stubtest_allowlists/py38.txt b/tests/stubtest_allowlists/py38.txt index c19cc00ddb14..357ee1cc1cf8 100644 --- a/tests/stubtest_allowlists/py38.txt +++ b/tests/stubtest_allowlists/py38.txt @@ -51,7 +51,6 @@ re.Pattern.scanner # Undocumented and not useful. #6405 sched.Event.__doc__ # __slots__ is overridden ssl.PROTOCOL_SSLv3 # Depends on ssl compilation ssl.RAND_egd # Depends on openssl compilation -sys.UnraisableHookArgs # Not exported from sys types.ClassMethodDescriptorType.__get__ types.CodeType.replace # stubtest thinks default values are None but None doesn't work at runtime types.MethodDescriptorType.__get__ diff --git a/tests/stubtest_allowlists/py39.txt b/tests/stubtest_allowlists/py39.txt index 746a46a6a65b..f15b936d0cf1 100644 --- a/tests/stubtest_allowlists/py39.txt +++ b/tests/stubtest_allowlists/py39.txt @@ -62,7 +62,6 @@ sched.Event.__doc__ # __slots__ is overridden ssl.PROTOCOL_SSLv3 # Depends on ssl compilation ssl.RAND_egd # Depends on openssl compilation symtable.SymbolTable.has_exec -sys.UnraisableHookArgs # Not exported from sys types.ClassMethodDescriptorType.__get__ types.CodeType.replace # stubtest thinks default values are None but None doesn't work at runtime types.GenericAlias.__getattr__ From 38bcdccf800eab37b892346cbc5b9060ee0a34da Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 18:13:52 +0000 Subject: [PATCH 02/13] Update stdlib/sys.pyi --- stdlib/sys.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 66a76fd722cf..5140b14955a3 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -224,7 +224,7 @@ class _hash_info(_immutable_structseq[Any | int], tuple[int, int, int, int, int, @property def seed_bits(self) -> int: ... @property - def cutoff(self) -> int: ... + def cutoff(self) -> int: ... # undocumented implementation: _implementation From fffd896a33f19e365b70686e4ce9c0f1ce2e7e55 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 18:16:02 +0000 Subject: [PATCH 03/13] Update stdlib/sys.pyi --- stdlib/sys.pyi | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 5140b14955a3..64cc3cde982c 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -340,7 +340,6 @@ if sys.version_info < (3, 9): def setcheckinterval(__n: int) -> None: ... # deprecated if sys.version_info >= (3, 8): - # not exported by sys class _UnraisableHookArgs: exc_type: Type[BaseException] exc_value: BaseException | None From 524016a782ffbce1429d1d5a99cf3498e55d811e Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 20:20:24 +0000 Subject: [PATCH 04/13] Update sys.pyi --- stdlib/sys.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 64cc3cde982c..f75d527d9cba 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -49,7 +49,7 @@ displayhook: Callable[[object], Any] excepthook: Callable[[Type[BaseException], BaseException, TracebackType | None], Any] exec_prefix: str executable: str -float_repr_style: str +float_repr_style: Literal["short", "legacy"] hexversion: int last_type: Type[BaseException] | None last_value: BaseException | None From 8dd35c6631f197d9e8d4b5fd5aa995620eb7036d Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 20:49:39 +0000 Subject: [PATCH 05/13] Add `sys._implementation.__getattr__` --- stdlib/sys.pyi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index f75d527d9cba..1a644858326f 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -233,6 +233,10 @@ class _implementation: version: _version_info hexversion: int cache_tag: str + # Define __getattr__, as the documentation states: + # > sys.implementation may contain additional attributes specific to the Python implementation. + # > These non-standard attributes must start with an underscore, and are not described here. + def __getattr__(self, name: str) -> Any: ... int_info: _int_info From e894440770ce7600b149ba8e11d596ceab0373ee Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 21:07:47 +0000 Subject: [PATCH 06/13] Update stdlib/sys.pyi Co-authored-by: Akuli --- stdlib/sys.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 1a644858326f..f3303d9d943a 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -179,7 +179,7 @@ else: float_info: _float_info @final -class _float_info(_immutable_structseq[float], tuple[float, int, int, float, int, int, float, int, int, int, int]): +class _float_info(_immutable_structseq[float], tuple[float, int, int, float, int, int, int, int, float, int, int]): @property def max(self) -> float: ... # DBL_MAX @property From cbb845ec2d725b338b90598dec365de0c8c5cec2 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 21:19:29 +0000 Subject: [PATCH 07/13] Address review --- stdlib/sys.pyi | 60 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index f3303d9d943a..4c0726c23dd5 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -1,4 +1,5 @@ import sys +from _typeshed import structseq from builtins import object as _object from importlib.abc import PathEntryFinder from importlib.machinery import ModuleSpec @@ -89,26 +90,13 @@ if sys.platform == "win32": winver: str _xoptions: dict[Any, Any] -# Similar to _typeshed.structseq, but unlike most other `structseq` classes in the stdlib, -# the `n_fields` ClassVar attributes in the sys-module structseq classes are read-only. -class _sys_structseq: - @property - def n_fields(self) -> int: ... - @property - def n_sequence_fields(self) -> int: ... - @property - def n_unnamed_fields(self) -> int: ... - -class _immutable_structseq(_sys_structseq, Generic[_T_co]): - def __new__(cls: Type[_T], sequence: Iterable[_T_co], dict: dict[str, Any] = ...) -> _T: ... - -class _uninstantiable_structseq(_sys_structseq): +class _uninstantiable_structseq(structseq[Any]): # type ignore because mypy doesn't like __new__ returning NoReturn def __new__(cls, *args: Any, **kwargs: Any) -> NoReturn: ... # type: ignore[misc] flags: _flags -if sys.version_info >= (3, 7): +if sys.version_info >= (3, 10): @final class _flags( _uninstantiable_structseq, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int, int] @@ -146,6 +134,40 @@ if sys.version_info >= (3, 7): @property def warn_default_encoding(self) -> int: ... # undocumented +elif sys.version_info >= (3, 7): + @final + class _flags(_uninstantiable_structseq, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int]): + @property + def debug(self) -> int: ... + @property + def inspect(self) -> int: ... + @property + def interactive(self) -> int: ... + @property + def optimize(self) -> int: ... + @property + def dont_write_bytecode(self) -> int: ... + @property + def no_user_site(self) -> int: ... + @property + def no_site(self) -> int: ... + @property + def ignore_environment(self) -> int: ... + @property + def verbose(self) -> int: ... + @property + def bytes_warning(self) -> int: ... + @property + def quiet(self) -> int: ... + @property + def hash_randomization(self) -> int: ... + @property + def isolated(self) -> int: ... + @property + def dev_mode(self) -> bool: ... + @property + def utf8_mode(self) -> int: ... + else: @final class _flags(_uninstantiable_structseq, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int]): @@ -179,7 +201,7 @@ else: float_info: _float_info @final -class _float_info(_immutable_structseq[float], tuple[float, int, int, float, int, int, int, int, float, int, int]): +class _float_info(structseq[float], tuple[float, int, int, float, int, int, int, int, float, int, int]): @property def max(self) -> float: ... # DBL_MAX @property @@ -206,7 +228,7 @@ class _float_info(_immutable_structseq[float], tuple[float, int, int, float, int hash_info: _hash_info @final -class _hash_info(_immutable_structseq[Any | int], tuple[int, int, int, int, int, str, int, int, int]): +class _hash_info(structseq[Any | int], tuple[int, int, int, int, int, str, int, int, int]): @property def width(self) -> int: ... @property @@ -241,7 +263,7 @@ class _implementation: int_info: _int_info @final -class _int_info(_immutable_structseq[int], tuple[int, int]): +class _int_info(structseq[int], tuple[int, int]): @property def bits_per_digit(self) -> int: ... @property @@ -357,7 +379,7 @@ if sys.version_info >= (3, 8): _AsyncgenHook = Optional[Callable[[AsyncGenerator[Any, Any]], None]] @final -class _asyncgen_hooks(_immutable_structseq[_AsyncgenHook], tuple[_AsyncgenHook, _AsyncgenHook]): +class _asyncgen_hooks(structseq[_AsyncgenHook], tuple[_AsyncgenHook, _AsyncgenHook]): @property def firstiter(self) -> _AsyncgenHook: ... @property From 3cdea980e317c87599150368f966c2449d01737d Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 21:25:38 +0000 Subject: [PATCH 08/13] Revert change to `UnraisableHookArgs`, fix imports --- stdlib/sys.pyi | 22 ++++------------------ tests/stubtest_allowlists/py310.txt | 1 + tests/stubtest_allowlists/py38.txt | 1 + tests/stubtest_allowlists/py39.txt | 1 + 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 4c0726c23dd5..1d0660cc6cd9 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -5,22 +5,7 @@ from importlib.abc import PathEntryFinder from importlib.machinery import ModuleSpec from io import TextIOWrapper from types import FrameType, ModuleType, TracebackType -from typing import ( - Any, - AsyncGenerator, - Callable, - Generic, - Iterable, - NoReturn, - Optional, - Protocol, - Sequence, - TextIO, - Type, - TypeVar, - Union, - overload, -) +from typing import Any, AsyncGenerator, Generic, NoReturn, Optional, Protocol, Sequence, TextIO, Type, TypeVar, Union, overload from typing_extensions import Literal, final _T = TypeVar("_T") @@ -366,13 +351,14 @@ if sys.version_info < (3, 9): def setcheckinterval(__n: int) -> None: ... # deprecated if sys.version_info >= (3, 8): - class _UnraisableHookArgs: + # Doesn't exist at runtime, but exported in the stubs so pytest etc. can annotate their code more easily. + class UnraisableHookArgs: exc_type: Type[BaseException] exc_value: BaseException | None exc_traceback: TracebackType | None err_msg: str | None object: _object | None - unraisablehook: Callable[[_UnraisableHookArgs], Any] + unraisablehook: Callable[[UnraisableHookArgs], Any] def addaudithook(hook: Callable[[str, tuple[Any, ...]], Any]) -> None: ... def audit(__event: str, *args: Any) -> None: ... diff --git a/tests/stubtest_allowlists/py310.txt b/tests/stubtest_allowlists/py310.txt index f77d9d227c88..390ca296106c 100644 --- a/tests/stubtest_allowlists/py310.txt +++ b/tests/stubtest_allowlists/py310.txt @@ -66,6 +66,7 @@ re.Pattern.scanner # Undocumented and not useful. #6405 ssl.PROTOCOL_SSLv3 # Depends on ssl compilation ssl.RAND_egd # Depends on openssl compilation symtable.SymbolTable.has_exec +sys.UnraisableHookArgs # Not exported from sys types.ClassMethodDescriptorType.__get__ types.CodeType.replace # stubtest thinks default values are None but None doesn't work at runtime types.GenericAlias.__getattr__ diff --git a/tests/stubtest_allowlists/py38.txt b/tests/stubtest_allowlists/py38.txt index 357ee1cc1cf8..c19cc00ddb14 100644 --- a/tests/stubtest_allowlists/py38.txt +++ b/tests/stubtest_allowlists/py38.txt @@ -51,6 +51,7 @@ re.Pattern.scanner # Undocumented and not useful. #6405 sched.Event.__doc__ # __slots__ is overridden ssl.PROTOCOL_SSLv3 # Depends on ssl compilation ssl.RAND_egd # Depends on openssl compilation +sys.UnraisableHookArgs # Not exported from sys types.ClassMethodDescriptorType.__get__ types.CodeType.replace # stubtest thinks default values are None but None doesn't work at runtime types.MethodDescriptorType.__get__ diff --git a/tests/stubtest_allowlists/py39.txt b/tests/stubtest_allowlists/py39.txt index f15b936d0cf1..746a46a6a65b 100644 --- a/tests/stubtest_allowlists/py39.txt +++ b/tests/stubtest_allowlists/py39.txt @@ -62,6 +62,7 @@ sched.Event.__doc__ # __slots__ is overridden ssl.PROTOCOL_SSLv3 # Depends on ssl compilation ssl.RAND_egd # Depends on openssl compilation symtable.SymbolTable.has_exec +sys.UnraisableHookArgs # Not exported from sys types.ClassMethodDescriptorType.__get__ types.CodeType.replace # stubtest thinks default values are None but None doesn't work at runtime types.GenericAlias.__getattr__ From 4c63b714416f1ee19588b3fca98d21f901e002b6 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 21:27:51 +0000 Subject: [PATCH 09/13] Fix --- stdlib/sys.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 1d0660cc6cd9..33a8b8bc1c6a 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -5,7 +5,7 @@ from importlib.abc import PathEntryFinder from importlib.machinery import ModuleSpec from io import TextIOWrapper from types import FrameType, ModuleType, TracebackType -from typing import Any, AsyncGenerator, Generic, NoReturn, Optional, Protocol, Sequence, TextIO, Type, TypeVar, Union, overload +from typing import Any, AsyncGenerator, Callable, NoReturn, Optional, Protocol, Sequence, TextIO, Type, TypeVar, Union, overload from typing_extensions import Literal, final _T = TypeVar("_T") From 0b84123b526200f00eb6afca3772f59a237a91be Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 22:08:17 +0000 Subject: [PATCH 10/13] Suite mask --- stdlib/sys.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 33a8b8bc1c6a..057fa510d301 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -325,7 +325,7 @@ if sys.platform == "win32": @property def service_pack_major(self) -> int: ... @property - def suite_mast(self) -> int: ... + def suite_mask(self) -> int: ... @property def product_type(self) -> int: ... @property From 9e4615a90970c3d48928f4386a7475383b684353 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 22:30:23 +0000 Subject: [PATCH 11/13] Improve `sys._flags` --- stdlib/sys.pyi | 130 ++++++++++++++----------------------------------- 1 file changed, 36 insertions(+), 94 deletions(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 057fa510d301..26e78bb54971 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -82,106 +82,48 @@ class _uninstantiable_structseq(structseq[Any]): flags: _flags if sys.version_info >= (3, 10): - @final - class _flags( - _uninstantiable_structseq, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int, int] - ): - @property - def debug(self) -> int: ... - @property - def inspect(self) -> int: ... - @property - def interactive(self) -> int: ... - @property - def optimize(self) -> int: ... - @property - def dont_write_bytecode(self) -> int: ... - @property - def no_user_site(self) -> int: ... - @property - def no_site(self) -> int: ... - @property - def ignore_environment(self) -> int: ... - @property - def verbose(self) -> int: ... - @property - def bytes_warning(self) -> int: ... - @property - def quiet(self) -> int: ... - @property - def hash_randomization(self) -> int: ... - @property - def isolated(self) -> int: ... - @property - def dev_mode(self) -> bool: ... - @property - def utf8_mode(self) -> int: ... - @property - def warn_default_encoding(self) -> int: ... # undocumented - + _FlagTuple = tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int, int] elif sys.version_info >= (3, 7): - @final - class _flags(_uninstantiable_structseq, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int]): - @property - def debug(self) -> int: ... - @property - def inspect(self) -> int: ... - @property - def interactive(self) -> int: ... - @property - def optimize(self) -> int: ... - @property - def dont_write_bytecode(self) -> int: ... - @property - def no_user_site(self) -> int: ... - @property - def no_site(self) -> int: ... - @property - def ignore_environment(self) -> int: ... - @property - def verbose(self) -> int: ... - @property - def bytes_warning(self) -> int: ... - @property - def quiet(self) -> int: ... - @property - def hash_randomization(self) -> int: ... - @property - def isolated(self) -> int: ... + _FlagTuple = tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, bool, int] +else: + _FlagTuple = tuple[int, int, int, int, int, int, int, int, int, int, int, int, int] + +@final +class _flags(_uninstantiable_structseq, _FlagTuple): + @property + def debug(self) -> int: ... + @property + def inspect(self) -> int: ... + @property + def interactive(self) -> int: ... + @property + def optimize(self) -> int: ... + @property + def dont_write_bytecode(self) -> int: ... + @property + def no_user_site(self) -> int: ... + @property + def no_site(self) -> int: ... + @property + def ignore_environment(self) -> int: ... + @property + def verbose(self) -> int: ... + @property + def bytes_warning(self) -> int: ... + @property + def quiet(self) -> int: ... + @property + def hash_randomization(self) -> int: ... + @property + def isolated(self) -> int: ... + if sys.version_info >= (3, 7): @property def dev_mode(self) -> bool: ... @property def utf8_mode(self) -> int: ... - -else: - @final - class _flags(_uninstantiable_structseq, tuple[int, int, int, int, int, int, int, int, int, int, int, int, int]): - @property - def debug(self) -> int: ... - @property - def inspect(self) -> int: ... - @property - def interactive(self) -> int: ... - @property - def optimize(self) -> int: ... - @property - def dont_write_bytecode(self) -> int: ... + if sys.version_info >= (3, 10): @property - def no_user_site(self) -> int: ... - @property - def no_site(self) -> int: ... - @property - def ignore_environment(self) -> int: ... - @property - def verbose(self) -> int: ... - @property - def bytes_warning(self) -> int: ... - @property - def quiet(self) -> int: ... - @property - def hash_randomization(self) -> int: ... - @property - def isolated(self) -> int: ... + def warn_default_encoding(self) -> int: ... # undocumented float_info: _float_info From 2bd2c1dba620750cf16688e77c2754c93f5086b7 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jan 2022 22:34:29 +0000 Subject: [PATCH 12/13] Delete no-longer-used `TypeVar` --- stdlib/sys.pyi | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 26e78bb54971..3e669c4698b0 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -9,7 +9,6 @@ from typing import Any, AsyncGenerator, Callable, NoReturn, Optional, Protocol, from typing_extensions import Literal, final _T = TypeVar("_T") -_T_co = TypeVar("_T_co", covariant=True) # The following type alias are stub-only and do not exist during runtime _ExcInfo = tuple[Type[BaseException], BaseException, TracebackType] From 7897583bf4f9d226390b95fce6f27f69f0eabeaf Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 5 Jan 2022 12:41:25 +0000 Subject: [PATCH 13/13] Change `_uninstantiable_structseq` from a class to a type alias --- stdlib/sys.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/sys.pyi b/stdlib/sys.pyi index 3e669c4698b0..93c9a27ddff0 100644 --- a/stdlib/sys.pyi +++ b/stdlib/sys.pyi @@ -74,9 +74,9 @@ if sys.platform == "win32": winver: str _xoptions: dict[Any, Any] -class _uninstantiable_structseq(structseq[Any]): - # type ignore because mypy doesn't like __new__ returning NoReturn - def __new__(cls, *args: Any, **kwargs: Any) -> NoReturn: ... # type: ignore[misc] +# Type alias used as a mixin for structseq classes that cannot be instantiated at runtime +# This can't be represented in the type system, so we just use `structseq[Any]` +_uninstantiable_structseq = structseq[Any] flags: _flags