Metadata-Version: 2.4
Name: reportforge
Version: 0.1.0
Summary: Générateur de rapports professionnels multi-format (PDF, HTML, DOCX, XLSX)
Author-email: ReportForge Contributors <contact@reportforge.dev>
License: MIT
Project-URL: Homepage, https://github.com/yourname/reportforge
Project-URL: Documentation, https://reportforge.readthedocs.io
Project-URL: Repository, https://github.com/yourname/reportforge
Project-URL: Bug Tracker, https://github.com/yourname/reportforge/issues
Keywords: report,pdf,html,docx,xlsx,generator,charts,data
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business
Classifier: Topic :: Text Processing
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: <4.0,>=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: reportlab<5.0.0,>=4.0.0
Requires-Dist: python-docx<2.0.0,>=1.0.0
Requires-Dist: openpyxl<4.0.0,>=3.1.0
Requires-Dist: matplotlib<4.0.0,>=3.7.0
Provides-Extra: connectors
Requires-Dist: requests<3.0.0,>=2.31.0; extra == "connectors"
Requires-Dist: sqlalchemy<3.0.0,>=2.0.0; extra == "connectors"
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Provides-Extra: all
Requires-Dist: reportforge[connectors,dev]; extra == "all"
Dynamic: license-file

# reportforge

