Skip to main content

Noria

SQL-first data pipeline framework
Jinja2 templating · multi-base de données · monitoring intégré

PyPI Python MIT


"Noria" — la roue hydraulique qui fait circuler l'eau avec précision et régularité.
Ici, vos données circulent avec la même fiabilité.


Pourquoi Noria ?

Besoin Solution Noria
Écrire du SQL, pas du Python ORM Templates Jinja2 directement dans vos fichiers .sql
Changer de BDD sans tout réécrire Macros cross-DB compilées selon le dialecte cible
Orchestrer des dépendances entre requêtes DAG déclaratif en YAML, exécution parallèle
Voir ce qui se passe Dashboard de monitoring intégré, historique SQLite
Démarrer en 2 minutes pip install noria && noria init mon_projet && noria run

Installation

Noria s'installe dans un environnement Python : un dossier de travail qui contiendra Noria et vos projets.

# Installer uv (une seule fois sur votre machine)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Créer votre espace de travail et y installer Noria
mkdir data_projets && cd data_projets
uv venv                          # crée l'environnement Python (.venv)
source .venv/bin/activate        # l'active (à refaire à chaque nouveau terminal)
uv pip install noria

noria version                    # vérification : affiche la version installée

Sans uv : python3 -m venv .venv && source .venv/bin/activate && pip install noria fait exactement la même chose.

« noria : commande introuvable » ? L'environnement n'est pas activé : relancez source .venv/bin/activate depuis le dossier data_projets.


Démarrage rapide

noria init mon_pipeline          # Noria pose quelques questions (base de données…)
                                 # Entrée pour garder les valeurs par défaut
cd mon_pipeline
noria run                        # exécute le pipeline d'exemple

Organisation générée :

data_projets/            ← espace de travail (environnement Python)
├── .venv/               ← Noria installé ici
└── mon_pipeline/        ← votre projet Noria
    ├── noria.yml
    ├── envs/
    └── sql/

Pour un deuxième projet : revenez dans data_projets, puis noria init autre_projet.


Structure d'un projet Noria

mon_pipeline/
├── noria.yml                  # Configuration du pipeline
├── sql/
│   ├── macros/                # Macros Jinja2 réutilisables
│   │   └── utils.sql.j2
│   ├── 01_clients.sql         # Requêtes SQL avec templates Jinja2
│   └── 02_rapport.sql
├── params/
│   └── prod.yml               # Paramètres par environnement
└── .noria/
    ├── data.db                # Base DuckDB locale (développement)
    └── tracking.db            # Historique des exécutions

Configuration — noria.yml

name: mon_pipeline
description: "Pipeline de données clients"

database:
  dialect: duckdb          # duckdb | postgresql | bigquery | snowflake
  database: .noria/data.db

params:
  date_min: "2024-01-01"
  schema: main

monitoring:
  enabled: true
  port: 7070

jobs:
  clients_actifs:
    sql: sql/01_clients.sql
    target: "{{ params.schema }}.clients_actifs"
    write_mode: replace        # voir tableau des modes d'écriture
    active: true
    description: "Clients avec au moins une commande"

  rapport:
    sql: sql/02_rapport.sql
    target: "{{ params.schema }}.rapport"
    write_mode: replace
    after:
      - clients_actifs          # exécuté après clients_actifs
    pre_hook:
      file: sql/hooks/pre_rapport.sql
    post_hook:
      file: sql/hooks/post_rapport.sql

Écrire du SQL avec Jinja2

-- sql/01_clients.sql

SELECT
    {{ cast('id', 'VARCHAR') }}             AS id_client,  -- adapté au dialecte
    first_name || ' ' || last_name          AS nom,
    {{ date_trunc('month', 'created_at') }} AS mois_inscription,
    {{ coalesce('phone', "'N/A'") }}        AS telephone

FROM source_schema.customers
WHERE created_at >= '{{ params.date_min }}'

{% if params.actif_only %}
  AND actif = TRUE
{% endif %}

Macros cross-base de données

Macro Jinja2 PostgreSQL compilé DuckDB compilé
{{ cast('id', 'TEXT') }} id::TEXT CAST(id AS TEXT)
{{ date_trunc('month', 'ts') }} DATE_TRUNC('month', ts) DATE_TRUNC('month', ts)
{{ current_timestamp() }} NOW() CURRENT_TIMESTAMP
{{ concat('a', 'b') }} CONCAT(a, b) CONCAT(a, b)
{{ coalesce('a', '0') }} COALESCE(a, 0) COALESCE(a, 0)
{{ safe_divide('num', 'den') }} CASE WHEN den=0 THEN NULL... CASE WHEN den=0 THEN NULL...
{{ to_char('ts', 'YYYY-MM') }} TO_CHAR(ts, 'YYYY-MM') STRFTIME(ts, '%Y-%m')
{{ limit(10) }} LIMIT 10 LIMIT 10
{{ schema_table('s', 't') }} s.t s.t

Macros personnalisées

