Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0081add
refactor: io/hdf, processing/harmonization, core modules, logging, mi…
benjello Feb 27, 2026
657e2fb
chore: typing for core, io, processing; CHANGELOG 6.5.0
benjello Feb 27, 2026
1399465
matching: NND hot deck en pur Python (pandas + numpy)
benjello Mar 2, 2026
7b78df1
Retrait de stata_files_to_data_frames
benjello Mar 2, 2026
ff37ede
refactor: add policy package + deprecate legacy modules
benjello Mar 2, 2026
f19fb11
refactor: move input_dataframe_generator to tests, coicop/matching/st…
benjello Mar 2, 2026
3da51d7
refactor: move calmar/calibration to policy, add placeholders with De…
benjello Mar 2, 2026
7062454
refactor: move scenarios to policy, add placeholders with Deprecation…
benjello Mar 2, 2026
e429ff4
Add typing to policy folder and related modules
benjello Mar 3, 2026
3a71fac
Release 1.0: retrait des ré-exports et DeprecationWarning
benjello Mar 2, 2026
b79bc4a
breaking: remove survey-manager placeholders and deprecation shims
benjello Mar 2, 2026
ef83dff
chore: remove scenarios placeholders and DeprecationWarnings
benjello Mar 2, 2026
2d94af5
fix: reduce pytest warnings (logging, HDF5, tests)
benjello Mar 2, 2026
5744223
Changelog: add typing section for 1.0.0
benjello Mar 3, 2026
daa5978
RFC-002: config.yaml + manifests, migration script, DeprecationWarning
benjello Mar 3, 2026
9d494cd
feat: store backends (HDF5/Parquet/Zarr), store_format in manifest, m…
benjello Mar 3, 2026
37bb0d9
Bump version
benjello Mar 10, 2026
3430a12
Again
benjello Mar 10, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,4 @@ tags
# Tests files
*.parquet
test_*.json
.claude/settings.json
47 changes: 46 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,49 @@
# Changelog
# Changelog

# 8.0.0

* **Store backends** (choix du format de stockage des tables)
- **io/backends**: Backends HDF5, Parquet et Zarr (abstraction `StoreBackend`) ; `get_backend(name)`, `get_available_backend_names()`, `register_backend()` pour étendre.
- **Zarr** : backend optionnel (`pip install openfisca-survey-manager[zarr]`) ; une table = un groupe zarr dans un répertoire `.zarr` par survey.
- **Survey** : attribut `zarr_file_path` ; `fill_store(store_format="zarr")` et lecture via `get_values` pour zarr.
- **Table** : écriture/lecture et `_is_stored` délégués aux backends ; `_get_store_path_and_format()` unifie les chemins.
- **build-collection** : option `--zarr` en plus de `--parquet` ; défaut HDF5 avec avertissement.
- **Docs** : `docs/ZARR-BACKEND.md` (utilisation Zarr, compression, parallélisation).

* **Manifest (RFC-002) : store_format**
- **manifest.yaml** : clé optionnelle `store_format` (hdf5, parquet, zarr) au niveau dataset ; par défaut `parquet` au chargement.
- **SurveyCollection.load** : depuis un manifest, applique `store_format` et déduit les chemins de store (`hdf5_file_path`, `parquet_file_path`, `zarr_file_path`) à partir de `default_output_dir`.
- **Script de migration** : infère `store_format` depuis le JSON legacy (`parquet_file_path` / `zarr_file_path` / `hdf5_file_path`) et l’écrit dans le manifest généré.
- **RFC-002** : exemple de manifest avec `store_format` ; section 3.5 et 4.2 mises à jour.

# 7.0.0

* **Breaking**: Version 7.0 — retrait des ré-exports et des DeprecationWarning
- **Suppression des modules de compatibilité** : `config`, `paths`, `tables`, `surveys`, `survey_collections`, `read_sas`, `read_spss`, `read_dbf`, `calibration`, `calmar`, `utils` sont supprimés. Utiliser les imports canoniques (voir `docs/MIGRATION_IMPORTS.md`).
- **`load_table`** : déplacé de `utils` vers `openfisca_survey_manager.core.dataset` (et exporté depuis `core`).
- Tous les imports internes ont été migrés vers `configuration.paths`, `configuration.models`, `core.dataset`, `core.survey`, `core.table`, `io.readers`, `processing.weights`, `common.misc`.