Générateur de rapports professionnels, 100 % piloté par des données Python
(aucun HTML/CSS/template à écrire par l'utilisateur final de la librairie).

## Python Support

- **Python 3.8, 3.9, 3.10, 3.11, 3.12**

## Installation

```bash
# Installation de base
pip install reportforge

# Installation avec connecteurs (CSV, SQL, API)
pip install reportforge[connectors]

# Installation de développement
pip install reportforge[dev]
```

## Dependencies

### Core Dependencies
- `reportlab >= 4.0.0, < 5.0.0` - PDF generation
- `python-docx >= 1.0.0, < 2.0.0` - DOCX generation
- `openpyxl >= 3.1.0, < 4.0.0` - XLSX generation
- `matplotlib >= 3.7.0, < 4.0.0` - Chart generation

### Optional Dependencies (connectors)
- `requests >= 2.31.0, < 3.0.0` - HTTP API connector
- `sqlalchemy >= 2.0.0, < 3.0.0` - SQL connector (optional, SQLite built-in)

## Pourquoi cette architecture

- **Python** est le bon choix stratégique ici (pas un choix par défaut) :
  l'écosystème `reportlab` (PDF bas niveau, contrôle au point près),
  `python-docx` (Word natif), `openpyxl` (Excel natif) et `matplotlib`
  (graphiques) est mature, stable, sans dépendance à un moteur de rendu
  navigateur, et couvre exactement les 4 familles de formats visées.
- **Une seule description (`ReportSpec`) → 4 moteurs de rendu natifs**
  (`render_pdf.py`, `render_html.py`, `render_docx.py`, `render_xlsx.py`),
  chacun traduisant la même grille et les mêmes blocs dans les primitives
  natives du format cible (tables reportlab, CSS Grid, tableaux Word,
  cellules Excel). C'est un choix assumé : un PDF, un DOCX et un XLSX ne
  partagent pas de moteur de mise en page, donc la fidélité pixel-parfaite
  entre formats n'existe nulle part dans l'industrie — reportforge vise une
  fidélité *visuelle* forte (mêmes couleurs, mêmes proportions, mêmes
  graphiques) plutôt qu'une illusion de fidélité totale.
- **HTML** est généré comme document autonome (CSS généré dynamiquement à
  partir du `Theme`, images en base64) : ouvrable dans n'importe quel
  navigateur, imprimable en PDF par le navigateur si besoin.
- Les graphiques (`matplotlib`, backend `Agg`) sont rendus **une seule
  fois** en PNG et réutilisés tels quels dans les 4 formats : le rendu
  visuel du graphique est donc strictement identique partout.

## Utilisation

```python
from reportforge import (
    ReportSpec, Theme, GridConfig, TextBlock, TableBlock,
    StatBlock, CalcBlock, ChartBlock, SpacerBlock, Report,
)

theme = Theme(primary="#0F3D3E", accent="#E0A458", font_family="Helvetica")
grid = GridConfig(columns=12, col_gap_mm=4, row_gap_mm=5)   # nombre de colonnes 100% configurable

spec = ReportSpec(title="Mon rapport", theme=theme, grid=grid)
spec.add(TextBlock(col_span=12, level="heading", content="Introduction"))
spec.add(StatBlock(col_span=4, label="Ventes", value=12000, delta=8.2))
spec.add(ChartBlock(col_span=8, chart_type="bar",
                     categories=["Jan", "Fev", "Mar"],
                     series={"CA": [10, 12, 9]}))
spec.add(TableBlock(col_span=12, headers=["Produit", "CA"], rows=[["A", 100], ["B", 200]]))

report = Report(spec)
report.export("rapport.pdf")     # ou .html / .docx / .xlsx
report.export_all("rapport")     # génère les 4 formats d'un coup
```

## Blocs disponibles

| Bloc          | Usage                                                             |
|---------------|--------------------------------------------------------------------|
| `TextBlock`   | Titre, sous-titre, paragraphe, légende (markdown léger `**gras**`) |
| `TableBlock`  | Tableau de données, alignement/format par colonne, zébrage        |
| `StatBlock`   | Indicateur clé (valeur + variation en %)                           |
| `CalcBlock`   | Indicateur calculé dynamiquement (`sum/mean/median/min/max/count`) |
| `ChartBlock`  | Graphique `bar/barh/line/area/pie/scatter`, multi-séries           |
| `SpacerBlock` | Espacement vertical                                                |

Chaque bloc a un `col_span` (largeur en colonnes de grille) et un `style`
(`BlockStyle`) : couleur de fond, couleur de texte, taille de police,
gras, alignement, bordure — sans aucune limite, tout est piloté par le
`Theme` (couleurs globales) et surchargeable bloc par bloc.

## Connecteurs (CSV / SQL / API)

Trois sources de données, une seule représentation intermédiaire
(`RecordSet`, liste de dict) et un seul jeu de méthodes de conversion
vers les blocs — écrit une fois, partagé par les trois.

```python
from reportforge.connectors import CSVConnector, SQLConnector, APIConnector

# CSV — typage numérique automatique par colonne
rs = CSVConnector("ventes.csv", delimiter=";").records()

# SQL — 3 modes au choix, aucun driver imposé :
rs = SQLConnector(sqlite_path="ventes.db").query("SELECT region, ca FROM ventes")
# ou : SQLConnector(connection=psycopg2.connect(...))          # tout driver DB-API 2.0
# ou : SQLConnector(sqlalchemy_url="postgresql://...")         # via SQLAlchemy

# API — JSON REST, extraction par chemin, pagination optionnelle
rs = APIConnector(
    "https://api.exemple.com/ventes", bearer_token="xxx",
    json_path="data.results", next_url_path="data.next_page", max_pages=5,
).records()

# Depuis n'importe quel RecordSet :
table = rs.to_table_block(col_span=12, title="Détail")
chart = rs.to_chart_block(category_field="region", value_fields=["ca"], chart_type="bar")
stat  = rs.to_stat_block(value_field="ca", agg="sum", label="CA total", unit="BIF")
calc  = rs.to_calc_block(value_field="ca", agg="mean", label="CA moyen")
```

`RecordSet` expose aussi `.filter()`, `.select()`, `.sort()`, `.limit()`
et `.group_by()` pour préparer les données avant conversion en bloc.
Les erreurs de connexion/requête lèvent `ConnectorError` (message clair,
jamais d'exception brute du driver sous-jacent).

## Étendre

Le point d'extension est `reportforge/engine.py::_RENDERERS`. Ajouter un
format = écrire un `render_xxx(spec, output_path)` de plus et l'enregistrer
dans ce dictionnaire ; tout le reste (spec, grille, thème, blocs) est déjà
partagé.
