diff --git a/README.md b/README.md index 2a94144..6263590 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,73 @@ # DataCivicLab Toolkit -Toolkit Python per pipeline dati riproducibili `RAW -> CLEAN -> MART`, con approccio SQL-first, audit degli artefatti e run tracking persistente. +Dato un `dataset.yml` e del SQL, il toolkit scarica i dati pubblici, li trasforma +e produce un mart pronto per l'analisi. Un solo comando e' sufficiente per far +girare l'intera pipeline: + +```bash +toolkit run all --config dataset.yml +``` + +Richiede Python 3.10+. Non serve installare DuckDB separatamente. + +## Installazione + +```bash +git clone https://github.com/dataciviclab/toolkit.git +cd toolkit +pip install -e .[dev] +``` + +## Quickstart + +Prova il toolkit in pochi minuti con il progetto di esempio incluso nella repo, +senza bisogno di dati reali. + +Windows PowerShell: + +```powershell +pip install -e ".[dev]" +toolkit run all -c project-example/dataset.yml +toolkit validate all -c project-example/dataset.yml +toolkit status --dataset project_example --year 2022 --config project-example/dataset.yml +``` + +Linux/macOS: + +```bash +pip install -e ".[dev]" +toolkit run all -c project-example/dataset.yml +toolkit validate all -c project-example/dataset.yml +toolkit status --dataset project_example --year 2022 --config project-example/dataset.yml +``` + +Se il comando `toolkit` non e' nel `PATH` dopo l'installazione, puoi usare +direttamente il modulo Python: + +```bash +python -m toolkit.cli.app run all --config dataset.yml +``` + +Il percorso canonico per i repo dataset clonati dal template e': + +1. `toolkit run all --config dataset.yml` +2. `toolkit validate all --config dataset.yml` +3. `toolkit status --dataset --year --latest --config dataset.yml` +4. notebook locali che leggono gli output reali sotto `root/data/...` + +Per leggere gli output dal notebook senza duplicare la path logic: + +```bash +toolkit inspect paths --config dataset.yml --year 2024 --json +``` + +Contratto completo tra toolkit e notebook: [docs/notebook-contract.md](docs/notebook-contract.md) + +Validazione rapida della config prima di eseguire la pipeline: + +```bash +toolkit run all --config dataset.yml --dry-run +``` ## Ruolo Nell'Ecosistema @@ -48,63 +115,6 @@ Il toolkit include: - comandi CLI `run`, `resume`, `status`, `validate`, `profile`, `inspect` - `project-example/` offline per smoke test locale -## Installazione - -```bash -git clone https://github.com/dataciviclab/toolkit.git -cd toolkit -pip install -e .[dev] -``` - -Richiede Python 3.10+. - -## CLI Naming Note - -Il comando CLI canonico del progetto e' `toolkit`. - -Se nel tuo ambiente c'e' una collisione di nome o il console script non e' nel `PATH`, puoi usare direttamente il modulo Python: - -```bash -python -m toolkit.cli.app run all --config dataset.yml -``` - -## Quickstart - -Il percorso canonico per i repo dataset clonati dal template e': - -1. `toolkit run all --config dataset.yml` -2. `toolkit validate all --config dataset.yml` -3. `toolkit status --dataset --year --latest --config dataset.yml` -4. notebook locali che leggono gli output reali sotto `root/data/...` - -Giro offline completo con il progetto di esempio, eseguibile in pochi minuti su una macchina pulita. - -Windows PowerShell: - -```powershell -$env:TOOLKIT_OUTDIR = Join-Path $env:TEMP "dataciviclab-toolkit-quickstart" -py -m pip install -e ".[dev]" -py -m toolkit.cli.app run all -c project-example/dataset.yml -py -m toolkit.cli.app validate all -c project-example/dataset.yml -py -m toolkit.cli.app status --dataset project_example --year 2022 --config project-example/dataset.yml -``` - -Linux/macOS: - -```bash -export TOOLKIT_OUTDIR="$(mktemp -d)/dataciviclab-toolkit-quickstart" -python -m pip install -e ".[dev]" -python -m toolkit.cli.app run all -c project-example/dataset.yml -python -m toolkit.cli.app validate all -c project-example/dataset.yml -python -m toolkit.cli.app status --dataset project_example --year 2022 --config project-example/dataset.yml -``` - -Validazione rapida della config prima di eseguire la pipeline: - -```bash -toolkit run all --config dataset.yml --dry-run -``` - Interpretazione errori config: - `Config validation failed: output.: Extra inputs are not permitted` -> campo non supportato diff --git a/docs/conventions.md b/docs/conventions.md index 948091a..2ffa09c 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -106,3 +106,68 @@ Non usarlo quando: - RAW: `raw_validation.json` - CLEAN: `_validate/clean_validation.json` - MART: `_validate/mart_validation.json` + +## Fonti pubbliche italiane — quirks noti + +Pattern ricorrenti su CSV e XLSX da portali pubblici italiani. Da considerare +prima di scrivere `clean.sql` e `clean.read`. + +### Encoding + +La maggior parte dei portali PA produce file in `cp1252` (Windows-1252), non UTF-8. +Dichiarare sempre l'encoding esplicitamente: + +```yaml +clean: + read: + encoding: cp1252 +``` + +Se non dichiarato e il file contiene caratteri accentati, il run fallisce o +produce artefatti silenziosi. + +### ZIP con XLSX annidati + +Alcune fonti (es. MEF/Finanze, ISTAT) distribuiscono un archivio ZIP che +contiene uno o piu XLSX. Il toolkit non estrae ZIP automaticamente: il RAW +extractor deve essere configurato per gestire il pattern ZIP → file interno. + +Verificare con `toolkit scout-url ` se la sorgente e` un ZIP prima di +configurare l'extractor. + +### Schema instabile tra annualita + +I CSV multi-anno di fonti come IRPEF, AIFA o SIOPE cambiano spesso: +- colonne aggiunte o rimosse tra un anno e l'altro +- nomi colonna con varianti ortografiche (maiuscolo/minuscolo, spazi vs underscore) +- righe di intestazione o footer aggiuntive in alcuni anni + +Usare `toolkit inspect schema-diff --config dataset.yml --json` per confrontare +i segnali RAW tra anni prima di scrivere il `clean.sql`. + +Per CSV con schema posizionale quasi stabile, usare `normalize_rows_to_columns: true` +(vedi sezione Positional Fixed Schema). + +### Colonne con nomi impliciti o posizionali + +Alcuni CSV non hanno header o hanno un header non standard (riga 2, merged cell +da XLSX). Dichiarare: + +```yaml +clean: + read: + header: false + skip: 1 # righe da saltare prima dell'header reale +``` + +### Chiavi territoriali + +Le chiavi geografiche nei dataset PA italiani non sono sempre ISTAT-standard: + +- codici ISTAT comuni a 6 cifre vs 3+3 (provincia+comune) +- nomi comune con varianti storiche (fusioni, cambio denominazione) +- codici regione con offset legacy + +Dichiarare i limiti noti nel `notes.md` del candidate e nel README di `analisi/`. +Non tentare di normalizzare le chiavi nel `clean.sql` senza documentare la +scelta esplicitamente. diff --git a/docs/feature-stability.md b/docs/feature-stability.md index 723eff1..27044a2 100644 --- a/docs/feature-stability.md +++ b/docs/feature-stability.md @@ -18,6 +18,8 @@ Questa matrice serve a chiarire cosa il toolkit considera percorso canonico, cos | artifact policy `minimal|standard|debug` | supported / advanced | tuning operativo | | `legacy_aliases` | compatibility only | non promuovere nei repo nuovi | | config legacy | compatibility only | usare `--strict-config` nei repo nuovi | +| `scout_url` | experimental | scouting rapido di un URL pubblico — non fa parte del workflow canonico | + Lettura equivalente a livello package: - core runtime: `toolkit.raw`, `toolkit.clean`, `toolkit.mart`, `toolkit.cli` (`run`, `validate`, `status`, `inspect`) diff --git a/docs/publish_check.md b/docs/publish_check.md index bb7e222..fe717a9 100644 --- a/docs/publish_check.md +++ b/docs/publish_check.md @@ -1,18 +1,12 @@ # Publish Readiness Check -Publication blockers from the previous audit have been addressed: - -- a root `LICENSE` file is present -- `pyproject.toml` now includes `license` and `authors` metadata -- the quickstart and publish notes no longer contain stale pre-release TODOs - ## What is ready -- Core CLI flow exists and is usable from source with `python -m toolkit.cli.app` / `py -m toolkit.cli.app`. +- Core CLI flow exists and is usable after install with `toolkit`. - Main commands expose help and non-zero failures on bad input: - - `py -m toolkit.cli.app --help` - - `py -m toolkit.cli.app run --help` - - `py -m toolkit.cli.app run all -c does-not-exist.yml` + - `toolkit --help` + - `toolkit run --help` + - `toolkit run all -c does-not-exist.yml` - Root resolution is deterministic and documented: - precedence is `dataset.yml root` -> `DCL_ROOT` -> `base_dir` - no fallback to `cwd` @@ -55,25 +49,25 @@ Publication blockers from the previous audit have been addressed: Windows PowerShell: ```powershell -py -m pip install -e ".[dev]" -py -m ruff check . -py -m pytest -q -py -m toolkit.cli.app --help -py -m toolkit.cli.app run --help -py -m toolkit.cli.app run all -c project-example/dataset.yml -py -m toolkit.cli.app status --dataset project_example --year 2022 --config project-example/dataset.yml +pip install -e ".[dev]" +ruff check . +pytest -q +toolkit --help +toolkit run --help +toolkit run all -c project-example/dataset.yml +toolkit status --dataset project_example --year 2022 --config project-example/dataset.yml git ls-files | Select-String -Pattern '(_smoke_out|_test_out|\.pytest_cache|\.ruff_cache|\.egg-info)' ``` Linux/macOS: ```bash -python -m pip install -e ".[dev]" -python -m ruff check . -python -m pytest -q -python -m toolkit.cli.app --help -python -m toolkit.cli.app run --help -python -m toolkit.cli.app run all -c project-example/dataset.yml -python -m toolkit.cli.app status --dataset project_example --year 2022 --config project-example/dataset.yml +pip install -e ".[dev]" +ruff check . +pytest -q +toolkit --help +toolkit run --help +toolkit run all -c project-example/dataset.yml +toolkit status --dataset project_example --year 2022 --config project-example/dataset.yml git ls-files | grep -E '(_smoke_out|_test_out|\.pytest_cache|\.ruff_cache|\.egg-info)' ``` diff --git a/docs/runtime-boundaries.md b/docs/runtime-boundaries.md index ce33f23..1532d71 100644 --- a/docs/runtime-boundaries.md +++ b/docs/runtime-boundaries.md @@ -19,11 +19,18 @@ Sono le superfici che i repo dataset e il `project-template` dovrebbero consider Queste aree restano supportate, ma non fanno parte del percorso canonico: - `toolkit.profile` +- `toolkit.cross` — output multi-anno (`run cross_year`) - `toolkit.cli.cmd_resume` - `toolkit.cli.cmd_profile` - esecuzione parziale `run raw|clean|mart` -Servono per recovery, diagnostica e casi sporchi, non come baseline per i repo nuovi. +Servono per recovery, diagnostica e output specializzati, non come baseline per i repo nuovi. + +## Experimental + +Funzionalita' presenti ma non ancora parte del contratto stabile: + +- `toolkit.cli.cmd_scout_url` (`toolkit scout-url`) — scouting rapido di un URL pubblico ## Compatibility Only diff --git a/tests/conftest.py b/tests/conftest.py index 8423ebf..38b6b6a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -35,9 +35,7 @@ "test_registry.py", } -COMPAT_TESTS = { - "test_deprecated_shims.py", -} +COMPAT_TESTS: set[str] = set() def pytest_collection_modifyitems(items: list[pytest.Item]) -> None: