Add drift_analysis/src/drift_analysis/core.py
This commit is contained in:
commit
7854afa614
1 changed files with 108 additions and 0 deletions
108
drift_analysis/src/drift_analysis/core.py
Normal file
108
drift_analysis/src/drift_analysis/core.py
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import List, Tuple, Dict
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FrozenRun:
|
||||||
|
"""Datenmodell für einen einzelnen Frozen-Run."""
|
||||||
|
run_id: str
|
||||||
|
status: str
|
||||||
|
is_pinned: bool
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if not isinstance(self.run_id, str):
|
||||||
|
raise ValueError("run_id muss ein String sein")
|
||||||
|
if not isinstance(self.status, str):
|
||||||
|
raise ValueError("status muss ein String sein")
|
||||||
|
if not isinstance(self.is_pinned, bool):
|
||||||
|
raise ValueError("is_pinned muss ein bool sein")
|
||||||
|
|
||||||
|
|
||||||
|
def load_frozen_runs(path: str) -> List[FrozenRun]:
|
||||||
|
"""Lädt FrozenRun-Daten aus einer JSON-Datei und validiert sie."""
|
||||||
|
file_path = Path(path)
|
||||||
|
if not file_path.exists() or not file_path.is_file():
|
||||||
|
raise FileNotFoundError(f"Datei nicht gefunden: {path}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with file_path.open('r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
raise ValueError(f"Ungültiges JSON-Format in {path}: {e}") from e
|
||||||
|
|
||||||
|
if not isinstance(data, list):
|
||||||
|
raise ValueError("Eingabedatei muss eine Liste von Objekten enthalten")
|
||||||
|
|
||||||
|
runs = []
|
||||||
|
for entry in data:
|
||||||
|
try:
|
||||||
|
run = FrozenRun(
|
||||||
|
run_id=entry["run_id"],
|
||||||
|
status=entry["status"],
|
||||||
|
is_pinned=entry["is_pinned"]
|
||||||
|
)
|
||||||
|
runs.append(run)
|
||||||
|
except KeyError as e:
|
||||||
|
raise ValueError(f"Fehlendes Feld in Eintrag: {e}") from e
|
||||||
|
except ValueError as e:
|
||||||
|
raise ValueError(f"Ungültiger Eintrag: {e}") from e
|
||||||
|
|
||||||
|
return runs
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_warn_rate(frozen_runs: List[FrozenRun], threshold: float) -> Tuple[int, int]:
|
||||||
|
"""Berechnet die Anzahl der WARN-Ergebnisse und Gesamtanzahl."""
|
||||||
|
if not isinstance(threshold, (float, int)):
|
||||||
|
raise ValueError("threshold muss eine Zahl sein")
|
||||||
|
|
||||||
|
total_runs = len(frozen_runs)
|
||||||
|
warn_count = sum(1 for run in frozen_runs if run.status.upper() == "WARN")
|
||||||
|
|
||||||
|
return warn_count, total_runs
|
||||||
|
|
||||||
|
|
||||||
|
def generate_report(warn_count: int, total_runs: int, threshold: float) -> Dict[str, object]:
|
||||||
|
"""Erzeugt einen Bericht über Warnquote und Bewertung im JSON-Format."""
|
||||||
|
if total_runs <= 0:
|
||||||
|
warn_rate = 0.0
|
||||||
|
else:
|
||||||
|
warn_rate = warn_count / total_runs
|
||||||
|
|
||||||
|
status = "OK" if warn_rate <= threshold else "WARN"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"warn_rate": round(warn_rate, 4),
|
||||||
|
"threshold": threshold,
|
||||||
|
"status": status,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Analyse der Warnquote bei Drift-Checks.")
|
||||||
|
parser.add_argument("--input", required=True, help="Pfad zur JSON-Datei mit Frozen-Runs")
|
||||||
|
parser.add_argument("--threshold", type=float, default=0.3, help="Warnschwelle für Drift-Erkennung")
|
||||||
|
parser.add_argument("--output", default="output/report.json", help="Ausgabedatei für den JSON-Report")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
frozen_runs = load_frozen_runs(args.input)
|
||||||
|
warn_count, total_runs = calculate_warn_rate(frozen_runs, args.threshold)
|
||||||
|
report = generate_report(warn_count, total_runs, args.threshold)
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(args.output), exist_ok=True)
|
||||||
|
with open(args.output, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(report, f, indent=2)
|
||||||
|
|
||||||
|
print(json.dumps(report, indent=2))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler: {e}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in a new issue