electricore


Nameelectricore JSON
Version 1.3.3 PyPI version JSON
download
home_pagehttps://github.com/Energie-De-Nantes/electricore
SummaryMoteur de traitement données énergétiques françaises - Architecture Polars/DuckDB pour flux Enedis
upload_time2025-10-10 07:24:30
maintainerNone
docs_urlNone
authorVirgile
requires_python>=3.12
licenseGPLv3
keywords energy electricity enedis polars duckdb etl turpe linky grid data-processing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # ⚡ 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"
}
        
Elapsed time: 1.62582s