* **Typing** (no breaking API changes)
- **policy**: Add `py.typed` marker; type hints on `legislation_asof`, `variables`, `coicop`, `matching`, `statshelpers`, `calmar`, `calibration`, `simulation_builder`, `aggregates`, `simulations`, and scenarios (`abstract_scenario`, `reform_scenario`).
- **configuration**: Type hints on `Config.__init__` and `save` in `configuration.models`.
- **processing**: Type return of `__getattr__` in `processing/__init__.py`.

# 6.5.0

* Typing (no breaking API changes)
- **core**: Type hints on `core.table` (Table), `core.survey` (Survey, NoMoreDataError), `core.dataset` (SurveyCollection); `TYPE_CHECKING` for circular refs; class attributes with defaults where needed
- **io**: Type hints on `io.readers` (read_sas, read_spss, read_dbf with `Optional[list[str]]` for cols); `io.writers` and `io.hdf` already typed
- **processing**: Type hints on `processing.cleaning`, `processing.harmonization`, `processing.weights.calmar` (linear, logit, calmar, check_calmar, etc.), `processing.weights.calibration` (Calibration class and methods)
- **Docs**: Update `REFACTORING_PLAN.md` §3.3 (typing core, io, processing done)

# 6.4.0

* Refactor (no breaking API changes)
- **io/hdf**: Extract HDF5 write logic into `io.hdf` (`write_table_to_hdf5`); `io.writers` re-exports for compatibility
- **processing/harmonization**: Add `harmonize_data_frame_columns` (lowercase, rename ident); used in `Survey.get_values`; export from `processing`
- **core**: Add `core.table`, `core.survey`, `core.dataset` (Table, Survey, NoMoreDataError, SurveyCollection); root `tables.py`, `surveys.py`, `survey_collections.py` re-export for compatibility
- **Logging**: Extend to all modules — add logger to `configuration.models`, `google_colab`, `statshelpers`; fix typo "folloging" → "following" in `core.table`
- **Docs**: Add `docs/MIGRATION_IMPORTS.md` (import mapping and steps when re-exports will be removed, with breaking-change warning); update `REFACTORING_PLAN.md` (§3.4 Logging done)

# 6.3.1

Expand Down
154 changes: 154 additions & 0 deletions docs/MIGRATION_IMPORTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Migration des imports après retrait des ré-exports

Ce document décrit les changements à effectuer **lorsqu’on retirera les ré-exports** (fichiers de compatibilité) à la racine du package : mise à jour de tous les imports vers les nouveaux chemins, puis suppression des anciens modules.

**Référence** : `docs/REFACTORING_PLAN.md`.

---

## Mise en garde

Le retrait des ré-exports est une **breaking change** : tout code (interne ou externe) qui importe depuis les anciens chemins (`config`, `paths`, `tables`, `surveys`, `survey_collections`, `read_sas`, `read_spss`, `read_dbf`, `calibration`, `calmar`, `utils`) verra ses imports **échouer** (`ModuleNotFoundError`). Il faut migrer tous les imports **avant** de supprimer les fichiers listés en section 3, et documenter le changement dans le CHANGELOG pour les projets dépendants (ex. openfisca-france-data).

---

## 1. Correspondance ancien → nouveau

| Ancien import (à supprimer) | Nouvel import (à utiliser) |
|-----------------------------|----------------------------|
| `from openfisca_survey_manager.config import Config` | `from openfisca_survey_manager.configuration.models import Config` |
| `from openfisca_survey_manager.paths import ...` | `from openfisca_survey_manager.configuration.paths import ...` |
| `from openfisca_survey_manager.tables import Table` | `from openfisca_survey_manager.core.table import Table` |
| `from openfisca_survey_manager.surveys import Survey` | `from openfisca_survey_manager.core.survey import Survey` |
| `from openfisca_survey_manager.surveys import NoMoreDataError` | `from openfisca_survey_manager.core.survey import NoMoreDataError` |
| `from openfisca_survey_manager.survey_collections import SurveyCollection` | `from openfisca_survey_manager.core.dataset import SurveyCollection` |
| `from openfisca_survey_manager.read_sas import read_sas` | `from openfisca_survey_manager.io.readers import read_sas` |
| `from openfisca_survey_manager.read_spss import read_spss` | `from openfisca_survey_manager.io.readers import read_spss` |
| `from openfisca_survey_manager.read_dbf import read_dbf` | `from openfisca_survey_manager.io.readers import read_dbf` |
| `from openfisca_survey_manager.calibration import Calibration` | `from openfisca_survey_manager.processing.weights import Calibration` |
| `from openfisca_survey_manager.calmar import calmar` | `from openfisca_survey_manager.processing.weights import calmar` |
| `from openfisca_survey_manager.calmar import check_calmar` | `from openfisca_survey_manager.processing.weights import check_calmar` |
| `from openfisca_survey_manager.utils import do_nothing, load_table, ...` | Voir section 2 (utils) |

