diff --git a/tests/test_raw_run_format_args.py b/tests/test_raw_run_format_args.py index d2e784a..86aac0c 100644 --- a/tests/test_raw_run_format_args.py +++ b/tests/test_raw_run_format_args.py @@ -2,6 +2,8 @@ from __future__ import annotations +from pathlib import Path + import pytest from toolkit.raw._fetch_utils import _format_args @@ -16,6 +18,22 @@ def test_format_args_simple_year_substitution(self) -> None: result = _format_args(args, 2023) assert result["url"] == "https://example.com/data2023.csv" + def test_format_args_path_year_substitution(self) -> None: + """local_file path normalized to Path still substitutes {year}. + + Regression: _normalize_paths converts args.path to a PosixPath; the + {year} placeholder must be replaced on Path values too. + """ + args = {"path": Path("/repo/_local/seed/dati/{year}/ETA_{year}.CSV")} + result = _format_args(args, 2024) + assert result["path"] == Path("/repo/_local/seed/dati/2024/ETA_2024.CSV") + + def test_format_args_path_without_year_untouched(self) -> None: + """Path without {year} is returned unchanged (same type).""" + args = {"path": Path("/repo/anagrafica/_data/CompartoContratto.CSV")} + result = _format_args(args, 2024) + assert result["path"] == Path("/repo/anagrafica/_data/CompartoContratto.CSV") + def test_format_args_no_url_suffix_by_year(self) -> None: """Without url_suffix_by_year, output is unchanged.""" args = {"url": "https://example.com/data{year}.csv", "other": "value"} diff --git a/toolkit/raw/_fetch_utils.py b/toolkit/raw/_fetch_utils.py index 433878a..380c677 100644 --- a/toolkit/raw/_fetch_utils.py +++ b/toolkit/raw/_fetch_utils.py @@ -10,6 +10,7 @@ from collections.abc import Callable from datetime import datetime, timezone from pathlib import Path +from typing import Any from urllib.parse import urlparse from toolkit.core.exceptions import DownloadError @@ -22,9 +23,17 @@ def _format_args(args: dict, year: int) -> dict: - formatted = {} + formatted: dict[str, Any] = {} for k, v in (args or {}).items(): - if isinstance(v, str) and "{year}" in v: + if isinstance(v, Path): + # _normalize_paths converte i path relativi in PosixPath: il + # placeholder {year} va sostituito anche su valori Path (es. + # raw.sources[].args.path per local_file). + if "{year}" in str(v): + formatted[k] = Path(str(v).replace("{year}", str(year))) + else: + formatted[k] = v + elif isinstance(v, str) and "{year}" in v: # replace instead of str.format to avoid conflicts with SPARQL {} braces formatted[k] = v.replace("{year}", str(year)) else: @@ -35,7 +44,9 @@ def _format_args(args: dict, year: int) -> dict: if isinstance(suffix_map, dict): suffix = suffix_map.get(year, "") if isinstance(suffix, str): - formatted["url"] = formatted["url"] + suffix + # url può essere Path (local_file): normalizza a str per il suffix + base_url = str(formatted["url"]) + formatted["url"] = base_url + suffix # Remove url_suffix_by_year from output — internal config, not for consumers formatted.pop("url_suffix_by_year", None) return formatted