Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions core/wren/src/wren/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ def convert_mdl_to_project(mdl_json: dict) -> list[ProjectFile]:
)

# ── Models ────────────────────────────────────────────────
for i, model in enumerate(mdl_json.get("models", [])):
for i, model in enumerate(mdl_json.get("models", []) or []):
if not isinstance(model, dict):
raise ValueError(
f"Model at index {i} must be an object, got {type(model).__name__}"
)
model_snake = _convert_keys_to_snake(model)
if "name" not in model_snake:
raise ValueError(f"Model at index {i} is missing required 'name' field")
Expand Down Expand Up @@ -226,7 +230,11 @@ def convert_mdl_to_project(mdl_json: dict) -> list[ProjectFile]:
)

# ── Views ─────────────────────────────────────────────────
for i, view in enumerate(mdl_json.get("views", [])):
for i, view in enumerate(mdl_json.get("views", []) or []):
if not isinstance(view, dict):
raise ValueError(
f"View at index {i} must be an object, got {type(view).__name__}"
)
view_snake = _convert_keys_to_snake(view)
if "name" not in view_snake:
raise ValueError(f"View at index {i} is missing required 'name' field")
Expand Down Expand Up @@ -941,6 +949,15 @@ def validate_project(project_path: Path) -> list[ValidationError]:

# Check models
for i, model in enumerate(models):
if not isinstance(model, dict):
errors.append(
ValidationError(
"error",
f"models[{i}]",
f"model entry must be an object, got {type(model).__name__}",
)
)
continue
src = model.get("_source_dir", f"models[{i}]")
src_path = f"models/{src}/metadata.yml"
name = model.get("name")
Expand Down Expand Up @@ -1098,6 +1115,15 @@ def validate_project(project_path: Path) -> list[ValidationError]:

# Check views
for i, view in enumerate(views):
if not isinstance(view, dict):
errors.append(
ValidationError(
"error",
f"views[{i}]",
f"view entry must be an object, got {type(view).__name__}",
)
)
continue
src_dir = view.get("_source_dir", f"views[{i}]")
name = view.get("name")
if not name:
Expand Down
10 changes: 10 additions & 0 deletions core/wren/tests/unit/test_convert_mdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,3 +383,13 @@ def test_cli_init_from_mdl_force(tmp_path: Path, sample_mdl_file: Path):
assert "Imported MDL" in result.output
project = yaml.safe_load((tmp_path / "wren_project.yml").read_text())
assert project["schema_version"] == 2


def test_convert_mdl_rejects_non_dict_model():
with pytest.raises(ValueError, match="must be an object"):
convert_mdl_to_project({"models": ["not-a-dict"], "views": []})


def test_convert_mdl_rejects_non_dict_view():
with pytest.raises(ValueError, match="View at index 0 must be an object"):
convert_mdl_to_project({"models": [], "views": [None]})
Loading