**Symboles exportés par `paths`** (même noms dans `configuration.paths`) :
`config_ini`, `default_config_files_directory`, `is_in_ci`, `openfisca_survey_manager_location`, `private_run_with_data`, `test_config_files_directory`.

**Symboles exportés par `utils`** :
- Depuis `common.misc` : `asof`, `do_nothing`, `inflate_parameter_leaf`, `inflate_parameters`, `parameters_asof`, `variables_asof`.
- Définis dans `utils.py` : `load_table` (à déplacer vers un module adapté, ex. `core` ou `io`, avant suppression de `utils.py`).

---

## 2. Fichiers à modifier quand on retire les ré-exports

Avant (ou en même temps que) la suppression des fichiers listés en section 3, mettre à jour les imports dans les fichiers suivants.

### 2.1 Imports depuis `config`, `paths`

| Fichier | Remplacer |
|---------|-----------|
| `tests/input_dataframe_generator.py` | `paths` → `configuration.paths` (module déplacé dans `tests/`) |
| `scripts/build_collection.py` | `paths` → `configuration.paths` |
| `temporary.py` | `paths` → `configuration.paths` |
| `google_colab.py` | `paths` → `configuration.paths` |
| `coicop.py` | `paths` → `configuration.paths` |
| `matching.py` | `paths` → `configuration.paths` |
| `tests/test_read_sas.py` | `paths` → `configuration.paths` ; `read_sas` → `io.readers` |
| `tests/test_quantile.py` | `paths` → `configuration.paths` |
| `tests/test_scenario.py` | `paths` → `configuration.paths` |

### 2.2 Imports depuis `survey_collections`, `surveys`, `tables`

| Fichier | Remplacer |
|---------|-----------|
| `tests/input_dataframe_generator.py` | `survey_collections`, `surveys` → `core.dataset`, `core.survey` |
| `simulations.py` | `survey_collections`, `utils` → `core.dataset` ; utils → `common.misc` + module de `load_table` |
| `utils.py` | `survey_collections` → `core.dataset` (pour `load_table`) |
| `scripts/build_collection.py` | `survey_collections`, `surveys` → `core.dataset`, `core.survey` |
| `scenarios/abstract_scenario.py` | `calibration`, `surveys` → `processing.weights`, `core.survey` |
| `tests/test_surveys.py` | `survey_collections`, `surveys` → `core.dataset`, `core.survey` |
| `tests/test_coverage_boost.py` | `survey_collections`, `surveys`, `utils` → idem |
| `tests/test_add_survey_to_collection.py` | `survey_collections` → `core.dataset` |
| `tests/test_parquet.py` | `survey_collections` → `core.dataset` ; `surveys` (NoMoreDataError) → `core.survey` |

### 2.3 Imports depuis `read_sas`, `read_spss`, `read_dbf`

| Fichier | Remplacer |
|---------|-----------|
| `core/table.py` | `from openfisca_survey_manager import read_sas` → `from openfisca_survey_manager.io.readers import read_sas` ; `read_sas.read_sas` → `read_sas` dans `reader_by_source_format`. Puis `from openfisca_survey_manager.read_spss import read_spss` → `from openfisca_survey_manager.io.readers import read_spss` (dans le try/except). |
| `tests/test_read_sas.py` | `from ...paths import ...` → `configuration.paths` ; `from ...read_sas import read_sas` → `from ...io.readers import read_sas` |

### 2.4 Imports depuis `calibration`, `calmar`

| Fichier | Remplacer |
|---------|-----------|
| `scenarios/abstract_scenario.py` | `calibration` → `processing.weights` |
| `tests/test_calibration.py` | `calibration` → `processing.weights` |
| `tests/test_calmar.py` | `calmar` → `processing.weights` |

### 2.5 Imports depuis `utils`

