Skip to content

Commit 8b51be6

Browse files
committed
Add @solid_base (PEP 800)
1 parent e238ea6 commit 8b51be6

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# Unreleased
2+
3+
- Add the `@typing_extensions.solid_base` decorator, as specified
4+
in PEP 800. Patch by Jelle Zijlstra.
5+
16
# Release 4.14.1 (July 4, 2025)
27

38
- Fix usage of `typing_extensions.TypedDict` nested inside other types

doc/index.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,17 @@ Decorators
748748
improved, and ``typing_extensions`` backports these performance
749749
improvements.
750750

751+
.. decorator:: solid_base
752+
753+
See :pep:`800`. A class decorator that marks a class as a "solid base", meaning that
754+
child classes of the decorated class cannot inherit from other solid bases that are not
755+
parent classes of the decorated class.
756+
757+
This helps type checkers to detect unreachable code and to understand when two types
758+
can overlap.
759+
760+
.. versionadded:: 4.15.0
761+
751762
Functions
752763
~~~~~~~~~
753764

src/test_typing_extensions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
reveal_type,
102102
runtime,
103103
runtime_checkable,
104+
solid_base,
104105
)
105106

106107
NoneType = type(None)
@@ -6669,6 +6670,18 @@ def cached(self): ...
66696670
self.assertIs(True, Methods.cached.__final__)
66706671

66716672

6673+
class SolidBaseTests(BaseTestCase):
6674+
def test_solid_base_unmodified(self):
6675+
class C: ...
6676+
self.assertIs(C, solid_base(C))
6677+
6678+
def test_dunder_solid_base(self):
6679+
@solid_base
6680+
class C: ...
6681+
6682+
self.assertIs(C.__solid_base__, True)
6683+
6684+
66726685
class RevealTypeTests(BaseTestCase):
66736686
def test_reveal_type(self):
66746687
obj = object()

src/typing_extensions.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,32 @@ class Other(Leaf): # Error reported by type checker
315315
return f
316316

317317

318+
if hasattr(typing, "solid_base"):
319+
solid_base = typing.solid_base
320+
else:
321+
def solid_base(cls):
322+
"""This decorator marks a class a solid base.
323+
Child classes of a solid base cannot inherit from other solid bases that are
324+
not parent classes of the solid base.
325+
326+
For example:
327+
328+
@solid_base
329+
class Solid1: pass
330+
331+
@solid_base
332+
class Solid2: pass
333+
334+
class Solid3(Solid1, Solid2): pass # Type checker error
335+
336+
Type checkers can use solid bases to detect unreachable code
337+
and determine when two types can overlap.
338+
339+
See PEP 800."""
340+
cls.__solid_base__ = True
341+
return cls
342+
343+
318344
def IntVar(name):
319345
return typing.TypeVar(name)
320346

0 commit comments

Comments
 (0)