Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ea1e60e
mark version to 3.14
youknowone Jan 13, 2026
7594ef5
upgrade site to 3.14.2
youknowone Jan 13, 2026
280caea
upgrade venvlauncher
youknowone Jan 13, 2026
8d901a7
Implement bool(NotImplemented)
youknowone Jan 13, 2026
2fe140f
Fix bytes/bytearray fromhex
youknowone Jan 13, 2026
db01a1d
Remove pickle from itertools
youknowone Jan 13, 2026
eafa0c0
Fix int rounding
youknowone Jan 13, 2026
24bff8d
fix unsigned validation
youknowone Jan 13, 2026
f5b44f5
Fix Exception.__init__
youknowone Jan 13, 2026
0793bd3
co_consts
youknowone Jan 13, 2026
fdfede7
fix win clippy
youknowone Jan 16, 2026
51b6286
PEP 649 annotation phase 1
youknowone Jan 13, 2026
353a9f6
PEP 649 annotation phase 2
youknowone Jan 13, 2026
a78b569
PEP 649 annotation phase 3
youknowone Jan 13, 2026
566b6f4
PEP 649 annotation phase 4
youknowone Jan 14, 2026
dc93614
Add annotationlib,ann_module from 3.14.2
youknowone Jan 15, 2026
37cc6b4
fix whats_left to support __annotate__
youknowone Jan 16, 2026
96038e4
partially patch inspect for PEP 649 in 3.13
youknowone Jan 14, 2026
346481d
partially patch Lib/typing to 3.14
youknowone Jan 15, 2026
076d692
Upgrade string from CPython 3.14.2
Jan 15, 2026
5227938
mark and unmark unittest functions
youknowone Jan 17, 2026
33689c1
Fix jit failure
youknowone Jan 14, 2026
65e08c0
Update ensurepip from 3.14.2
Jan 16, 2026
ef22bf4
Update _colorize from CPython 3.14.2
Jan 16, 2026
d75f272
Update argparse from CPython 3.14.2
Jan 16, 2026
314a615
Update calendar from CPython 3.14.2
Jan 16, 2026
133bdf6
auto_mark_test uses regex to check Run tests? sequentially
youknowone Jan 17, 2026
faeed2c
clean up
youknowone Jan 17, 2026
60fb438
Auto-format: ruff check --select I --fix
github-actions[bot] Jan 17, 2026
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
Prev Previous commit
Next Next commit
partially patch Lib/typing to 3.14
  • Loading branch information
youknowone committed Jan 17, 2026
commit 346481d95e87bd94da00affee525e6247fcb1590
85 changes: 70 additions & 15 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,17 @@
]


def _type_convert(arg, module=None, *, allow_special_forms=False):
class _LazyAnnotationLib:
def __getattr__(self, attr):
global _lazy_annotationlib
import annotationlib
_lazy_annotationlib = annotationlib
return getattr(annotationlib, attr)

_lazy_annotationlib = _LazyAnnotationLib()


def _type_convert(arg, module=None, *, allow_special_forms=False, owner=None):
"""For converting None to type(None), and strings to ForwardRef."""
if arg is None:
return type(None)
Expand All @@ -170,7 +180,7 @@ def _type_convert(arg, module=None, *, allow_special_forms=False):
return arg


def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=False):
def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=False, owner=None):
"""Check that the argument is a type, and return it (internal helper).

As a special case, accept None and return type(None) instead. Also wrap strings
Expand All @@ -188,7 +198,7 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=
if is_argument:
invalid_generic_forms += (Final,)

arg = _type_convert(arg, module=module, allow_special_forms=allow_special_forms)
arg = _type_convert(arg, module=module, allow_special_forms=allow_special_forms, owner=owner)
if (isinstance(arg, _GenericAlias) and
arg.__origin__ in invalid_generic_forms):
raise TypeError(f"{arg} is not valid as type argument")
Expand Down Expand Up @@ -2443,7 +2453,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {})
else:
base_globals = globalns
ann = base.__dict__.get('__annotations__', {})
ann = _lazy_annotationlib.get_annotations(base)
if isinstance(ann, types.GetSetDescriptorType):
ann = {}
base_locals = dict(vars(base)) if localns is None else localns
Expand Down Expand Up @@ -2477,7 +2487,10 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
localns = globalns
elif localns is None:
localns = globalns
hints = getattr(obj, '__annotations__', None)
try:
hints = _lazy_annotationlib.get_annotations(obj)
except TypeError:
hints = getattr(obj, '__annotations__', None)
if hints is None:
# Return empty annotations for something that _could_ have them.
if isinstance(obj, _allowed_types):
Expand Down Expand Up @@ -3005,7 +3018,13 @@ def __new__(cls, typename, bases, ns):
raise TypeError(
'can only inherit from a NamedTuple type and Generic')
bases = tuple(tuple if base is _NamedTuple else base for base in bases)
types = ns.get('__annotations__', {})
if "__annotations__" in ns:
types = ns["__annotations__"]
elif (annotate := _lazy_annotationlib.get_annotate_from_class_namespace(ns)) is not None:
types = _lazy_annotationlib.call_annotate_function(
annotate, _lazy_annotationlib.Format.VALUE)
else:
types = {}
default_names = []
for field_name in types:
if field_name in ns:
Expand Down Expand Up @@ -3160,16 +3179,26 @@ def __new__(cls, name, bases, ns, total=True):
else:
generic_base = ()

ns_annotations = ns.pop('__annotations__', None)

tp_dict = type.__new__(_TypedDictMeta, name, (*generic_base, dict), ns)

if not hasattr(tp_dict, '__orig_bases__'):
tp_dict.__orig_bases__ = bases

annotations = {}
own_annotations = ns.get('__annotations__', {})
if ns_annotations is not None:
own_annotate = None
own_annotations = ns_annotations
elif (own_annotate := _lazy_annotationlib.get_annotate_from_class_namespace(ns)) is not None:
own_annotations = _lazy_annotationlib.call_annotate_function(
own_annotate, _lazy_annotationlib.Format.FORWARDREF, owner=tp_dict
)
else:
own_annotate = None
own_annotations = {}
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
own_annotations = {
n: _type_check(tp, msg, module=tp_dict.__module__)
own_checked_annotations = {
n: _type_check(tp, msg, owner=tp_dict, module=tp_dict.__module__)
for n, tp in own_annotations.items()
}
required_keys = set()
Expand All @@ -3178,8 +3207,6 @@ def __new__(cls, name, bases, ns, total=True):
mutable_keys = set()

for base in bases:
annotations.update(base.__dict__.get('__annotations__', {}))

base_required = base.__dict__.get('__required_keys__', set())
required_keys |= base_required
optional_keys -= base_required
Expand All @@ -3191,8 +3218,7 @@ def __new__(cls, name, bases, ns, total=True):
readonly_keys.update(base.__dict__.get('__readonly_keys__', ()))
mutable_keys.update(base.__dict__.get('__mutable_keys__', ()))

annotations.update(own_annotations)
for annotation_key, annotation_type in own_annotations.items():
for annotation_key, annotation_type in own_checked_annotations.items():
qualifiers = set(_get_typeddict_qualifiers(annotation_type))
if Required in qualifiers:
is_required = True
Expand Down Expand Up @@ -3223,7 +3249,36 @@ def __new__(cls, name, bases, ns, total=True):
f"Required keys overlap with optional keys in {name}:"
f" {required_keys=}, {optional_keys=}"
)
tp_dict.__annotations__ = annotations

def __annotate__(format):
annos = {}
for base in bases:
if base is Generic:
continue
base_annotate = base.__annotate__
if base_annotate is None:
continue
base_annos = _lazy_annotationlib.call_annotate_function(
base_annotate, format, owner=base)
annos.update(base_annos)
if own_annotate is not None:
own = _lazy_annotationlib.call_annotate_function(
own_annotate, format, owner=tp_dict)
if format != _lazy_annotationlib.Format.STRING:
own = {
n: _type_check(tp, msg, module=tp_dict.__module__)
for n, tp in own.items()
}
elif format == _lazy_annotationlib.Format.STRING:
own = _lazy_annotationlib.annotations_to_string(own_annotations)
elif format in (_lazy_annotationlib.Format.FORWARDREF, _lazy_annotationlib.Format.VALUE):
own = own_checked_annotations
else:
raise NotImplementedError(format)
annos.update(own)
return annos

tp_dict.__annotate__ = __annotate__
tp_dict.__required_keys__ = frozenset(required_keys)
tp_dict.__optional_keys__ = frozenset(optional_keys)
tp_dict.__readonly_keys__ = frozenset(readonly_keys)
Expand Down