Skip to content

Restore NullContext as a distinct class with virtual subclass semantics#218

Merged
timkpaine merged 1 commit into
mainfrom
pit/nullcontext-virtual
May 27, 2026
Merged

Restore NullContext as a distinct class with virtual subclass semantics#218
timkpaine merged 1 commit into
mainfrom
pit/nullcontext-virtual

Conversation

@ptomecek
Copy link
Copy Markdown
Collaborator

Problem

NullContext is currently aliased to ContextBase (commit fc64400, PR #166). This preserved substitutability (any context can be passed where NullContext is expected) but degraded introspection: for a model declaring context: NullContext, .context_type.__name__ reports "ContextBase" with the abstract base's docstring, which is confusing for users.

Approach

Reintroduce NullContext as a distinct subclass of ContextBase with a metaclass that lies in __instancecheck__ / __subclasscheck__: any ContextBase instance or subclass virtually satisfies NullContext. The lie is gated to NullContext itself, so user-defined subclasses of NullContext follow normal class-hierarchy rules.

Pydantic v2's instance fast-path in model_validate respects the lie, so original context instances flow through unchanged — same as the alias today.

Behavior

Before (alias) After (this PR)
m.context_type.__name__ ContextBase NullContext
docstring ContextBase's NullContext's ✅
isinstance(date_ctx, NullContext) True True
m(date_ctx) on NullContext model passes through unchanged passes through unchanged
MyNull(NullContext) subclass behaves as plain subclass yes yes (gating)
Polymorphic type_ discriminator ContextBase NullContext

Tests

All 841 tests pass on the local suite. No existing tests required modification.

Cache invalidation note

tokenize(NullContext()) differs from tokenize(ContextBase()) (the discriminator value changes). Any persisted cache keyed under the old alias semantics will miss once on first re-evaluation. Not a correctness issue, just a one-time invalidation worth a release note.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

Test Results

843 tests  ±0   841 ✅ ±0   1m 45s ⏱️ +2s
  1 suites ±0     2 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 3a93c18. ± Comparison against base commit 68a35ff.

♻️ This comment has been updated with latest results.

Previously `NullContext` was a direct alias of `ContextBase`. This preserved
substitutability (any context could be passed where a `NullContext` was
expected) but degraded introspection: `.context_type.__name__` reported
"ContextBase" with the abstract base's docstring, which was confusing for
users of models that declare `context: NullContext`.

Reintroduce `NullContext` as a distinct subclass of `ContextBase` whose
metaclass lies in `__instancecheck__` / `__subclasscheck__` so that any
`ContextBase` instance/subclass virtually satisfies `NullContext`. The lie
is gated to `NullContext` itself, so user-defined subclasses follow normal
class-hierarchy rules. Pydantic's v2 instance fast-path in `model_validate`
respects the lie, so original context instances flow through unchanged.

Net effect: zero behavior change at runtime; introspection now reports
`NullContext` with its own docstring.

Signed-off-by: Pascal Tomecek <pascal.tomecek@cubistsystematic.com>
@ptomecek ptomecek force-pushed the pit/nullcontext-virtual branch from 03fc8ab to 3a93c18 Compare May 27, 2026 18:07
@ptomecek ptomecek marked this pull request as ready for review May 27, 2026 18:08
@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.37%. Comparing base (68a35ff) to head (3a93c18).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #218   +/-   ##
=======================================
  Coverage   95.37%   95.37%           
=======================================
  Files         142      142           
  Lines       11428    11437    +9     
  Branches      623      625    +2     
=======================================
+ Hits        10899    10908    +9     
  Misses        399      399           
  Partials      130      130           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@timkpaine timkpaine merged commit 9a364f5 into main May 27, 2026
12 checks passed
@timkpaine timkpaine deleted the pit/nullcontext-virtual branch May 27, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants