Skip to content

Commit 26ace2b

Browse files
authored
Merge branch 'main' into add-coverage
2 parents b16e770 + abaaafd commit 26ace2b

File tree

5 files changed

+56
-2
lines changed

5 files changed

+56
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
# Unreleased
1+
# Release 4.15.0rc1 (August 18, 2025)
22

3+
- Add the `@typing_extensions.disjoint_base` decorator, as specified
4+
in PEP 800. Patch by Jelle Zijlstra.
35
- Add `typing_extensions.type_repr`, a backport of
46
[`annotationlib.type_repr`](https://docs.python.org/3.14/library/annotationlib.html#annotationlib.type_repr),
57
introduced in Python 3.14 (CPython PR [#124551](https://github.com/python/cpython/pull/124551),

doc/index.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,17 @@ Decorators
705705
Inheriting from a deprecated class now also raises a runtime
706706
:py:exc:`DeprecationWarning`.
707707

708+
.. decorator:: disjoint_base
709+
710+
See :pep:`800`. A class decorator that marks a class as a "disjoint base", meaning that
711+
child classes of the decorated class cannot inherit from other disjoint bases that are not
712+
parent classes of the decorated class.
713+
714+
This helps type checkers to detect unreachable code and to understand when two types
715+
can overlap.
716+
717+
.. versionadded:: 4.15.0
718+
708719
.. decorator:: final
709720

710721
See :py:func:`typing.final` and :pep:`591`. In ``typing`` since 3.8.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "flit_core.buildapi"
66
# Project metadata
77
[project]
88
name = "typing_extensions"
9-
version = "4.14.1"
9+
version = "4.15.0rc1"
1010
description = "Backported and Experimental Type Hints for Python 3.9+"
1111
readme = "README.md"
1212
requires-python = ">=3.9"

src/test_typing_extensions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
clear_overloads,
8585
dataclass_transform,
8686
deprecated,
87+
disjoint_base,
8788
evaluate_forward_ref,
8889
final,
8990
get_annotations,
@@ -6670,6 +6671,18 @@ def cached(self): ...
66706671
self.assertIs(True, Methods.cached.__final__)
66716672

66726673

6674+
class DisjointBaseTests(BaseTestCase):
6675+
def test_disjoint_base_unmodified(self):
6676+
class C: ...
6677+
self.assertIs(C, disjoint_base(C))
6678+
6679+
def test_dunder_disjoint_base(self):
6680+
@disjoint_base
6681+
class C: ...
6682+
6683+
self.assertIs(C.__disjoint_base__, True)
6684+
6685+
66736686
class RevealTypeTests(BaseTestCase):
66746687
def test_reveal_type(self):
66756688
obj = object()

src/typing_extensions.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
'clear_overloads',
7272
'dataclass_transform',
7373
'deprecated',
74+
'disjoint_base',
7475
'Doc',
7576
'evaluate_forward_ref',
7677
'get_overloads',
@@ -321,6 +322,33 @@ class Other(Leaf): # Error reported by type checker
321322
return f
322323

323324

325+
if hasattr(typing, "disjoint_base"): # 3.15
326+
disjoint_base = typing.disjoint_base
327+
else:
328+
def disjoint_base(cls):
329+
"""This decorator marks a class as a disjoint base.
330+
331+
Child classes of a disjoint base cannot inherit from other disjoint bases that are
332+
not parent classes of the disjoint base.
333+
334+
For example:
335+
336+
@disjoint_base
337+
class Disjoint1: pass
338+
339+
@disjoint_base
340+
class Disjoint2: pass
341+
342+
class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error
343+
344+
Type checkers can use knowledge of disjoint bases to detect unreachable code
345+
and determine when two types can overlap.
346+
347+
See PEP 800."""
348+
cls.__disjoint_base__ = True
349+
return cls
350+
351+
324352
def IntVar(name):
325353
return typing.TypeVar(name)
326354

0 commit comments

Comments
 (0)