overpass/TASK.md

2.5 KiB

Task 12 — Storage-Abstraktion mit ABC

Rückblick Task 11: Externe Konfiguration

Ihr habt alle Konfigurationswerte in eine config.yaml ausgelagert. Die wichtigsten Punkte:

  • Config vs. Umgebungsvariablen: In die YAML-Datei gehören Werte, die das Verhalten der Applikation steuern (Bboxen, Timeouts, aktive Queries). In Umgebungsvariablen (.env) gehören Secrets und Deployment-spezifische Werte (Passwörter, API-Keys, Datenbankpfade) — also alles, was nicht ins Git-Repository soll.
  • Ungültiger PoiType-Wert: PoiType("gondelbahn") wirft einen ValueError, weil der Wert nicht im Enum existiert. Das ist eigentlich gut — fail fast. In main.py könnte man diesen Fehler abfangen und eine sprechende Fehlermeldung ausgeben.
  • Path(__file__).parent / "config.yaml": Gleiche Logik wie bei den Query-Dateien — der Pfad wird immer relativ zur main.py aufgelöst, nicht zum Arbeitsverzeichnis.

Aufgabe

Aktuell landen die gefetchten POIs nirgends — sie werden nur geloggt und dann verworfen. Ziel ist es, die POIs in eine JSON-Datei zu speichern.

Wir wollen das aber so umsetzen, dass das Storage-Backend später leicht ausgetauscht werden kann (z.B. gegen eine Datenbank) — ohne main.py oder die Fetch-Logik anzufassen.

Konkret:

  1. Lege eine neue Datei storage.py an.
  2. Definiere darin eine abstrakte Basisklasse Storage (erbt von ABC) mit einer abstrakten Methode:
   @abstractmethod
   def store(self, pois: list[POI]) -> str:
       ...

Die Methode soll die POIs speichern und einen Identifier zurückgeben (z.B. den Dateipfad oder Tabellennamen). 3. Implementiere eine konkrete Klasse JsonStorage(Storage):

  • Nimmt einen output_dir: str | Path im Konstruktor entgegen.
  • store() schreibt alle POIs als JSON-Datei in dieses Verzeichnis, benannt nach dem poi_type (z.B. bergbahn.json).
  1. Instanziiere JsonStorage in main.py und rufe nach dem Fetchen storage.store(pois) auf.
  2. Ergänze in config.yaml einen storage-Abschnitt:
   storage:
     output_dir: ./data/results

Fragen zum Nachdenken:

  • Was ist eine abstrakte Basisklasse (ABC) — und was passiert, wenn man Storage() direkt instanziiert oder eine Unterklasse schreibt, die store() nicht implementiert?
  • Warum gibt store() einen str zurück (den Identifier) statt nichts (None)?
  • Was wäre der Nachteil, wenn main.py direkt JsonStorage instanziieren und überall verwenden würde — ohne das Storage-Interface?