Skip to content

Extract shared from_dict validation helpers for model classes (#70)#80

Merged
wpak-ai merged 3 commits into
masterfrom
feat/extract-shared-decorator
May 26, 2026
Merged

Extract shared from_dict validation helpers for model classes (#70)#80
wpak-ai merged 3 commits into
masterfrom
feat/extract-shared-decorator

Conversation

@bradjin8
Copy link
Copy Markdown
Collaborator

@bradjin8 bradjin8 commented May 26, 2026

Summary

Centralizes the repeated from_dict validation pattern (dict check, required keys, type checks, SchemaError raising) in a new models/from_dict_validation.py module. All six model classes that used copy-pasted boilerplate now call shared helpers; model-specific rules stay in each class.

  • New: require_dict, require_key, require_non_empty_str, require_non_empty_str_field, require_non_empty_str_fields, require_truthy, require_type, require_optional_str
  • Refactored: Workspace, Composer, WorkspaceLocalComposer, Bubble, CliSessionMeta, ExportEntry
  • Unchanged: SchemaError message shape (missing vs invalid field, field names, type hints); frozen dataclass constructors; service-layer call sites

Closes #70

Test plan

  • pytest tests/test_models.py — all model schema tests pass unchanged
  • pytest tests/test_models_wired_at_read_sites.py — read-site wiring still calls from_dict
  • Full suite: pytest (306 passed, 4 skipped)

Summary by CodeRabbit

  • Refactor
    • Standardized and consolidated input/validation across models, improving consistency when loading or syncing data and producing clearer, more actionable error messages for invalid or missing fields.
  • Tests
    • Added unit tests to verify validation helpers produce correct error types and messages for missing or invalid fields.

Review Change Stack

@bradjin8 bradjin8 self-assigned this May 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d63e6c7-ec14-4ab5-852b-76004cd6020d

📥 Commits

Reviewing files that changed from the base of the PR and between f846aaf and 55d8ad1.

📒 Files selected for processing (2)
  • models/from_dict_validation.py
  • tests/test_from_dict_validation.py

📝 Walkthrough

Walkthrough

Introduces models/from_dict_validation.py with reusable require_* helpers and updates Workspace, Composer, WorkspaceLocalComposer, Bubble, CliSessionMeta, and ExportEntry to use those helpers for from_dict validation instead of inline isinstance checks and manual SchemaError raising.

Changes

Validation Helpers and Model Migrations

Layer / File(s) Summary
Validation helpers foundation
models/from_dict_validation.py
Adds 9 reusable validation helpers (require_dict, require_key, require_non_empty_str, require_non_empty_str_field, require_non_empty_str_fields, require_truthy, require_type, require_optional_str) that raise SchemaError with type-based hints.
Workspace model migration
models/workspace.py
Workspace.from_dict now validates raw with require_dict, workspace_id with require_non_empty_str, and folder with require_optional_str.
Conversation models migration
models/conversation.py
Composer.from_dict uses require_dict, require_non_empty_str, require_key, and require_type; WorkspaceLocalComposer.from_dict and Bubble.from_dict use require_dict and require_non_empty_str_field.
CLI session and export models migration
models/cli_session.py, models/export.py
CliSessionMeta.from_dict uses require_dict and require_truthy; ExportEntry.from_dict uses require_dict and require_non_empty_str_fields.
Validation tests
tests/test_from_dict_validation.py
Adds tests asserting error field metadata and distinct messages for missing vs invalid non-empty string fields.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 Five validators hopped into a heap,

I stitched their checks so errors speak neat;
No more scattered crumbs across the floor,
One-hop functions tidy up the store,
Now from_dicts hop clean on every beat.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: extracting shared validation helpers from multiple model classes into a centralized module.
Linked Issues check ✅ Passed All acceptance criteria from issue #70 are met: shared helpers centralize validation logic, six model classes refactored to use them, model-specific rules preserved, SchemaError messages retain detail, tests pass, and PR is open for review.
Out of Scope Changes check ✅ Passed All changes are directly related to extracting shared validation helpers as specified in issue #70; no unrelated refactoring or feature additions are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/extract-shared-decorator

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@models/from_dict_validation.py`:
- Around line 38-44: The code currently uses value = raw.get(key) which converts
absent keys to None and causes the isinstance check to raise an "invalid field"
SchemaError; change the logic to first detect missing keys (e.g., if key not in
raw) and raise the appropriate "missing required field" SchemaError for that
key/model before performing type/emptiness checks on value, then keep the
existing isinstance(value, str) and non-empty validation to raise the "invalid
field" SchemaError when the key is present but wrong; apply the same fix to the
other helper at the corresponding block that currently uses raw.get(...) (the
block around lines 56-62).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c2ff1c2-3af3-4383-81aa-6c6507cb389d

📥 Commits

Reviewing files that changed from the base of the PR and between e6bae8c and f61d27f.

📒 Files selected for processing (5)
  • models/cli_session.py
  • models/conversation.py
  • models/export.py
  • models/from_dict_validation.py
  • models/workspace.py

Comment thread models/from_dict_validation.py Outdated
@bradjin8 bradjin8 requested review from clean6378-max-it and timon0305 and removed request for timon0305 May 26, 2026 20:29
@clean6378-max-it
Copy link
Copy Markdown
Collaborator

models/from_dict_validation.py — add a small tests/test_from_dict_validation.py asserting message text for require_non_empty_str_fields / require_non_empty_str_field: absent key → missing required field, wrong type → invalid field. test_schema_error_message_distinguishes_missing_from_invalid covers the contract generically but not these helpers post-f846aaf.

models/from_dict_validation.py:69 — expand require_truthy docstring to note falsy values (None, "", 0) are treated as missing (matches prior CliSessionMeta behavior).

@clean6378-max-it clean6378-max-it requested a review from wpak-ai May 26, 2026 21:50
@wpak-ai wpak-ai merged commit adb75a4 into master May 26, 2026
16 checks passed
@wpak-ai wpak-ai deleted the feat/extract-shared-decorator branch May 26, 2026 22:00
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.

Extract shared from_dict base/decorator across 5 model classes

3 participants