Créez vos propres macros dans sql/macros/*.sql.j2 :

{# sql/macros/utils.sql.j2 #}
{% macro panier_moyen(montant, quantite) %}
  {{ safe_divide(montant, quantite) }}
{% endmacro %}

Puis utilisez-les dans n'importe quel fichier SQL :

{% from 'utils.sql.j2' import panier_moyen %}
SELECT {{ panier_moyen('SUM(amount)', 'COUNT(id)') }} AS panier_moyen
FROM orders

Modes d'écriture (write_mode)

Mode Comportement
replace DROP TABLE + CREATE TABLE AS SELECT
append INSERT INTO … SELECT
truncate TRUNCATE + INSERT
merge DELETE sur les clés + INSERT (nécessite merge_key)
create_if_not_exists Crée seulement si absente
safe_replace Comme replace, annulé si la requête retourne trop peu de lignes
incremental DELETE sur une partition (incremental_key) + INSERT
scd2 Historisation SCD2 avec _valid_from, _valid_to, _is_current
update UPDATE des colonnes ciblées sur les clés (update_key)

CLI — Commandes

noria init <nom>               # Initialiser un projet
noria validate                 # Valider config + DAG (sans connexion BDD)
noria compile                  # Prévisualiser le SQL compilé
noria compile --job mon_job    # Compiler un seul job
noria run                      # Lancer tout le pipeline
noria run --job mon_job        # Lancer un job spécifique
noria run --dry-run            # Compiler sans exécuter
noria run --workers 8          # Parallélisme (défaut: 4)
noria run --param date_min=2024-06-01  # Surcharger un paramètre
noria run --log-file noria.log # Écrire les logs dans un fichier
noria run --log-format json    # Format JSON (avec run_id et job)
noria jobs                     # Lister les jobs et dépendances
noria status                   # Voir l'historique des exécutions
noria monitor                  # Ouvrir le dashboard web

Paramétrage par environnement

# Développement (défaut)
noria run

# Production via surcharge CLI
noria run --param schema=prod --param date_min=2023-01-01

# Variables d'environnement dans noria.yml
# database.password: ${DB_PASSWORD}

Hooks pre/post

jobs:
  ma_tache:
    sql: sql/ma_tache.sql
    pre_hook:
      file: sql/hooks/pre.sql     # Exécuté avant le job
      ignore_on_error: false
    post_hook:
      file: sql/hooks/post.sql    # Exécuté après
      ignore_on_error: true       # Erreur non bloquante
    on_failure_hook:
      file: sql/hooks/alerte.sql  # Exécuté une fois après un échec définitif

Monitoring

Le dashboard web est inclus par défaut :

noria monitor             # Ouvre http://localhost:7070
  • Historique de toutes les exécutions
  • Détail par tâche : statut, durée, lignes écrites, erreurs
  • Rafraîchissement automatique (HTMX)

L'historique est stocké localement dans .noria/tracking.db (SQLite, zéro config).


API Python

from noria.core.pipeline import Pipeline

# Lancer le pipeline
pipeline = Pipeline("./mon_projet", params_override={"schema": "staging"})
results = pipeline.run()

# Compilation uniquement
compiled_sql = pipeline.compile(task_name="ma_tache")
print(compiled_sql["ma_tache"])

# Historique
history = pipeline.history(limit=5)

Ajouter un dialecte personnalisé

from noria.adapters import register_adapter
from noria.adapters.base import BaseAdapter
from sqlalchemy import create_engine

class MyAdapter(BaseAdapter):
    dialect_name = "mydb"
    
    def create_engine(self, db_config):
        return create_engine(f"mydb://...")
    
    # ... implémenter les méthodes abstraites

register_adapter("mydb", MyAdapter)

Tests

make install-dev
make test
make test-cov   # avec rapport de couverture HTML

Contribuer

  1. Fork le dépôt
  2. make install-dev
  3. Créer une branche feature
  4. make test + make lint avant de soumettre

Licence

MIT © Noria Contributors

Metadata

Release files for noria 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for noria 0.1.3
File Size Uploaded
noria-0.1.3.tar.gz 1.7 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for noria 0.1.3
File Interpreter ABI Platform
noria-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 1.8 MB

Release files / noria-0.1.3.tar.gz

Download URL noria-0.1.3.tar.gz
Size 1.7 MB
Tags Source
SHA-256 checksum
How to use checksums
fbba4e3691429f8eeacd0cfa33ad2a08880c1ee4ee748e3d5c224296dc9acc46
BLAKE2b-256 checksum
How to use checksums
4a801d5b98da4ded497f7c31cc1709b09d7bb4d5ea0975a34d9b7c49e7ae5b72
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / noria-0.1.3-py3-none-any.whl

Download URL noria-0.1.3-py3-none-any.whl
Size 107.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9e27ac7f36ceb8a0d81d04f32a9c52a4254518beaaaf71e8eccf3deda0a41692
BLAKE2b-256 checksum
How to use checksums
1863fc1c194e585a44b21e9962043efddc9cd7be470f4b8b027c0716234f4391
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page