Repository navigation
feat(python): read a model's declaration and check rule A (#1386) - #1433
Conversation
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
905205f to
2d76b18
Compare
`@stackencrypt.model("users")` reads a class's fields when the class is
defined. A field without exactly one stash marker raises
`DeclarationError` at the class statement. It works with dataclasses,
attrs, Pydantic, `NamedTuple`, and SQLAlchemy classes.
`DECLARATION_MARKER_NOT_OUTERMOST` is a new error code, for a marker in
the wrong place. The spec's `DECLARATION_NOT_OUTERMOST` moves to #1387.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codes such as `declaration_no_marker` and the reason `rule_a` follow the amendment on #1341. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2d76b18 to
bac90dd
Compare
cipherstash-agent
left a comment
There was a problem hiding this comment.
Review attestation
Reviewed bac90dd · posted from Claude Code · model claude-sonnet-5-5 · effort medium
Sources: code-review · claude-sonnet-5-5 (cross-checked inline by the posting session)
Skills: code-review, review-cross-check, review-post
Findings (4): 1 major, 3 minor — 4 inline, 0 below.
Two candidate findings were dropped: the pydantic __pydantic_fields__ fallback (refuted — on pydantic 2.9.2 get_type_hints returns only the declared fields) and the unbounded test extra (documented design decision in the PR).
Generated by Claude Code
cipherstash-bot
left a comment
There was a problem hiding this comment.
Recommendation: 🟡 merge after changes
Three changes before merging: fix the wrong field name in declaration_hints_unresolved for ClassVar fields, and add tests for _is_class_level and for refused Mapped[...] columns. Nothing else blocks the merge.
Other findings not posted as comments
- Optional: no test declares a decorated subclass, so base-class fields are not checked in the plan.
languages/python/python/stackencrypt/_declaration.py:123 - Optional: no test declares
Annotated[Mapped[str], TextEq]on a dataclass, so thefrom_hints=Falserule is not pinned._declaration.py:258 - Optional: no test puts the unresolved hint on an undecorated base class, so the MRO walk in
_unresolved_fieldis not checked._declaration.py:176
How this review was made
| Agent | Model | Review type | Result |
|---|---|---|---|
| claude | claude-opus-5-5 | test-gap | 3 found, 2 posted |
| claude | claude-opus-5-5 | rust | 0 found, 0 posted |
| claude | claude-opus-5-5 | python | 1 found, 1 posted |
| claude | claude-opus-5-5 | infracode | 0 found, 0 posted |
| codex | gpt-5.6-terra | test-gap | 1 found, 1 posted |
| codex | gpt-5.6-terra | rust | 0 found, 0 posted |
| codex | gpt-5.6-terra | python | 0 found, 0 posted |
| codex | gpt-5.6-terra | infracode | 0 found, 0 posted |
Synthesis: claude-sonnet-5-5 merged the findings, removed duplicates and dropped findings it could not confirm in the code. 1 posted finding(s) were raised by two or more models.
Plain language: the reader test did not run; only the word-and-shape check was applied.
Stack: position 5 of 15 (#1405, #1406, #1414, #1415, *️⃣ #1433, #1437, #1453, #1499, #1509, #1510, #1511, #1513, #1516, #1517, #1582). *️⃣ marks this pull request.
Context loaded: the description, 3 linked issue(s) and 7 discussion entries.
Summary
A Python developer marks a class as a model with
@stackencrypt.model("users"). The decorator now reads the class's fields when the class is defined. A field without exactly one stash marker raisesDeclarationErrorat the class statement, so the developer sees the mistake where they wrote it.A stash marker says how a field is stored.
TextEqencrypts it,Passthroughstores it as it is, andIgnoreleaves it out.Changes
_declaration.py: themodeldecorator and the field reader._errors.py:StashErrorandDeclarationError.NamedTuple, and SQLAlchemy classes. Each test runs twice, with and withoutfrom __future__ import annotations.pyproject.toml: attrs, Pydantic, and SQLAlchemy join thetestextra only. The package itself imports none of them.Verification
mise run test: 113 passed and 2 skipped, on Python 3.14.mypy --strictpasses. pyright reports 0 errors.pnpm run test:scripts: 83 test files pass.Related
Closes #1386. Part of #1341.
Review notes
DECLARATION_MARKER_NOT_OUTERMOSTis a new error code, for a marker in the wrong place, such asAnnotated[Mapped[str], TextEq]. The spec'sDECLARATION_NOT_OUTERMOSTstays for the decorator order. The constructor check in python: declaration meaning — type table, hints, engine check, constructor #1387 finds that.🤖 Generated with Claude Code