atmo_data_wrapper | ||
demos | ||
docs | ||
examples | ||
tests | ||
.gitignore | ||
credentials.json.example | ||
LICENSE | ||
MANIFEST.in | ||
pyproject.toml | ||
requirements-dev.txt | ||
requirements.txt | ||
setup.py |
Wrapper Python pour l'API Atmo Data
Ce projet fournit un wrapper Python pour l'API Atmo Data (https://admindata.atmo-france.org), permettant d'accéder facilement aux données de qualité de l'air et de pollution des Associations agréées de surveillance de la qualité de l’air (AASQA) françaises. Atmo Data est un agrégateur national des données produites par les AASQA en accès libre et sous licence ODbL, géré par Atmo France (https://www.atmo-france.org), la Fédération des Associations agréées de surveillance de la qualité de l'air.
Elle met à disposition 6 flux agrégés sur les 4 thèmes suivants :
- indice ATMO de la qualité de l'air
- les épisodes de pollution
- les émissions à l'échelle de la région et de l'établissement public de coopération intercommunale (EPCI)
- l'indice pollen
Chacun peut donc bénéficier gratuitement de ces données mises en open data sous licence ODbL, en indiquant la source "Atmo France et les Associations agréées de surveillance de la qualité de l’air" ou "Atmo France / AASQA" dans sa version courte.
La documentation de l'API est disponible en ligne à l'adresse : https://admindata.atmo-france.org/api/doc/v2. La Notice technique et d’information des données open data sur la qualité de l’air disponibles sur Atmo Data (Version 1er avril 2025) est disponible en ligne à l'adresse : https://www.atmo-france.org/sites/federation/files/medias/documents/2025-04/notice_Atmo_Data_1eravril2025.pdf.
Structure du projet
atmo-data-wrapper/
├── atmo_data_wrapper/ # Package principal
│ ├── __init__.py # Exports principaux du package
│ └── core/ # Module central
│ ├── __init__.py # Exports du module core
│ ├── client.py # Client principal pour l'API
│ ├── models.py # Classes pour les données typées
│ ├── constants.py # Constantes et configurations
│ ├── utils.py # Fonctions utilitaires
│ └── exceptions.py # Exceptions personnalisées
├── examples/ # Scripts d'exemples
│ ├── __init__.py
│ ├── example_usage.py # Exemples d'utilisation des endpoints
│ ├── example_save_files.py # Exemples de sauvegarde
│ ├── example_data_models.py # Exemples avec objets typés
│ ├── example_aasqa_utilities.py # Exemples fonctions utilitaires AASQA
│ ├── example_aasqa_advanced.py # Analyses avancées AASQA
│ ├── example_synthese_nancy.py # Exemple synthèse complète
│ └── setup_credentials.py # Configuration des credentials
├── demos/ # Scripts de démonstration complète
│ ├── __init__.py
│ ├── demo_atmo_functions.py # Démonstration complète IndiceAtmo
│ ├── demo_pollen_functions.py # Démonstration complète IndicePollen
│ ├── demo_emission_functions.py # Démonstration complète EmissionData
│ ├── demo_licence_atmo.py # Démonstration licence Atmo France
│ └── demo_episode_functions.py # Démonstration complète EpisodePollution
├── tests/ # Tests unitaires
│ ├── __init__.py
│ ├── test_validations.py # Tests de validation
│ ├── test_save_functionality.py # Tests de sauvegarde
│ ├── test_typed_client.py # Tests d'intégration modèles
│ ├── test_real_connection.py # Test de connexion réelle à l'API
│ └── test_credentials_system.py # Tests du système de credentials
├── docs/ # Documentation
│ ├── README.md # Documentation principale
│ ├── QUICKSTART.md # Guide de démarrage rapide
│ ├── DOCUMENTATION_DEMOS.md # Documentation des scripts de démonstration
│ ├── JOURNAL.md # Journal de développement
│ ├── notice_Atmo_Data_1eravril2025.md # Notice officielle API
│ └── swagger.json # Spécification API
├── credentials.json.example # Modèle de fichier credentials
├── credentials.json # Vos identifiants (à créer, ignoré par git)
├── setup.py # Configuration du package
├── pyproject.toml # Configuration moderne du package
├── requirements.txt # Dépendances de production
├── requirements-dev.txt # Dépendances de développement
├── MANIFEST.in # Fichiers à inclure dans le package
├── LICENSE # Licence MIT
└── .gitignore # Fichiers à ignorer par git
Installation
Installation depuis le repository local
# Cloner ou télécharger le project
git clone https://github.com/atmo-france/atmo-data-wrapper.git
cd atmo-data-wrapper
# Installation en mode développement
pip install -e .
# Ou installation normale
pip install .
Dépendances
Le package nécessite Python 3.7+ et les dépendances suivantes :
pip install requests>=2.25.0
Installation des dépendances de développement
pip install -r requirements-dev.txt
Configuration des credentials
0. Pré requis : Demander l'autorisation
L'accès aux données requiert l'autorisation d'un d'administrateur de l'application API Atmo Data. Vous pouvez réaliser une demande de création de compte à cette adresse : https://admindata.atmo-france.org/inscription-api.
Pour vous connecter à l'API Atmo Data, vous devez créer un fichier de configuration avec vos identifiants.
1. Créer le fichier credentials.json
# Copier le fichier exemple
cp credentials.json.example credentials.json
# Éditer avec vos identifiants
nano credentials.json
2. Format du fichier credentials.json
{
"username": "votre_nom_utilisateur",
"password": "votre_mot_de_passe",
"api_url": "https://api.atmo-data.org"
}
Important :
- Le fichier
credentials.json
est ajouté au.gitignore
pour éviter de commiter vos identifiants - Remplacez les valeurs par vos vrais identifiants fournis par Atmo Data
- L'URL de l'API peut être modifiée si nécessaire
Utilisation
Authentification
Méthode recommandée : Fichier credentials.json
from atmo_data_wrapper import AtmoDataClient, AASQA_CODES, POLLUANTS
# Connexion automatique avec credentials.json
client = AtmoDataClient()
client.auto_login() # Utilise automatiquement credentials.json
Fonctions utilitaires AASQA
Le wrapper fournit des fonctions utilitaires pour faciliter la manipulation des codes AASQA et la recherche d'organismes :
from atmo_data_wrapper import (
get_aasqa_by_department,
get_aasqa_info,
search_aasqa_by_name,
get_departments_count,
validate_department_coverage,
get_aasqa_statistics
)
# Trouver l'AASQA d'un département
aasqa_code = get_aasqa_by_department("54") # Nancy
print(f"Département 54 -> AASQA {aasqa_code}") # "44" (Grand Est)
# Informations complètes d'une AASQA
info = get_aasqa_info("44")
print(f"Organisme: {info['organisme']}") # "ATMO Grand-Est"
print(f"Site web: {info['site_web']}") # URL officielle
print(f"Départements: {info['departements']}") # Liste des départements
# Recherche par nom
resultats = search_aasqa_by_name("Atmo")
for r in resultats:
print(f"{r['organisme']} - {r['region']}")
# Statistiques
stats = get_aasqa_statistics()
print(f"Nombre total d'AASQA: {stats['total_aasqa']}")
print(f"Couverture moyenne: {stats['average_coverage']:.1f} départements/AASQA")
Licence et mentions légales
Conformément aux exigences d'Atmo France, le wrapper fournit des fonctions pour afficher les mentions légales requises :
from atmo_data_wrapper import get_atmo_licence, print_atmo_licence
# Version courte (recommandée)
print(get_atmo_licence("courte"))
# "Atmo France / AASQA"
# Version longue (officielle)
print(get_atmo_licence("longue"))
# "Atmo France et les Associations agréées de surveillance de la qualité de l'air"
# Version complète avec licence ODbL
print_atmo_licence("complete")
# Affiche les détails complets de la licence
# Utilisation dans un script
data = client.get_indices_atmo()
print(f"Source: {get_atmo_licence('courte')}")
Méthode alternative : Identifiants directs
# Connexion avec identifiants fournis directement
client = AtmoDataClient()
client.login("votre_username", "votre_password")
# Ou mélange des deux (override du fichier)
client.login(username="autre_user") # password vient du fichier
Récupération des indices ATMO
# Indices d'aujourd'hui
indices = client.get_indices_atmo()
# Indices d'une date spécifique
indices = client.get_indices_atmo(date="2024-06-08")
# Indices pour une région spécifique (utilisation des constantes)
indices = client.get_indices_atmo(aasqa="11") # AASQA_CODES['11'] = Île-de-France
Épisodes de pollution
# Épisodes en cours (3 jours)
episodes = client.get_episodes_3jours()
# Épisodes historiques
episodes = client.get_episodes_historique(date="2024-06-08")
# Filtre par polluant (utilisation des constantes)
episodes = client.get_episodes_3jours(polluant=POLLUANTS[2]) # PM10
Données d'émissions
# Émissions par région
emissions = client.get_emissions(echelle="region")
# Émissions par EPCI
emissions = client.get_emissions(echelle="epci", aasqa="11")
Indices pollen
# Indices pollen actuels
pollens = client.get_indices_pollens()
# Avec alertes uniquement
pollens = client.get_indices_pollens(alerte=True)
Objets typés et modèles de données
Le wrapper utilise des objets typés pour faciliter l'exploitation des données. Chaque type de données retourné par l'API est représenté par une classe spécialisée avec des méthodes helper.
Types de données disponibles
- IndiceAtmo : Indices de qualité de l'air ATMO (0-7)
- EpisodePollution : Épisodes de pollution atmosphérique
- EmissionData : Données d'inventaires des émissions
- IndicePollen : Indices polliniques (0-6)
- AtmoDataCollection : Collection gérant plusieurs objets
Utilisation avec objets typés
from atmo_data_wrapper import AtmoDataClient, Coordinates
client = AtmoDataClient()
client.auto_login() # Connexion avec credentials.json
# Les données GeoJSON retournent des objets typés
indices = client.get_indices_atmo(aasqa="11") # Retourne AtmoDataCollection
# Parcourir les données avec méthodes helper
for indice in indices:
print(f"Zone: {indice.lib_zone}")
print(f"Qualité: {indice.get_qualificatif()}")
print(f"Couleur: {indice.get_color()[0]}") # Couleur hex
if indice.is_poor_quality():
worst_pol, code = indice.get_worst_pollutant()
print(f"Attention: {worst_pol} élevé ({code})")
# Statistiques sur la collection
stats = indices.get_statistics()
print(f"Qualité moyenne: {stats['quality_stats']['moyenne']:.1f}")
# Filtrage géographique
paris = Coordinates(2.3522, 48.8566)
nearby = indices.filter_by_coordinates(paris, radius_km=20)
Classes et méthodes disponibles
IndiceAtmo
get_qualificatif()
: Qualificatif textuel (Bon, Moyen, etc.)get_color()
: Couleur hex et RGB associéeis_good_quality()
/is_poor_quality()
: Tests de qualitéget_worst_pollutant()
: Polluant le plus problématiqueget_pollutants_summary()
: Résumé de tous les polluants
EpisodePollution
is_alert_active()
: Vérifie si une alerte est en coursget_alert_level()
: Niveau d'alerte (Information/Alerte/Aucune)get_polluant_code()
: Code du polluant principal
EmissionData
get_emission_density(polluant)
: Densité d'émission par km²get_emission_per_capita(polluant)
: Émission par habitantget_total_emissions()
: Toutes les émissionsget_secteur_name()
: Nom du secteur d'émission
IndicePollen
is_alert_active()
: Alerte pollen activeget_highest_pollen()
: Espèce avec l'indice le plus élevéget_dangerous_pollens()
: Liste des pollens à risque élevéget_pollens_summary()
: Détail par espèce avec émojisget_responsible_pollens()
: Taxons responsables selon l'API
AtmoDataCollection
filter_by_aasqa(code)
: Filtrage par régionfilter_by_coordinates(center, radius)
: Filtrage géographiqueget_statistics()
: Statistiques de la collectionto_summary()
: Résumé textuel
API Endpoints
get_indices_atmo()
- Indices de qualité de l'air ATMOget_episodes_3jours()
- Épisodes de pollution sur 3 joursget_episodes_historique()
- Épisodes de pollution historiquesget_emissions()
- Inventaires des émissionsget_indices_pollens()
- Indices pollen
Codes AASQA
Le wrapper fournit des constantes enrichies avec sites web et départements couverts :
- 01: Guadeloupe (Gwad'Air) - Département 971
- 02: Martinique (Madininair) - Département 972
- 03: Guyane (Atmo Guyane) - Département 973
- 04: La Réunion (Atmo Réunion) - Département 974
- 06: Mayotte (Hawa Mayotte) - Département 976
- 11: Île-de-France (Airparif) - Départements 75, 77, 78, 91, 92, 93, 94, 95
- 24: Centre-Val de Loire (Lig'Air) - Départements 18, 28, 36, 37, 41, 45
- 27: Bourgogne-Franche-Comté (Atmo BFC) - Départements 21, 25, 39, 58, 70, 71, 89, 90
- 28: Normandie (Atmo Normandie) - Départements 14, 27, 50, 61, 76
- 32: Hauts-de-France (Atmo HDF) - Départements 02, 59, 60, 62, 80
- 44: Grand Est (ATMO Grand-Est) - Départements 08, 10, 51, 52, 54, 55, 57, 67, 68, 88
- 52: Pays de la Loire (Air Pays de la Loire) - Départements 44, 49, 53, 72, 85
- 53: Bretagne (Air Breizh) - Départements 22, 29, 35, 56
- 75: Nouvelle-Aquitaine (Atmo NA) - Départements 16, 17, 19, 23, 24, 33, 40, 47, 64, 79, 86, 87
- 76: Occitanie (Atmo Occitanie) - Départements 09, 11, 12, 30, 31, 32, 34, 46, 48, 65, 66, 81, 82
- 84: Auvergne-Rhône-Alpes (Atmo AURA) - Départements 01, 03, 07, 15, 26, 38, 42, 43, 63, 69, 73, 74
- 93: Provence-Alpes-Côte d'Azur (AtmoSud) - Départements 04, 05, 06, 13, 83, 84
- 94: Corse (Qualitair) - Départements 2A, 2B
Accès programmatique :
from atmo_data_wrapper import AASQA_CODES
info = AASQA_CODES['44']
print(f"Site web: {info['site_web']}")
print(f"Départements: {info['departements']}")
Gestion des erreurs
Le wrapper utilise des exceptions personnalisées pour gérer différents types d'erreurs :
from atmo_data_wrapper import AtmoDataClient, AtmoDataException
try:
client = AtmoDataClient()
client.auto_login()
indices = client.get_indices_atmo()
except ValueError as e:
print(f"Erreur de validation: {e}")
except AtmoDataException as e:
print(f"Erreur API: {e}")
except Exception as e:
print(f"Erreur inattendue: {e}")
Types d'exceptions disponibles
AtmoDataException
: Exception de baseAuthenticationError
: Erreur d'authentificationValidationError
: Erreur de validation des paramètresAPIError
: Erreur de l'API Atmo DataNetworkError
: Erreur de réseauDataError
: Erreur dans le traitement des données
Validation des paramètres
Le wrapper valide automatiquement tous les paramètres avant d'envoyer les requêtes :
- Formats : Seuls
geojson
etcsv
sont acceptés - Codes AASQA : Validation contre la liste des codes valides (01-94)
- Polluants : Validation contre la liste des polluants supportés
- Dates : Validation du format YYYY-MM-DD et de l'existence de la date
- Indices : Validation des codes qualificatifs ATMO (0-7) et pollen (0-6)
- Bounding box : Validation du format et de la cohérence des coordonnées
Exemple d'erreur de validation :
try:
client.get_indices_atmo(format="xml") # Format invalide
except ValueError as e:
print(e) # "Format invalide: xml. Formats valides: ['geojson', 'csv']"
Sauvegarde des données
Le wrapper permet de sauvegarder facilement les résultats de l'API dans différents formats :
# Récupérer des données
indices = client.get_indices_atmo(aasqa="11")
# Sauvegarder en JSON
json_file = client.save_to_file(indices, "data/indices_atmo", "json")
# Sauvegarder en CSV
csv_file = client.save_to_file(indices, "data/indices_atmo", "csv")
# Sauvegarder en GeoJSON
geojson_file = client.save_to_file(indices, "data/indices_atmo", "geojson")
Formats supportés pour la sauvegarde :
json
- Format JSON standardcsv
- Format CSV avec extraction automatique des propriétésgeojson
- Format GeoJSON (données géographiques)
Fonctionnalités :
- Création automatique de répertoires : Les dossiers parents sont créés si nécessaire
- Extensions automatiques : Les extensions (.json, .csv, .geojson) sont ajoutées automatiquement
- Extraction CSV intelligente : Conversion automatique des données GeoJSON vers CSV avec coordonnées
- Validation des formats : Vérification de la compatibilité des données avec le format choisi
Formats de sortie API
L'API supporte deux formats :
geojson
(par défaut)csv
Tests et Exemples
Scripts d'exemples
example_usage.py
- Exemples d'utilisation des endpoints (données brutes)example_save_files.py
- Exemples de sauvegarde de donnéesexample_data_models.py
- Exemples avec objets typés et méthodes helperexample_aasqa_utilities.py
- Exemples des fonctions utilitaires AASQAexample_aasqa_advanced.py
- Analyses avancées et statistiques AASQAdemo_licence_atmo.py
- Démonstration des fonctions de licenceexample_synthese_tomblaine.py
- Exemple de synthèse complète (Atmo + Pollen)
Scripts de démonstration complète
demo_atmo_functions.py
- Démonstration complète de la classe IndiceAtmodemo_pollen_functions.py
- Démonstration complète de la classe IndicePollendemo_emission_functions.py
- Démonstration complète de la classe EmissionDatademo_episode_functions.py
- Démonstration complète de la classe EpisodePollution
Ces scripts illustrent toutes les fonctionnalités de chaque classe avec des données réelles de l'API. Voir DOCUMENTATION_DEMOS.md
pour une documentation détaillée.
Scripts de test
test_validations.py
- Tests de validation des paramètrestest_save_functionality.py
- Tests de sauvegarde de fichierstest_typed_client.py
- Tests d'intégration des modèles typéstest_real_connection.py
- Test de connexion réelle à l'API
Test de votre configuration
# Vérifier la configuration et tester la connexion
python tests/test_real_connection.py
Ce script vérifie :
- La présence et validité du fichier
credentials.json
- La connexion à l'API
- Le bon fonctionnement des différents endpoints
- Les objets typés et leurs méthodes
Exécution des scripts
# Scripts d'exemples
python examples/example_usage.py
python examples/example_data_models.py
python examples/example_aasqa_utilities.py
python examples/demo_licence_atmo.py
# Scripts de démonstration
python demos/demo_atmo_functions.py
python demos/demo_pollen_functions.py
# Tests
python -m pytest tests/
Nouvelles fonctionnalités
Architecture améliorée
- Séparation des constantes et utilitaires : Les constantes sont dans
constants.py
, les fonctions utilitaires dansutils.py
- Constantes enrichies : Les codes AASQA incluent maintenant sites web et départements
- Mapping des codes : Constantes séparées pour les épisodes de pollution et les taxons de pollens
Fonctions utilitaires AASQA
- Recherche par département ou nom d'organisme
- Statistiques de couverture territoriale
- Validation de l'intégrité des données
- Analyses comparatives entre organismes
Conformité légale
- Fonctions dédiées pour les mentions légales Atmo France
- Respect de la licence ODbL
- Intégration facilitée dans rapports et applications
Organisation du projet
- Dossier
archives/
pour l'historique des anciens scripts - Structure claire et maintenable
- Documentation complète et à jour