Skip to content
Merged
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
2 changes: 2 additions & 0 deletions docs/config-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ I path relativi sono sempre risolti rispetto alla directory che contiene `datase
|---|---|---|
| `dataset.name` | `string` | nessuno |
| `dataset.years` | `list[int]` | nessuno |
| `dataset.tags` | `list[string]` | `[]` |
| `dataset.category` | `string \| null` | `null` |

## raw

Expand Down
2 changes: 2 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ def make_config(
source_id=model.dataset.source_id,
years=list(model.dataset.years),
time_coverage=model.dataset.time_coverage,
tags=list(model.dataset.tags or []),
category=model.dataset.category,
_model=model,
)

Expand Down
71 changes: 71 additions & 0 deletions tests/test_config_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,3 +585,74 @@ def test_mart_required_tables_explicit_subset(tmp_path: Path):

cfg = load_config(yml)
assert cfg.mart.required_tables == ["table_a"]


@pytest.mark.contract
def test_dataset_tags_default_empty(tmp_path: Path):
"""dataset.tags defaults to [] when omitted."""
yml = tmp_path / "dataset.yml"
_yml(yml)
cfg = load_config(yml)
assert cfg.tags == []


@pytest.mark.contract
def test_dataset_tags_parsed(tmp_path: Path):
"""dataset.tags è parsato correttamente da YAML lista."""
yml = tmp_path / "dataset.yml"
_yml_str(
yml,
"dataset:\n"
" name: demo\n"
" years: [2024]\n"
" tags: [sanità, farmaceutica, spesa-pubblica]\n"
"raw: {}\n"
"clean: {}\n"
"mart: {}",
)
cfg = load_config(yml)
assert cfg.tags == ["sanità", "farmaceutica", "spesa-pubblica"]


@pytest.mark.contract
def test_dataset_category_default_none(tmp_path: Path):
"""dataset.category defaults to None when omitted."""
yml = tmp_path / "dataset.yml"
_yml(yml)
cfg = load_config(yml)
assert cfg.category is None


@pytest.mark.contract
def test_dataset_category_parsed(tmp_path: Path):
"""dataset.category è parsato correttamente da YAML."""
yml = tmp_path / "dataset.yml"
_yml_str(
yml,
"dataset:\n name: demo\n years: [2024]\n category: sanità\nraw: {}\nclean: {}\nmart: {}",
)
cfg = load_config(yml)
assert cfg.category == "sanità"


@pytest.mark.policy
def test_dataset_tags_and_category_with_source_id(tmp_path: Path):
"""tags e category convivono con source_id e time_coverage."""
yml = tmp_path / "dataset.yml"
_yml_str(
yml,
"dataset:\n"
" name: demo\n"
" years: [2024]\n"
" source_id: test_source\n"
" tags: [tag1, tag2]\n"
" category: test-category\n"
"raw: {}\n"
"clean: {}\n"
"mart: {}",
)
cfg = load_config(yml)
assert cfg.dataset == "demo"
assert cfg.source_id == "test_source"
assert cfg.tags == ["tag1", "tag2"]
assert cfg.category == "test-category"
26 changes: 26 additions & 0 deletions tests/test_dataset_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,32 @@ def test_source_id(self, tmp_path: Path) -> None:
result = load_dataset_manifest(tmp_path)
assert result["source_id"] == "istat_sdmx"

def test_tags_default_empty(self, tmp_path: Path) -> None:
_write_dataset(tmp_path, {"dataset": {"name": "test"}})
result = load_dataset_manifest(tmp_path)
assert result["tags"] == []

def test_tags_parsed(self, tmp_path: Path) -> None:
_write_dataset(
tmp_path,
{"dataset": {"name": "test", "tags": ["sanità", "farmaceutica"]}},
)
result = load_dataset_manifest(tmp_path)
assert result["tags"] == ["sanità", "farmaceutica"]

def test_category_default_none(self, tmp_path: Path) -> None:
_write_dataset(tmp_path, {"dataset": {"name": "test"}})
result = load_dataset_manifest(tmp_path)
assert result["category"] is None

def test_category_parsed(self, tmp_path: Path) -> None:
_write_dataset(
tmp_path,
{"dataset": {"name": "test", "category": "sanità"}},
)
result = load_dataset_manifest(tmp_path)
assert result["category"] == "sanità"

def test_empty_years_default(self, tmp_path: Path) -> None:
_write_dataset(tmp_path, {"dataset": {"name": "test"}})
result = load_dataset_manifest(tmp_path)
Expand Down
7 changes: 6 additions & 1 deletion toolkit/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ class ToolkitConfig:
time_coverage: TimeCoverage | None

# Internal: the typed model (used by typed properties below)
_model: ToolkitConfigModel = field(repr=False, compare=False)
_model: ToolkitConfigModel

tags: list[str] = field(default_factory=list)
category: str | None = None

# --- Typed accessors ---

Expand Down Expand Up @@ -116,5 +119,7 @@ def load_config(
source_id=model.dataset.source_id,
years=list(model.dataset.years),
time_coverage=model.dataset.time_coverage,
tags=list(model.dataset.tags or []),
category=model.dataset.category,
_model=model,
)
4 changes: 3 additions & 1 deletion toolkit/core/config_models/shared_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from pathlib import Path
from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, field_validator, model_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator


_SAFE_SQL_IDENTIFIER_RE = r"^[A-Za-z_][A-Za-z0-9_]*$"
Expand Down Expand Up @@ -104,6 +104,8 @@ class DatasetBlock(BaseModel):
years: list[int]
source_id: str | None = None
time_coverage: TimeCoverage | None = None
tags: list[str] = Field(default_factory=list)
category: str | None = None


class SupportDatasetConfig(BaseModel):
Expand Down
2 changes: 2 additions & 0 deletions toolkit/core/dataset_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ def load_dataset_manifest(path: str | Path) -> dict[str, Any]:
"years": ds.get("years") or [],
"source_id": ds.get("source_id"),
"time_coverage": ds.get("time_coverage"),
"tags": ds.get("tags") or [],
"category": ds.get("category"),
}

# raw.sources
Expand Down
3 changes: 3 additions & 0 deletions toolkit/mcp/schema_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ def dataset_info(config_path: str) -> dict[str, Any]:
return {
"dataset": cfg.dataset if hasattr(cfg, "dataset") else None,
"config_path": str(config),
"source_id": cfg.source_id if hasattr(cfg, "source_id") else None,
"years": list(cfg.years) if hasattr(cfg, "years") else [],
"time_coverage": time_cov,
"source_urls": source_urls,
Expand All @@ -407,6 +408,8 @@ def dataset_info(config_path: str) -> dict[str, Any]:
"has_mart": has_mart,
"mart_tables": mart_tables,
"support_datasets": support_list,
"tags": list(cfg.tags) if hasattr(cfg, "tags") else [],
"category": cfg.category if hasattr(cfg, "category") else None,
}


Expand Down
Loading