Skip to content

fix(pydantic): skip non-dict models in list_models#2564

Closed
Bartok9 wants to merge 2 commits into
Canner:mainfrom
Bartok9:fix/pydantic-list-models-non-dict-20260722
Closed

fix(pydantic): skip non-dict models in list_models#2564
Bartok9 wants to merge 2 commits into
Canner:mainfrom
Bartok9:fix/pydantic-list-models-non-dict-20260722

Conversation

@Bartok9

@Bartok9 Bartok9 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Harden _run_list_models so non-dict / incomplete MDL model rows do not KeyError the pydantic-ai tool.

Real behavior proof

$ python3 -m pytest sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py -v
1 passed

License

sdk/wren-pydantic/** Apache-2.0.

Summary by CodeRabbit

  • Bug Fixes

    • Improved model listing reliability when manifests contain incomplete or malformed entries.
    • Invalid model entries are now skipped instead of causing errors.
    • Missing or incorrectly formatted column and property details are handled safely.
  • Tests

    • Added coverage to ensure invalid model definitions are ignored and valid model details are still parsed correctly.

Corrupted MDL rows caused KeyError/TypeError in wren_list_models.
Skip non-dicts and entries without name; coerce columns/properties.
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

_run_list_models now filters malformed manifest entries, normalizes unexpected field types, and constructs summaries defensively. A focused unit test verifies filtering and derived summary fields.

Changes

Model listing guards

Layer / File(s) Summary
Defensive model summary building
sdk/wren-pydantic/src/wren_pydantic/_tools.py
_run_list_models skips non-dictionary or nameless entries and handles non-list columns and non-dictionary properties values.
Malformed manifest validation
sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py
Unit coverage verifies malformed entries are skipped and valid summaries retain expected column counts and descriptions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • Canner/WrenAI#2522: Updates the same model-listing function with similar malformed manifest guards and tests.
  • Canner/WrenAI#2547: Hardens related model listing and description handling for malformed entries.
  • Canner/WrenAI#2562: Adds defensive handling to a related manifest model-rendering path.

Suggested labels: python

Poem

I’m a rabbit guarding models today,
Bad little entries get whisked away.
Columns may wobble, properties stray,
Valid summaries still find their way.
Hop, test, and ship—hip-hip-hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 clearly matches the main change: skipping non-dict models in list_models.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py (1)

9-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Most of this stubbing is dead code for the exec-based extraction approach used below.

sys.path.insert(...) and the sys.modules[...] registrations (Lines 16-27, 32-48) are only meaningful if something actually imports these modules. Since the test never imports _tools (it extracts and execs just the function body — Lines 49-70), none of these sys.modules entries are ever looked up except as a scratch place to grab WrenError/should_propagate/to_model_retry before dropping them into ns. This can be simplified to defining those three values directly (e.g. plain classes/lambdas) without touching sys.modules or sys.path at all.

♻️ Simplification
-ROOT = Path(__file__).resolve().parents[2]
-SRC = ROOT / "src"
-
-# Stub heavy deps before loading _tools
-sys.path.insert(0, str(SRC))
-
-# Provide minimal ModelSummary used by _tools
-models_mod = types.ModuleType("wren_pydantic._models")
-
-
-class ModelSummary:
-    def __init__(self, name, column_count, description=None):
-        self.name = name
-        self.column_count = column_count
-        self.description = description
-
-
-models_mod.ModelSummary = ModelSummary
-sys.modules["wren_pydantic._models"] = models_mod
-
-# Other imports in _tools — stub at package boundary by executing only the function
-# Extract function source with ast and exec in isolation is heavy; load module with stubs.
-
-for name in [
-    "wren",
-    "wren.model",
-    "wren.model.error",
-    "wren.engine",
-    "pydantic_ai",
-    "pydantic_ai.exceptions",
-    "wren_pydantic",
-    "wren_pydantic._errors",
-    "wren_pydantic._toolkit",
-]:
-    sys.modules.setdefault(name, types.ModuleType(name))
-
-sys.modules["wren.model.error"].WrenError = type("WrenError", (Exception,), {})
-sys.modules["wren_pydantic._errors"].should_propagate = lambda e: False
-sys.modules["wren_pydantic._errors"].to_model_retry = lambda e: e
+ROOT = Path(__file__).resolve().parents[2]
+SRC = ROOT / "src"
+
+
+class ModelSummary:
+    def __init__(self, name, column_count, description=None):
+        self.name = name
+        self.column_count = column_count
+        self.description = description
+
+
+WrenError = type("WrenError", (Exception,), {})
+should_propagate = lambda e: False
+to_model_retry = lambda e: e
🤖 Prompt for 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.

In `@sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py` around lines 9 -
48, Remove the unused sys.path insertion and sys.modules stubs from
test_run_list_models_guard.py. In the exec-based extraction setup, define the
required ModelSummary, WrenError, should_propagate, and to_model_retry values
directly in the execution namespace, preserving the existing test behavior
without package/module registration.
🤖 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 `@sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py`:
- Around line 49-70: Add WrenToolkit to the ns dictionary before exec(code, ns),
using a suitable placeholder or imported symbol so _run_list_models annotation
evaluation succeeds on Python 3.11/3.12. Also replace the line-prefix extraction
with AST-based parsing to reliably isolate the _run_list_models function without
depending on top-level def/class text patterns.

---

Nitpick comments:
In `@sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py`:
- Around line 9-48: Remove the unused sys.path insertion and sys.modules stubs
from test_run_list_models_guard.py. In the exec-based extraction setup, define
the required ModelSummary, WrenError, should_propagate, and to_model_retry
values directly in the execution namespace, preserving the existing test
behavior without package/module registration.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6b20b9d0-9ca5-42ec-89a5-a152b0284d6f

📥 Commits

Reviewing files that changed from the base of the PR and between f4b45ed and 8591da4.

📒 Files selected for processing (2)
  • sdk/wren-pydantic/src/wren_pydantic/_tools.py
  • sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py

Comment thread sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py Outdated
The previous own loads stubbed wren_pydantic._models and exec'd a slice of
_tools, which caused collection NameError/ImportError for sibling unit tests.
Use the real _run_list_models entrypoint with a MagicMock toolkit instead.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py (1)

10-25: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert normalization of malformed fields, not only filtering.

The test verifies that invalid rows are excluded and that valid summaries preserve derived fields, but it does not prove that a named model with non-list columns or non-dict properties is safely converted to column_count=0 and description=None. Add explicit assertions for those cases so regressions in the new defensive normalization are caught.

🤖 Prompt for 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.

In `@sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py` around lines 10 -
25, The test test_skips_bad_models should explicitly verify normalization of
malformed fields on the "ok" model: assert its non-list columns produce
column_count=0 and its non-dict properties produce description=None, while
preserving the existing assertions for the valid "t" model.
🤖 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.

Nitpick comments:
In `@sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py`:
- Around line 10-25: The test test_skips_bad_models should explicitly verify
normalization of malformed fields on the "ok" model: assert its non-list columns
produce column_count=0 and its non-dict properties produce description=None,
while preserving the existing assertions for the valid "t" model.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 94bf3c45-3976-4756-a327-84009f2fdcde

📥 Commits

Reviewing files that changed from the base of the PR and between 8591da4 and a929a0b.

📒 Files selected for processing (1)
  • sdk/wren-pydantic/tests/unit/test_run_list_models_guard.py

@Bartok9

Bartok9 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Closing as superseded — equivalent guard already landed on main via #2522 (fix(pydantic): skip non-dict models in list_models). This branch no longer rebases cleanly and the behavior is already present in _run_list_models.

@Bartok9 Bartok9 closed this Jul 24, 2026
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