Skip to content

feat(python): check what a model's declaration means (#1387) - #1437

Draft
yujiyokoo wants to merge 2 commits into
feat/python-sdk-declaration-readerfrom
feat/python-sdk-declaration-meaning
Draft

yujiyokoo wants to merge 2 commits into
feat/python-sdk-declaration-readerfrom
feat/python-sdk-declaration-meaning

Conversation

@yujiyokoo

Copy link
Copy Markdown
Contributor

Summary

@stackencrypt.model now checks what a declaration means, at the class statement. It refuses a field type that does not match its marker, a constructor decrypt could not call, and a plan the engine refuses. So a wrong model fails at import, before any database call.

A marker such as TextEq names an EQL type. EQL is CipherStash's encrypted column format in PostgreSQL.

Changes

Decorator checks (_declaration.py), after rule A:

  • declaration_unproducible: the engine cannot produce the marker yet.
  • declaration_type_mismatch: the value type is not exactly the kind's Python type, such as str for TextEq.
  • declaration_not_outermost: the decorator ran below @dataclass, so the class had no constructor yet.
  • declaration_constructor_missing_field: the constructor does not take a field's name, such as with init=False or a Pydantic alias.
  • declaration_ignore_required: an Ignore field has no default.
  • An engine refusal of the plan becomes a DeclarationError with the engine's code, such as stack_encrypt_dynamic_plan.

Engine check. crates/core/src/plan.rs builds the plan frame and runs the engine's plan_with. The EQL resolver is the Go guest's targets.rs, compiled in place through #[path], so both SDKs run one resolver. eql-bindings is a new path dependency. Its lock entries match the EQL workspace's versions.

CI. tests-python.yml also runs on changes to eql-bindings and targets.rs. python-ci.test.mjs checks that the filter selects every #[path] file.

Verification

  • pytest: 195 passed and 2 skipped, on Python 3.14 and 3.9.
  • cargo test, clippy, cargo fmt --check, mypy strict, and pyright are clean.
  • pnpm run test:scripts: 83 of 83 files pass.
  • The python-ci checks fail when the new filter entries are removed.
  • A build without the eql feature stops with the intended compile_error!.

Related

Closes #1387. Part of #1341.

Review notes

  • Start with _check_value_type and _check_constructor, then plan.rs.
  • #[path] means the Python crate must list every dependency of targets.rs. A Go change that adds one fails tests-python.yml at once.
  • Python refuses an unproducible marker before the engine does, as the spec asks.
  • JsonSearch has no Python type in v1, so it fails with declaration_type_mismatch.
  • A passthrough field reaches the engine with no "type" key. The encrypt ticket can add one.

🤖 Generated with Claude Code

yujiyokoo and others added 2 commits October 29, 2026 17:06
The decorator now checks each field's type against its marker, the
constructor, and the plan with the engine's own reader. The EQL
resolver is the Go guest's targets.rs, compiled in place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A constructor that lacks a field is now its own error, apart from the
decorator order. Pydantic aliases are read from Pydantic. A test covers
a relationship to a class defined later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Oct 29, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 2dc6d3d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
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.

1 participant