Thanks to visit codestin.com
Credit goes to github.com

Skip to content

3.14: add annotationlib, update typing and inspect #13985

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
359 changes: 26 additions & 333 deletions stdlib/@tests/stubtest_allowlists/py314.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions stdlib/VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ _weakrefset: 3.0-
_winapi: 3.3-
abc: 3.0-
aifc: 3.0-3.12
annotationlib: 3.14-
antigravity: 3.0-
argparse: 3.0-
array: 3.0-
Expand Down
11 changes: 11 additions & 0 deletions stdlib/_typeshed/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,14 @@ else:
from enum import Enum

class StrEnum(str, Enum): ...

# Objects that appear in annotations or in type expressions.
# Similar to PEP 747's TypeForm but a little broader.
AnnotationForm: TypeAlias = Any

if sys.version_info >= (3, 14):
from annotationlib import Format

# These return annotations, which can be arbitrary objects
AnnotateFunc: TypeAlias = Callable[[Format], dict[str, AnnotationForm]]
EvaluateFunc: TypeAlias = Callable[[Format], AnnotationForm]
132 changes: 132 additions & 0 deletions stdlib/annotationlib.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import sys
from typing import Literal

if sys.version_info >= (3, 14):
import enum
import types
from _typeshed import AnnotateFunc, AnnotationForm, EvaluateFunc, SupportsItems
from collections.abc import Mapping
from typing import Any, ParamSpec, TypeVar, TypeVarTuple, final, overload
from warnings import deprecated

__all__ = [
"Format",
"ForwardRef",
"call_annotate_function",
"call_evaluate_function",
"get_annotate_from_class_namespace",
"get_annotations",
"annotations_to_string",
"type_repr",
]

class Format(enum.IntEnum):
VALUE = 1
VALUE_WITH_FAKE_GLOBALS = 2
FORWARDREF = 3
STRING = 4

@final
class ForwardRef:
__forward_is_argument__: bool
__forward_is_class__: bool
__forward_module__: str | None
def __init__(
self, arg: str, *, module: str | None = None, owner: object = None, is_argument: bool = True, is_class: bool = False
) -> None: ...
@overload
def evaluate(
self,
*,
globals: dict[str, Any] | None = None,
locals: Mapping[str, Any] | None = None,
type_params: tuple[TypeVar | ParamSpec | TypeVarTuple, ...] | None = None,
owner: object = None,
format: Literal[Format.STRING],
) -> str: ...
@overload
def evaluate(
self,
*,
globals: dict[str, Any] | None = None,
locals: Mapping[str, Any] | None = None,
type_params: tuple[TypeVar | ParamSpec | TypeVarTuple, ...] | None = None,
owner: object = None,
format: Literal[Format.FORWARDREF],
) -> AnnotationForm | ForwardRef: ...
@overload
def evaluate(
self,
*,
globals: dict[str, Any] | None = None,
locals: Mapping[str, Any] | None = None,
type_params: tuple[TypeVar | ParamSpec | TypeVarTuple, ...] | None = None,
owner: object = None,
format: Format = Format.VALUE, # noqa: Y011
) -> AnnotationForm: ...
@deprecated("Use ForwardRef.evaluate() or typing.evaluate_forward_ref() instead.")
def _evaluate(
self,
globalns: dict[str, Any] | None,
localns: Mapping[str, Any] | None,
type_params: tuple[TypeVar | ParamSpec | TypeVarTuple, ...] = ...,
*,
recursive_guard: frozenset[str],
) -> AnnotationForm: ...
@property
def __forward_arg__(self) -> str: ...
@property
def __forward_code__(self) -> types.CodeType: ...
def __eq__(self, other: object) -> bool: ...
def __hash__(self) -> int: ...
def __or__(self, other: Any) -> types.UnionType: ...
def __ror__(self, other: Any) -> types.UnionType: ...

@overload
def call_evaluate_function(evaluate: EvaluateFunc, format: Literal[Format.STRING], *, owner: object = None) -> str: ...
@overload
def call_evaluate_function(
evaluate: EvaluateFunc, format: Literal[Format.FORWARDREF], *, owner: object = None
) -> AnnotationForm | ForwardRef: ...
@overload
def call_evaluate_function(evaluate: EvaluateFunc, format: Format, *, owner: object = None) -> AnnotationForm: ...
@overload
def call_annotate_function(
annotate: AnnotateFunc, format: Literal[Format.STRING], *, owner: object = None
) -> dict[str, str]: ...
@overload
def call_annotate_function(
annotate: AnnotateFunc, format: Literal[Format.FORWARDREF], *, owner: object = None
) -> dict[str, AnnotationForm | ForwardRef]: ...
@overload
def call_annotate_function(annotate: AnnotateFunc, format: Format, *, owner: object = None) -> dict[str, AnnotationForm]: ...
def get_annotate_from_class_namespace(obj: Mapping[str, object]) -> AnnotateFunc | None: ...
@overload
def get_annotations(
obj: Any, # any object with __annotations__ or __annotate__
*,
globals: dict[str, object] | None = None,
locals: Mapping[str, object] | None = None,
eval_str: bool = False,
format: Literal[Format.STRING],
) -> dict[str, str]: ...
@overload
def get_annotations(
obj: Any,
*,
globals: dict[str, object] | None = None,
locals: Mapping[str, object] | None = None,
eval_str: bool = False,
format: Literal[Format.FORWARDREF],
) -> dict[str, AnnotationForm | ForwardRef]: ...
@overload
def get_annotations(
obj: Any,
*,
globals: dict[str, object] | None = None,
locals: Mapping[str, object] | None = None,
eval_str: bool = False,
format: Format = Format.VALUE, # noqa: Y011
) -> dict[str, AnnotationForm]: ...
def type_repr(value: object) -> str: ...
def annotations_to_string(annotations: SupportsItems[str, object]) -> dict[str, str]: ...
11 changes: 10 additions & 1 deletion stdlib/builtins.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import sys
import types
from _collections_abc import dict_items, dict_keys, dict_values
from _typeshed import (
AnnotationForm,
AnyStr_co,
ConvertibleToFloat,
ConvertibleToInt,
Expand Down Expand Up @@ -72,6 +73,9 @@ from typing_extensions import ( # noqa: Y023
deprecated,
)

if sys.version_info >= (3, 14):
from _typeshed import AnnotateFunc

_T = TypeVar("_T")
_I = TypeVar("_I", default=int)
_T_co = TypeVar("_T_co", covariant=True)
Expand Down Expand Up @@ -215,6 +219,9 @@ class type:
def __ror__(self, value: Any, /) -> types.UnionType: ...
if sys.version_info >= (3, 12):
__type_params__: tuple[TypeVar | ParamSpec | TypeVarTuple, ...]
__annotations__: dict[str, AnnotationForm]
if sys.version_info >= (3, 14):
__annotate__: AnnotateFunc | None

class super:
@overload
Expand Down Expand Up @@ -1017,7 +1024,9 @@ class function:
def __globals__(self) -> dict[str, Any]: ...
__name__: str
__qualname__: str
__annotations__: dict[str, Any]
__annotations__: dict[str, AnnotationForm]
if sys.version_info >= (3, 14):
__annotate__: AnnotateFunc | None
__kwdefaults__: dict[str, Any]
if sys.version_info >= (3, 10):
@property
Expand Down
60 changes: 53 additions & 7 deletions stdlib/inspect.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import dis
import enum
import sys
import types
from _typeshed import StrPath
from _typeshed import AnnotationForm, StrPath
from collections import OrderedDict
from collections.abc import AsyncGenerator, Awaitable, Callable, Coroutine, Generator, Mapping, Sequence, Set as AbstractSet
from types import (
Expand All @@ -28,6 +28,9 @@ from types import (
from typing import Any, ClassVar, Final, Literal, NamedTuple, Protocol, TypeVar, overload
from typing_extensions import ParamSpec, Self, TypeAlias, TypeGuard, TypeIs

if sys.version_info >= (3, 14):
from annotationlib import Format

if sys.version_info >= (3, 11):
__all__ = [
"ArgInfo",
Expand Down Expand Up @@ -139,6 +142,8 @@ if sys.version_info >= (3, 11):
"getasyncgenstate",
"BufferFlags",
]
if sys.version_info >= (3, 14):
__all__ += ["CO_HAS_DOCSTRING", "CO_METHOD", "ispackage"]

_P = ParamSpec("_P")
_T = TypeVar("_T")
Expand Down Expand Up @@ -172,6 +177,9 @@ CO_COROUTINE: Final = 128
CO_ITERABLE_COROUTINE: Final = 256
CO_ASYNC_GENERATOR: Final = 512
TPFLAGS_IS_ABSTRACT: Final = 1048576
if sys.version_info >= (3, 14):
CO_HAS_DOCSTRING: Final = 67108864
CO_METHOD: Final = 134217728

modulesbyfile: dict[str, Any]

Expand Down Expand Up @@ -199,6 +207,11 @@ def getmodulename(path: StrPath) -> str | None: ...
def ismodule(object: object) -> TypeIs[ModuleType]: ...
def isclass(object: object) -> TypeIs[type[Any]]: ...
def ismethod(object: object) -> TypeIs[MethodType]: ...

if sys.version_info >= (3, 14):
# Not TypeIs because it does not return True for all modules
def ispackage(object: object) -> TypeGuard[ModuleType]: ...

def isfunction(object: object) -> TypeIs[FunctionType]: ...

if sys.version_info >= (3, 12):
Expand Down Expand Up @@ -294,7 +307,18 @@ _IntrospectableCallable: TypeAlias = Callable[..., Any]
#
# Introspecting callables with the Signature object
#
if sys.version_info >= (3, 10):
if sys.version_info >= (3, 14):
def signature(
obj: _IntrospectableCallable,
*,
follow_wrapped: bool = True,
globals: Mapping[str, Any] | None = None,
locals: Mapping[str, Any] | None = None,
eval_str: bool = False,
annotation_format: Format = Format.VALUE, # noqa: Y011
) -> Signature: ...

elif sys.version_info >= (3, 10):
def signature(
obj: _IntrospectableCallable,
*,
Expand Down Expand Up @@ -323,7 +347,19 @@ class Signature:
def bind_partial(self, *args: Any, **kwargs: Any) -> BoundArguments: ...
def replace(self, *, parameters: Sequence[Parameter] | type[_void] | None = ..., return_annotation: Any = ...) -> Self: ...
__replace__ = replace
if sys.version_info >= (3, 10):
if sys.version_info >= (3, 14):
@classmethod
def from_callable(
cls,
obj: _IntrospectableCallable,
*,
follow_wrapped: bool = True,
globals: Mapping[str, Any] | None = None,
locals: Mapping[str, Any] | None = None,
eval_str: bool = False,
annotation_format: Format = Format.VALUE, # noqa: Y011
) -> Self: ...
elif sys.version_info >= (3, 10):
@classmethod
def from_callable(
cls,
Expand All @@ -337,20 +373,24 @@ class Signature:
else:
@classmethod
def from_callable(cls, obj: _IntrospectableCallable, *, follow_wrapped: bool = True) -> Self: ...
if sys.version_info >= (3, 13):
if sys.version_info >= (3, 14):
def format(self, *, max_width: int | None = None, quote_annotation_strings: bool = True) -> str: ...
elif sys.version_info >= (3, 13):
def format(self, *, max_width: int | None = None) -> str: ...

def __eq__(self, other: object) -> bool: ...
def __hash__(self) -> int: ...

if sys.version_info >= (3, 10):
if sys.version_info >= (3, 14):
from annotationlib import get_annotations as get_annotations
elif sys.version_info >= (3, 10):
def get_annotations(
obj: Callable[..., object] | type[object] | ModuleType, # any callable, class, or module
*,
globals: Mapping[str, Any] | None = None, # value types depend on the key
locals: Mapping[str, Any] | None = None, # value types depend on the key
eval_str: bool = False,
) -> dict[str, Any]: ... # values are type expressions
) -> dict[str, AnnotationForm]: ... # values are type expressions

# The name is the same as the enum's name in CPython
class _ParameterKind(enum.IntEnum):
Expand Down Expand Up @@ -461,7 +501,13 @@ class ArgInfo(NamedTuple):
locals: dict[str, Any]

def getargvalues(frame: FrameType) -> ArgInfo: ...
def formatannotation(annotation: object, base_module: str | None = None) -> str: ...

if sys.version_info >= (3, 14):
def formatannotation(annotation: object, base_module: str | None = None, *, quote_annotation_strings: bool = True) -> str: ...

else:
def formatannotation(annotation: object, base_module: str | None = None) -> str: ...

def formatannotationrelativeto(object: object) -> Callable[[object], str]: ...

if sys.version_info < (3, 11):
Expand Down
13 changes: 11 additions & 2 deletions stdlib/types.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
from _typeshed import MaybeNone, SupportsKeysAndGetItem
from _typeshed import AnnotationForm, MaybeNone, SupportsKeysAndGetItem
from _typeshed.importlib import LoaderProtocol
from collections.abc import (
AsyncGenerator,
Expand All @@ -19,6 +19,9 @@ from importlib.machinery import ModuleSpec
from typing import Any, ClassVar, Literal, TypeVar, final, overload
from typing_extensions import ParamSpec, Self, TypeAliasType, TypeVarTuple, deprecated

if sys.version_info >= (3, 14):
from _typeshed import AnnotateFunc

__all__ = [
"FunctionType",
"LambdaType",
Expand Down Expand Up @@ -77,7 +80,9 @@ class FunctionType:
def __globals__(self) -> dict[str, Any]: ...
__name__: str
__qualname__: str
__annotations__: dict[str, Any]
__annotations__: dict[str, AnnotationForm]
if sys.version_info >= (3, 14):
__annotate__: AnnotateFunc | None
__kwdefaults__: dict[str, Any] | None
if sys.version_info >= (3, 10):
@property
Expand Down Expand Up @@ -352,6 +357,10 @@ class ModuleType:
# Redeclaring `__doc__` here helps some type checkers understand that `__doc__` is available
# as an implicit global in all modules, similar to `__name__`, `__file__`, `__spec__`, etc.
__doc__: str | None
__annotations__: dict[str, AnnotationForm]
if sys.version_info >= (3, 14):
__annotate__: AnnotateFunc | None

def __init__(self, name: str, doc: str | None = ...) -> None: ...
# __getattr__ doesn't exist at runtime,
# but having it here in typeshed makes dynamic imports
Expand Down
Loading