# ⚡ ElectriCore - Moteur de traitement données énergétiques
**ElectriCore** est un outil libre pour reprendre le contrôle des données du réseau électrique français. Architecture moderne **Polars + DuckDB** pour transformer les flux bruts Enedis en données exploitables par LibreWatt, Odoo et autres outils de suivi énergétique.
## 🎯 Objectifs
Un outil de calcul énergétique **performant** et **maintenable** pour :
- ✅ **Transformer** les flux XML/CSV Enedis en données structurées
- ✅ **Calculer** les indicateurs essentiels (périmètre, abonnements, consommations, TURPE)
- ✅ **Exposer** les données via API REST sécurisée
- ✅ **Intégrer** avec Odoo et autres systèmes tiers
---
## 🏗️ Architecture - 3 Modules Principaux
```
electricore/
├── etl/ # 📥 ETL - Extraction & Transformation (DLT)
│ ├── sources/ # Sources de données (SFTP Enedis)
│ ├── transformers/ # Transformations modulaires (crypto, archive, parsers)
│ └── connectors/ # Connecteurs externes (Odoo)
│
├── core/ # 🧮 CORE - Calculs énergétiques (Polars)
│ ├── models/ # Modèles Pandera (validation des données)
│ ├── pipelines/ # Pipelines de calcul (périmètre, abonnements, énergie, turpe)
│ └── loaders/ # Query builders (DuckDB, Polars)
│
└── api/ # 🌐 API - Accès aux données (FastAPI)
├── services/ # Services de requêtage (DuckDB)
└── main.py # Application FastAPI avec authentification
```
### Diagramme de flux
```mermaid
graph TB
SFTP_Enedis[/SFTP Enedis\] --> ETL_Enedis[ETL<br/>#40;data load tool#41;]
SFTP_Axpo[/SFTP Axpo<br/>Courbes\] -.-> ETL_Axpo[ETL<br/>#40;data load tool#41;]
ETL_Enedis --> DuckDB[(DuckDB)]
ETL_Axpo -.-> DuckDB
Odoo[(Odoo ERP)] --> OdooReader[OdooReader]
OdooWriter[OdooWriter] --> Odoo
DuckDB --> API[API REST<br/>#40;FastAPI#41;]
DuckDB -->|Query Builder| Core[Core Pipelines<br/>#40;Polars#41;]
OdooReader -->|Query Builder| Core
OdooReader --> API
Core --> API
Core --> OdooWriter
API -->|JSON| Client[\Clients API/]
style API fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#fff
style DuckDB fill:#1976D2,stroke:#0D47A1,color:#fff
style Odoo fill:#FF9800,stroke:#E65100,color:#fff
style Core fill:#9C27B0,stroke:#4A148C,color:#fff
style ETL_Axpo stroke-dasharray: 5 5
```
---
## 📥 Module ETL - Extraction & Transformation
Pipeline ETL modulaire basé sur **DLT** (Data Load Tool) pour extraire et transformer les flux Enedis.
### Flux supportés
| Flux | Description | Tables générées |
|--------|------------------------------|-------------------------------|
| **C15** | Changements contractuels | `flux_c15` |
| **F12** | Facturation distributeur | `flux_f12` |
| **F15** | Facturation détaillée | `flux_f15_detail` |
| **R15** | Relevés avec événements | `flux_r15`, `flux_r15_acc` |
| **R151**| Relevés périodiques | `flux_r151` |
| **R64** | Relevés JSON timeseries | `flux_r64` |
### Architecture modulaire
```python
# Pipeline ETL avec transformers chaînables
encrypted_files | decrypt_transformer | unzip_transformer | parse_transformer
```
**Transformers disponibles** :
- `crypto.py` - Déchiffrement AES
- `archive.py` - Extraction ZIP
- `parsers.py` - Parsing XML/CSV
### Utilisation
```bash
# Test rapide (2 fichiers)
poetry run python electricore/etl/pipeline_production.py test
# R151 complet (~6 secondes)
poetry run python electricore/etl/pipeline_production.py r151
# Tous les flux (production)
poetry run python electricore/etl/pipeline_production.py all
```
**Résultat** : Base DuckDB `electricore/etl/flux_enedis_pipeline.duckdb` avec toutes les tables flux.
📖 **Documentation complète** : [electricore/etl/README.md](electricore/etl/README.md)
---
## 🧮 Module Core - Calculs Énergétiques Polars
Pipelines de calculs énergétiques basés sur **Polars pur** (LazyFrames + expressions fonctionnelles).
### Pipelines disponibles
#### 1. **Périmètre** - Détection changements contractuels
```python
from electricore.core.pipelines.perimetre import pipeline_perimetre
from electricore.core.loaders import c15
# Depuis DuckDB avec Query Builder
historique_lf = (
c15()
.filter({"Date_Evenement": ">= '2024-01-01'"})
.limit(1000)
.lazy()
)
perimetre_df = pipeline_perimetre(historique_lf).collect()
# Colonnes: pdl, Date_Evenement, impacte_abonnement, impacte_energie, resume_modification
```
#### 2. **Abonnements** - Périodes d'abonnement
```python
from electricore.core.pipelines.abonnements import pipeline_abonnements
# Calcul périodes d'abonnement avec bornes temporelles
abonnements_df = pipeline_abonnements(
perimetre_lf,
date_debut="2024-01-01",
date_fin="2024-12-31"
).collect()
# Colonnes: pdl, debut, fin, nb_jours, Puissance_Souscrite, Formule_Tarifaire_Acheminement
```
#### 3. **Énergies** - Consommations par cadran
```python
from electricore.core.pipelines.energie import pipeline_energie
from electricore.core.loaders import releves
relevés_lf = releves().filter({"date_releve": ">= '2024-01-01'"}).lazy()
energies_df = pipeline_energie(
perimetre_lf,
relevés_lf,
date_debut="2024-01-01",
date_fin="2024-12-31"
).collect()
# Colonnes: pdl, debut, fin, energie_hp, energie_hc, energie_base, ...
```
#### 4. **TURPE** - Calcul taxes réglementaires
```python
from electricore.core.pipelines.turpe import ajouter_turpe_fixe, ajouter_turpe_variable
# TURPE fixe (abonnement)
abonnements_turpe_df = ajouter_turpe_fixe(abonnements_df).collect()
# Colonnes: ..., turpe_fixe_annuel, turpe_fixe_journalier, turpe_fixe_periode
# TURPE variable (énergies)
energies_turpe_df = ajouter_turpe_variable(energies_df).collect()
# Colonnes: ..., turpe_hpb, turpe_hcb, turpe_hph, turpe_hch, turpe_variable_total
```
#### 5. **Facturation** - Pipeline complet
```python
from electricore.core.pipelines.orchestration import facturation
# Pipeline complet : périmètre → abonnements → énergies
resultat = facturation(
historique_lf,
relevés_lf,
date_debut="2024-01-01",
date_fin="2024-12-31"
)
# Résultats disponibles
print(resultat.abonnements.collect()) # Périodes d'abonnement
print(resultat.energies.collect()) # Consommations
print(resultat.factures.collect()) # Synthèses mensuelles
```
### 🔧 Interfaces de Requêtage
#### DuckDB Query Builder - Architecture Fonctionnelle Modulaire
**Architecture en 6 modules** pour performance et maintenabilité :
- `config.py` - Configuration et connexions DuckDB
- `expressions.py` - Expressions Polars pures réutilisables
- `transforms.py` - Transformations composables avec `compose()`
- `sql.py` - Génération SQL fonctionnelle (dataclasses frozen)
- `query.py` - Query builder immutable (`DuckDBQuery`)
- `__init__.py` - API publique + helper `_CTEQuery` pour requêtes CTE
```python
from electricore.core.loaders import c15, r151, releves, releves_harmonises
# Historique périmètre (flux C15)
historique = (
c15()
.filter({"Date_Evenement": ">= '2024-01-01'"})
.limit(100)
.collect()
)
# Relevés périodiques (flux R151)
relevés = (
r151()
.filter({"pdl": ["PDL123", "PDL456"]})
.limit(1000)
.lazy() # Retourne LazyFrame pour optimisations
)
# Relevés unifiés (R151 + R15) avec CTE
tous_releves = releves().collect()
# Relevés harmonisés (R151 + R64) avec CTE
releves_cross_flux = (
releves_harmonises()
.filter({"flux_origine": "R64"})
.collect()
)
```
**Fonctions disponibles** : `c15()`, `r151()`, `r15()`, `f15()`, `r64()`, `releves()`, `releves_harmonises()`
**Caractéristiques** :
- ✅ Immutabilité garantie (frozen dataclasses)
- ✅ Composition fonctionnelle pure
- ✅ Lazy evaluation optimisée
- ✅ Support CTE (Common Table Expressions)
- ✅ Validation Pandera intégrée
📖 **Documentation complète** : [electricore/core/loaders/DUCKDB_INTEGRATION_GUIDE.md](electricore/core/loaders/DUCKDB_INTEGRATION_GUIDE.md)
#### Odoo Query Builder - Intégration ERP
```python
from electricore.core.loaders import OdooReader
import polars as pl
config = {
'url': 'https://odoo.example.com',
'db': 'production',
'username': 'api_user',
'password': 'secret'
}
with OdooReader(config) as odoo:
# Query builder avec navigation relationnelle
factures_df = (
odoo.query('sale.order', domain=[('x_pdl', '!=', False)])
.follow('invoice_ids', fields=['name', 'invoice_date', 'amount_total'])
.filter(pl.col('amount_total') > 100)
.collect()
)
# Enrichissement avec données liées
commandes_enrichies = (
odoo.query('sale.order', fields=['name', 'date_order'])
.enrich('partner_id', fields=['name', 'email'])
.collect()
)
```
**Méthodes disponibles** : `.query()`, `.follow()`, `.enrich()`, `.filter()`, `.select()`, `.rename()`, `.collect()`
📖 **Documentation complète** : [docs/odoo-query-builder.md](docs/odoo-query-builder.md)
---
## 🌐 Module API - Accès aux Données
API REST sécurisée basée sur **FastAPI** pour accéder aux données flux depuis DuckDB.
### Endpoints
#### Publics (sans authentification)
- `GET /` - Informations API et tables disponibles
- `GET /health` - Statut API et base de données
- `GET /docs` - Documentation Swagger interactive
#### Sécurisés (authentification requise)
- `GET /flux/{table_name}` - Données d'une table flux
- `GET /flux/{table_name}/info` - Métadonnées d'une table
- `GET /admin/api-keys` - Configuration clés API
### Utilisation
```bash
# Démarrer l'API
poetry run uvicorn electricore.api.main:app --reload
# Requête avec authentification
curl -H "X-API-Key: votre_cle" "http://localhost:8000/flux/r151?limit=10"
# Filtrer par PDL
curl -H "X-API-Key: votre_cle" "http://localhost:8000/flux/c15?prm=12345678901234"
# Métadonnées d'une table
curl -H "X-API-Key: votre_cle" "http://localhost:8000/flux/r151/info"
```
### Configuration
Créer un fichier `.env` :
```bash
# Clé API (générer avec: python -c "import secrets; print(secrets.token_urlsafe(32))")
API_KEY=votre_cle_secrete_generee
# Ou plusieurs clés
API_KEYS=cle1,cle2,cle3
# Options d'authentification
ENABLE_API_KEY_HEADER=true
ENABLE_API_KEY_QUERY=false
```
📖 **Documentation complète** : [electricore/api/README.md](electricore/api/README.md)
---
## 🚀 Installation & Usage
### Prérequis
- Python 3.12+
- Poetry
### Installation
```bash
# Cloner le projet
git clone https://github.com/votre-org/electricore.git
cd electricore
# Installer les dépendances
poetry install
```
### Commandes essentielles
```bash
# Tests
poetry run pytest -q
# Pipeline ETL complet
poetry run python electricore/etl/pipeline_production.py all
# API FastAPI
poetry run uvicorn electricore.api.main:app --reload
# Notebooks interactifs (Marimo)
poetry run marimo edit notebooks/demo_pipeline_abonnements_polars.py
```
---
## 🧪 Tests & Validation
Suite de tests moderne avec **186 tests** (tous passants ✅) :
### Infrastructure de test
- ✅ **Configuration pytest** : 8 markers (unit, integration, slow, smoke, duckdb, odoo, hypothesis, skip_ci)
- ✅ **Fixtures partagées** : Connexions DuckDB temporaires, données minimales, helpers d'assertion
- ✅ **Tests paramétrés** : 39 tests avec `@pytest.mark.parametrize` pour réduire duplication
- ✅ **Tests snapshot** : 10 tests Syrupy pour détection automatique de régression
- ✅ **Script anonymisation** : Extraction sécurisée de cas métier réels
### Types de tests
- **Tests unitaires** (26 paramétrés) - Expressions Polars pures (périmètre, TURPE)
- **Tests d'intégration** (10 snapshot) - Pipelines complets avec validation Pandera
- **Tests DuckDB** - Query builders et transformations
- **Fixtures métier** - Cas réels (MCT, MES/RES, changements)
### Commandes
```bash
# Tous les tests
pytest
# Tests rapides uniquement
pytest -m unit
# Tests critiques (CI)
pytest -m smoke
# Exécution parallèle
pytest -n auto
# Avec coverage
pytest --cov=electricore --cov-report=html
```
**Couverture** : 49% (focus sur qualité plutôt que quantité)
📖 Documentation complète : [tests/README.md](tests/README.md)
---
## 📊 Migration Polars - Complète ✅
ElectriCore utilise une architecture **100% Polars** pour des performances optimales.
### Avantages de l'architecture Polars
- ⚡ **Performance** : Zero-copy, vectorisation SIMD, multi-threading
- 🔧 **Lazy evaluation** : Optimisations automatiques des requêtes
- 🧩 **Expressions pures** : Code fonctionnel composable et testable
- 🌐 **Écosystème moderne** : Compatible Arrow, DuckDB, Cloud
- 🚀 **Pérenne** : Abandon dépendances pandas historiques
### Pipelines migrés
- ✅ **Pipeline périmètre** : 8 expressions composables + validation
- ✅ **Pipeline abonnements** : Calcul périodes avec bornes temporelles
- ✅ **Pipeline énergies** : Calcul consommations tous cadrans
- ✅ **Pipeline TURPE** : Taxes fixes + variables avec validation réglementaire
- ✅ **Pipeline facturation** : Orchestration complète avec agrégations
---
## 🗺️ Roadmap
### Complété ✅
- Migration Polars complète (périmètre, abonnements, énergies, turpe)
- Query Builder DuckDB avec architecture fonctionnelle modulaire (6 modules)
- Connecteur Odoo avec Query Builder
- API FastAPI sécurisée avec authentification
- Pipeline ETL modulaire avec DLT
- Tests unitaires et validation (140 tests passent)
### En cours 🔄
- CI/CD GitHub Actions
- Documentation API détaillée (OpenAPI)
- Suivi et métriques de performance
### À venir 📅
- API SOAP Enedis (alternative SFTP)
- Gestion prestations et affaires
- Nouveaux connecteurs (Axpo, autres sources)
- Calculs avancés (MCT, cas complexes)
- Suivi des souscriptions aux services de données
---
## 📚 Documentation Complémentaire
- [ETL README](electricore/etl/README.md) - Pipeline extraction & transformation
- [API README](electricore/api/README.md) - API REST et authentification
- [Intégration DuckDB](electricore/core/loaders/DUCKDB_INTEGRATION_GUIDE.md) - Query Builder DuckDB
- [Query Builder Odoo](docs/odoo-query-builder.md) - Intégration Odoo
- [Conventions Dates](docs/conventions-dates-enedis.md) - Formats temporels Enedis
- [Vision Architecture](docs/archi/) - Documentation architecture détaillée
---
## 🤝 Contribution
Les contributions sont les bienvenues ! Avant toute modification :
1. Lancer les tests : `poetry run pytest -q`
2. Vérifier la cohérence avec les patterns Polars existants
3. Documenter les nouvelles fonctionnalités
4. Suivre les conventions de code du projet
---
## 📄 Licence
GPLv3 - Voir [LICENSE](LICENSE)
---
## 🙏 Remerciements
- **Polars** - Framework data processing moderne
- **DuckDB** - Base analytique embarquée
- **DLT** - Pipeline ETL déclaratif
- **FastAPI** - Framework API performant
- **Pandera** - Validation schémas données
Raw data
{
"_id": null,
"home_page": "https://github.com/Energie-De-Nantes/electricore",
"name": "electricore",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": "energy, electricity, enedis, polars, duckdb, etl, turpe, linky, grid, data-processing",
"author": "Virgile",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/6b/88/f61ffa3ca6aba5d5e91b7f45b0a3948881cb35d7085db9a96b2eec0cde6b/electricore-1.3.3.tar.gz",
"platform": null,
"description": "# \u26a1 ElectriCore - Moteur de traitement donn\u00e9es \u00e9nerg\u00e9tiques\n\n**ElectriCore** est un outil libre pour reprendre le contr\u00f4le des donn\u00e9es du r\u00e9seau \u00e9lectrique fran\u00e7ais. Architecture moderne **Polars + DuckDB** pour transformer les flux bruts Enedis en donn\u00e9es exploitables par LibreWatt, Odoo et autres outils de suivi \u00e9nerg\u00e9tique.\n\n## \ud83c\udfaf Objectifs\n\nUn outil de calcul \u00e9nerg\u00e9tique **performant** et **maintenable** pour :\n- \u2705 **Transformer** les flux XML/CSV Enedis en donn\u00e9es structur\u00e9es\n- \u2705 **Calculer** les indicateurs essentiels (p\u00e9rim\u00e8tre, abonnements, consommations, TURPE)\n- \u2705 **Exposer** les donn\u00e9es via API REST s\u00e9curis\u00e9e\n- \u2705 **Int\u00e9grer** avec Odoo et autres syst\u00e8mes tiers\n\n---\n\n## \ud83c\udfd7\ufe0f Architecture - 3 Modules Principaux\n\n```\nelectricore/\n\u251c\u2500\u2500 etl/ # \ud83d\udce5 ETL - Extraction & Transformation (DLT)\n\u2502 \u251c\u2500\u2500 sources/ # Sources de donn\u00e9es (SFTP Enedis)\n\u2502 \u251c\u2500\u2500 transformers/ # Transformations modulaires (crypto, archive, parsers)\n\u2502 \u2514\u2500\u2500 connectors/ # Connecteurs externes (Odoo)\n\u2502\n\u251c\u2500\u2500 core/ # \ud83e\uddee CORE - Calculs \u00e9nerg\u00e9tiques (Polars)\n\u2502 \u251c\u2500\u2500 models/ # Mod\u00e8les Pandera (validation des donn\u00e9es)\n\u2502 \u251c\u2500\u2500 pipelines/ # Pipelines de calcul (p\u00e9rim\u00e8tre, abonnements, \u00e9nergie, turpe)\n\u2502 \u2514\u2500\u2500 loaders/ # Query builders (DuckDB, Polars)\n\u2502\n\u2514\u2500\u2500 api/ # \ud83c\udf10 API - Acc\u00e8s aux donn\u00e9es (FastAPI)\n \u251c\u2500\u2500 services/ # Services de requ\u00eatage (DuckDB)\n \u2514\u2500\u2500 main.py # Application FastAPI avec authentification\n```\n\n### Diagramme de flux\n\n```mermaid\ngraph TB\n SFTP_Enedis[/SFTP Enedis\\] --> ETL_Enedis[ETL<br/>#40;data load tool#41;]\n SFTP_Axpo[/SFTP Axpo<br/>Courbes\\] -.-> ETL_Axpo[ETL<br/>#40;data load tool#41;]\n ETL_Enedis --> DuckDB[(DuckDB)]\n ETL_Axpo -.-> DuckDB\n Odoo[(Odoo ERP)] --> OdooReader[OdooReader]\n OdooWriter[OdooWriter] --> Odoo\n\n DuckDB --> API[API REST<br/>#40;FastAPI#41;]\n DuckDB -->|Query Builder| Core[Core Pipelines<br/>#40;Polars#41;]\n OdooReader -->|Query Builder| Core\n OdooReader --> API\n Core --> API\n Core --> OdooWriter\n\n API -->|JSON| Client[\\Clients API/]\n\n style API fill:#4CAF50,stroke:#2E7D32,stroke-width:3px,color:#fff\n style DuckDB fill:#1976D2,stroke:#0D47A1,color:#fff\n style Odoo fill:#FF9800,stroke:#E65100,color:#fff\n style Core fill:#9C27B0,stroke:#4A148C,color:#fff\n style ETL_Axpo stroke-dasharray: 5 5\n```\n\n---\n\n## \ud83d\udce5 Module ETL - Extraction & Transformation\n\nPipeline ETL modulaire bas\u00e9 sur **DLT** (Data Load Tool) pour extraire et transformer les flux Enedis.\n\n### Flux support\u00e9s\n\n| Flux | Description | Tables g\u00e9n\u00e9r\u00e9es |\n|--------|------------------------------|-------------------------------|\n| **C15** | Changements contractuels | `flux_c15` |\n| **F12** | Facturation distributeur | `flux_f12` |\n| **F15** | Facturation d\u00e9taill\u00e9e | `flux_f15_detail` |\n| **R15** | Relev\u00e9s avec \u00e9v\u00e9nements | `flux_r15`, `flux_r15_acc` |\n| **R151**| Relev\u00e9s p\u00e9riodiques | `flux_r151` |\n| **R64** | Relev\u00e9s JSON timeseries | `flux_r64` |\n\n### Architecture modulaire\n\n```python\n# Pipeline ETL avec transformers cha\u00eenables\nencrypted_files | decrypt_transformer | unzip_transformer | parse_transformer\n```\n\n**Transformers disponibles** :\n- `crypto.py` - D\u00e9chiffrement AES\n- `archive.py` - Extraction ZIP\n- `parsers.py` - Parsing XML/CSV\n\n### Utilisation\n\n```bash\n# Test rapide (2 fichiers)\npoetry run python electricore/etl/pipeline_production.py test\n\n# R151 complet (~6 secondes)\npoetry run python electricore/etl/pipeline_production.py r151\n\n# Tous les flux (production)\npoetry run python electricore/etl/pipeline_production.py all\n```\n\n**R\u00e9sultat** : Base DuckDB `electricore/etl/flux_enedis_pipeline.duckdb` avec toutes les tables flux.\n\n\ud83d\udcd6 **Documentation compl\u00e8te** : [electricore/etl/README.md](electricore/etl/README.md)\n\n---\n\n## \ud83e\uddee Module Core - Calculs \u00c9nerg\u00e9tiques Polars\n\nPipelines de calculs \u00e9nerg\u00e9tiques bas\u00e9s sur **Polars pur** (LazyFrames + expressions fonctionnelles).\n\n### Pipelines disponibles\n\n#### 1. **P\u00e9rim\u00e8tre** - D\u00e9tection changements contractuels\n```python\nfrom electricore.core.pipelines.perimetre import pipeline_perimetre\nfrom electricore.core.loaders import c15\n\n# Depuis DuckDB avec Query Builder\nhistorique_lf = (\n c15()\n .filter({\"Date_Evenement\": \">= '2024-01-01'\"})\n .limit(1000)\n .lazy()\n)\n\nperimetre_df = pipeline_perimetre(historique_lf).collect()\n# Colonnes: pdl, Date_Evenement, impacte_abonnement, impacte_energie, resume_modification\n```\n\n#### 2. **Abonnements** - P\u00e9riodes d'abonnement\n```python\nfrom electricore.core.pipelines.abonnements import pipeline_abonnements\n\n# Calcul p\u00e9riodes d'abonnement avec bornes temporelles\nabonnements_df = pipeline_abonnements(\n perimetre_lf,\n date_debut=\"2024-01-01\",\n date_fin=\"2024-12-31\"\n).collect()\n# Colonnes: pdl, debut, fin, nb_jours, Puissance_Souscrite, Formule_Tarifaire_Acheminement\n```\n\n#### 3. **\u00c9nergies** - Consommations par cadran\n```python\nfrom electricore.core.pipelines.energie import pipeline_energie\nfrom electricore.core.loaders import releves\n\nrelev\u00e9s_lf = releves().filter({\"date_releve\": \">= '2024-01-01'\"}).lazy()\n\nenergies_df = pipeline_energie(\n perimetre_lf,\n relev\u00e9s_lf,\n date_debut=\"2024-01-01\",\n date_fin=\"2024-12-31\"\n).collect()\n# Colonnes: pdl, debut, fin, energie_hp, energie_hc, energie_base, ...\n```\n\n#### 4. **TURPE** - Calcul taxes r\u00e9glementaires\n```python\nfrom electricore.core.pipelines.turpe import ajouter_turpe_fixe, ajouter_turpe_variable\n\n# TURPE fixe (abonnement)\nabonnements_turpe_df = ajouter_turpe_fixe(abonnements_df).collect()\n# Colonnes: ..., turpe_fixe_annuel, turpe_fixe_journalier, turpe_fixe_periode\n\n# TURPE variable (\u00e9nergies)\nenergies_turpe_df = ajouter_turpe_variable(energies_df).collect()\n# Colonnes: ..., turpe_hpb, turpe_hcb, turpe_hph, turpe_hch, turpe_variable_total\n```\n\n#### 5. **Facturation** - Pipeline complet\n```python\nfrom electricore.core.pipelines.orchestration import facturation\n\n# Pipeline complet : p\u00e9rim\u00e8tre \u2192 abonnements \u2192 \u00e9nergies\nresultat = facturation(\n historique_lf,\n relev\u00e9s_lf,\n date_debut=\"2024-01-01\",\n date_fin=\"2024-12-31\"\n)\n\n# R\u00e9sultats disponibles\nprint(resultat.abonnements.collect()) # P\u00e9riodes d'abonnement\nprint(resultat.energies.collect()) # Consommations\nprint(resultat.factures.collect()) # Synth\u00e8ses mensuelles\n```\n\n### \ud83d\udd27 Interfaces de Requ\u00eatage\n\n#### DuckDB Query Builder - Architecture Fonctionnelle Modulaire\n\n**Architecture en 6 modules** pour performance et maintenabilit\u00e9 :\n- `config.py` - Configuration et connexions DuckDB\n- `expressions.py` - Expressions Polars pures r\u00e9utilisables\n- `transforms.py` - Transformations composables avec `compose()`\n- `sql.py` - G\u00e9n\u00e9ration SQL fonctionnelle (dataclasses frozen)\n- `query.py` - Query builder immutable (`DuckDBQuery`)\n- `__init__.py` - API publique + helper `_CTEQuery` pour requ\u00eates CTE\n\n```python\nfrom electricore.core.loaders import c15, r151, releves, releves_harmonises\n\n# Historique p\u00e9rim\u00e8tre (flux C15)\nhistorique = (\n c15()\n .filter({\"Date_Evenement\": \">= '2024-01-01'\"})\n .limit(100)\n .collect()\n)\n\n# Relev\u00e9s p\u00e9riodiques (flux R151)\nrelev\u00e9s = (\n r151()\n .filter({\"pdl\": [\"PDL123\", \"PDL456\"]})\n .limit(1000)\n .lazy() # Retourne LazyFrame pour optimisations\n)\n\n# Relev\u00e9s unifi\u00e9s (R151 + R15) avec CTE\ntous_releves = releves().collect()\n\n# Relev\u00e9s harmonis\u00e9s (R151 + R64) avec CTE\nreleves_cross_flux = (\n releves_harmonises()\n .filter({\"flux_origine\": \"R64\"})\n .collect()\n)\n```\n\n**Fonctions disponibles** : `c15()`, `r151()`, `r15()`, `f15()`, `r64()`, `releves()`, `releves_harmonises()`\n\n**Caract\u00e9ristiques** :\n- \u2705 Immutabilit\u00e9 garantie (frozen dataclasses)\n- \u2705 Composition fonctionnelle pure\n- \u2705 Lazy evaluation optimis\u00e9e\n- \u2705 Support CTE (Common Table Expressions)\n- \u2705 Validation Pandera int\u00e9gr\u00e9e\n\n\ud83d\udcd6 **Documentation compl\u00e8te** : [electricore/core/loaders/DUCKDB_INTEGRATION_GUIDE.md](electricore/core/loaders/DUCKDB_INTEGRATION_GUIDE.md)\n\n#### Odoo Query Builder - Int\u00e9gration ERP\n\n```python\nfrom electricore.core.loaders import OdooReader\nimport polars as pl\n\nconfig = {\n 'url': 'https://odoo.example.com',\n 'db': 'production',\n 'username': 'api_user',\n 'password': 'secret'\n}\n\nwith OdooReader(config) as odoo:\n # Query builder avec navigation relationnelle\n factures_df = (\n odoo.query('sale.order', domain=[('x_pdl', '!=', False)])\n .follow('invoice_ids', fields=['name', 'invoice_date', 'amount_total'])\n .filter(pl.col('amount_total') > 100)\n .collect()\n )\n\n # Enrichissement avec donn\u00e9es li\u00e9es\n commandes_enrichies = (\n odoo.query('sale.order', fields=['name', 'date_order'])\n .enrich('partner_id', fields=['name', 'email'])\n .collect()\n )\n```\n\n**M\u00e9thodes disponibles** : `.query()`, `.follow()`, `.enrich()`, `.filter()`, `.select()`, `.rename()`, `.collect()`\n\n\ud83d\udcd6 **Documentation compl\u00e8te** : [docs/odoo-query-builder.md](docs/odoo-query-builder.md)\n\n---\n\n## \ud83c\udf10 Module API - Acc\u00e8s aux Donn\u00e9es\n\nAPI REST s\u00e9curis\u00e9e bas\u00e9e sur **FastAPI** pour acc\u00e9der aux donn\u00e9es flux depuis DuckDB.\n\n### Endpoints\n\n#### Publics (sans authentification)\n- `GET /` - Informations API et tables disponibles\n- `GET /health` - Statut API et base de donn\u00e9es\n- `GET /docs` - Documentation Swagger interactive\n\n#### S\u00e9curis\u00e9s (authentification requise)\n- `GET /flux/{table_name}` - Donn\u00e9es d'une table flux\n- `GET /flux/{table_name}/info` - M\u00e9tadonn\u00e9es d'une table\n- `GET /admin/api-keys` - Configuration cl\u00e9s API\n\n### Utilisation\n\n```bash\n# D\u00e9marrer l'API\npoetry run uvicorn electricore.api.main:app --reload\n\n# Requ\u00eate avec authentification\ncurl -H \"X-API-Key: votre_cle\" \"http://localhost:8000/flux/r151?limit=10\"\n\n# Filtrer par PDL\ncurl -H \"X-API-Key: votre_cle\" \"http://localhost:8000/flux/c15?prm=12345678901234\"\n\n# M\u00e9tadonn\u00e9es d'une table\ncurl -H \"X-API-Key: votre_cle\" \"http://localhost:8000/flux/r151/info\"\n```\n\n### Configuration\n\nCr\u00e9er un fichier `.env` :\n\n```bash\n# Cl\u00e9 API (g\u00e9n\u00e9rer avec: python -c \"import secrets; print(secrets.token_urlsafe(32))\")\nAPI_KEY=votre_cle_secrete_generee\n\n# Ou plusieurs cl\u00e9s\nAPI_KEYS=cle1,cle2,cle3\n\n# Options d'authentification\nENABLE_API_KEY_HEADER=true\nENABLE_API_KEY_QUERY=false\n```\n\n\ud83d\udcd6 **Documentation compl\u00e8te** : [electricore/api/README.md](electricore/api/README.md)\n\n---\n\n## \ud83d\ude80 Installation & Usage\n\n### Pr\u00e9requis\n\n- Python 3.12+\n- Poetry\n\n### Installation\n\n```bash\n# Cloner le projet\ngit clone https://github.com/votre-org/electricore.git\ncd electricore\n\n# Installer les d\u00e9pendances\npoetry install\n```\n\n### Commandes essentielles\n\n```bash\n# Tests\npoetry run pytest -q\n\n# Pipeline ETL complet\npoetry run python electricore/etl/pipeline_production.py all\n\n# API FastAPI\npoetry run uvicorn electricore.api.main:app --reload\n\n# Notebooks interactifs (Marimo)\npoetry run marimo edit notebooks/demo_pipeline_abonnements_polars.py\n```\n\n---\n\n## \ud83e\uddea Tests & Validation\n\nSuite de tests moderne avec **186 tests** (tous passants \u2705) :\n\n### Infrastructure de test\n\n- \u2705 **Configuration pytest** : 8 markers (unit, integration, slow, smoke, duckdb, odoo, hypothesis, skip_ci)\n- \u2705 **Fixtures partag\u00e9es** : Connexions DuckDB temporaires, donn\u00e9es minimales, helpers d'assertion\n- \u2705 **Tests param\u00e9tr\u00e9s** : 39 tests avec `@pytest.mark.parametrize` pour r\u00e9duire duplication\n- \u2705 **Tests snapshot** : 10 tests Syrupy pour d\u00e9tection automatique de r\u00e9gression\n- \u2705 **Script anonymisation** : Extraction s\u00e9curis\u00e9e de cas m\u00e9tier r\u00e9els\n\n### Types de tests\n\n- **Tests unitaires** (26 param\u00e9tr\u00e9s) - Expressions Polars pures (p\u00e9rim\u00e8tre, TURPE)\n- **Tests d'int\u00e9gration** (10 snapshot) - Pipelines complets avec validation Pandera\n- **Tests DuckDB** - Query builders et transformations\n- **Fixtures m\u00e9tier** - Cas r\u00e9els (MCT, MES/RES, changements)\n\n### Commandes\n\n```bash\n# Tous les tests\npytest\n\n# Tests rapides uniquement\npytest -m unit\n\n# Tests critiques (CI)\npytest -m smoke\n\n# Ex\u00e9cution parall\u00e8le\npytest -n auto\n\n# Avec coverage\npytest --cov=electricore --cov-report=html\n```\n\n**Couverture** : 49% (focus sur qualit\u00e9 plut\u00f4t que quantit\u00e9)\n\n\ud83d\udcd6 Documentation compl\u00e8te : [tests/README.md](tests/README.md)\n\n---\n\n## \ud83d\udcca Migration Polars - Compl\u00e8te \u2705\n\nElectriCore utilise une architecture **100% Polars** pour des performances optimales.\n\n### Avantages de l'architecture Polars\n\n- \u26a1 **Performance** : Zero-copy, vectorisation SIMD, multi-threading\n- \ud83d\udd27 **Lazy evaluation** : Optimisations automatiques des requ\u00eates\n- \ud83e\udde9 **Expressions pures** : Code fonctionnel composable et testable\n- \ud83c\udf10 **\u00c9cosyst\u00e8me moderne** : Compatible Arrow, DuckDB, Cloud\n- \ud83d\ude80 **P\u00e9renne** : Abandon d\u00e9pendances pandas historiques\n\n### Pipelines migr\u00e9s\n\n- \u2705 **Pipeline p\u00e9rim\u00e8tre** : 8 expressions composables + validation\n- \u2705 **Pipeline abonnements** : Calcul p\u00e9riodes avec bornes temporelles\n- \u2705 **Pipeline \u00e9nergies** : Calcul consommations tous cadrans\n- \u2705 **Pipeline TURPE** : Taxes fixes + variables avec validation r\u00e9glementaire\n- \u2705 **Pipeline facturation** : Orchestration compl\u00e8te avec agr\u00e9gations\n\n---\n\n## \ud83d\uddfa\ufe0f Roadmap\n\n### Compl\u00e9t\u00e9 \u2705\n- Migration Polars compl\u00e8te (p\u00e9rim\u00e8tre, abonnements, \u00e9nergies, turpe)\n- Query Builder DuckDB avec architecture fonctionnelle modulaire (6 modules)\n- Connecteur Odoo avec Query Builder\n- API FastAPI s\u00e9curis\u00e9e avec authentification\n- Pipeline ETL modulaire avec DLT\n- Tests unitaires et validation (140 tests passent)\n\n### En cours \ud83d\udd04\n- CI/CD GitHub Actions\n- Documentation API d\u00e9taill\u00e9e (OpenAPI)\n- Suivi et m\u00e9triques de performance\n\n### \u00c0 venir \ud83d\udcc5\n- API SOAP Enedis (alternative SFTP)\n- Gestion prestations et affaires\n- Nouveaux connecteurs (Axpo, autres sources)\n- Calculs avanc\u00e9s (MCT, cas complexes)\n- Suivi des souscriptions aux services de donn\u00e9es\n\n---\n\n## \ud83d\udcda Documentation Compl\u00e9mentaire\n\n- [ETL README](electricore/etl/README.md) - Pipeline extraction & transformation\n- [API README](electricore/api/README.md) - API REST et authentification\n- [Int\u00e9gration DuckDB](electricore/core/loaders/DUCKDB_INTEGRATION_GUIDE.md) - Query Builder DuckDB\n- [Query Builder Odoo](docs/odoo-query-builder.md) - Int\u00e9gration Odoo\n- [Conventions Dates](docs/conventions-dates-enedis.md) - Formats temporels Enedis\n- [Vision Architecture](docs/archi/) - Documentation architecture d\u00e9taill\u00e9e\n\n---\n\n## \ud83e\udd1d Contribution\n\nLes contributions sont les bienvenues ! Avant toute modification :\n\n1. Lancer les tests : `poetry run pytest -q`\n2. V\u00e9rifier la coh\u00e9rence avec les patterns Polars existants\n3. Documenter les nouvelles fonctionnalit\u00e9s\n4. Suivre les conventions de code du projet\n\n---\n\n## \ud83d\udcc4 Licence\n\nGPLv3 - Voir [LICENSE](LICENSE)\n\n---\n\n## \ud83d\ude4f Remerciements\n\n- **Polars** - Framework data processing moderne\n- **DuckDB** - Base analytique embarqu\u00e9e\n- **DLT** - Pipeline ETL d\u00e9claratif\n- **FastAPI** - Framework API performant\n- **Pandera** - Validation sch\u00e9mas donn\u00e9es",
"bugtrack_url": null,
"license": "GPLv3",
"summary": "Moteur de traitement donn\u00e9es \u00e9nerg\u00e9tiques fran\u00e7aises - Architecture Polars/DuckDB pour flux Enedis",
"version": "1.3.3",
"project_urls": {
"Changelog": "https://github.com/Energie-De-Nantes/electricore/blob/main/CHANGELOG.md",
"Documentation": "https://github.com/Energie-De-Nantes/electricore/blob/main/README.md",
"Homepage": "https://github.com/Energie-De-Nantes/electricore",
"Issues": "https://github.com/Energie-De-Nantes/electricore/issues",
"Repository": "https://github.com/Energie-De-Nantes/electricore"
},
"split_keywords": [
"energy",
" electricity",
" enedis",
" polars",
" duckdb",
" etl",
" turpe",
" linky",
" grid",
" data-processing"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "e2b8e2fc2e4e6dfb1360ffc31f6abbfb00cf626569acb5aac86b7422daa2e59d",
"md5": "c8540d0887333b54b3a41be841448e54",
"sha256": "deeb0a9e9931770b179c570c763330c22b2ffd0cb41316d086ee006801422c51"
},
"downloads": -1,
"filename": "electricore-1.3.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c8540d0887333b54b3a41be841448e54",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 132352,
"upload_time": "2025-10-10T07:24:29",
"upload_time_iso_8601": "2025-10-10T07:24:29.135369Z",
"url": "https://files.pythonhosted.org/packages/e2/b8/e2fc2e4e6dfb1360ffc31f6abbfb00cf626569acb5aac86b7422daa2e59d/electricore-1.3.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "6b88f61ffa3ca6aba5d5e91b7f45b0a3948881cb35d7085db9a96b2eec0cde6b",
"md5": "fc07e873829aeec38844760db6304a1a",
"sha256": "aee0a87e80151dfa08cc20ff65d2cb79f4c01ad14738482d53612503b83dfca1"
},
"downloads": -1,
"filename": "electricore-1.3.3.tar.gz",
"has_sig": false,
"md5_digest": "fc07e873829aeec38844760db6304a1a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 102989,
"upload_time": "2025-10-10T07:24:30",
"upload_time_iso_8601": "2025-10-10T07:24:30.818384Z",
"url": "https://files.pythonhosted.org/packages/6b/88/f61ffa3ca6aba5d5e91b7f45b0a3948881cb35d7085db9a96b2eec0cde6b/electricore-1.3.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-10 07:24:30",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Energie-De-Nantes",
"github_project": "electricore",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "electricore"
}