Skip to content

Fix dead isinstance check in _decorator_infos_for_class() - #13858

Merged
Viicos merged 1 commit into
pydantic:mainfrom
kratos0718:fix-computed-field-dead-isinstance
Sep 25, 2026
Merged

Viicos merged 1 commit into
pydantic:mainfrom
kratos0718:fix-computed-field-dead-isinstance

Conversation

@kratos0718

@kratos0718 kratos0718 commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

What

_decorator_infos_for_class's final else branch (reached for computed fields, after every other DecoratorInfo subtype has been ruled out by the preceding elif chain) contained:

isinstance(var_value, ComputedFieldInfo)

as a bare statement. The boolean result is computed and immediately discarded, so this line has no effect at all — not even for static type narrowing, since a bare expression statement doesn't narrow anything for mypy/pyright. It also checks the wrong variable: var_value is the PydanticDescriptorProxy itself, not its .decorator_info — so even if the result were used, this specific check would always evaluate to False.

Fix

assert isinstance(info, ComputedFieldInfo)

This checks the right variable (info, the actual DecoratorInfo) and turns the no-op into a real invariant check, matching the same style already used a few lines above at PydanticDescriptorProxy.__post_init__ (line 186: isinstance(self.decorator_info, ComputedFieldInfo)).

Right now this branch really can only be reached with a ComputedFieldInfo, so nothing changes for any current input. The value is defensive: if a DecoratorInfo subtype is ever added without updating this elif chain to match, this now fails fast with a clear AssertionError at class-creation time, instead of silently filing it under res.computed_fields and surfacing a confusing AttributeError much later, deep inside update_from_config.

Small and mechanical enough that I went straight to a PR per the template's "unless your change is trivial" note — happy to open an issue first instead if you'd rather discuss it there.

Testing

Full suite: 6110 passed, 1 pre-existing failure (test_generic_model_pickle_different_module, a subprocess/cloudpickle environment issue) reproduced identically on main with this change reverted, so unrelated to this diff.

The else branch (reached for computed fields, after every other
DecoratorInfo subtype has been ruled out) called
isinstance(var_value, ComputedFieldInfo) as a bare statement: the
boolean result was computed and immediately discarded, so it had no
effect. It also checked the wrong variable — var_value is the
PydanticDescriptorProxy, not its .decorator_info, so the check would
always have been False even if its result had been used.

Changed it to assert isinstance(info, ComputedFieldInfo), matching
the same invariant-check style already used a few lines above at
PydanticDescriptorProxy.__post_init__ (line 186). This makes the
implicit assumption in this branch an explicit, enforced one: if a
future DecoratorInfo subtype is ever added without a matching elif
here, this now fails fast with a clear AssertionError at class
creation time instead of silently mis-classifying it as a computed
field and surfacing a confusing AttributeError later in
update_from_config.

Full test suite passes (6110 passed, 1 pre-existing unrelated
failure in test_generic_model_pickle_different_module reproduced
identically on main without this change).
@codspeed

codspeed Bot commented Sep 24, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 216 untouched benchmarks
⏩ 163 skipped benchmarks1


Comparing kratos0718:fix-computed-field-dead-isinstance (61b5844) with main (0384c97)

Open in CodSpeed

Footnotes

  1. 163 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@github-actions

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  pydantic/_internal
  _decorators.py
Project Total  

This report was generated by python-coverage-comment-action

@Viicos Viicos added the relnotes-ignore Omit this PR from the release notes. label Sep 25, 2026
@Viicos Viicos changed the title Fix dead isinstance check in _decorator_infos_for_class Fix dead isinstance check in _decorator_infos_for_class() Sep 25, 2026
@Viicos
Viicos merged commit dae7e20 into pydantic:main Sep 25, 2026
91 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

relnotes-ignore Omit this PR from the release notes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants