From 00a95c5b9f624500e1acf0d254fd3b32d835b772 Mon Sep 17 00:00:00 2001 From: Zio Gabber <78922322+Gabrymi93@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:44:07 +0100 Subject: [PATCH 1/2] fix(raw): _format_args sostituisce {year} anche su path normalizzati Path Regressione: _normalize_paths converte args.path (local_file) in PosixPath; il placeholder {year} non veniva sostituito su valori Path, quindi i seed locali con {year} nel path fallivano. Ora sostituito anche su Path. Test: +2 (path con {year} sostituito, path senza {year} invariato). --- tests/test_raw_run_format_args.py | 18 ++++++++++++++++++ toolkit/raw/_fetch_utils.py | 10 +++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/test_raw_run_format_args.py b/tests/test_raw_run_format_args.py index d2e784aa..86aac0c2 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 433878a8..9e532c24 100644 --- a/toolkit/raw/_fetch_utils.py +++ b/toolkit/raw/_fetch_utils.py @@ -24,7 +24,15 @@ def _format_args(args: dict, year: int) -> dict: formatted = {} 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: From f049f6f2bfa5d540fe42fe5e345daa3fe7c9d615 Mon Sep 17 00:00:00 2001 From: Zio Gabber <78922322+Gabrymi93@users.noreply.github.com> Date: Sun, 9 Aug 2026 09:53:47 +0100 Subject: [PATCH 2/2] =?UTF-8?q?fix(raw):=20tipizzazione=20mypy=20=5Fformat?= =?UTF-8?q?=5Fargs=20(dict[str,=20Any],=20url=20Path=E2=86=92str)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI: mypy falliva — formatted non tipizzato inferiva url come Path, poi assegnazione str e Path+str. Ora formatted: dict[str, Any] e base_url = str(formatted['url']) prima del suffix. --- toolkit/raw/_fetch_utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/toolkit/raw/_fetch_utils.py b/toolkit/raw/_fetch_utils.py index 9e532c24..380c6779 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,7 +23,7 @@ def _format_args(args: dict, year: int) -> dict: - formatted = {} + formatted: dict[str, Any] = {} for k, v in (args or {}).items(): if isinstance(v, Path): # _normalize_paths converte i path relativi in PosixPath: il @@ -43,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