From 460c09d122124f1c47e3ba05ba4ae040288b8216 Mon Sep 17 00:00:00 2001 From: Stephen Morton Date: Fri, 8 Nov 2024 08:45:59 -0800 Subject: [PATCH] add _contextvars for proper naming (#12981) On 3.9 and lower, the contextvars types call themselves builtins.* which we can't and won't match. This improves naming fidelity for 3.10 and newer. --- stdlib/@tests/stubtest_allowlists/common.txt | 2 +- stdlib/@tests/stubtest_allowlists/py311.txt | 1 - stdlib/@tests/stubtest_allowlists/py312.txt | 1 - stdlib/@tests/stubtest_allowlists/py313.txt | 1 - stdlib/@tests/stubtest_allowlists/py38.txt | 2 +- stdlib/VERSIONS | 1 + stdlib/_contextvars.pyi | 61 +++++++++++++++++++ stdlib/contextvars.pyi | 62 +------------------- 8 files changed, 65 insertions(+), 66 deletions(-) create mode 100644 stdlib/_contextvars.pyi diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index 2d9b998e7..0e1fed25d 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -382,7 +382,7 @@ codecs.CodecInfo.streamreader codecs.CodecInfo.streamwriter collections.UserList.sort # Runtime has *args but will error if any are supplied -contextvars.Context.__init__ # C signature is broader than what is actually accepted +_?contextvars.Context.__init__ # C signature is broader than what is actually accepted # The Dialect properties are initialized as None in Dialect but their values are enforced in _Dialect csv.Dialect.delimiter diff --git a/stdlib/@tests/stubtest_allowlists/py311.txt b/stdlib/@tests/stubtest_allowlists/py311.txt index 5df7f76eb..89755650e 100644 --- a/stdlib/@tests/stubtest_allowlists/py311.txt +++ b/stdlib/@tests/stubtest_allowlists/py311.txt @@ -144,7 +144,6 @@ weakref.ProxyType.__reversed__ # Doesn't really exist # C signature is broader than what is actually accepted ast.ExtSlice.__new__ ast.Index.__new__ -contextvars.Context.__init__ # Undocumented implementation details cgi.FieldStorage.bufsize diff --git a/stdlib/@tests/stubtest_allowlists/py312.txt b/stdlib/@tests/stubtest_allowlists/py312.txt index bb9e5483f..73f1f46e5 100644 --- a/stdlib/@tests/stubtest_allowlists/py312.txt +++ b/stdlib/@tests/stubtest_allowlists/py312.txt @@ -149,7 +149,6 @@ sys.last_exc # C signature is broader than what is actually accepted ast.ExtSlice.__new__ ast.Index.__new__ -contextvars.Context.__init__ # Treated an alias of a typing class in the stubs, # they are generic to type checkers anyway. diff --git a/stdlib/@tests/stubtest_allowlists/py313.txt b/stdlib/@tests/stubtest_allowlists/py313.txt index f1dd24712..7962be452 100644 --- a/stdlib/@tests/stubtest_allowlists/py313.txt +++ b/stdlib/@tests/stubtest_allowlists/py313.txt @@ -125,7 +125,6 @@ sys.last_exc # C signature is broader than what is actually accepted ast.ExtSlice.__new__ ast.Index.__new__ -contextvars.Context.__init__ # Treated an alias of a typing class in the stubs, # they are generic to type checkers anyway. diff --git a/stdlib/@tests/stubtest_allowlists/py38.txt b/stdlib/@tests/stubtest_allowlists/py38.txt index ace9fd787..547d84e03 100644 --- a/stdlib/@tests/stubtest_allowlists/py38.txt +++ b/stdlib/@tests/stubtest_allowlists/py38.txt @@ -113,7 +113,7 @@ tkinter.Tcl tkinter.Tk.__init__ # Exists at runtime, but missing from stubs -contextvars.ContextVar.__class_getitem__ +_?contextvars.ContextVar.__class_getitem__ datetime.datetime_CAPI dummy_threading.ExceptHookArgs dummy_threading.Lock diff --git a/stdlib/VERSIONS b/stdlib/VERSIONS index df358de1c..fddd2761e 100644 --- a/stdlib/VERSIONS +++ b/stdlib/VERSIONS @@ -28,6 +28,7 @@ _codecs: 3.0- _collections_abc: 3.3- _compat_pickle: 3.1- _compression: 3.5- +_contextvars: 3.7- _csv: 3.0- _ctypes: 3.0- _curses: 3.0- diff --git a/stdlib/_contextvars.pyi b/stdlib/_contextvars.pyi new file mode 100644 index 000000000..2e21a8c5d --- /dev/null +++ b/stdlib/_contextvars.pyi @@ -0,0 +1,61 @@ +import sys +from collections.abc import Callable, Iterator, Mapping +from typing import Any, ClassVar, Generic, TypeVar, final, overload +from typing_extensions import ParamSpec + +if sys.version_info >= (3, 9): + from types import GenericAlias + +_T = TypeVar("_T") +_D = TypeVar("_D") +_P = ParamSpec("_P") + +@final +class ContextVar(Generic[_T]): + @overload + def __init__(self, name: str) -> None: ... + @overload + def __init__(self, name: str, *, default: _T) -> None: ... + def __hash__(self) -> int: ... + @property + def name(self) -> str: ... + @overload + def get(self) -> _T: ... + @overload + def get(self, default: _T, /) -> _T: ... + @overload + def get(self, default: _D, /) -> _D | _T: ... + def set(self, value: _T, /) -> Token[_T]: ... + def reset(self, token: Token[_T], /) -> None: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +@final +class Token(Generic[_T]): + @property + def var(self) -> ContextVar[_T]: ... + @property + def old_value(self) -> Any: ... # returns either _T or MISSING, but that's hard to express + MISSING: ClassVar[object] + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... + +def copy_context() -> Context: ... + +# It doesn't make sense to make this generic, because for most Contexts each ContextVar will have +# a different value. +@final +class Context(Mapping[ContextVar[Any], Any]): + def __init__(self) -> None: ... + @overload + def get(self, key: ContextVar[_T], default: None = None, /) -> _T | None: ... + @overload + def get(self, key: ContextVar[_T], default: _T, /) -> _T: ... + @overload + def get(self, key: ContextVar[_T], default: _D, /) -> _T | _D: ... + def run(self, callable: Callable[_P, _T], *args: _P.args, **kwargs: _P.kwargs) -> _T: ... + def copy(self) -> Context: ... + def __getitem__(self, key: ContextVar[_T], /) -> _T: ... + def __iter__(self) -> Iterator[ContextVar[Any]]: ... + def __len__(self) -> int: ... + def __eq__(self, value: object, /) -> bool: ... diff --git a/stdlib/contextvars.pyi b/stdlib/contextvars.pyi index dd5ea0acb..22dc33006 100644 --- a/stdlib/contextvars.pyi +++ b/stdlib/contextvars.pyi @@ -1,63 +1,3 @@ -import sys -from collections.abc import Callable, Iterator, Mapping -from typing import Any, ClassVar, Generic, TypeVar, final, overload -from typing_extensions import ParamSpec - -if sys.version_info >= (3, 9): - from types import GenericAlias +from _contextvars import Context as Context, ContextVar as ContextVar, Token as Token, copy_context as copy_context __all__ = ("Context", "ContextVar", "Token", "copy_context") - -_T = TypeVar("_T") -_D = TypeVar("_D") -_P = ParamSpec("_P") - -@final -class ContextVar(Generic[_T]): - @overload - def __init__(self, name: str) -> None: ... - @overload - def __init__(self, name: str, *, default: _T) -> None: ... - def __hash__(self) -> int: ... - @property - def name(self) -> str: ... - @overload - def get(self) -> _T: ... - @overload - def get(self, default: _T, /) -> _T: ... - @overload - def get(self, default: _D, /) -> _D | _T: ... - def set(self, value: _T, /) -> Token[_T]: ... - def reset(self, token: Token[_T], /) -> None: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - -@final -class Token(Generic[_T]): - @property - def var(self) -> ContextVar[_T]: ... - @property - def old_value(self) -> Any: ... # returns either _T or MISSING, but that's hard to express - MISSING: ClassVar[object] - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... - -def copy_context() -> Context: ... - -# It doesn't make sense to make this generic, because for most Contexts each ContextVar will have -# a different value. -@final -class Context(Mapping[ContextVar[Any], Any]): - def __init__(self) -> None: ... - @overload - def get(self, key: ContextVar[_T], default: None = None, /) -> _T | None: ... - @overload - def get(self, key: ContextVar[_T], default: _T, /) -> _T: ... - @overload - def get(self, key: ContextVar[_T], default: _D, /) -> _T | _D: ... - def run(self, callable: Callable[_P, _T], *args: _P.args, **kwargs: _P.kwargs) -> _T: ... - def copy(self) -> Context: ... - def __getitem__(self, key: ContextVar[_T], /) -> _T: ... - def __iter__(self) -> Iterator[ContextVar[Any]]: ... - def __len__(self) -> int: ... - def __eq__(self, value: object, /) -> bool: ...