Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-typing_extensions for
openSUSE:Factory checked in at 2026-08-18 16:35:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-typing_extensions (Old)
and /work/SRC/openSUSE:Factory/.python-typing_extensions.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-typing_extensions"
Tue Aug 18 16:35:19 2026 rev:33 rq:1370852 version:4.16.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-typing_extensions/python-typing_extensions.changes
2025-12-09 12:49:28.577711503 +0100
+++
/work/SRC/openSUSE:Factory/.python-typing_extensions.new.1258/python-typing_extensions.changes
2026-08-18 16:35:24.477619897 +0200
@@ -1,0 +2,53 @@
+Wed Aug 12 10:02:17 UTC 2026 - Daniel Garcia <[email protected]>
+
+- Drop not needed patch py314-fix-tests.patch
+- Add upstream patch
+ remove-obsolete-literal-deduplication-assertion.patch
+ (gh#python/typing_extensions#785, bsc#1274786)
+- Update to 4.16.0:
+ * Avoid a DeprecationWarning when deprecated is applied to a
+ coroutine function on Python 3.14.0.
+ * Make `typing_extensions.TypeAliasType`'s `__module__` attribute
+ writable. Backport of CPython PR
[#149172](https://github.com/python/cpython/pull/149172).
+ * Fix setting of `__required_keys__` and `__optional_keys__` when
+ inheriting keys with the same name.
+ * Add support for `AsyncIterator`, `io.Reader`, `io.Writer` and
+ `os.PathLike` protocols as bases for other protocols.
+ * Fix incorrect behaviour on Python 3.9 and Python 3.10 that meant
+ that calling `isinstance` with
+ `typing_extensions.Concatenate[...]` or
+ `typing_extensions.Unpack[...]` as the first argument could have a
+ different result in some situations depending on whether or not a
+ profiling function had been set using `sys.setprofile`. This
+ affected both CPython and PyPy implementations. Patch by Brian
+ Schubert.
+ * Fix `__init_subclass__()` behavior in the presence of multiple
+ inheritance involving an `@deprecated`*decorated base class.
+ Backport of CPython PR
[#138210](https://github.com/python/cpython/pull/138210)
+ by Brian Schubert.
+ * Raise `TypeError` when attempting to subclass
+ `typing_extensions.ParamSpec` on Python 3.9. The `typing`
+ implementation has always raised an error, and the
+ `typing_extensions` implementation has raised an error on Python
+ 3.10+ since `typing_extensions` v4.6.0. Patch by Brian Schubert.
+ * Add the `bound`, `covariant`, `contravariant`, and
+ `infer_variance` parameters to `TypeVarTuple`.
+ * Officially support the `bound`, `covariant`, `contravariant` and
+ `infer_variance` parameters to `ParamSpec`. Improve the validation
+ of these parameters at runtime.
+ * Rename `typing_extensions.Sentinel` to
+ `typing_extensions.sentinel`, following the name that has been
+ adopted for `builtins.sentinel` on Python 3.15.
+ `typing_extensions.Sentinel` is retained as a soft*deprecated
+ alias for backwards compatibility.
+ * Add support for pickling sentinels.
+ * Sentinels now preserve their identity when copied or deep*copied.
+ * Deprecate passing `name` as a keyword argument or `repr` as a
+ positional argument to the `sentinel` constructor.
+ * The default repr of a sentinel `X = sentinel("X")` is now `X`
+ rather than `<X>`.
+ * Deprecate arbitrary attribute assignments to sentinels.
+ * Deprecate subclassing sentinels.
+ * Add support for Python 3.15.
+
+-------------------------------------------------------------------
Old:
----
py314-fix-tests.patch
typing_extensions-4.15.0.tar.gz
New:
----
remove-obsolete-literal-deduplication-assertion.patch
typing_extensions-4.16.0.tar.gz
----------(Old B)----------
Old:
- Drop not needed patch py314-fix-tests.patch
- Add upstream patch
----------(Old E)----------
----------(New B)----------
New:- Add upstream patch
remove-obsolete-literal-deduplication-assertion.patch
(gh#python/typing_extensions#785, bsc#1274786)
----------(New E)----------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-typing_extensions.spec ++++++
--- /var/tmp/diff_new_pack.MlG9iH/_old 2026-08-18 16:35:26.062676656 +0200
+++ /var/tmp/diff_new_pack.MlG9iH/_new 2026-08-18 16:35:26.064676728 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-typing_extensions
#
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -27,13 +27,14 @@
%{?sle15_python_module_pythons}
Name: python-typing_extensions%{psuffix}
-Version: 4.15.0
+Version: 4.16.0
Release: 0
Summary: Backported and Experimental Type Hints for Python 3.8+
License: Python-2.0
URL: https://github.com/python/typing_extensions
Source0:
https://files.pythonhosted.org/packages/source/t/typing_extensions/typing_extensions-%{version}.tar.gz
-Patch1: py314-fix-tests.patch
+# PATCH-FIX-UPSTREAM remove-obsolete-literal-deduplication-assertion.patch
gh#python/typing_extensions#785
+Patch1: remove-obsolete-literal-deduplication-assertion.patch
BuildRequires: %{python_module base >= 3.9}
BuildRequires: %{python_module flit-core >= 3.4 with %python-flit-core < 4}
BuildRequires: %{python_module pip}
++++++ remove-obsolete-literal-deduplication-assertion.patch ++++++
diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py
index 996d466c..938f2acc 100644
--- a/src/test_typing_extensions.py
+++ b/src/test_typing_extensions.py
@@ -1337,8 +1337,6 @@ def test_args(self):
self.assertEqual(Literal[1, 2, 3].__args__, (1, 2, 3))
self.assertEqual(Literal[1, 2, 3, 3].__args__, (1, 2, 3))
self.assertEqual(Literal[1, Literal[2], Literal[3, 4]].__args__, (1,
2, 3, 4))
- # Mutable arguments will not be deduplicated
- self.assertEqual(Literal[[], []].__args__, ([], []))
def test_union_of_literals(self):
self.assertEqual(Union[Literal[1], Literal[2]].__args__,
++++++ typing_extensions-4.15.0.tar.gz -> typing_extensions-4.16.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/typing_extensions-4.15.0/CHANGELOG.md
new/typing_extensions-4.16.0/CHANGELOG.md
--- old/typing_extensions-4.15.0/CHANGELOG.md 2025-08-25 15:47:32.338627600
+0200
+++ new/typing_extensions-4.16.0/CHANGELOG.md 2026-07-02 10:38:47.439686500
+0200
@@ -1,3 +1,51 @@
+# Release 4.16.0 (July 2, 2025)
+
+No user-facing changes since 4.16.0rc2.
+
+# Release 4.16.0rc2 (June 25, 2026)
+
+- Avoid a `DeprecationWarning` when `deprecated` is applied to a coroutine
function on
+ Python 3.14.0.
+
+# Release 4.16.0rc1 (June 24, 2026)
+
+- Make `typing_extensions.TypeAliasType`'s `__module__` attribute writable.
+ Backport of CPython PR
+ [#149172](https://github.com/python/cpython/pull/149172).
+- Fix setting of `__required_keys__` and `__optional_keys__` when inheriting
+ keys with the same name.
+- Add support for `AsyncIterator`, `io.Reader`, `io.Writer` and `os.PathLike`
protocols
+ as bases for other protocols.
+- Fix incorrect behaviour on Python 3.9 and Python 3.10 that meant that
+ calling `isinstance` with `typing_extensions.Concatenate[...]` or
+ `typing_extensions.Unpack[...]` as the first argument could have a different
+ result in some situations depending on whether or not a profiling function
had been
+ set using `sys.setprofile`. This affected both CPython and PyPy
implementations.
+ Patch by Brian Schubert.
+- Fix `__init_subclass__()` behavior in the presence of multiple inheritance
involving
+ an `@deprecated`-decorated base class. Backport of CPython PR
+ [#138210](https://github.com/python/cpython/pull/138210) by Brian Schubert.
+- Raise `TypeError` when attempting to subclass `typing_extensions.ParamSpec`
on
+ Python 3.9. The `typing` implementation has always raised an error, and the
+ `typing_extensions` implementation has raised an error on Python 3.10+ since
+ `typing_extensions` v4.6.0. Patch by Brian Schubert.
+- Add the `bound`, `covariant`, `contravariant`, and `infer_variance`
parameters
+ to `TypeVarTuple`.
+- Officially support the `bound`, `covariant`, `contravariant` and
`infer_variance`
+ parameters to `ParamSpec`. Improve the validation of these parameters at
runtime.
+- Rename `typing_extensions.Sentinel` to `typing_extensions.sentinel`,
following the
+ name that has been adopted for `builtins.sentinel` on Python 3.15.
+ `typing_extensions.Sentinel` is retained as a soft-deprecated alias for
backwards
+ compatibility.
+- Add support for pickling sentinels.
+- Sentinels now preserve their identity when copied or deep-copied.
+- Deprecate passing `name` as a keyword argument or `repr` as a positional
argument
+ to the `sentinel` constructor.
+- The default repr of a sentinel `X = sentinel("X")` is now `X` rather than
`<X>`.
+- Deprecate arbitrary attribute assignments to sentinels.
+- Deprecate subclassing sentinels.
+- Add support for Python 3.15.
+
# Release 4.15.0 (August 25, 2025)
No user-facing changes since 4.15.0rc1.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/typing_extensions-4.15.0/PKG-INFO
new/typing_extensions-4.16.0/PKG-INFO
--- old/typing_extensions-4.15.0/PKG-INFO 1970-01-01 01:00:00.000000000
+0100
+++ new/typing_extensions-4.16.0/PKG-INFO 1970-01-01 01:00:00.000000000
+0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: typing_extensions
-Version: 4.15.0
+Version: 4.16.0
Summary: Backported and Experimental Type Hints for Python 3.9+
Keywords:
annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing
Author-email: "Guido van Rossum, Jukka Lehtosalo, Ćukasz Langa, Michael Lee"
<[email protected]>
@@ -19,6 +19,7 @@
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Software Development
License-File: LICENSE
Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/typing_extensions-4.15.0/pyproject.toml
new/typing_extensions-4.16.0/pyproject.toml
--- old/typing_extensions-4.15.0/pyproject.toml 2025-08-25 15:47:32.339627500
+0200
+++ new/typing_extensions-4.16.0/pyproject.toml 2026-07-02 10:38:47.440689600
+0200
@@ -6,7 +6,7 @@
# Project metadata
[project]
name = "typing_extensions"
-version = "4.15.0"
+version = "4.16.0"
description = "Backported and Experimental Type Hints for Python 3.9+"
readme = "README.md"
requires-python = ">=3.9"
@@ -40,6 +40,7 @@
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
"Topic :: Software Development",
]
@@ -90,7 +91,6 @@
"UP014",
"UP019",
"UP035",
- "UP038",
"UP045", # X | None instead of Optional[X]
# Not relevant here
"RUF012", # Use ClassVar for mutables
@@ -123,6 +123,7 @@
[tool.coverage.report]
fail_under = 96
+precision = 2
show_missing = true
# Omit files that are created in temporary directories during tests.
# If not explicitly omitted they will result in warnings in the report.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/typing_extensions-4.15.0/src/test_typing_extensions.py
new/typing_extensions-4.16.0/src/test_typing_extensions.py
--- old/typing_extensions-4.15.0/src/test_typing_extensions.py 2025-08-25
15:47:32.340627400 +0200
+++ new/typing_extensions-4.16.0/src/test_typing_extensions.py 2026-07-02
10:38:47.441705700 +0200
@@ -10,6 +10,7 @@
import inspect
import io
import itertools
+import os
import pickle
import re
import subprocess
@@ -102,6 +103,7 @@
reveal_type,
runtime,
runtime_checkable,
+ sentinel,
type_repr,
)
@@ -132,6 +134,26 @@
TYPING_3_14_0 = sys.version_info[:3] >= (3, 14, 0)
+TYPING_3_15_0 = sys.version_info[:3] >= (3, 15, 0)
+
+TYPING_3_15_0_BETA_1 = sys.version_info[:5] == (3, 15, 0, 'beta', 1)
+
+# We cannot control the repr of `TypeVarTuple` on versions of Python
+# where `typing_extensions.TypeVarTuple()` does not return an instance
+# of `typing_extensions.TypeVarTuple`. At time of writing, that's Python
+# versions 3.11-3.14 inclusive (but not 3.10 or 3.15+). The exact version
+# range has changed in the past and may do so again in the future.
+#
+# Note that we do not do an `isinstance()` check here because
+# `typing_extensions.TypeVarTuple` does some trickery to pretend that
+# instances of `typing.TypeVar` are also instances of
+# `typing_extensions.TypeVarTuple` on Python 3.11-3.14.
+# (Possibly we're being a little too clever for our own good there.)
+GOOD_TYPEVARTUPLE_REPR_EXPECTED = (
+ type(typing_extensions.TypeVarTuple("Ts"))
+ is typing_extensions.TypeVarTuple
+)
+
# https://github.com/python/cpython/pull/27017 was backported into some 3.9
and 3.10
# versions, but not all
HAS_FORWARD_MODULE = "module" in
inspect.signature(typing._type_check).parameters
@@ -531,6 +553,14 @@
pickled = pickle.dumps(self.bottom_type, protocol=proto)
self.assertIs(self.bottom_type, pickle.loads(pickled))
+ @skipUnless(TYPING_3_10_0, "PEP 604 has yet to be")
+ def test_or(self):
+ self.assertEqual(self.bottom_type | int, Union[self.bottom_type, int])
+ self.assertEqual(int | self.bottom_type, Union[int, self.bottom_type])
+
+ self.assertEqual(get_args(self.bottom_type | int), (self.bottom_type,
int))
+ self.assertEqual(get_args(int | self.bottom_type), (int,
self.bottom_type))
+
class NoReturnTests(BottomTypeTestsMixin, BaseTestCase):
bottom_type = NoReturn
@@ -805,6 +835,25 @@
self.assertEqual(D.inited, 3)
+ def test_existing_init_subclass_in_sibling_base(self):
+ @deprecated("A will go away soon")
+ class A:
+ pass
+ class B:
+ def __init_subclass__(cls, x):
+ super().__init_subclass__()
+ cls.inited = x
+
+ with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"):
+ class C(A, B, x=42):
+ pass
+ self.assertEqual(C.inited, 42)
+
+ with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"):
+ class D(B, A, x=42):
+ pass
+ self.assertEqual(D.inited, 42)
+
def test_init_subclass_has_correct_cls(self):
init_subclass_saw = None
@@ -1729,11 +1778,9 @@
annotation : annotation,
Optional[int] : Optional[int],
Optional[List[str]] : Optional[List[str]],
- Optional[annotation] : Optional[annotation],
+ Optional[annotation] : Optional[annotation],
Union[str, None, str] : Optional[str],
Unpack[Tuple[int, None]]: Unpack[Tuple[int, None]],
- # Note: A starred *Ts will use typing.Unpack in 3.11+ see Issue
#485
- Unpack[Ts] : Unpack[Ts],
}
# contains a ForwardRef, TypeVar(~prefix) or no expression
do_not_stringify_cases = {
@@ -1749,7 +1796,15 @@
Union[str, "Union[None, StrAlias]"]: Optional[str],
Union["annotation", T_default] : Union[annotation, T_default],
Annotated["annotation", "nested"] : Annotated[Union[int, None],
"data", "nested"],
+ # Note: A starred *Ts will use typing.Unpack in 3.11+ see Issue
#485
+ Unpack[Ts] : Unpack[Ts],
}
+ # Note: A starred *Ts will use typing.Unpack in 3.11+ see Issue #485
+ if TYPING_3_15_0:
+ # The repr is typing.Unpack[~Ts], which cannot be evaluated.
+ do_not_stringify_cases[Unpack[Ts]] = Unpack[Ts]
+ else:
+ cases[Unpack[Ts]] = Unpack[Ts]
if TYPING_3_10_0: # cannot construct UnionTypes before 3.10
do_not_stringify_cases["str | NoneAlias | StrAlias"] = str | None
cases[str | None] = Optional[str]
@@ -2210,6 +2265,39 @@
Union[typing_extensions.Generator, typing.Deque]
)
+ def test_setattr(self):
+ origin = collections.abc.Generator
+ alias = typing_extensions.Generator
+ original_name = alias._name
+
+ def cleanup():
+ for obj in origin, alias:
+ for attr in 'foo', '__dunder__':
+ try:
+ delattr(obj, attr)
+ except Exception:
+ pass
+ try:
+ alias._name = original_name
+ except Exception:
+ pass
+
+ self.addCleanup(cleanup)
+
+ # Attribute assignment on generic alias sets attribute on origin
+ alias.foo = 1
+ self.assertEqual(alias.foo, 1)
+ self.assertEqual(origin.foo, 1)
+ # Except for dunders...
+ alias.__dunder__ = 2
+ self.assertEqual(alias.__dunder__, 2)
+ self.assertRaises(AttributeError, lambda: origin.__dunder__)
+
+ # ...and certain known attributes
+ alias._name = "NewName"
+ self.assertEqual(alias._name, "NewName")
+ self.assertRaises(AttributeError, lambda: origin._name)
+
class OtherABCTests(BaseTestCase):
@@ -2379,6 +2467,16 @@
class ProUserId(UserId):
...
+ def test_module_with_incomplete_sys(self):
+ def does_not_exist(*args):
+ raise AttributeError
+ with (
+ patch("sys._getframemodulename", does_not_exist, create=True),
+ patch("sys._getframe", does_not_exist, create=True),
+ ):
+ X = NewType("X", int)
+ self.assertEqual(X.__module__, None)
+
class Coordinate(Protocol):
x: int
@@ -3799,9 +3897,15 @@
class CustomProtocol(TestCase, Protocol):
pass
+ class CustomPathLikeProtocol(os.PathLike, Protocol):
+ pass
+
class CustomContextManager(typing.ContextManager, Protocol):
pass
+ class CustomAsyncIterator(typing.AsyncIterator, Protocol):
+ pass
+
@skip_if_py312b1
def test_typing_extensions_protocol_allowlist(self):
@runtime_checkable
@@ -4438,8 +4542,12 @@
child = _make_td(
child_future, "Child", {"child": "int"}, "Base",
{"Base": base}
)
- base_anno = typing.ForwardRef("int", module="builtins") if
base_future else int
- child_anno = typing.ForwardRef("int", module="builtins")
if child_future else int
+ if sys.version_info >= (3, 14):
+ base_anno = typing.ForwardRef("int",
module="builtins", owner=base) if base_future else int
+ child_anno = typing.ForwardRef("int",
module="builtins", owner=child) if child_future else int
+ else:
+ base_anno = typing.ForwardRef("int",
module="builtins") if base_future else int
+ child_anno = typing.ForwardRef("int",
module="builtins") if child_future else int
self.assertEqual(base.__annotations__, {'base': base_anno})
self.assertEqual(
child.__annotations__, {'child': child_anno, 'base':
base_anno}
@@ -4568,6 +4676,47 @@
class Wrong(*bases):
pass
+ def test_keys_inheritance_with_same_name(self):
+ class NotTotal(TypedDict, total=False):
+ a: int
+
+ class Total(NotTotal):
+ a: int
+
+ self.assertEqual(NotTotal.__required_keys__, frozenset())
+ self.assertEqual(NotTotal.__optional_keys__, frozenset(['a']))
+ self.assertEqual(Total.__required_keys__, frozenset(['a']))
+ self.assertEqual(Total.__optional_keys__, frozenset())
+
+ class Base(TypedDict):
+ a: NotRequired[int]
+ b: Required[int]
+
+ class Child(Base):
+ a: Required[int]
+ b: NotRequired[int]
+
+ self.assertEqual(Base.__required_keys__, frozenset(['b']))
+ self.assertEqual(Base.__optional_keys__, frozenset(['a']))
+ self.assertEqual(Child.__required_keys__, frozenset(['a']))
+ self.assertEqual(Child.__optional_keys__, frozenset(['b']))
+
+ def test_multiple_inheritance_with_same_key(self):
+ class Base1(TypedDict):
+ a: NotRequired[int]
+
+ class Base2(TypedDict):
+ a: Required[str]
+
+ class Child(Base1, Base2):
+ pass
+
+ # Last base wins
+ self.assertEqual(Child.__annotations__, {'a': Required[str]})
+ self.assertEqual(Child.__required_keys__, frozenset(['a']))
+ self.assertEqual(Child.__optional_keys__, frozenset())
+
+
def test_closed_values(self):
class Implicit(TypedDict): ...
class ExplicitTrue(TypedDict, closed=True): ...
@@ -5297,6 +5446,17 @@
def test_dunder_dict(self):
self.assertIsInstance(TypedDict.__dict__, dict)
+ @skipUnless(TYPING_3_10_0, "PEP 604 has yet to be")
+ def test_or(self):
+ class TD(TypedDict):
+ a: int
+
+ self.assertEqual(TD | int, Union[TD, int])
+ self.assertEqual(int | TD, Union[int, TD])
+
+ self.assertEqual(get_args(TD | int), (TD, int))
+ self.assertEqual(get_args(int | TD), (int, TD))
+
class AnnotatedTests(BaseTestCase):
def test_repr(self):
@@ -5519,6 +5679,19 @@
BA2
)
+ @skipUnless(TYPING_3_11_0, "TODO: evaluate nested forward refs in Python <
3.11")
+ def test_get_type_hints_genericalias(self):
+ def foobar(x: list['X']): ...
+ X = Annotated[int, (1, 10)]
+ self.assertEqual(
+ get_type_hints(foobar, globals(), locals()),
+ {'x': list[int]}
+ )
+ self.assertEqual(
+ get_type_hints(foobar, globals(), locals(), include_extras=True),
+ {'x': list[Annotated[int, (1, 10)]]}
+ )
+
def test_get_type_hints_refs(self):
Const = Annotated[T, "Const"]
@@ -5973,6 +6146,11 @@
# The actual test:
self.assertEqual(result1, result2)
+ def test_subclass(self):
+ with self.assertRaises(TypeError):
+ class MyParamSpec(ParamSpec):
+ pass
+
class ConcatenateTests(BaseTestCase):
def test_basics(self):
@@ -6131,6 +6309,47 @@
self.assertTrue(typing._is_param_expr(concat))
self.assertTrue(typing._is_param_expr(typing_concat))
+ def
test_isinstance_results_unaffected_by_presence_of_tracing_function(self):
+ # See https://github.com/python/typing_extensions/issues/661
+
+ code = textwrap.dedent(
+ """\
+ import sys, typing
+
+ def trace_call(*args):
+ return trace_call
+
+ def run():
+ sys.modules.pop("typing_extensions", None)
+ from typing_extensions import Concatenate
+ return isinstance(Concatenate[...], typing._GenericAlias)
+ isinstance_result_1 = run()
+ sys.setprofile(trace_call)
+ isinstance_result_2 = run()
+ sys.stdout.write(f"{isinstance_result_1} {isinstance_result_2}")
+ """
+ )
+
+ # Run this in an isolated process or it pollutes the environment
+ # and makes other tests fail:
+ try:
+ proc = subprocess.run(
+ [sys.executable, "-c", code], check=True, capture_output=True,
text=True,
+ )
+ except subprocess.CalledProcessError as exc:
+ print("stdout", exc.stdout, sep="\n")
+ print("stderr", exc.stderr, sep="\n")
+ raise
+
+ # Sanity checks that assert the test is working as expected
+ self.assertIsInstance(proc.stdout, str)
+ result1, result2 = proc.stdout.split(" ")
+ self.assertIn(result1, {"True", "False"})
+ self.assertIn(result2, {"True", "False"})
+
+ # The actual test:
+ self.assertEqual(result1, result2)
+
class TypeGuardTests(BaseTestCase):
def test_basics(self):
TypeGuard[int] # OK
@@ -6335,6 +6554,14 @@
pickled = pickle.dumps(LiteralString, protocol=proto)
self.assertIs(LiteralString, pickle.loads(pickled))
+ @skipUnless(TYPING_3_10_0, "PEP 604 has yet to be")
+ def test_or(self):
+ self.assertEqual(LiteralString | int, Union[LiteralString, int])
+ self.assertEqual(int | LiteralString, Union[int, LiteralString])
+
+ self.assertEqual(get_args(LiteralString | int), (LiteralString, int))
+ self.assertEqual(get_args(int | LiteralString), (int, LiteralString))
+
class SelfTests(BaseTestCase):
def test_basics(self):
@@ -6382,6 +6609,14 @@
pickled = pickle.dumps(Self, protocol=proto)
self.assertIs(Self, pickle.loads(pickled))
+ @skipUnless(TYPING_3_10_0, "PEP 604 has yet to be")
+ def test_or(self):
+ self.assertEqual(Self | int, Union[Self, int])
+ self.assertEqual(int | Self, Union[int, Self])
+
+ self.assertEqual(get_args(Self | int), (Self, int))
+ self.assertEqual(get_args(int | Self), (int, Self))
+
class UnpackTests(BaseTestCase):
def test_basic_plain(self):
@@ -6390,10 +6625,16 @@
with self.assertRaises(TypeError):
Unpack()
+ @skipIf(GOOD_TYPEVARTUPLE_REPR_EXPECTED, "TypeVarTuples have a bad repr on
this version")
def test_repr(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(repr(Unpack[Ts]), f'{Unpack.__module__}.Unpack[Ts]')
+ @skipUnless(GOOD_TYPEVARTUPLE_REPR_EXPECTED, "TypeVarTuples have a bad
repr on this version")
+ def test_repr_py315(self):
+ Ts = TypeVarTuple('Ts')
+ self.assertEqual(repr(Unpack[Ts]), f'{Unpack.__module__}.Unpack[~Ts]')
+
def test_cannot_subclass_vars(self):
with self.assertRaises(TypeError):
class V(Unpack[TypeVarTuple('Ts')]):
@@ -6537,6 +6778,46 @@
self.assertFalse(isinstance(Unpack[Ts], TypeVar))
self.assertFalse(isinstance(Unpack[Ts], typing.TypeVar))
+ def
test_isinstance_results_unaffected_by_presence_of_tracing_function(self):
+ # See https://github.com/python/typing_extensions/issues/661
+
+ code = textwrap.dedent(
+ """\
+ import sys, typing
+
+ def trace_call(*args):
+ return trace_call
+
+ def run():
+ sys.modules.pop("typing_extensions", None)
+ from typing_extensions import TypeVarTuple, Unpack
+ return isinstance(Unpack[TypeVarTuple("Ts")], typing.TypeVar)
+ isinstance_result_1 = run()
+ sys.setprofile(trace_call)
+ isinstance_result_2 = run()
+ sys.stdout.write(f"{isinstance_result_1} {isinstance_result_2}")
+ """
+ )
+
+ # Run this in an isolated process or it pollutes the environment
+ # and makes other tests fail:
+ try:
+ proc = subprocess.run(
+ [sys.executable, "-c", code], check=True, capture_output=True,
text=True,
+ )
+ except subprocess.CalledProcessError as exc:
+ print("stdout", exc.stdout, sep="\n")
+ print("stderr", exc.stderr, sep="\n")
+ raise
+
+ # Sanity checks that assert the test is working as expected
+ self.assertIsInstance(proc.stdout, str)
+ result1, result2 = proc.stdout.split(" ")
+ self.assertIn(result1, {"True", "False"})
+ self.assertIn(result2, {"True", "False"})
+
+ # The actual test:
+ self.assertEqual(result1, result2)
class TypeVarTupleTests(BaseTestCase):
@@ -6548,9 +6829,50 @@
Ys = TypeVarTuple('Ys')
self.assertNotEqual(Xs, Ys)
+ @skipIf(GOOD_TYPEVARTUPLE_REPR_EXPECTED, "TypeVarTuples have a bad repr on
this version")
def test_repr(self):
Ts = TypeVarTuple('Ts')
+ Ts_co = TypeVarTuple('Ts_co', covariant=True)
+ Ts_contra = TypeVarTuple('Ts_contra', contravariant=True)
+ Ts_infer = TypeVarTuple('Ts_infer', infer_variance=True)
+ Ts_2 = TypeVarTuple('Ts_2')
self.assertEqual(repr(Ts), 'Ts')
+ self.assertEqual(repr(Ts_2), 'Ts_2')
+
+ self.assertEqual(repr(Ts_co), 'Ts_co')
+ self.assertEqual(repr(Ts_contra), 'Ts_contra')
+ self.assertEqual(repr(Ts_infer), 'Ts_infer')
+
+ @skipUnless(GOOD_TYPEVARTUPLE_REPR_EXPECTED, "TypeVarTuples have a bad
repr on this version")
+ def test_repr_py315(self):
+ Ts = TypeVarTuple('Ts')
+ Ts_co = TypeVarTuple('Ts_co', covariant=True)
+ Ts_contra = TypeVarTuple('Ts_contra', contravariant=True)
+ Ts_infer = TypeVarTuple('Ts_infer', infer_variance=True)
+ Ts_2 = TypeVarTuple('Ts_2')
+ self.assertEqual(repr(Ts), '~Ts')
+ self.assertEqual(repr(Ts_2), '~Ts_2')
+
+ self.assertEqual(repr(Ts_co), '+Ts_co')
+ self.assertEqual(repr(Ts_contra), '-Ts_contra')
+ self.assertEqual(repr(Ts_infer), 'Ts_infer')
+
+ def test_variance(self):
+ Ts_co = TypeVarTuple('Ts_co', covariant=True)
+ Ts_contra = TypeVarTuple('Ts_contra', contravariant=True)
+ Ts_infer = TypeVarTuple('Ts_infer', infer_variance=True)
+
+ self.assertIs(Ts_co.__covariant__, True)
+ self.assertIs(Ts_co.__contravariant__, False)
+ self.assertIs(Ts_co.__infer_variance__, False)
+
+ self.assertIs(Ts_contra.__covariant__, False)
+ self.assertIs(Ts_contra.__contravariant__, True)
+ self.assertIs(Ts_contra.__infer_variance__, False)
+
+ self.assertIs(Ts_infer.__covariant__, False)
+ self.assertIs(Ts_infer.__contravariant__, False)
+ self.assertIs(Ts_infer.__infer_variance__, True)
def test_no_redefinition(self):
self.assertNotEqual(TypeVarTuple('Ts'), TypeVarTuple('Ts'))
@@ -6853,7 +7175,10 @@
self.assertLessEqual(exclude, actual_names)
def test_typing_extensions_defers_when_possible(self):
- exclude = set()
+ # These two are currently always different to `typing.TypedDict`
+ # as PEP 764 has not yet been accepted/implemented upstream.
+ exclude = {'TypedDict', 'is_typeddict'}
+
if sys.version_info < (3, 10):
exclude |= {'get_args', 'get_origin'}
if sys.version_info < (3, 10, 1):
@@ -6868,16 +7193,18 @@
}
if sys.version_info < (3, 13):
exclude |= {
- 'NamedTuple', 'Protocol', 'runtime_checkable', 'Generator',
+ 'NamedTuple', 'runtime_checkable', 'Generator',
'AsyncGenerator', 'ContextManager', 'AsyncContextManager',
'ParamSpec', 'TypeVar', 'TypeVarTuple', 'get_type_hints',
}
- if sys.version_info < (3, 14):
+ if sys.version_info < (3, 15):
+ exclude |= {
+ 'TypeAliasType', 'Protocol'
+ }
+ if sys.version_info < (3, 15):
exclude |= {
- 'TypeAliasType'
+ 'TypeVarTuple'
}
- if not typing_extensions._PEP_728_IMPLEMENTED:
- exclude |= {'TypedDict', 'is_typeddict'}
for item in typing_extensions.__all__:
if item not in exclude and hasattr(typing, item):
self.assertIs(
@@ -7194,7 +7521,7 @@
def test_same_as_typing_NamedTuple(self):
self.assertEqual(
- set(dir(NamedTuple)) - {"__text_signature__"},
+ set(dir(NamedTuple)),
set(dir(typing.NamedTuple))
)
self.assertIs(type(NamedTuple), type(typing.NamedTuple))
@@ -7711,42 +8038,61 @@
self.assertEqual(A[float, [range], int].__args__, (float, (range,),
int))
-class NoDefaultTests(BaseTestCase):
+class SentinelTestsMixin:
@skip_if_py313_beta_1
def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
- s = pickle.dumps(NoDefault, proto)
+ s = pickle.dumps(self.sentinel_type, proto)
loaded = pickle.loads(s)
- self.assertIs(NoDefault, loaded)
+ self.assertIs(self.sentinel_type, loaded)
@skip_if_py313_beta_1
def test_doc(self):
- self.assertIsInstance(NoDefault.__doc__, str)
+ self.assertIsInstance(self.sentinel_type.__doc__, str)
def test_constructor(self):
- self.assertIs(NoDefault, type(NoDefault)())
with self.assertRaises(TypeError):
- type(NoDefault)(1)
-
- def test_repr(self):
- self.assertRegex(repr(NoDefault), r'typing(_extensions)?\.NoDefault')
+ type(self.sentinel_type)(1)
def test_no_call(self):
with self.assertRaises(TypeError):
- NoDefault()
+ self.sentinel_type()
@skip_if_py313_beta_1
def test_immutable(self):
with self.assertRaises(AttributeError):
- NoDefault.foo = 'bar'
+ self.sentinel_type.foo = 'bar'
with self.assertRaises(AttributeError):
- NoDefault.foo
+ self.sentinel_type.foo
# TypeError is consistent with the behavior of NoneType
with self.assertRaises(TypeError):
- type(NoDefault).foo = 3
+ type(self.sentinel_type).foo = 3
with self.assertRaises(AttributeError):
- type(NoDefault).foo
+ type(self.sentinel_type).foo
+
+
+class NoDefaultTests(SentinelTestsMixin, BaseTestCase):
+ sentinel_type = NoDefault
+
+ def test_repr(self):
+ if hasattr(typing, 'NoDefault'):
+ mod_name = 'typing'
+ else:
+ mod_name = "typing_extensions"
+ self.assertEqual(repr(NoDefault), f"{mod_name}.NoDefault")
+
+
+class NoExtraItemsTests(SentinelTestsMixin, BaseTestCase):
+ sentinel_type = NoExtraItems
+
+ @skipIf(TYPING_3_15_0, "repr changed in 3.15")
+ def test_repr(self):
+ self.assertEqual(repr(NoExtraItems), "typing_extensions.NoExtraItems")
+
+ @skipUnless(TYPING_3_15_0, "repr changed in 3.15")
+ def test_repr_py315(self):
+ self.assertEqual(repr(NoExtraItems), "NoExtraItems")
class TypeVarInferVarianceTests(BaseTestCase):
@@ -8025,11 +8371,12 @@
"attribute '__parameters__' of 'typing.TypeAliasType' objects is
not writable",
):
Simple.__parameters__ = (T,)
- with self.assertRaisesRegex(
- AttributeError,
- "attribute '__module__' of 'typing.TypeAliasType' objects is not
writable",
- ):
- Simple.__module__ = 42
+
+ # __module__ is the exception---it's assignable
+ module_sentinel = object()
+ Simple.__module__ = module_sentinel
+ self.assertIs(Simple.__module__, module_sentinel)
+
with self.assertRaisesRegex(
AttributeError,
"'typing.TypeAliasType' object has no attribute 'some_attribute'",
@@ -9268,11 +9615,11 @@
float,
)
self.assertIs(evaluate_forward_ref(typing.ForwardRef("int"),
globals={"int": str}), str)
+
import builtins
- from test import support
- with support.swap_attr(builtins, "int", dict):
- self.assertIs(evaluate_forward_ref(typing.ForwardRef("int")), dict)
+ with patch.object(builtins, "int", dict):
+ self.assertIs(evaluate_forward_ref(typing.ForwardRef("int")),
dict)
def test_nested_strings(self):
# This variable must have a different name TypeVar
@@ -9322,43 +9669,100 @@
class TestSentinels(BaseTestCase):
+ SENTINEL = sentinel("TestSentinels.SENTINEL")
+
def test_sentinel_no_repr(self):
- sentinel_no_repr = Sentinel('sentinel_no_repr')
+ sentinel_no_repr = sentinel('sentinel_no_repr')
+
+ self.assertEqual(sentinel_no_repr.__name__, 'sentinel_no_repr')
+ self.assertEqual(repr(sentinel_no_repr), 'sentinel_no_repr')
+
+ @skipIf(TYPING_3_15_0, reason="'Passing 'repr' as a positional argument
was removed in 3.15")
+ def test_sentinel_deprecated_argument_repr(self):
+ with self.assertWarnsRegex(DeprecationWarning, r"Passing 'repr' as a
positional argument is deprecated; pass it by keyword instead."):
+ sentinel_argument_repr = sentinel('sentinel_argument_repr',
'argument_repr')
- self.assertEqual(sentinel_no_repr._name, 'sentinel_no_repr')
- self.assertEqual(repr(sentinel_no_repr), '<sentinel_no_repr>')
+ self.assertEqual(repr(sentinel_argument_repr), 'argument_repr')
- def test_sentinel_explicit_repr(self):
- sentinel_explicit_repr = Sentinel('sentinel_explicit_repr',
repr='explicit_repr')
+ @skipIf(TYPING_3_15_0_BETA_1, reason="'repr' parameter is not yet
available in 3.15.0b1")
+ def test_sentinel_keyword_repr(self):
+ sentinel_keyword_repr = sentinel('sentinel_keyword_repr',
repr='keyword_repr')
- self.assertEqual(repr(sentinel_explicit_repr), 'explicit_repr')
+ self.assertEqual(repr(sentinel_keyword_repr), 'keyword_repr')
@skipIf(sys.version_info < (3, 10), reason='New unions not available in
3.9')
def test_sentinel_type_expression_union(self):
- sentinel = Sentinel('sentinel')
+ sentinel_type = sentinel('sentinel')
- def func1(a: int | sentinel = sentinel): pass
- def func2(a: sentinel | int = sentinel): pass
+ def func1(a: int | sentinel_type = sentinel_type): pass
+ def func2(a: sentinel_type | int = sentinel_type): pass
- self.assertEqual(func1.__annotations__['a'], Union[int, sentinel])
- self.assertEqual(func2.__annotations__['a'], Union[sentinel, int])
+ self.assertEqual(func1.__annotations__['a'], Union[int, sentinel_type])
+ self.assertEqual(func2.__annotations__['a'], Union[sentinel_type, int])
def test_sentinel_not_callable(self):
- sentinel = Sentinel('sentinel')
+ sentinel_ = sentinel('sentinel')
with self.assertRaisesRegex(
TypeError,
- "'Sentinel' object is not callable"
+ "'sentinel' object is not callable"
):
+ sentinel_()
+
+ def test_sentinel_copy_identity(self):
+ self.assertIs(self.SENTINEL, copy.copy(self.SENTINEL))
+ self.assertIs(self.SENTINEL, copy.deepcopy(self.SENTINEL))
+
+ anonymous_sentinel = sentinel("anonymous_sentinel")
+ self.assertIs(anonymous_sentinel, copy.copy(anonymous_sentinel))
+ self.assertIs(anonymous_sentinel, copy.deepcopy(anonymous_sentinel))
+
+ def test_sentinel_picklable_qualified(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ self.assertIs(self.SENTINEL,
pickle.loads(pickle.dumps(self.SENTINEL, protocol=proto)))
+
+ def test_sentinel_picklable_anonymous(self):
+ anonymous_sentinel = sentinel("anonymous_sentinel") # Anonymous
sentinel can not be pickled
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.assertRaisesRegex(
+ pickle.PicklingError,
+ r"attribute lookup anonymous_sentinel on \w+ failed|not found
as \w+.anonymous_sentinel"
+ ):
+ self.assertIs(anonymous_sentinel,
pickle.loads(pickle.dumps(anonymous_sentinel, protocol=proto)))
+
+ @skipIf(TYPING_3_15_0, reason='Deprecated sentinel APIs were removed in
3.15')
+ def test_sentinel_deprecated(self):
+ with self.assertWarnsRegex(DeprecationWarning, r"Subclassing sentinel
is deprecated"):
+ class SentinelSubclass(Sentinel):
+ pass
+ with self.assertRaisesRegex(TypeError, r"First parameter 'name' is
required"):
sentinel()
- def test_sentinel_not_picklable(self):
- sentinel = Sentinel('sentinel')
- with self.assertRaisesRegex(
- TypeError,
- "Cannot pickle 'Sentinel' object"
- ):
- pickle.dumps(sentinel)
+ with self.assertWarnsRegex(DeprecationWarning, r"Passing 'name' as a
keyword argument is deprecated"):
+ my_sentinel = Sentinel(name="my_sentinel")
+ with self.assertWarnsRegex(DeprecationWarning, r"Setting attribute
'foo' on sentinel objects is deprecated"):
+ my_sentinel.foo = "bar"
+ with self.assertWarnsRegex(DeprecationWarning, r"Setting attribute
'__name__' on sentinel objects is deprecated"):
+ my_sentinel.__name__ = "bar"
+
+ @skipUnless(TYPING_3_15_0, reason='Deprecated sentinel APIs are available
before 3.15')
+ def test_sentinel_removed_deprecated_apis(self):
+ with self.assertRaises(TypeError):
+ class SentinelSubclass(Sentinel):
+ pass
+ with self.assertRaises(TypeError):
+ sentinel()
+ with self.assertRaises(TypeError):
+ Sentinel(name="my_sentinel")
+ with self.assertRaises(AttributeError):
+ sentinel('my_sentinel').foo = "bar"
+ with self.assertRaises(AttributeError):
+ sentinel('my_sentinel').__name__ = "bar"
+
+def load_tests(loader, tests, pattern):
+ import doctest
+ tests.addTests(doctest.DocTestSuite(typing_extensions))
+ return tests
if __name__ == '__main__': # pragma: no cover
main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/typing_extensions-4.15.0/src/typing_extensions.py
new/typing_extensions-4.16.0/src/typing_extensions.py
--- old/typing_extensions-4.15.0/src/typing_extensions.py 2025-08-25
15:47:32.341627600 +0200
+++ new/typing_extensions-4.16.0/src/typing_extensions.py 2026-07-02
10:38:47.441705700 +0200
@@ -91,6 +91,7 @@
'overload',
'override',
'Protocol',
+ 'sentinel',
'Sentinel',
'reveal_type',
'runtime',
@@ -148,7 +149,6 @@
'ValuesView',
'cast',
'no_type_check',
- 'no_type_check_decorator',
]
# for backward compatibility
@@ -160,18 +160,122 @@
# Added with bpo-45166 to 3.10.1+ and some 3.9 versions
_FORWARD_REF_HAS_CLASS = "__forward_is_class__" in typing.ForwardRef.__slots__
-# The functions below are modified copies of typing internal helpers.
-# They are needed by _ProtocolMeta and they provide support for PEP 646.
+
+def _caller(depth=1, default='__main__'):
+ try:
+ return sys._getframemodulename(depth + 1) or default
+ except AttributeError: # For platforms without _getframemodulename()
+ pass
+ try:
+ return sys._getframe(depth + 1).f_globals.get('__name__', default)
+ except (AttributeError, ValueError): # For platforms without _getframe()
+ pass
+ return None
-class _Sentinel:
- def __repr__(self):
- return "<sentinel>"
+# Placeholder for sentinel methods, because sentinels can not have their own
sentinels
+_sentinel_placeholder = object()
+
+if hasattr(builtins, "sentinel"): # 3.15+
+ sentinel = builtins.sentinel
+else:
+ class sentinel:
+ """Create a unique sentinel object.
+
+ *name* should be the name of the variable to which the return value
+ shall be assigned.
+ """
+
+ def __init__(
+ self,
+ __name: str = _sentinel_placeholder,
+ __repr: typing.Optional[str] = _sentinel_placeholder,
+ /,
+ *,
+ repr: typing.Optional[str] = None,
+ name: str = _sentinel_placeholder,
+ ) -> None:
+ if name is not _sentinel_placeholder:
+ warnings.warn(
+ "Passing 'name' as a keyword argument is deprecated; "
+ "pass it positionally instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ __name = name
+ if __name is _sentinel_placeholder:
+ raise TypeError("First parameter 'name' is required")
+ if __repr is not _sentinel_placeholder:
+ warnings.warn(
+ "Passing 'repr' as a positional argument is deprecated; "
+ "pass it by keyword instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ repr = __repr
+
+ self._name = __name
+ self._repr = repr if repr is not None else __name
+
+ # For pickling as a singleton:
+ self.__module__ = _caller()
+
+ def __init_subclass__(cls):
+ warnings.warn(
+ "Subclassing sentinel is deprecated "
+ "and will be disallowed in Python 3.15",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ super().__init_subclass__()
+
+ def __setattr__(self, attr: str, value: object) -> None:
+ if attr not in {"_name", "_repr", "__module__"}:
+ warnings.warn(
+ f"Setting attribute {attr!r} on sentinel objects is
deprecated "
+ "and will be disallowed in Python 3.15.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ super().__setattr__(attr, value)
+
+ @property
+ def __name__(self) -> str:
+ return self._name
+
+ @__name__.setter
+ def __name__(self, value: str) -> None:
+ self._name = value
+
+ def __repr__(self) -> str:
+ return self._repr
+
+ if sys.version_info < (3, 11):
+ # The presence of this method convinces typing._type_check
+ # that Sentinels are types.
+ def __call__(self, *args, **kwargs):
+ raise TypeError(f"{type(self).__name__!r} object is not
callable")
+
+ # Breakpoint: https://github.com/python/cpython/pull/21515
+ if sys.version_info >= (3, 10):
+ def __or__(self, other):
+ return typing.Union[self, other]
+ def __ror__(self, other):
+ return typing.Union[other, self]
+
+ def __reduce__(self) -> str:
+ """Reduce this sentinel to a singleton."""
+ return self.__name__ # Module is taken from the __module__
attribute
+
+Sentinel = sentinel
-_marker = _Sentinel()
+_marker = sentinel("sentinel")
+# The functions below are modified copies of typing internal helpers.
+# They are needed by _ProtocolMeta and they provide support for PEP 646.
+
# Breakpoint: https://github.com/python/cpython/pull/27342
if sys.version_info >= (3, 10):
def _should_collect_from_parameters(t):
@@ -524,7 +628,9 @@
class _SpecialGenericAlias(typing._SpecialGenericAlias, _root=True):
- def __init__(self, origin, nparams, *, inst=True, name=None,
defaults=()):
+ def __init__(self, origin, nparams, *, defaults, inst=True, name=None):
+ assert nparams > 0, "`nparams` must be a positive integer"
+ assert defaults, "Must always specify a non-empty sequence for
`defaults`"
super().__init__(origin, nparams, inst=inst, name=name)
self._defaults = defaults
@@ -542,20 +648,14 @@
msg = "Parameters to generic types must be types."
params = tuple(typing._type_check(p, msg) for p in params)
if (
- self._defaults
- and len(params) < self._nparams
+ len(params) < self._nparams
and len(params) + len(self._defaults) >= self._nparams
):
params = (*params, *self._defaults[len(params) -
self._nparams:])
actual_len = len(params)
if actual_len != self._nparams:
- if self._defaults:
- expected = f"at least {self._nparams -
len(self._defaults)}"
- else:
- expected = str(self._nparams)
- if not self._nparams:
- raise TypeError(f"{self} is not a generic class")
+ expected = f"at least {self._nparams - len(self._defaults)}"
raise TypeError(
f"Too {'many' if actual_len > self._nparams else 'few'}"
f" arguments for {self};"
@@ -587,10 +687,13 @@
_PROTO_ALLOWLIST = {
'collections.abc': [
'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable',
- 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer',
+ 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection',
+ 'Reversible', 'Buffer',
],
'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'],
+ 'io': ['Reader', 'Writer'],
'typing_extensions': ['Buffer'],
+ 'os': ['PathLike'],
}
@@ -612,22 +715,12 @@
return attrs
-def _caller(depth=1, default='__main__'):
- try:
- return sys._getframemodulename(depth + 1) or default
- except AttributeError: # For platforms without _getframemodulename()
- pass
- try:
- return sys._getframe(depth + 1).f_globals.get('__name__', default)
- except (AttributeError, ValueError): # For platforms without _getframe()
- pass
- return None
-
-
# `__match_args__` attribute was removed from protocol members in 3.13,
# we want to backport this change to older Python versions.
-# Breakpoint: https://github.com/python/cpython/pull/110683
-if sys.version_info >= (3, 13):
+# 3.14 additionally added `io.Reader`, `io.Writer` and `os.PathLike` to
+# the list of allowed protocol allowlist.
+# https://github.com/python/cpython/issues/127647
+if sys.version_info >= (3, 14):
Protocol = typing.Protocol
else:
def _allow_reckless_class_checks(depth=2):
@@ -1038,10 +1131,10 @@
# Update this to something like >=3.13.0b1 if and when
-# PEP 728 is implemented in CPython
-_PEP_728_IMPLEMENTED = False
+# PEP 764 is implemented in CPython
+_PEP_764_IMPLEMENTED = False
-if _PEP_728_IMPLEMENTED:
+if _PEP_764_IMPLEMENTED:
# The standard library TypedDict in Python 3.9.0/1 does not honour the
"total"
# keyword with old-style TypedDict(). See
https://bugs.python.org/issue42059
# The standard library TypedDict below Python 3.11 does not store runtime
@@ -1051,7 +1144,8 @@
# to enable better runtime introspection.
# On 3.13 we deprecate some odd ways of creating TypedDicts.
# Also on 3.13, PEP 705 adds the ReadOnly[] qualifier.
- # PEP 728 (still pending) makes more changes.
+ # PEP 728 (Python 3.15+) adds the `extra_items` and `closed` keywords.
+ # PEP 764 (still pending) allows the `TypedDict` special form to be
subscripted.
TypedDict = typing.TypedDict
_TypedDictMeta = typing._TypedDictMeta
is_typeddict = typing.is_typeddict
@@ -1155,8 +1249,14 @@
if sys.version_info <= (3, 14):
annotations.update(base_dict.get('__annotations__', {}))
- required_keys.update(base_dict.get('__required_keys__', ()))
- optional_keys.update(base_dict.get('__optional_keys__', ()))
+ base_required = base_dict.get('__required_keys__', set())
+ required_keys |= base_required
+ optional_keys -= base_required
+
+ base_optional = base_dict.get('__optional_keys__', set())
+ required_keys -= base_optional
+ optional_keys |= base_optional
+
readonly_keys.update(base_dict.get('__readonly_keys__', ()))
mutable_keys.update(base_dict.get('__mutable_keys__', ()))
@@ -1184,13 +1284,19 @@
qualifiers = set(_get_typeddict_qualifiers(annotation_type))
if Required in qualifiers:
- required_keys.add(annotation_key)
+ is_required = True
elif NotRequired in qualifiers:
- optional_keys.add(annotation_key)
- elif total:
+ is_required = False
+ else:
+ is_required = total
+
+ if is_required:
required_keys.add(annotation_key)
+ optional_keys.discard(annotation_key)
else:
optional_keys.add(annotation_key)
+ required_keys.discard(annotation_key)
+
if ReadOnly in qualifiers:
mutable_keys.discard(annotation_key)
readonly_keys.add(annotation_key)
@@ -1798,7 +1904,7 @@
paramspec = typing.ParamSpec(name, bound=bound,
covariant=covariant,
contravariant=contravariant)
- paramspec.__infer_variance__ = infer_variance
+ paramspec.__infer_variance__ = bool(infer_variance)
_set_default(paramspec, default)
_set_module(paramspec)
@@ -1894,10 +2000,7 @@
self.__covariant__ = bool(covariant)
self.__contravariant__ = bool(contravariant)
self.__infer_variance__ = bool(infer_variance)
- if bound:
- self.__bound__ = typing._type_check(bound, 'Bound must be a
type.')
- else:
- self.__bound__ = None
+ self.__bound__ = bound
_DefaultMixin.__init__(self, default)
# for pickling:
@@ -1929,6 +2032,9 @@
def __call__(self, *args, **kwargs):
pass
+ def __init_subclass__(cls) -> None:
+ raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable
base type")
+
# 3.9
if not hasattr(typing, 'Concatenate'):
@@ -1956,7 +2062,9 @@
__class__ = typing._GenericAlias
def __init__(self, origin, args):
- super().__init__(args)
+ # Cannot use `super().__init__` here because of the `__class__`
assignment
+ # in the class body
(https://github.com/python/typing_extensions/issues/661)
+ list.__init__(self, args)
self.__origin__ = origin
self.__args__ = args
@@ -2259,10 +2367,10 @@
return typing._GenericAlias(self, (item,))
-# 3.14+?
+# 3.15+?
if hasattr(typing, 'TypeForm'):
TypeForm = typing.TypeForm
-# <=3.13
+# <=3.14
else:
class _TypeFormForm(_ExtensionsSpecialForm, _root=True):
# TypeForm(X) is equivalent to X but indicates to the type checker
@@ -2515,7 +2623,10 @@
def __getitem__(self, args):
if self.__typing_is_unpacked_typevartuple__:
return args
- return super().__getitem__(args)
+ # Cannot use `super().__getitem__` here because of the `__class__`
assignment
+ # in the class body on Python <=3.11
+ # (https://github.com/python/typing_extensions/issues/661)
+ return typing._GenericAlias.__getitem__(self, args)
@_UnpackSpecialForm
def Unpack(self, parameters):
@@ -2537,20 +2648,33 @@
return newargs
-if _PEP_696_IMPLEMENTED:
+if sys.version_info >= (3, 15):
from typing import TypeVarTuple
elif hasattr(typing, "TypeVarTuple"): # 3.11+
- # Add default parameter - PEP 696
+ # Add default parameter - PEP 696 and bound/variance parameters
class TypeVarTuple(metaclass=_TypeVarLikeMeta):
"""Type variable tuple."""
_backported_typevarlike = typing.TypeVarTuple
- def __new__(cls, name, *, default=NoDefault):
- tvt = typing.TypeVarTuple(name)
- _set_default(tvt, default)
+ def __new__(cls, name, *, bound=None,
+ covariant=False, contravariant=False,
+ infer_variance=False, default=NoDefault):
+
+ if _PEP_696_IMPLEMENTED:
+ # can pass default argument
+ tvt = typing.TypeVarTuple(name, default=default)
+ else:
+ tvt = typing.TypeVarTuple(name)
+ _set_default(tvt, default)
+
+ tvt.__bound__ = bound
+ tvt.__covariant__ = bool(covariant)
+ tvt.__contravariant__ = bool(contravariant)
+ tvt.__infer_variance__ = bool(infer_variance)
+
_set_module(tvt)
def _typevartuple_prepare_subst(alias, args):
@@ -2655,8 +2779,13 @@
def __iter__(self):
yield self.__unpacked__
- def __init__(self, name, *, default=NoDefault):
+ def __init__(self, name, *, bound=None, covariant=False,
contravariant=False,
+ infer_variance=False, default=NoDefault):
self.__name__ = name
+ self.__covariant__ = bool(covariant)
+ self.__contravariant__ = bool(contravariant)
+ self.__infer_variance__ = bool(infer_variance)
+ self.__bound__ = bound
_DefaultMixin.__init__(self, default)
# for pickling:
@@ -2667,7 +2796,15 @@
self.__unpacked__ = Unpack[self]
def __repr__(self):
- return self.__name__
+ if self.__infer_variance__:
+ prefix = ''
+ elif self.__covariant__:
+ prefix = '+'
+ elif self.__contravariant__:
+ prefix = '-'
+ else:
+ prefix = '~'
+ return prefix + self.__name__
def __hash__(self):
return object.__hash__(self)
@@ -2873,9 +3010,9 @@
return arg
-# Python 3.13.3+ contains a fix for the wrapped __new__
-# Breakpoint: https://github.com/python/cpython/pull/132160
-if sys.version_info >= (3, 13, 3):
+# Python 3.13.8+ and 3.14.1+ contain a fix for the wrapped __init_subclass__
+# Breakpoint: https://github.com/python/cpython/pull/138210
+if ((3, 13, 8) <= sys.version_info < (3, 14)) or sys.version_info >= (3, 14,
1):
deprecated = warnings.deprecated
else:
_T = typing.TypeVar("_T")
@@ -2968,33 +3105,32 @@
arg.__new__ = staticmethod(__new__)
- original_init_subclass = arg.__init_subclass__
- # We need slightly different behavior if __init_subclass__
- # is a bound method (likely if it was implemented in Python)
- if isinstance(original_init_subclass, MethodType):
- original_init_subclass = original_init_subclass.__func__
+ if "__init_subclass__" in arg.__dict__:
+ # __init_subclass__ is directly present on the decorated
class.
+ # Synthesize a wrapper that calls this method directly.
+ original_init_subclass = arg.__init_subclass__
+ # We need slightly different behavior if __init_subclass__
+ # is a bound method (likely if it was implemented in
Python).
+ # Otherwise, it likely means it's a builtin such as
+ # object's implementation of __init_subclass__.
+ if isinstance(original_init_subclass, MethodType):
+ original_init_subclass =
original_init_subclass.__func__
@functools.wraps(original_init_subclass)
def __init_subclass__(*args, **kwargs):
warnings.warn(msg, category=category,
stacklevel=stacklevel + 1)
return original_init_subclass(*args, **kwargs)
-
- arg.__init_subclass__ = classmethod(__init_subclass__)
- # Or otherwise, which likely means it's a builtin such as
- # object's implementation of __init_subclass__.
else:
- @functools.wraps(original_init_subclass)
- def __init_subclass__(*args, **kwargs):
+ def __init_subclass__(cls, *args, **kwargs):
warnings.warn(msg, category=category,
stacklevel=stacklevel + 1)
- return original_init_subclass(*args, **kwargs)
+ return super(arg, cls).__init_subclass__(*args,
**kwargs)
- arg.__init_subclass__ = __init_subclass__
+ arg.__init_subclass__ = classmethod(__init_subclass__)
arg.__deprecated__ = __new__.__deprecated__ = msg
__init_subclass__.__deprecated__ = msg
return arg
elif callable(arg):
- import asyncio.coroutines
import functools
import inspect
@@ -3003,11 +3139,13 @@
warnings.warn(msg, category=category,
stacklevel=stacklevel + 1)
return arg(*args, **kwargs)
- if asyncio.coroutines.iscoroutinefunction(arg):
+ if inspect.iscoroutinefunction(arg):
# Breakpoint: https://github.com/python/cpython/pull/99247
if sys.version_info >= (3, 12):
wrapper = inspect.markcoroutinefunction(wrapper)
else:
+ import asyncio.coroutines
+
wrapper._is_coroutine =
asyncio.coroutines._is_coroutine
arg.__deprecated__ = wrapper.__deprecated__ = msg
@@ -3579,14 +3717,14 @@
return typing.Union[other, self]
-# Breakpoint: https://github.com/python/cpython/pull/124795
-if sys.version_info >= (3, 14):
+# Breakpoint: https://github.com/python/cpython/pull/149172
+if sys.version_info >= (3, 15):
TypeAliasType = typing.TypeAliasType
-# <=3.13
+# <=3.14
else:
# Breakpoint: https://github.com/python/cpython/pull/103764
if sys.version_info >= (3, 12):
- # 3.12-3.13
+ # 3.12-3.14
def _is_unionable(obj):
"""Corresponds to is_unionable() in unionobject.c in CPython."""
return obj is None or isinstance(obj, (
@@ -3699,7 +3837,7 @@
self.__name__ = name
def __setattr__(self, name: str, value: object, /) -> None:
- if hasattr(self, "__name__"):
+ if hasattr(self, "__name__") and name != "__module__":
self._raise_attribute_error(name)
super().__setattr__(name, value)
@@ -3710,7 +3848,7 @@
# Match the Python 3.12 error messages exactly
if name == "__name__":
raise AttributeError("readonly attribute")
- elif name in {"__value__", "__type_params__", "__parameters__",
"__module__"}:
+ elif name in {"__value__", "__type_params__", "__parameters__"}:
raise AttributeError(
f"attribute '{name}' of 'typing.TypeAliasType' objects "
"is not writable"
@@ -3829,8 +3967,8 @@
>>> class P(Protocol):
... def a(self) -> str: ...
... b: int
- >>> get_protocol_members(P)
- frozenset({'a', 'b'})
+ >>> get_protocol_members(P) == frozenset({'a', 'b'})
+ True
Raise a TypeError for arguments that are not Protocols.
"""
@@ -4207,44 +4345,6 @@
)
-class Sentinel:
- """Create a unique sentinel object.
-
- *name* should be the name of the variable to which the return value shall
be assigned.
-
- *repr*, if supplied, will be used for the repr of the sentinel object.
- If not provided, "<name>" will be used.
- """
-
- def __init__(
- self,
- name: str,
- repr: typing.Optional[str] = None,
- ):
- self._name = name
- self._repr = repr if repr is not None else f'<{name}>'
-
- def __repr__(self):
- return self._repr
-
- if sys.version_info < (3, 11):
- # The presence of this method convinces typing._type_check
- # that Sentinels are types.
- def __call__(self, *args, **kwargs):
- raise TypeError(f"{type(self).__name__!r} object is not callable")
-
- # Breakpoint: https://github.com/python/cpython/pull/21515
- if sys.version_info >= (3, 10):
- def __or__(self, other):
- return typing.Union[self, other]
-
- def __ror__(self, other):
- return typing.Union[other, self]
-
- def __getstate__(self):
- raise TypeError(f"Cannot pickle {type(self).__name__!r} object")
-
-
if sys.version_info >= (3, 14, 0, "beta"):
type_repr = annotationlib.type_repr
else:
@@ -4302,11 +4402,16 @@
"ValuesView",
"cast",
"no_type_check",
- "no_type_check_decorator",
# This is private, but it was defined by typing_extensions for a long time
# and some users rely on it.
"_AnnotatedAlias",
]
+
+# Breakpoint: https://github.com/python/cpython/pull/133602
+if sys.version_info < (3, 15, 0):
+ _typing_names.append("no_type_check_decorator")
+ __all__.append("no_type_check_decorator")
+
globals().update(
{name: getattr(typing, name) for name in _typing_names if hasattr(typing,
name)}
)