aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/typing.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/typing.py')
-rw-r--r--Lib/typing.py144
1 files changed, 45 insertions, 99 deletions
diff --git a/Lib/typing.py b/Lib/typing.py
index f70dcd0b5b7..ed1dd4fc641 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -956,12 +956,8 @@ def evaluate_forward_ref(
"""Evaluate a forward reference as a type hint.
This is similar to calling the ForwardRef.evaluate() method,
- but unlike that method, evaluate_forward_ref() also:
-
- * Recursively evaluates forward references nested within the type hint.
- * Rejects certain objects that are not valid type hints.
- * Replaces type hints that evaluate to None with types.NoneType.
- * Supports the *FORWARDREF* and *STRING* formats.
+ but unlike that method, evaluate_forward_ref() also
+ recursively evaluates forward references nested within the type hint.
*forward_ref* must be an instance of ForwardRef. *owner*, if given,
should be the object that holds the annotations that the forward reference
@@ -981,23 +977,24 @@ def evaluate_forward_ref(
if forward_ref.__forward_arg__ in _recursive_guard:
return forward_ref
- try:
- value = forward_ref.evaluate(globals=globals, locals=locals,
- type_params=type_params, owner=owner)
- except NameError:
- if format == _lazy_annotationlib.Format.FORWARDREF:
- return forward_ref
- else:
- raise
-
- type_ = _type_check(
- value,
- "Forward references must evaluate to types.",
- is_argument=forward_ref.__forward_is_argument__,
- allow_special_forms=forward_ref.__forward_is_class__,
- )
+ if format is None:
+ format = _lazy_annotationlib.Format.VALUE
+ value = forward_ref.evaluate(globals=globals, locals=locals,
+ type_params=type_params, owner=owner, format=format)
+
+ if (isinstance(value, _lazy_annotationlib.ForwardRef)
+ and format == _lazy_annotationlib.Format.FORWARDREF):
+ return value
+
+ if isinstance(value, str):
+ value = _make_forward_ref(value, module=forward_ref.__forward_module__,
+ owner=owner or forward_ref.__owner__,
+ is_argument=forward_ref.__forward_is_argument__,
+ is_class=forward_ref.__forward_is_class__)
+ if owner is None:
+ owner = forward_ref.__owner__
return _eval_type(
- type_,
+ value,
globals,
locals,
type_params,
@@ -1649,6 +1646,9 @@ class _UnionGenericAliasMeta(type):
return True
return NotImplemented
+ def __hash__(self):
+ return hash(Union)
+
class _UnionGenericAlias(metaclass=_UnionGenericAliasMeta):
"""Compatibility hack.
@@ -2335,12 +2335,12 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
# This only affects ForwardRefs.
base_globals, base_locals = base_locals, base_globals
for name, value in ann.items():
- if value is None:
- value = type(None)
if isinstance(value, str):
value = _make_forward_ref(value, is_argument=False, is_class=True)
value = _eval_type(value, base_globals, base_locals, base.__type_params__,
format=format, owner=obj)
+ if value is None:
+ value = type(None)
hints[name] = value
if include_extras or format == Format.STRING:
return hints
@@ -2374,8 +2374,6 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
localns = globalns
type_params = getattr(obj, "__type_params__", ())
for name, value in hints.items():
- if value is None:
- value = type(None)
if isinstance(value, str):
# class-level forward refs were handled above, this must be either
# a module-level annotation or a function argument annotation
@@ -2384,7 +2382,10 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False,
is_argument=not isinstance(obj, types.ModuleType),
is_class=False,
)
- hints[name] = _eval_type(value, globalns, localns, type_params, format=format, owner=obj)
+ value = _eval_type(value, globalns, localns, type_params, format=format, owner=obj)
+ if value is None:
+ value = type(None)
+ hints[name] = value
return hints if include_extras else {k: _strip_annotations(t) for k, t in hints.items()}
@@ -2906,7 +2907,7 @@ class NamedTupleMeta(type):
types = ns["__annotations__"]
field_names = list(types)
annotate = _make_eager_annotate(types)
- elif (original_annotate := _lazy_annotationlib.get_annotate_function(ns)) is not None:
+ elif (original_annotate := _lazy_annotationlib.get_annotate_from_class_namespace(ns)) is not None:
types = _lazy_annotationlib.call_annotate_function(
original_annotate, _lazy_annotationlib.Format.FORWARDREF)
field_names = list(types)
@@ -2968,7 +2969,7 @@ class NamedTupleMeta(type):
return nm_tpl
-def NamedTuple(typename, fields=_sentinel, /, **kwargs):
+def NamedTuple(typename, fields, /):
"""Typed version of namedtuple.
Usage::
@@ -2988,48 +2989,9 @@ def NamedTuple(typename, fields=_sentinel, /, **kwargs):
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
"""
- if fields is _sentinel:
- if kwargs:
- deprecated_thing = "Creating NamedTuple classes using keyword arguments"
- deprecation_msg = (
- "{name} is deprecated and will be disallowed in Python {remove}. "
- "Use the class-based or functional syntax instead."
- )
- else:
- deprecated_thing = "Failing to pass a value for the 'fields' parameter"
- example = f"`{typename} = NamedTuple({typename!r}, [])`"
- deprecation_msg = (
- "{name} is deprecated and will be disallowed in Python {remove}. "
- "To create a NamedTuple class with 0 fields "
- "using the functional syntax, "
- "pass an empty list, e.g. "
- ) + example + "."
- elif fields is None:
- if kwargs:
- raise TypeError(
- "Cannot pass `None` as the 'fields' parameter "
- "and also specify fields using keyword arguments"
- )
- else:
- deprecated_thing = "Passing `None` as the 'fields' parameter"
- example = f"`{typename} = NamedTuple({typename!r}, [])`"
- deprecation_msg = (
- "{name} is deprecated and will be disallowed in Python {remove}. "
- "To create a NamedTuple class with 0 fields "
- "using the functional syntax, "
- "pass an empty list, e.g. "
- ) + example + "."
- elif kwargs:
- raise TypeError("Either list of fields or keywords"
- " can be provided to NamedTuple, not both")
- if fields is _sentinel or fields is None:
- import warnings
- warnings._deprecated(deprecated_thing, message=deprecation_msg, remove=(3, 15))
- fields = kwargs.items()
types = {n: _type_check(t, f"field {n} annotation must be a type")
for n, t in fields}
field_names = [n for n, _ in fields]
-
nt = _make_nmtuple(typename, field_names, _make_eager_annotate(types), module=_caller())
nt.__orig_bases__ = (NamedTuple,)
return nt
@@ -3084,15 +3046,17 @@ class _TypedDictMeta(type):
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
- if "__annotations__" in ns:
+ if ns_annotations is not None:
own_annotate = None
- own_annotations = ns["__annotations__"]
- elif (own_annotate := _lazy_annotationlib.get_annotate_function(ns)) is not 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
)
@@ -3162,7 +3126,7 @@ class _TypedDictMeta(type):
if base_annotate is None:
continue
base_annos = _lazy_annotationlib.call_annotate_function(
- base.__annotate__, format, owner=base)
+ base_annotate, format, owner=base)
annos.update(base_annos)
if own_annotate is not None:
own = _lazy_annotationlib.call_annotate_function(
@@ -3198,7 +3162,7 @@ class _TypedDictMeta(type):
__instancecheck__ = __subclasscheck__
-def TypedDict(typename, fields=_sentinel, /, *, total=True):
+def TypedDict(typename, fields, /, *, total=True):
"""A simple typed namespace. At runtime it is equivalent to a plain dict.
TypedDict creates a dictionary type such that a type checker will expect all
@@ -3253,24 +3217,6 @@ def TypedDict(typename, fields=_sentinel, /, *, total=True):
username: str # the "username" key can be changed
"""
- if fields is _sentinel or fields is None:
- import warnings
-
- if fields is _sentinel:
- deprecated_thing = "Failing to pass a value for the 'fields' parameter"
- else:
- deprecated_thing = "Passing `None` as the 'fields' parameter"
-
- example = f"`{typename} = TypedDict({typename!r}, {{{{}}}})`"
- deprecation_msg = (
- "{name} is deprecated and will be disallowed in Python {remove}. "
- "To create a TypedDict class with 0 fields "
- "using the functional syntax, "
- "pass an empty dictionary, e.g. "
- ) + example + "."
- warnings._deprecated(deprecated_thing, message=deprecation_msg, remove=(3, 15))
- fields = {}
-
ns = {'__annotations__': dict(fields)}
module = _caller()
if module is not None:
@@ -3477,7 +3423,7 @@ class IO(Generic[AnyStr]):
pass
@abstractmethod
- def readlines(self, hint: int = -1) -> List[AnyStr]:
+ def readlines(self, hint: int = -1) -> list[AnyStr]:
pass
@abstractmethod
@@ -3493,7 +3439,7 @@ class IO(Generic[AnyStr]):
pass
@abstractmethod
- def truncate(self, size: int = None) -> int:
+ def truncate(self, size: int | None = None) -> int:
pass
@abstractmethod
@@ -3505,11 +3451,11 @@ class IO(Generic[AnyStr]):
pass
@abstractmethod
- def writelines(self, lines: List[AnyStr]) -> None:
+ def writelines(self, lines: list[AnyStr]) -> None:
pass
@abstractmethod
- def __enter__(self) -> 'IO[AnyStr]':
+ def __enter__(self) -> IO[AnyStr]:
pass
@abstractmethod
@@ -3523,11 +3469,11 @@ class BinaryIO(IO[bytes]):
__slots__ = ()
@abstractmethod
- def write(self, s: Union[bytes, bytearray]) -> int:
+ def write(self, s: bytes | bytearray) -> int:
pass
@abstractmethod
- def __enter__(self) -> 'BinaryIO':
+ def __enter__(self) -> BinaryIO:
pass
@@ -3548,7 +3494,7 @@ class TextIO(IO[str]):
@property
@abstractmethod
- def errors(self) -> Optional[str]:
+ def errors(self) -> str | None:
pass
@property
@@ -3562,7 +3508,7 @@ class TextIO(IO[str]):
pass
@abstractmethod
- def __enter__(self) -> 'TextIO':
+ def __enter__(self) -> TextIO:
pass