You've already forked donnees_meteo
Commit initial
This commit is contained in:
0
scripts/__init__.py
Normal file
0
scripts/__init__.py
Normal file
52
scripts/check_missing_values.py
Normal file
52
scripts/check_missing_values.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# scripts/check_missing_values.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
from meteo.quality import summarize_missing_values
|
||||
|
||||
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
print(" Assurez-vous d'avoir généré le dataset minuté.")
|
||||
return
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
print(f"Dataset chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
print(f" Colonnes : {list(df.columns)}")
|
||||
|
||||
summary = summarize_missing_values(df)
|
||||
|
||||
print()
|
||||
print("=== Synthèse des valeurs manquantes ===")
|
||||
print(f"Total de cellules : {summary.total_cells}")
|
||||
print(f"Cellules manquantes : {summary.missing_cells}")
|
||||
print(f"Fraction manquante : {summary.fraction_missing:.6f}")
|
||||
print(f"Lignes complètes : {summary.rows_fully_complete}")
|
||||
print(f"Lignes avec des trous : {summary.rows_with_missing}")
|
||||
print(f"Fraction lignes complètes : {summary.fraction_rows_complete:.6f}")
|
||||
|
||||
print()
|
||||
print("Valeurs manquantes par colonne :")
|
||||
for col, n_missing in summary.missing_by_column.items():
|
||||
print(f" - {col:13s} : {n_missing}")
|
||||
|
||||
if summary.missing_cells == 0:
|
||||
print()
|
||||
print("✔ Aucune valeur manquante dans le dataset minuté.")
|
||||
else:
|
||||
print()
|
||||
print("⚠ Il reste des valeurs manquantes.")
|
||||
print(" Exemple de lignes concernées :")
|
||||
rows_with_missing = df[df.isna().any(axis=1)]
|
||||
print(rows_with_missing.head(10))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
61
scripts/describe_minutely_dataset.py
Normal file
61
scripts/describe_minutely_dataset.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# scripts/describe_minutely_dataset.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
|
||||
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
print(" Assurez-vous d'avoir généré le dataset minuté.")
|
||||
return
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
print(f"Dataset minuté chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
print(f" Colonnes : {list(df.columns)}")
|
||||
print(f" Période : {df.index[0]} → {df.index[-1]}")
|
||||
print()
|
||||
|
||||
# 1. Résumé statistique classique
|
||||
print("=== describe() ===")
|
||||
print(df.describe())
|
||||
print()
|
||||
|
||||
# 2. Min / max par variable avec leurs dates
|
||||
print("=== Min / max avec dates ===")
|
||||
for col in df.columns:
|
||||
series = df[col]
|
||||
|
||||
min_val = series.min()
|
||||
max_val = series.max()
|
||||
min_ts = series.idxmin()
|
||||
max_ts = series.idxmax()
|
||||
|
||||
print(f"- {col}:")
|
||||
print(f" min = {min_val} à {min_ts}")
|
||||
print(f" max = {max_val} à {max_ts}")
|
||||
print()
|
||||
|
||||
# 3. Vérification rapide de la continuité temporelle
|
||||
print("=== Vérification de la continuité temporelle ===")
|
||||
diffs = df.index.to_series().diff().dropna()
|
||||
counts = diffs.value_counts().sort_index()
|
||||
|
||||
print("Différences d'intervalle (top 5):")
|
||||
print(counts.head())
|
||||
print()
|
||||
|
||||
nb_not_60s = (diffs != pd.Timedelta(minutes=1)).sum()
|
||||
print(f"Nombre d'intervalles ≠ 60s : {nb_not_60s}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
44
scripts/export_station_data.py
Normal file
44
scripts/export_station_data.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# tests/export_station_data.py
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import closing
|
||||
|
||||
from meteo.config import InfluxSettings
|
||||
from meteo.influx_client import create_influx_client
|
||||
from meteo.station_config import default_station_config
|
||||
from meteo.export import export_station_data
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""
|
||||
Exporte les données de la station météo vers un fichier CSV brut.
|
||||
|
||||
Par défaut, on exporte les 7 derniers jours dans `data/weather_raw_7d.csv`.
|
||||
"""
|
||||
settings = InfluxSettings.from_env()
|
||||
station_config = default_station_config()
|
||||
|
||||
print("Configuration InfluxDB :")
|
||||
print(f" URL : {settings.url}")
|
||||
print(f" Org : {settings.org}")
|
||||
print(f" Bucket : {settings.bucket}")
|
||||
print()
|
||||
|
||||
with closing(create_influx_client(settings)) as client:
|
||||
print("→ Export des 7 derniers jours…")
|
||||
output_path = export_station_data(
|
||||
client=client,
|
||||
bucket=settings.bucket,
|
||||
config=station_config,
|
||||
start="-7d", # à ajuster plus tard si besoin
|
||||
stop=None, # now()
|
||||
output_path="data/weather_raw_7d.csv",
|
||||
file_format="csv",
|
||||
)
|
||||
|
||||
print()
|
||||
print(f"✔ Export terminé : {output_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
49
scripts/export_station_data_full.py
Normal file
49
scripts/export_station_data_full.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# tests/export_station_data_full.py
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import closing
|
||||
|
||||
from meteo.config import InfluxSettings
|
||||
from meteo.influx_client import create_influx_client
|
||||
from meteo.station_config import default_station_config
|
||||
from meteo.export import export_station_data
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""
|
||||
Exporte l'historique complet de la station météo vers un fichier CSV.
|
||||
|
||||
On utilise `start=0`, ce qui signifie "depuis le début des données"
|
||||
(en pratique depuis l'epoch, donc tout ce que le bucket contient).
|
||||
"""
|
||||
settings = InfluxSettings.from_env()
|
||||
station_config = default_station_config()
|
||||
|
||||
print("Configuration InfluxDB :")
|
||||
print(f" URL : {settings.url}")
|
||||
print(f" Org : {settings.org}")
|
||||
print(f" Bucket : {settings.bucket}")
|
||||
print()
|
||||
|
||||
print("⚠ Attention : un export complet peut produire un fichier volumineux "
|
||||
"et prendre un certain temps si l'historique est long.")
|
||||
print()
|
||||
|
||||
with closing(create_influx_client(settings)) as client:
|
||||
print("→ Export de l'historique complet…")
|
||||
output_path = export_station_data(
|
||||
client=client,
|
||||
bucket=settings.bucket,
|
||||
config=station_config,
|
||||
start="0", # depuis le début des données
|
||||
stop=None, # jusqu'à maintenant
|
||||
output_path="data/weather_raw_full.csv",
|
||||
file_format="csv", # vous pouvez mettre "parquet" si vous préférez
|
||||
)
|
||||
|
||||
print()
|
||||
print(f"✔ Export terminé : {output_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
32
scripts/fill_formatted_1s.py
Normal file
32
scripts/fill_formatted_1s.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# scripts/fill_formatted_1s.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from meteo.dataset import load_raw_csv, fill_missing_with_previous
|
||||
|
||||
|
||||
INPUT_CSV_PATH = Path("data/weather_formatted_1s.csv")
|
||||
OUTPUT_CSV_PATH = Path("data/weather_filled_1s.csv")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not INPUT_CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {INPUT_CSV_PATH}")
|
||||
print(" Lancez d'abord : python -m scripts.format_raw_csv")
|
||||
return
|
||||
|
||||
df_1s = load_raw_csv(INPUT_CSV_PATH)
|
||||
print(f"Fichier 1s formaté chargé : {INPUT_CSV_PATH}")
|
||||
print(f" Lignes : {len(df_1s)}, colonnes : {list(df_1s.columns)}")
|
||||
|
||||
df_filled = fill_missing_with_previous(df_1s)
|
||||
print(f"Après propagation des dernières valeurs connues : {len(df_filled)} lignes")
|
||||
|
||||
OUTPUT_CSV_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
df_filled.to_csv(OUTPUT_CSV_PATH, index_label="time")
|
||||
print(f"✔ Fichier 1s 'complet' écrit dans : {OUTPUT_CSV_PATH.resolve()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
31
scripts/format_raw_csv.py
Normal file
31
scripts/format_raw_csv.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from meteo.dataset import load_raw_csv, combine_close_observations
|
||||
|
||||
|
||||
RAW_CSV_PATH = Path("data/weather_raw_full.csv")
|
||||
OUTPUT_CSV_PATH = Path("data/weather_formatted_1s.csv")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not RAW_CSV_PATH.exists():
|
||||
print(f"⚠ Fichier brut introuvable : {RAW_CSV_PATH}")
|
||||
return
|
||||
|
||||
df_raw = load_raw_csv(RAW_CSV_PATH)
|
||||
print(f"Fichier brut chargé : {RAW_CSV_PATH}")
|
||||
print(f" Lignes : {len(df_raw)}, colonnes : {list(df_raw.columns)}")
|
||||
print(f" Type d'index : {type(df_raw.index)}")
|
||||
|
||||
df_fmt = combine_close_observations(df_raw, freq="1s", agg="mean")
|
||||
print(f"Après combinaison (1s) : {len(df_fmt)} lignes")
|
||||
|
||||
OUTPUT_CSV_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
df_fmt.to_csv(OUTPUT_CSV_PATH, index_label="time")
|
||||
print(f"✔ Fichier formaté écrit dans : {OUTPUT_CSV_PATH.resolve()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
29
scripts/inspect_time_column.py
Normal file
29
scripts/inspect_time_column.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# scripts/inspect_time_column.py
|
||||
from __future__ import annotations
|
||||
|
||||
import pandas as pd
|
||||
from pathlib import Path
|
||||
|
||||
CSV_PATH = Path("data/weather_raw_full.csv")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
df = pd.read_csv(CSV_PATH, dtype={"time": "string"})
|
||||
print("Aperçu brut de la colonne 'time' :")
|
||||
print(df["time"].head(10))
|
||||
print()
|
||||
|
||||
# On tente de parser en ISO8601, mais sans lever d'erreur :
|
||||
parsed = pd.to_datetime(df["time"], format="ISO8601", errors="coerce")
|
||||
|
||||
invalid_mask = parsed.isna()
|
||||
nb_invalid = invalid_mask.sum()
|
||||
|
||||
print(f"Nombre de valeurs 'time' non parsables en ISO8601 : {nb_invalid}")
|
||||
if nb_invalid > 0:
|
||||
print("Exemples de valeurs problématiques :")
|
||||
print(df.loc[invalid_mask, "time"].drop_duplicates().head(20))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
46
scripts/list_time_gaps.py
Normal file
46
scripts/list_time_gaps.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# scripts/list_time_gaps.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
from meteo.gaps import find_time_gaps
|
||||
|
||||
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
return
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
print(f"Dataset minuté chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
|
||||
gaps = find_time_gaps(df)
|
||||
total_missing = sum(g.missing_intervals for g in gaps)
|
||||
|
||||
print()
|
||||
print("=== Gaps temporels détectés ===")
|
||||
print(f"Nombre de gaps : {len(gaps)}")
|
||||
print(f"Total minutes manquantes (théoriques) : {total_missing}")
|
||||
print()
|
||||
|
||||
if not gaps:
|
||||
print("✔ Aucun gap détecté, la série est parfaitement régulière.")
|
||||
return
|
||||
|
||||
print("Top 10 des gaps les plus longs :")
|
||||
gaps_sorted = sorted(gaps, key=lambda g: g.missing_intervals, reverse=True)[:10]
|
||||
for g in gaps_sorted:
|
||||
print(
|
||||
f"- De {g.before} à {g.after} "
|
||||
f"(durée: {g.duration}, manquants: {g.missing_intervals}, "
|
||||
f"de {g.missing_start} à {g.missing_end})"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
32
scripts/make_minutely_dataset.py
Normal file
32
scripts/make_minutely_dataset.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# scripts/make_minutely_dataset.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from meteo.dataset import load_raw_csv, resample_to_minutes
|
||||
|
||||
|
||||
FORMATTED_CSV_PATH = Path("data/weather_filled_1s.csv")
|
||||
OUTPUT_CSV_PATH = Path("data/weather_minutely.csv")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not FORMATTED_CSV_PATH.exists():
|
||||
print(f"⚠ Fichier formaté introuvable : {FORMATTED_CSV_PATH}")
|
||||
print(" Lancez d'abord : python -m scripts.format_raw_csv")
|
||||
return
|
||||
|
||||
df_1s = load_raw_csv(FORMATTED_CSV_PATH)
|
||||
print(f"Fichier 1s chargé : {FORMATTED_CSV_PATH}")
|
||||
print(f" Lignes : {len(df_1s)}, colonnes : {list(df_1s.columns)}")
|
||||
|
||||
df_min = resample_to_minutes(df_1s)
|
||||
print(f"Après resampling 60s : {len(df_min)} lignes")
|
||||
|
||||
OUTPUT_CSV_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
df_min.to_csv(OUTPUT_CSV_PATH, index_label="time")
|
||||
print(f"✔ Dataset minuté écrit dans : {OUTPUT_CSV_PATH.resolve()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
65
scripts/plot_temperature.py
Normal file
65
scripts/plot_temperature.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# scripts/plot_temperature.py
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from datetime import timedelta
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
|
||||
|
||||
CSV_PATH = Path("data/weather_minutely.csv")
|
||||
OUTPUT_DIR = Path("figures")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
print(" Assurez-vous d'avoir généré le dataset minuté.")
|
||||
return
|
||||
|
||||
# Chargement du dataset minuté
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
print(f"Dataset minuté chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
print(f" Colonnes : {list(df.columns)}")
|
||||
print(f" Période : {df.index[0]} → {df.index[-1]}")
|
||||
print()
|
||||
|
||||
# On ne garde que les N derniers jours pour un premier graphique
|
||||
last_n_days = 7
|
||||
end = df.index.max()
|
||||
start = end - pd.Timedelta(days=last_n_days)
|
||||
df_slice = df.loc[start:end]
|
||||
|
||||
if df_slice.empty:
|
||||
print("⚠ Aucun point dans l'intervalle choisi.")
|
||||
return
|
||||
|
||||
# Moyenne horaire pour lisser un peu la courbe
|
||||
df_hourly = df_slice.resample("1H").mean()
|
||||
|
||||
print(f"Intervalle tracé : {df_hourly.index[0]} → {df_hourly.index[-1]}")
|
||||
print(f"Nombre de points (moyenne horaire) : {len(df_hourly)}")
|
||||
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
output_path = OUTPUT_DIR / "temperature_last_7_days.png"
|
||||
|
||||
plt.figure()
|
||||
plt.plot(df_hourly.index, df_hourly["temperature"])
|
||||
plt.xlabel("Temps (UTC)")
|
||||
plt.ylabel("Température (°C)")
|
||||
plt.title("Température - Moyenne horaire sur les 7 derniers jours")
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.savefig(output_path, dpi=150)
|
||||
print(f"✔ Figure sauvegardée dans : {output_path.resolve()}")
|
||||
|
||||
# Optionnel : afficher la fenêtre graphique si vous lancez ça depuis un environnement graphique
|
||||
# plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
61
scripts/test_influx_connection.py
Normal file
61
scripts/test_influx_connection.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# tests/test_influx_connection.py
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import closing
|
||||
|
||||
from influxdb_client.client.exceptions import InfluxDBError
|
||||
|
||||
from meteo.config import InfluxSettings
|
||||
from meteo.influx_client import create_influx_client, test_basic_query
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""
|
||||
Teste la communication avec le serveur InfluxDB :
|
||||
|
||||
1. Chargement de la configuration depuis l'environnement.
|
||||
2. Ping du serveur.
|
||||
3. Exécution d'une requête simple sur le bucket configuré.
|
||||
"""
|
||||
settings = InfluxSettings.from_env()
|
||||
|
||||
print("Configuration InfluxDB chargée :")
|
||||
print(f" URL : {settings.url}")
|
||||
print(f" Org : {settings.org}")
|
||||
print(f" Bucket : {settings.bucket}")
|
||||
print()
|
||||
|
||||
# Utilisation de `closing` pour garantir la fermeture du client.
|
||||
with closing(create_influx_client(settings)) as client:
|
||||
print("→ Ping du serveur InfluxDB…")
|
||||
if not client.ping():
|
||||
raise SystemExit("Échec du ping InfluxDB. Vérifiez l'URL et l'état du serveur.")
|
||||
|
||||
print("✔ Ping OK")
|
||||
print("→ Requête de test sur le bucket…")
|
||||
|
||||
try:
|
||||
tables = test_basic_query(client, settings.bucket)
|
||||
except InfluxDBError as exc:
|
||||
raise SystemExit(f"Erreur lors de la requête Flux : {exc}") from exc
|
||||
|
||||
# On fait un retour synthétique
|
||||
nb_tables = len(tables)
|
||||
nb_records = sum(len(table.records) for table in tables)
|
||||
print(f"✔ Requête de test réussie : {nb_tables} table(s), {nb_records} enregistrement(s) trouvés.")
|
||||
|
||||
if nb_records == 0:
|
||||
print("⚠ Le bucket est accessible, mais aucune donnée sur la dernière heure.")
|
||||
else:
|
||||
# Affiche un aperçu de la première table / premier record
|
||||
first_table = tables[0]
|
||||
first_record = first_table.records[0]
|
||||
print("Exemple de point :")
|
||||
print(f" time : {first_record.get_time()}")
|
||||
print(f" measurement : {first_record.get_measurement()}")
|
||||
print(f" field : {first_record.get_field()}")
|
||||
print(f" value : {first_record.get_value()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
61
scripts/test_influx_entities.py
Normal file
61
scripts/test_influx_entities.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# tests/test_influx_entities.py
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import closing
|
||||
|
||||
from meteo.config import InfluxSettings
|
||||
from meteo.influx_client import create_influx_client
|
||||
from meteo.schema import (
|
||||
list_measurements,
|
||||
list_measurement_tag_keys,
|
||||
list_measurement_tag_values,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""
|
||||
Explore les tags des measurements du bucket :
|
||||
|
||||
- affiche les keys de tags pour chaque measurement
|
||||
- si un tag `entity_id` est présent, affiche la liste de ses valeurs
|
||||
"""
|
||||
settings = InfluxSettings.from_env()
|
||||
|
||||
print(f"Bucket InfluxDB : {settings.bucket}")
|
||||
print()
|
||||
|
||||
with closing(create_influx_client(settings)) as client:
|
||||
measurements = list_measurements(client, settings.bucket)
|
||||
|
||||
if not measurements:
|
||||
print("⚠ Aucun measurement trouvé dans ce bucket.")
|
||||
return
|
||||
|
||||
for meas in measurements:
|
||||
print(f"Measurement « {meas} »")
|
||||
tag_keys = list_measurement_tag_keys(client, settings.bucket, meas)
|
||||
if not tag_keys:
|
||||
print(" (aucun tag trouvé)")
|
||||
print()
|
||||
continue
|
||||
|
||||
print(" Tag keys :")
|
||||
for key in tag_keys:
|
||||
print(f" - {key}")
|
||||
|
||||
if "entity_id" in tag_keys:
|
||||
entity_ids = list_measurement_tag_values(
|
||||
client,
|
||||
settings.bucket,
|
||||
meas,
|
||||
tag="entity_id",
|
||||
)
|
||||
print(" entity_id possibles :")
|
||||
for eid in entity_ids:
|
||||
print(f" - {eid}")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
47
scripts/test_influx_schema.py
Normal file
47
scripts/test_influx_schema.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# tests/test_influx_schema.py
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import closing
|
||||
|
||||
from meteo.config import InfluxSettings
|
||||
from meteo.influx_client import create_influx_client
|
||||
from meteo.schema import list_measurements, list_measurement_fields
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""
|
||||
Explore le schéma du bucket InfluxDB configuré :
|
||||
|
||||
- liste des measurements disponibles
|
||||
- pour chacun, liste des champs (_field) et de leur type
|
||||
"""
|
||||
settings = InfluxSettings.from_env()
|
||||
|
||||
print(f"Bucket InfluxDB : {settings.bucket}")
|
||||
print()
|
||||
|
||||
with closing(create_influx_client(settings)) as client:
|
||||
measurements = list_measurements(client, settings.bucket)
|
||||
|
||||
if not measurements:
|
||||
print("⚠ Aucun measurement trouvé dans ce bucket.")
|
||||
return
|
||||
|
||||
print("Measurements disponibles :")
|
||||
for name in measurements:
|
||||
print(f" - {name}")
|
||||
print()
|
||||
|
||||
for name in measurements:
|
||||
print(f"Champs pour measurement « {name} » :")
|
||||
fields = list_measurement_fields(client, settings.bucket, name)
|
||||
if not fields:
|
||||
print(" (aucun champ trouvé)")
|
||||
else:
|
||||
for field in fields:
|
||||
print(f" - {field.name} (type: {field.type})")
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user