overrides

A Python decorator and metaclass that verify a method actually overrides its superclass counterpart, catching signature drift at class-creation time.

Library
PyPI
v7.7.0
270stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
43/100Fair
Development Activity12
Maintenance20
Community60
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
64/100Good
Architecture78
Code Quality72
Innovation70
Learning Curve35

overrides is a small, dependency-free Python library that closes a gap in the language’s object model: nothing normally stops a subclass method from silently drifting out of sync with the superclass method it’s meant to override. The @override decorator inspects the enclosing class body at decoration time (via bytecode disassembly and frame inspection) to find the referenced base classes, then verifies the overridden method exists there and that its signature and return type remain compatible with the original — raising a TypeError immediately at import time rather than surfacing as a subtle runtime bug months later.

For teams that want the check applied consistently, EnforceOverrides (a metaclass-based base class) requires every method shadowing a base-class method to carry the @override decorator, so accidental overrides can’t slip through undecorated. A companion @final decorator marks methods that must never be overridden at all. As a side effect, @override also copies the superclass docstring onto the overriding method when one isn’t already present, so linters that require docstrings on public methods don’t force boilerplate "See parent class." comments.

What You Get

  • An @override decorator that validates a subclass method genuinely overrides a superclass method — same name found in a base class, or it raises TypeError at class-definition time
  • Signature-compatibility checking (ensure_signature_is_compatible) covering parameter names, kinds, ordering, and subtype-aware return/parameter type annotations between super and sub methods
  • Automatic docstring inheritance: an overriding method without its own docstring picks up the superclass method’s docstring
  • EnforceOverrides metaclass that requires the @override decorator on any method shadowing a base-class method, catching accidental silent overrides across an entire class hierarchy
  • A @final decorator (and native typing.final on Python 3.11+) to mark methods that cannot be overridden, enforced against classes using EnforceOverrides
  • Optional check_signature=False and check_at_runtime=True flags for opting out of static signature checks or deferring validation until the method is actually called (useful for forward references)

Common Use Cases

  • Guarding plugin or driver interfaces where subclasses must implement an exact method contract and a typo’d or renamed method should fail loudly instead of silently not overriding anything
  • Enforcing API stability across a class hierarchy that’s actively refactored by multiple contributors, so a renamed or removed superclass method surfaces every stale subclass override immediately
  • Marking framework base-class methods as @final so downstream users of a library can’t accidentally break invariants by overriding methods that must run exactly as written
  • Reducing docstring boilerplate on overriding methods in codebases where linters (e.g. flake8 docstring rules) require every public method to have one
  • Adding override safety incrementally to an existing codebase via EnforceOverrides on a handful of hierarchies, without needing a broader static type-checking migration

Under The Hood

Architecture overrides/overrides.py implements the overrides/override decorators using sys._getframe combined with dis.get_instructions bytecode disassembly to locate the base-class names referenced in the enclosing class statement at decoration time (no explicit base-class argument required), then delegates signature compatibility checking to signature.py’s ensure_signature_is_compatible, which normalizes type annotations via typing_utils.py (a small vendored subtype-checking module) to compare parameter and return types between the super and sub methods. enforce.py provides an alternative, broader-reaching mechanism: EnforceOverridesMeta, a metaclass that walks every method in a class’s namespace at class-creation time and requires the @override decorator on anything shadowing a base-class method. final.py supplies a minimal decorator that just tags a method with __final__ for the enforcement machinery to check against. The result is a flat, single-purpose module layout with no external runtime dependencies, where the core technique is structural bytecode/frame introspection rather than requiring subclasses to declare their base class explicitly.

Tech Stack Pure Python (99.7% of the codebase) with zero runtime dependencies, built entirely on the standard library (inspect, dis, functools, typing). Packaging still uses a classic setup.py with distutils/setuptools rather than a modern pyproject.toml build backend, targeting Python 3.10+. CI (.github/workflows/ci.yml) runs a matrix across Python 3.10 through 3.14, installing via pip, running the test suite with pytest, and running mypy for static type checking — including a bespoke check_mypy.sh script that asserts an exact expected error count against intentionally-broken fixture files in mypy_fails/. The package ships a py.typed marker so downstream type checkers treat its own annotations as authoritative.

Code Quality The test suite spans eleven files covering decorator parameters, metaclass-based enforcement, @final behavior, signature compatibility edge cases, named/positional argument handling, and version-specific behavior (files suffixed _py38/_py3_10 for syntax gated by Python version), run with plain pytest across the full CI matrix. Type hints are used consistently throughout the source, mismatches raise explicit TypeErrors rather than failing silently, and naming is conventional. Notably, mypy verification goes beyond a simple pass/fail: check_mypy.sh checks that known-bad fixture code produces exactly the expected number of type errors, an unusually rigorous way of testing the library’s interaction with static type checkers. black, isort, and flake8 are listed in requirements-dev.txt but are not actually invoked in CI, so formatting/lint conformance isn’t automatically enforced.

What Makes It Unique Rather than the common approach of just checking that a method name exists somewhere in the MRO, overrides performs real bytecode disassembly and frame inspection to identify which base classes are being referenced in the surrounding class definition, then does a genuinely structural signature check — parameter names, kinds, ordering, and subtype-aware type compatibility for both parameters and return values — between the super and sub methods. It also offers two complementary enforcement styles: an opt-in per-method decorator for incremental adoption, and a metaclass (EnforceOverrides) that enforces the decorator hierarchy-wide, letting teams choose the level of strictness that fits an existing codebase without a larger typing migration.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search