461 lines
17 KiB
Python
461 lines
17 KiB
Python
#!/usr/bin/env python3
|
|||
|
|
"""
|
||
|
|
CSV-Validator für Lotto 6aus49 und Eurojackpot
|
||
|
|
|
||
|
|
Validiert CSV-Dateien auf:
|
||
|
|
- Korrekte Spaltenstruktur
|
||
|
|
- Datumformat und -konsistenz
|
||
|
|
- Zahlenbereich und Eindeutigkeit
|
||
|
|
- Wochentag (nur Mi/Sa für Lotto, nur Di/Fr für Eurojackpot)
|
||
|
|
- Chronologische Sortierung
|
||
|
|
- Duplikate
|
||
|
|
- Fehlende Werte
|
||
|
|
- Zukunftsdaten
|
||
|
|
"""
|
||
|
|
|
||
|
|
import pandas as pd
|
||
|
|
from datetime import datetime
|
||
|
|
import sys
|
||
|
|
import os
|
||
|
|
from typing import List, Dict, Tuple
|
||
|
|
|
||
|
|
|
||
|
|
class LottoCSVValidator:
|
||
|
|
"""Validator für Lotto 6aus49 CSV-Dateien."""
|
||
|
|
|
||
|
|
def __init__(self, csv_file: str):
|
||
|
|
self.csv_file = csv_file
|
||
|
|
self.df = None
|
||
|
|
self.errors = []
|
||
|
|
self.warnings = []
|
||
|
|
self.lottery_type = self._detect_lottery_type()
|
||
|
|
|
||
|
|
def _detect_lottery_type(self) -> str:
|
||
|
|
"""Erkennt ob Lotto oder Eurojackpot basierend auf Dateiname."""
|
||
|
|
basename = os.path.basename(self.csv_file).lower()
|
||
|
|
if 'eurojackpot' in basename:
|
||
|
|
return 'eurojackpot'
|
||
|
|
elif 'lotto' in basename:
|
||
|
|
return 'lotto'
|
||
|
|
else:
|
||
|
|
# Versuche anhand der Spalten zu erkennen
|
||
|
|
return 'unknown'
|
||
|
|
|
||
|
|
def load_csv(self) -> bool:
|
||
|
|
"""Lädt CSV-Datei."""
|
||
|
|
try:
|
||
|
|
if not os.path.exists(self.csv_file):
|
||
|
|
self.errors.append(f"❌ Datei existiert nicht: {self.csv_file}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
self.df = pd.read_csv(self.csv_file, sep=';')
|
||
|
|
|
||
|
|
# Auto-detect wenn noch unknown
|
||
|
|
if self.lottery_type == 'unknown':
|
||
|
|
if 'SZ2' in self.df.columns:
|
||
|
|
self.lottery_type = 'eurojackpot'
|
||
|
|
elif 'SZ' in self.df.columns:
|
||
|
|
self.lottery_type = 'lotto'
|
||
|
|
else:
|
||
|
|
self.errors.append("❌ Kann Lottery-Typ nicht erkennen")
|
||
|
|
return False
|
||
|
|
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.errors.append(f"❌ Fehler beim Laden: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
def validate_structure(self) -> bool:
|
||
|
|
"""Validiert Spaltenstruktur."""
|
||
|
|
if self.lottery_type == 'lotto':
|
||
|
|
expected_cols = ['datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'Z6', 'SZ']
|
||
|
|
elif self.lottery_type == 'eurojackpot':
|
||
|
|
expected_cols = ['datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'SZ1', 'SZ2']
|
||
|
|
else:
|
||
|
|
self.errors.append("❌ Unbekannter Lottery-Typ")
|
||
|
|
return False
|
||
|
|
|
||
|
|
actual_cols = list(self.df.columns)
|
||
|
|
|
||
|
|
if actual_cols != expected_cols:
|
||
|
|
self.errors.append(f"❌ Spaltenstruktur falsch")
|
||
|
|
self.errors.append(f" Erwartet: {expected_cols}")
|
||
|
|
self.errors.append(f" Gefunden: {actual_cols}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
return True
|
||
|
|
|
||
|
|
def validate_dates(self) -> bool:
|
||
|
|
"""Validiert Datumsspalte."""
|
||
|
|
valid = True
|
||
|
|
|
||
|
|
# Prüfe auf leere Daten
|
||
|
|
empty_dates = self.df[self.df['datum'].isna() | (self.df['datum'] == '')]
|
||
|
|
if len(empty_dates) > 0:
|
||
|
|
self.errors.append(f"❌ {len(empty_dates)} Zeile(n) mit fehlendem Datum:")
|
||
|
|
for idx in empty_dates.index[:5]: # Zeige max 5
|
||
|
|
self.errors.append(f" Zeile {idx + 2}")
|
||
|
|
if len(empty_dates) > 5:
|
||
|
|
self.errors.append(f" ... und {len(empty_dates) - 5} weitere")
|
||
|
|
valid = False
|
||
|
|
|
||
|
|
# Konvertiere Datum
|
||
|
|
try:
|
||
|
|
self.df['datum'] = pd.to_datetime(self.df['datum'], format='%Y-%m-%d', errors='coerce')
|
||
|
|
except Exception as e:
|
||
|
|
self.errors.append(f"❌ Fehler beim Parsen der Datumsangaben: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
# Prüfe auf ungültige Datumsangaben
|
||
|
|
invalid_dates = self.df[self.df['datum'].isna()]
|
||
|
|
if len(invalid_dates) > 0:
|
||
|
|
self.errors.append(f"❌ {len(invalid_dates)} ungültige Datumsangaben")
|
||
|
|
valid = False
|
||
|
|
|
||
|
|
# Prüfe auf Zukunftsdaten
|
||
|
|
today = datetime.now()
|
||
|
|
future_dates = self.df[self.df['datum'] > today]
|
||
|
|
if len(future_dates) > 0:
|
||
|
|
self.errors.append(f"❌ {len(future_dates)} Datum/Daten in der Zukunft:")
|
||
|
|
for idx, row in future_dates.iterrows():
|
||
|
|
self.errors.append(f" Zeile {idx + 2}: {row['datum'].strftime('%Y-%m-%d')}")
|
||
|
|
valid = False
|
||
|
|
|
||
|
|
# Prüfe Wochentage
|
||
|
|
if self.lottery_type == 'lotto':
|
||
|
|
# Historisch:
|
||
|
|
# 1955-1965: Sonntags (und manchmal Montags bei Feiertagen)
|
||
|
|
# 1965-2000: Samstags
|
||
|
|
# Ab 2000: Mittwoch + Samstag
|
||
|
|
weekday_names = {0: 'Mo', 1: 'Di', 2: 'Mi', 3: 'Do', 4: 'Fr', 5: 'Sa', 6: 'So'}
|
||
|
|
else: # eurojackpot
|
||
|
|
# Eurojackpot: Dienstag + Freitag
|
||
|
|
weekday_names = {0: 'Mo', 1: 'Di', 2: 'Mi', 3: 'Do', 4: 'Fr', 5: 'Sa', 6: 'So'}
|
||
|
|
|
||
|
|
wrong_weekdays = []
|
||
|
|
for idx, row in self.df.iterrows():
|
||
|
|
if pd.notna(row['datum']):
|
||
|
|
weekday = row['datum'].weekday()
|
||
|
|
date = row['datum']
|
||
|
|
|
||
|
|
if self.lottery_type == 'lotto':
|
||
|
|
# Lotto: Historische Regeln
|
||
|
|
if date < datetime(1965, 9, 1):
|
||
|
|
# Bis Aug 1965: Sonntag (und Montag bei Feiertagen)
|
||
|
|
if weekday not in [0, 6]: # Mo, So
|
||
|
|
wrong_weekdays.append((idx, date))
|
||
|
|
elif date < datetime(2000, 12, 1):
|
||
|
|
# Sep 1965 - Nov 2000: Nur Samstag
|
||
|
|
if weekday != 5: # Sa
|
||
|
|
wrong_weekdays.append((idx, date))
|
||
|
|
else:
|
||
|
|
# Ab Dez 2000: Mittwoch + Samstag
|
||
|
|
if weekday not in [2, 5]: # Mi, Sa
|
||
|
|
wrong_weekdays.append((idx, date))
|
||
|
|
else:
|
||
|
|
# Eurojackpot: Dienstag + Freitag
|
||
|
|
if weekday not in [1, 4]: # Di, Fr
|
||
|
|
wrong_weekdays.append((idx, date))
|
||
|
|
|
||
|
|
if len(wrong_weekdays) > 0:
|
||
|
|
# Filtere mögliche Feiertags-Sonderziehungen (< 5 pro Zeitraum = OK)
|
||
|
|
if len(wrong_weekdays) <= 5:
|
||
|
|
self.warnings.append(f"⚠️ {len(wrong_weekdays)} Ziehung(en) am ungewöhnlichen Wochentag (möglicherweise Feiertage):")
|
||
|
|
for idx, date in wrong_weekdays:
|
||
|
|
weekday_name = weekday_names[date.weekday()]
|
||
|
|
self.warnings.append(f" Zeile {idx + 2}: {date.strftime('%Y-%m-%d')} ({weekday_name})")
|
||
|
|
else:
|
||
|
|
self.errors.append(f"❌ {len(wrong_weekdays)} Ziehung(en) am falschen Wochentag:")
|
||
|
|
for idx, date in wrong_weekdays[:5]:
|
||
|
|
weekday_name = weekday_names[date.weekday()]
|
||
|
|
self.errors.append(f" Zeile {idx + 2}: {date.strftime('%Y-%m-%d')} ({weekday_name})")
|
||
|
|
if len(wrong_weekdays) > 5:
|
||
|
|
self.errors.append(f" ... und {len(wrong_weekdays) - 5} weitere")
|
||
|
|
valid = False
|
||
|
|
|
||
|
|
return valid
|
||
|
|
|
||
|
|
def validate_numbers(self) -> bool:
|
||
|
|
"""Validiert Zahlenwerte."""
|
||
|
|
valid = True
|
||
|
|
|
||
|
|
if self.lottery_type == 'lotto':
|
||
|
|
main_cols = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'Z6']
|
||
|
|
main_range = (1, 49)
|
||
|
|
sz_cols = ['SZ']
|
||
|
|
sz_range = (0, 9)
|
||
|
|
else: # eurojackpot
|
||
|
|
main_cols = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5']
|
||
|
|
main_range = (1, 50)
|
||
|
|
sz_cols = ['SZ1', 'SZ2']
|
||
|
|
sz_range = (1, 12)
|
||
|
|
|
||
|
|
# Prüfe Hauptzahlen
|
||
|
|
for col in main_cols:
|
||
|
|
# Fehlende Werte
|
||
|
|
missing = self.df[self.df[col].isna()]
|
||
|
|
if len(missing) > 0:
|
||
|
|
self.errors.append(f"❌ {len(missing)} fehlende Werte in Spalte {col}")
|
||
|
|
valid = False
|
||
|
|
|
||
|
|
# Zahlenbereich
|
||
|
|
out_of_range = self.df[
|
||
|
|
(self.df[col] < main_range[0]) |
|
||
|
|
(self.df[col] > main_range[1])
|
||
|
|
]
|
||
|
|
if len(out_of_range) > 0:
|
||
|
|
self.errors.append(f"❌ {len(out_of_range)} Werte außerhalb {main_range} in {col}")
|
||
|
|
for idx, row in out_of_range.head(3).iterrows():
|
||
|
|
self.errors.append(f" Zeile {idx + 2}: {row[col]}")
|
||
|
|
valid = False
|
||
|
|
|
||
|
|
# Prüfe Superzahl(en)
|
||
|
|
for col in sz_cols:
|
||
|
|
missing = self.df[self.df[col].isna()]
|
||
|
|
if len(missing) > 0:
|
||
|
|
self.warnings.append(f"⚠️ {len(missing)} fehlende Werte in Spalte {col}")
|
||
|
|
|
||
|
|
out_of_range = self.df[
|
||
|
|
(self.df[col] < sz_range[0]) |
|
||
|
|
(self.df[col] > sz_range[1])
|
||
|
|
]
|
||
|
|
if len(out_of_range) > 0:
|
||
|
|
self.errors.append(f"❌ {len(out_of_range)} Werte außerhalb {sz_range} in {col}")
|
||
|
|
valid = False
|
||
|
|
|
||
|
|
# Prüfe Eindeutigkeit der Hauptzahlen pro Zeile
|
||
|
|
duplicate_numbers = []
|
||
|
|
for idx, row in self.df.iterrows():
|
||
|
|
main_numbers = [row[col] for col in main_cols if pd.notna(row[col])]
|
||
|
|
if len(main_numbers) != len(set(main_numbers)):
|
||
|
|
duplicate_numbers.append((idx, main_numbers))
|
||
|
|
|
||
|
|
if len(duplicate_numbers) > 0:
|
||
|
|
self.errors.append(f"❌ {len(duplicate_numbers)} Zeile(n) mit doppelten Hauptzahlen:")
|
||
|
|
for idx, numbers in duplicate_numbers[:5]:
|
||
|
|
self.errors.append(f" Zeile {idx + 2}: {numbers}")
|
||
|
|
if len(duplicate_numbers) > 5:
|
||
|
|
self.errors.append(f" ... und {len(duplicate_numbers) - 5} weitere")
|
||
|
|
valid = False
|
||
|
|
|
||
|
|
# Prüfe Sortierung der Hauptzahlen pro Zeile
|
||
|
|
unsorted_rows = []
|
||
|
|
for idx, row in self.df.iterrows():
|
||
|
|
main_numbers = [row[col] for col in main_cols if pd.notna(row[col])]
|
||
|
|
if main_numbers != sorted(main_numbers):
|
||
|
|
unsorted_rows.append((idx, main_numbers))
|
||
|
|
|
||
|
|
if len(unsorted_rows) > 0:
|
||
|
|
self.warnings.append(f"⚠️ {len(unsorted_rows)} Zeile(n) mit unsortierten Zahlen:")
|
||
|
|
for idx, numbers in unsorted_rows[:3]:
|
||
|
|
self.warnings.append(f" Zeile {idx + 2}: {numbers}")
|
||
|
|
|
||
|
|
# Prüfe Sortierung der Eurozahlen (nur Eurojackpot)
|
||
|
|
if self.lottery_type == 'eurojackpot':
|
||
|
|
unsorted_euro = []
|
||
|
|
for idx, row in self.df.iterrows():
|
||
|
|
if pd.notna(row['SZ1']) and pd.notna(row['SZ2']):
|
||
|
|
if row['SZ1'] > row['SZ2']:
|
||
|
|
unsorted_euro.append((idx, row['SZ1'], row['SZ2']))
|
||
|
|
|
||
|
|
if len(unsorted_euro) > 0:
|
||
|
|
self.warnings.append(f"⚠️ {len(unsorted_euro)} Zeile(n) mit unsortierten Eurozahlen")
|
||
|
|
|
||
|
|
return valid
|
||
|
|
|
||
|
|
def validate_duplicates(self) -> bool:
|
||
|
|
"""Prüft auf doppelte Datumssätze."""
|
||
|
|
duplicates = self.df[self.df.duplicated(subset=['datum'], keep=False)]
|
||
|
|
|
||
|
|
if len(duplicates) > 0:
|
||
|
|
self.errors.append(f"❌ {len(duplicates)} doppelte Datumseinträge gefunden:")
|
||
|
|
for idx, row in duplicates.head(5).iterrows():
|
||
|
|
self.errors.append(f" Zeile {idx + 2}: {row['datum'].strftime('%Y-%m-%d')}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
return True
|
||
|
|
|
||
|
|
def validate_chronology(self) -> bool:
|
||
|
|
"""Prüft chronologische Sortierung."""
|
||
|
|
if len(self.df) < 2:
|
||
|
|
return True
|
||
|
|
|
||
|
|
unsorted = []
|
||
|
|
for i in range(len(self.df) - 1):
|
||
|
|
if self.df.iloc[i]['datum'] > self.df.iloc[i + 1]['datum']:
|
||
|
|
unsorted.append((i, self.df.iloc[i]['datum'], self.df.iloc[i + 1]['datum']))
|
||
|
|
|
||
|
|
if len(unsorted) > 0:
|
||
|
|
self.warnings.append(f"⚠️ {len(unsorted)} Stelle(n) mit falscher chronologischer Reihenfolge:")
|
||
|
|
for idx, date1, date2 in unsorted[:3]:
|
||
|
|
self.warnings.append(f" Zeile {idx + 2}: {date1.strftime('%Y-%m-%d')} > {date2.strftime('%Y-%m-%d')}")
|
||
|
|
|
||
|
|
return len(unsorted) == 0
|
||
|
|
|
||
|
|
def validate_completeness(self) -> bool:
|
||
|
|
"""Prüft auf Lücken in den Ziehungen."""
|
||
|
|
if len(self.df) < 2:
|
||
|
|
return True
|
||
|
|
|
||
|
|
if self.lottery_type == 'lotto':
|
||
|
|
# Lotto: 2x pro Woche (Mi, Sa)
|
||
|
|
expected_days = 3.5 # Durchschnitt
|
||
|
|
else:
|
||
|
|
# Eurojackpot: 2x pro Woche (Di, Fr)
|
||
|
|
expected_days = 3.5
|
||
|
|
|
||
|
|
gaps = []
|
||
|
|
for i in range(len(self.df) - 1):
|
||
|
|
date1 = self.df.iloc[i]['datum']
|
||
|
|
date2 = self.df.iloc[i + 1]['datum']
|
||
|
|
diff = (date2 - date1).days
|
||
|
|
|
||
|
|
# Wenn Lücke größer als 7 Tage, könnte Ziehung fehlen
|
||
|
|
if diff > 7:
|
||
|
|
gaps.append((i, date1, date2, diff))
|
||
|
|
|
||
|
|
if len(gaps) > 0:
|
||
|
|
self.warnings.append(f"⚠️ {len(gaps)} mögliche Lücke(n) in den Ziehungen (>7 Tage):")
|
||
|
|
for idx, date1, date2, diff in gaps[:5]:
|
||
|
|
self.warnings.append(f" Zeile {idx + 2}: {date1.strftime('%Y-%m-%d')} → {date2.strftime('%Y-%m-%d')} ({diff} Tage)")
|
||
|
|
if len(gaps) > 5:
|
||
|
|
self.warnings.append(f" ... und {len(gaps) - 5} weitere")
|
||
|
|
|
||
|
|
return True
|
||
|
|
|
||
|
|
def get_statistics(self) -> Dict:
|
||
|
|
"""Erstellt Statistiken."""
|
||
|
|
if self.df is None or len(self.df) == 0:
|
||
|
|
return {}
|
||
|
|
|
||
|
|
stats = {
|
||
|
|
'total_draws': len(self.df),
|
||
|
|
'date_range': (
|
||
|
|
self.df['datum'].min().strftime('%Y-%m-%d'),
|
||
|
|
self.df['datum'].max().strftime('%Y-%m-%d')
|
||
|
|
),
|
||
|
|
'years_covered': (self.df['datum'].max().year - self.df['datum'].min().year) + 1,
|
||
|
|
}
|
||
|
|
|
||
|
|
return stats
|
||
|
|
|
||
|
|
def validate_all(self) -> bool:
|
||
|
|
"""Führt alle Validierungen durch."""
|
||
|
|
print(f"\n{'='*70}")
|
||
|
|
print(f" CSV VALIDATOR")
|
||
|
|
print(f" Typ: {self.lottery_type.upper()}")
|
||
|
|
print(f"{'='*70}")
|
||
|
|
print(f"\n📁 Datei: {os.path.basename(self.csv_file)}")
|
||
|
|
|
||
|
|
if not self.load_csv():
|
||
|
|
return False
|
||
|
|
|
||
|
|
print(f"✅ Datei geladen: {len(self.df)} Zeilen")
|
||
|
|
|
||
|
|
# Alle Validierungen
|
||
|
|
checks = [
|
||
|
|
("Spaltenstruktur", self.validate_structure),
|
||
|
|
("Datumsangaben", self.validate_dates),
|
||
|
|
("Zahlenwerte", self.validate_numbers),
|
||
|
|
("Duplikate", self.validate_duplicates),
|
||
|
|
("Chronologie", self.validate_chronology),
|
||
|
|
("Vollständigkeit", self.validate_completeness),
|
||
|
|
]
|
||
|
|
|
||
|
|
print(f"\n🔍 VALIDIERUNG")
|
||
|
|
print("="*70)
|
||
|
|
|
||
|
|
all_valid = True
|
||
|
|
for check_name, check_func in checks:
|
||
|
|
try:
|
||
|
|
result = check_func()
|
||
|
|
status = "✅" if result else "❌"
|
||
|
|
print(f"{status} {check_name}")
|
||
|
|
if not result:
|
||
|
|
all_valid = False
|
||
|
|
except Exception as e:
|
||
|
|
print(f"❌ {check_name} - Fehler: {e}")
|
||
|
|
all_valid = False
|
||
|
|
|
||
|
|
# Statistiken
|
||
|
|
stats = self.get_statistics()
|
||
|
|
if stats:
|
||
|
|
print(f"\n📊 STATISTIKEN")
|
||
|
|
print("="*70)
|
||
|
|
print(f"Ziehungen gesamt: {stats['total_draws']}")
|
||
|
|
print(f"Zeitraum: {stats['date_range'][0]} bis {stats['date_range'][1]}")
|
||
|
|
print(f"Jahre: {stats['years_covered']}")
|
||
|
|
|
||
|
|
# Fehler ausgeben
|
||
|
|
if self.errors:
|
||
|
|
print(f"\n❌ FEHLER ({len(self.errors)})")
|
||
|
|
print("="*70)
|
||
|
|
for error in self.errors:
|
||
|
|
print(error)
|
||
|
|
|
||
|
|
# Warnungen ausgeben
|
||
|
|
if self.warnings:
|
||
|
|
print(f"\n⚠️ WARNUNGEN ({len(self.warnings)})")
|
||
|
|
print("="*70)
|
||
|
|
for warning in self.warnings:
|
||
|
|
print(warning)
|
||
|
|
|
||
|
|
# Zusammenfassung
|
||
|
|
print(f"\n{'='*70}")
|
||
|
|
if all_valid and not self.errors:
|
||
|
|
print("✅ VALIDIERUNG ERFOLGREICH - Keine Fehler gefunden!")
|
||
|
|
elif not self.errors and self.warnings:
|
||
|
|
print("✅ VALIDIERUNG OK - Nur Warnungen (keine kritischen Fehler)")
|
||
|
|
else:
|
||
|
|
print("❌ VALIDIERUNG FEHLGESCHLAGEN")
|
||
|
|
print("="*70)
|
||
|
|
|
||
|
|
return all_valid and len(self.errors) == 0
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
"""Hauptfunktion."""
|
||
|
|
import sys
|
||
|
|
|
||
|
|
# Standard-Dateien
|
||
|
|
default_files = {
|
||
|
|
'lotto': '/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Lotto/data/AlleLottozahlen.csv',
|
||
|
|
'eurojackpot': '/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/AlleEurojackpotzahlen.csv'
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(sys.argv) > 1:
|
||
|
|
# Benutzerdefinierte Datei
|
||
|
|
csv_file = sys.argv[1]
|
||
|
|
validator = LottoCSVValidator(csv_file)
|
||
|
|
success = validator.validate_all()
|
||
|
|
sys.exit(0 if success else 1)
|
||
|
|
else:
|
||
|
|
# Validiere beide Standard-Dateien
|
||
|
|
print("\n🎲 Validiere beide Lottery-Dateien...\n")
|
||
|
|
|
||
|
|
results = {}
|
||
|
|
for lottery_type, csv_file in default_files.items():
|
||
|
|
if os.path.exists(csv_file):
|
||
|
|
validator = LottoCSVValidator(csv_file)
|
||
|
|
results[lottery_type] = validator.validate_all()
|
||
|
|
else:
|
||
|
|
print(f"\n⚠️ {lottery_type.upper()}: Datei nicht gefunden: {csv_file}")
|
||
|
|
results[lottery_type] = False
|
||
|
|
|
||
|
|
# Gesamtergebnis
|
||
|
|
print("\n" + "="*70)
|
||
|
|
print(" GESAMTERGEBNIS")
|
||
|
|
print("="*70)
|
||
|
|
for lottery_type, success in results.items():
|
||
|
|
status = "✅" if success else "❌"
|
||
|
|
print(f"{status} {lottery_type.upper()}")
|
||
|
|
print("="*70)
|
||
|
|
|
||
|
|
all_success = all(results.values())
|
||
|
|
sys.exit(0 if all_success else 1)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|