https://github.com/python/cpython/commit/92164dc91712dcf27e2d526fa6ef8735a8356a36
commit: 92164dc91712dcf27e2d526fa6ef8735a8356a36
branch: main
author: Jelle Zijlstra <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-04-17T19:20:41-07:00
summary:

gh-148639: Implement PEP 800 (typing.disjoint_base) (#148640)

Co-authored-by: Victorien <[email protected]>
Co-authored-by: Petr Viktorin <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-04-15-20-32-55.gh-issue-148639.-dwsjB.rst
M Doc/library/typing.rst
M Doc/whatsnew/3.15.rst
M Lib/test/test_typing.py
M Lib/typing.py

diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index 2ce868cf84da9d..9150385bd5888d 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -3358,6 +3358,36 @@ Functions and decorators
 
    .. versionadded:: 3.12
 
+.. decorator:: disjoint_base
+
+   Decorator to mark a class as a disjoint base.
+
+   Type checkers do not allow child classes of a disjoint base ``C`` to
+   inherit from other disjoint bases that are not parent or child classes of 
``C``.
+
+   For example::
+
+       @disjoint_base
+       class Disjoint1: pass
+
+       @disjoint_base
+       class Disjoint2: pass
+
+       class Disjoint3(Disjoint1, Disjoint2): pass  # Type checker error
+
+   Type checkers can use knowledge of disjoint bases to detect unreachable code
+   and determine when two types can overlap.
+
+   The corresponding runtime concept is a solid base (see 
:ref:`multiple-inheritance`).
+   Classes that are solid bases at runtime can be marked with 
``@disjoint_base`` in stub files.
+   Users may also mark other classes as disjoint bases to indicate to type 
checkers that
+   multiple inheritance with other disjoint bases should not be allowed.
+
+   Note that the concept of a solid base is a CPython implementation
+   detail, and the exact set of standard library classes that are
+   disjoint bases at runtime may change in future versions of Python.
+
+   .. versionadded:: next
 
 .. decorator:: type_check_only
 
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 56cc71b40fce82..7cf4dc3701fa6e 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -80,6 +80,7 @@ Summary -- Release highlights
 * :pep:`728`: ``TypedDict`` with typed extra items
 * :pep:`747`: :ref:`Annotating type forms with TypeForm
   <whatsnew315-typeform>`
+* :pep:`800`: Disjoint bases in the type system
 * :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object
   <whatsnew315-pybyteswriter>`
 * :pep:`803`: :ref:`Stable ABI for Free-Threaded Builds <whatsnew315-abi3t>`
@@ -1290,6 +1291,13 @@ typing
   as it was incorrectly inferred in runtime before.
   (Contributed by Nikita Sobolev in :gh:`137191`.)
 
+* :pep:`800`: Add :deco:`typing.disjoint_base`, a new decorator marking a class
+  as a disjoint base. This is an advanced feature primarily intended to allow
+  type checkers to faithfully reflect the runtime semantics of types defined
+  as builtins or in compiled extensions. If a class ``C`` is a disjoint base, 
then
+  child classes of that class cannot inherit from other disjoint bases that are
+  not parent or child classes of ``C``. (Contributed by Jelle Zijlstra in 
:gh:`148639`.)
+
 
 unicodedata
 -----------
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 9c0172f6ba7f23..3fb974c517da7c 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -29,7 +29,7 @@
 from typing import assert_type, cast, runtime_checkable
 from typing import get_type_hints
 from typing import get_origin, get_args, get_protocol_members
-from typing import override
+from typing import override, disjoint_base
 from typing import is_typeddict, is_protocol
 from typing import reveal_type
 from typing import dataclass_transform
@@ -10920,6 +10920,18 @@ def bar(self):
         self.assertNotIn('__magic__', dir_items)
 
 
+class DisjointBaseTests(BaseTestCase):
+    def test_disjoint_base_unmodified(self):
+        class C: ...
+        self.assertIs(C, disjoint_base(C))
+
+    def test_dunder_disjoint_base(self):
+        @disjoint_base
+        class C: ...
+
+        self.assertIs(C.__disjoint_base__, True)
+
+
 class RevealTypeTests(BaseTestCase):
     def test_reveal_type(self):
         obj = object()
diff --git a/Lib/typing.py b/Lib/typing.py
index e78fb8b71a996c..868fec9e088cb5 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -126,6 +126,7 @@
     'cast',
     'clear_overloads',
     'dataclass_transform',
+    'disjoint_base',
     'evaluate_forward_ref',
     'final',
     'get_args',
@@ -2794,6 +2795,29 @@ class Other(Leaf):  # Error reported by type checker
     return f
 
 
+def disjoint_base(cls):
+    """This decorator marks a class as a disjoint base.
+
+    Child classes of a disjoint base cannot inherit from other disjoint bases 
that are
+    not parent or child classes of the disjoint base.
+
+    For example:
+
+        @disjoint_base
+        class Disjoint1: pass
+
+        @disjoint_base
+        class Disjoint2: pass
+
+        class Disjoint3(Disjoint1, Disjoint2): pass  # Type checker error
+
+    Type checkers can use knowledge of disjoint bases to detect unreachable 
code
+    and determine when two types can overlap.
+    """
+    cls.__disjoint_base__ = True
+    return cls
+
+
 # Some unconstrained type variables.  These were initially used by the 
container types.
 # They were never meant for export and are now unused, but we keep them around 
to
 # avoid breaking compatibility with users who import them.
diff --git 
a/Misc/NEWS.d/next/Library/2026-04-15-20-32-55.gh-issue-148639.-dwsjB.rst 
b/Misc/NEWS.d/next/Library/2026-04-15-20-32-55.gh-issue-148639.-dwsjB.rst
new file mode 100644
index 00000000000000..d7acdb0983837a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-04-15-20-32-55.gh-issue-148639.-dwsjB.rst
@@ -0,0 +1,2 @@
+Implement :pep:`800`, adding the :deco:`typing.disjoint_base` decorator.
+Patch by Jelle Zijlstra.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to