| Fichier | Remplacer |
|---------|-----------|
| `simulations.py` | `utils.do_nothing`, `utils.load_table` → `common.misc.do_nothing` + module contenant `load_table` |
| `tests/test_coverage_boost.py` | `utils.do_nothing` → `common.misc.do_nothing` |
| `tests/test_legislation_inflator.py` | `utils.inflate_parameters`, `parameters_asof` → `common.misc` |
| `tests/test_tax_benefit_system_asof.py` | `utils.parameters_asof`, `variables_asof` → `common.misc` |

**Note** : `load_table` dépend de `SurveyCollection` ; il doit vivre soit dans un module qui importe `core.dataset`, soit être déplacé (ex. `core.dataset` ou un module `io.loaders`) avant de supprimer `utils.py`.

---

## 3. Fichiers à supprimer (ré-exports)

Une fois tous les imports mis à jour selon les sections 1 et 2, on pourra supprimer les fichiers suivants (ils ne contiennent que des ré-exports) :

- `config.py`
- `paths.py`
- `tables.py`
- `surveys.py`
- `survey_collections.py`
- `read_sas.py`
- `read_spss.py`
- `read_dbf.py`
- `calibration.py`
- `calmar.py`
- `utils.py` (après déplacement de `load_table` et mise à jour des imports listés en 2.5)

---

## 4. Modules sans ré-export (imports canoniques)

Ces modules n’ont pas de fichier ré-export à la racine ; le code interne les utilise déjà. Pour du code externe ou de la doc, les imports canoniques sont :

| Symbole | Import canonique |
|---------|------------------|
| `harmonize_data_frame_columns` | `from openfisca_survey_manager.processing.harmonization import harmonize_data_frame_columns` (ou `from openfisca_survey_manager.processing import harmonize_data_frame_columns`) |
| `write_table_to_hdf5` | `from openfisca_survey_manager.io.hdf import write_table_to_hdf5` (ou `from openfisca_survey_manager.io.writers import write_table_to_hdf5`) |
| `write_table_to_parquet` | `from openfisca_survey_manager.io.writers import write_table_to_parquet` |

---

## 5. Package racine `openfisca_survey_manager`

Aujourd’hui le `__init__.py` du package n’expose que les exceptions. Si du code externe fait par exemple `from openfisca_survey_manager import read_sas`, il s’appuie sur le sous-module `read_sas.py`. **Après retrait des ré-exports**, ces chemins d’import ne seront plus valides (échec à l’import) ; les migrer vers `from openfisca_survey_manager.io.readers import read_sas` (voir section 1).

À faire avant ou après la migration : vérifier dans ce dépôt et les projets dépendants (openfisca-france-data, etc.) les imports depuis la racine du package ou depuis les anciens modules listés en section 3.

---

## 6. Ordre recommandé pour la migration

1. **Déplacer `load_table`** vers un module définitif (ex. `core.dataset` ou `io.loaders`) et mettre à jour les appels (section 2.5).
2. **Mettre à jour tous les imports internes** (section 2) vers les nouveaux chemins, fichier par fichier.
3. **Lancer la suite de tests** : `pytest` ; corriger les oublis jusqu’à 0 échec.
4. **Supprimer les fichiers de ré-export** listés en section 3.
5. **Vérifier les usages externes** (section 5) et documenter les changements dans le CHANGELOG (breaking changes).

---

## 7. Évolutions optionnelles ultérieures

