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)}
 )

Reply via email to