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

Avec uv (recommandé)

# Installer uv si ce n'est pas déjà fait
curl -LsSf https://astral.sh/uv/install.sh | sh

# Ajouter Noria à un projet uv
uv add noria

# Ou dans un environnement isolé
uv pip install noria

Avec pip

# macOS / Linux
pip3 install noria

# Avec support PostgreSQL
pip3 install noria[postgres]

# Avec toutes les options
pip3 install noria[all]

Conseil : installez Noria dans un environnement virtuel pour éviter les conflits.

python3 -m venv .venv && source .venv/bin/activate && pip install noria

Démarrage rapide

# 1. Créer un projet
noria init mon_pipeline
cd mon_pipeline

# 2. Vérifier la configuration
noria validate

# 3. Voir le SQL compilé sans exécuter
noria compile

# 4. Lancer le pipeline
noria run

# 5. Ouvrir le dashboard de monitoring
noria monitor

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
  database: .noria/data.db

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

monitoring:
  enabled: true
  port: 7070

tasks:
  clients_actifs:
    sql: sql/01_clients.sql
    target: "{{ params.schema }}.clients_actifs"
    write_mode: replace        # replace | append | truncate | merge
    active: true
    description: "Clients avec au moins une commande"

  rapport:
    sql: sql/02_rapport.sql
    target: "{{ params.schema }}.rapport"
    write_mode: replace
    depends_on:
      - 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, 'YYYY-MM')
{{ 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 INSERT ON CONFLICT (nécessite merge_key)
create_if_not_exists Crée seulement si absente

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 -t ma_tache # Compiler une seule tâche
noria run                 # Lancer tout le pipeline
noria run -t tache_a      # Lancer une tâche 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 tasks               # Lister les tâches 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

tasks:
  ma_tache:
    sql: sql/ma_tache.sql
    pre_hook:
      file: sql/hooks/pre.sql     # Exécuté avant la tâche
      ignore_on_error: false
    post_hook:
      file: sql/hooks/post.sql    # Exécuté après
      ignore_on_error: true       # Erreur non bloquante

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.1

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.1
File Size Uploaded
noria-0.1.1.tar.gz 1.7 MB Details

Built distribution (wheel)

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

Total release size: 1.8 MB

Release files / noria-0.1.1.tar.gz

Download URL noria-0.1.1.tar.gz
Size 1.7 MB
Tags Source
SHA-256 checksum
How to use checksums
cfac98858c8c9a54a020dc8cf6292c218dfb93a835f4f4641f3e68dc3185d27e
BLAKE2b-256 checksum
How to use checksums
58907e36557d5059f7d0a55fce4630d8430e68c8258b666504b11a67e63854b2
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 Sep 26, 2026.

Transparency log

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

Download URL noria-0.1.1-py3-none-any.whl
Size 96.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dca761c9eacea6acffa607125e9fea224cb71c02fabc68e3006bb2398c929529
BLAKE2b-256 checksum
How to use checksums
5230cb5ae702762c862406145864737716c6b080475eb7e30bf501d900b203e5
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 Sep 26, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

This release

0.1.1 This release

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