- Renommer le dossier `common/` en `utils/` une fois `utils.py` supprimé (comme prévu dans le plan de refactoring).
- Renommer `configuration/` en `config/` si on souhaite un nom plus court (en cohérence avec le plan).
- Ces renommages impliqueront une nouvelle vague de mise à jour des imports (configuration → config, common → utils).
23 changes: 14 additions & 9 deletions docs/REFACTORING_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ openfisca_survey_manager/
│ └── misc.py # helpers partagés (éviter imports circulaires)
├── scenarios/ # inchangé pour l’instant
├── policy/ # simulations, simulation_builder, aggregates (à terme autre paquet)
├── scripts/
├── tests/
└── ... (simulations, aggregates, etc. à placer selon responsabilité)
└── ...
```

**État actuel** : les dossiers suivants existent avec des `__init__.py` de préparation (pas de code déplacé encore) :
Expand All @@ -49,10 +50,12 @@ Le déplacement effectif des modules se fera par étapes pour garder la compatib

**Réalisé** :
- `io/readers.py` : `read_sas`, `read_spss`, `read_dbf` (anciens modules en ré-export).
- `common/misc.py` : helpers sans dépendance survey (`do_nothing`, `inflate_parameters`, `asof`, `parameters_asof`, `variables_asof`, `stata_files_to_data_frames`) ; `utils.py` importe depuis `common.misc` et garde `load_table`.
- `common/misc.py` : helpers sans dépendance survey (`do_nothing`, `inflate_parameters`, `asof`, `parameters_asof`, `variables_asof`) ; `utils.py` importe depuis `common.misc` et garde `load_table`.
- **Nettoyage** : `print()` remplacés par `logging` (matching, calmar, scenarios, scripts/build_collection, simulations). Exceptions génériques remplacées par `SurveyManagerError` / `SurveyConfigError` / `SurveyIOError` (survey_collections, tables, simulations, simulation_builder, surveys, scenarios, calmar).
- **processing/weights** : `calmar` et `Calibration` déplacés dans `processing/weights/calmar.py` et `processing/weights/calibration.py` ; `calibration.py` et `calmar.py` à la racine sont des ré-exports pour compatibilité.
- **processing/cleaning** : `clean_data_frame` déplacé dans `processing/cleaning.py` ; `tables.py` importe depuis `processing.cleaning` (compatibilité conservée).
- **policy/** : répertoire créé pour `simulations`, `simulation_builder`, `aggregates` (à terme déplacés dans un paquet dédié). Les modules à la racine (`simulations.py`, `simulation_builder.py`, `aggregates.py`) sont des placeholders avec `DeprecationWarning` qui ré-exportent depuis `policy`.
- **policy/tests/** : tests concernant le paquet policy (test_aggregates, test_compute_aggregate, test_compute_pivot_table, test_compute_winners_losers, test_create_data_frame_by_entity, test_marginal_tax_rate, test_summarize_variables). Ils importent depuis `openfisca_survey_manager.policy` et utilisent `create_randomly_initialized_survey_scenario` depuis `openfisca_survey_manager.tests.test_scenario`.

---

Expand Down Expand Up @@ -83,24 +86,26 @@ Aujourd’hui ces couches sont entremêlées (ex. lecture + nettoyage dans `tabl

### 3.1 Fonctions longues (> 100 lignes)

- Découper les grosses fonctions en étapes nommées, par exemple :
- `load_survey()` → `_parse_config()`, `_load_raw_data()`, `_transform()`, `_store()`.
- Cible : lisibilité et testabilité, sans changer le comportement.
- **Entamé** : découpage en étapes nommées sans changer le comportement.
- `core.table.Table.read_source` → `_read_csv_with_inferred_encoding()`, `_apply_stata_categorical_strategy()` ; `read_source()` orchestre.
- `core.survey.Survey.get_values` → `_get_values_from_hdf5()`, `_get_values_from_parquet()` ; `get_values()` orchestre et applique l’harmonisation.
- À poursuivre : autres modules (simulations, scenarios, scripts, processing/weights/calmar, etc.).

### 3.2 Dépendances circulaires

- **Vérifié** (imports à froid) : aucune dépendance circulaire. Chaîne cohérente : `exceptions` → `configuration` → `io`/`processing` → `core.table` → `core.survey` → `core.dataset` ; `utils` → `common.misc`, `survey_collections` ; `core.table` n'importe `Survey` qu'en tardif dans `Table.__init__`. Si des cycles apparaissent : extraire la logique commune dans `common/` ou `configuration/`.
- Si des modules s’importent mutuellement, extraire la logique commune dans `utils/` (ou `config/`) et faire dépendre les deux côtés de ce module commun.
- Vérifier avec des imports à froid (démarrer l’app et importer les sous-modules).

### 3.3 Typage Python

- Ajouter progressivement des type hints sur les signatures publiques (arguments et retours).
- Priorité : `core/`, `io/`, puis `processing/`.
- **Entamé** : type hints sur les signatures publiques de `core/`, `io/` et `processing/` (cleaning, harmonization, weights/calmar, weights/calibration).
- À poursuivre : reste du package (scenarios, simulations, etc.).

### 3.4 Logging

- Remplacer les `print()` par du `logging` structuré (déjà entamé dans matching, calmar).
- Étendre à tous les modules (readers, writers, calibration, etc.).
- **Fait** : `print()` remplacés par du `logging` structuré (matching, calmar, scenarios, scripts/build_collection, simulations, readers, writers, calibration, core, processing, etc.).
- **Fait** : logging étendu à tous les modules métier (configuration/models, google_colab, statshelpers, et l’ensemble des modules concernés).

### 3.5 Gestion d’erreurs centralisée

Expand Down
Loading