diff --git a/TASK.md b/TASK.md index f7bb1f1..99c4b47 100644 --- a/TASK.md +++ b/TASK.md @@ -1,41 +1,46 @@ -# Task 9 — PoiType als StrEnum +# Task 10 — Queries auslagern -## Rückblick Task 8: Python Package +## Rückblick Task 9: PoiType als StrEnum -Ihr habt das Projekt in ein Python-Package umgewandelt. Die wichtigsten Punkte: +Ihr habt den Magic String `"bergbahn"` durch eine `StrEnum` ersetzt. Die wichtigsten Punkte: -- **Modul vs. Package:** Ein einzelnes `.py`-File ist ein Modul. Ein Ordner mit - `__init__.py` ist ein Package — er kann mehrere Module bündeln und nach aussen - eine saubere API exponieren. -- **Relative Imports** (`from .models import POI`): Beziehen sich auf das eigene - Package, sind refactoring-sicher und machen klar, dass etwas intern ist. - Absolute Imports (`from overpass_project.models import POI`) funktionieren auch, - sind aber abhängig vom Paketnamen. -- **`from overpass import *`** ist problematisch, weil unklar ist, welche Namen - importiert werden — das kann zu Namenskollisionen führen und erschwert das Lesen - des Codes stark. +- **Magic Strings** sind rohe Strings, die eine bestimmte Bedeutung haben, aber nirgends + formal definiert oder geprüft werden. Tippfehler wie `"Bergbahn"` oder `"berg_bahn"` + fallen erst zur Laufzeit auf — oder gar nicht. +- **`PoiType("bergbahn")`** funktioniert bei `StrEnum` — Python findet den passenden + Member anhand des Wertes. Das ist nützlich, wenn Werte aus einer Config oder + Datenbank kommen. +- **Grenzen:** Enums sind statisch — neue POI-Typen erfordern eine Code-Änderung. + Für sehr dynamische Systeme (Typen kommen aus der DB) wäre eine andere Lösung nötig. ## Aufgabe -In `main.py` steht aktuell: - -```python -poi_type = "bergbahn" -``` - -Das ist ein sogenannter **Magic String** — ein roher String, dem man nicht ansieht, -welche Werte gültig sind, und der nirgends geprüft wird. +In `main.py` steht aktuell die Overpass-Query als langer hardcodierter String direkt +im Code. Das hat mehrere Nachteile: Der String ist schwer lesbar, nicht wiederverwendbar, +und für jeden neuen POI-Typ muss `main.py` angefasst werden. **Konkret:** -1. Füge in `models.py` eine `PoiType`-Klasse hinzu, die von `StrEnum` erbt, - mit den Werten `BERGBAHN` und `RESTAURANT`. -2. Ersetze in `main.py` den String `"bergbahn"` durch `PoiType.BERGBAHN`. -3. Passe den Import in `main.py` entsprechend an. +1. Lege einen Unterordner `queries/` im Package an. +2. Verschiebe die Bergbahn-Query in eine Datei `queries/bergbahn.overpassql`. + Der Platzhalter `{bbox}` bleibt erhalten — ergänze zusätzlich `{timeout}` und + `{maxsize}` als Platzhalter (statt Hardcoding im Query-String). +3. Schreibe in `fetcher.py` eine neue Funktion `load_query()`: +```python + def load_query(poi_type: PoiType, bbox: tuple, timeout: int, maxsize: int) -> str: + ... +``` + Sie soll die passende `.overpassql`-Datei laden und alle Platzhalter befüllen. +4. Passe `_fetch_overpass()` an: Sie bekommt nun die **fertige Query** (kein + `bbox`-Parameter mehr) und sendet sie direkt. +5. Passe `load_pois()` und `main.py` entsprechend an. + **Fragen zum Nachdenken:** -- Was ist der Unterschied zwischen `Enum` und `StrEnum`? -- Warum ist `PoiType.BERGBAHN` besser als der String `"bergbahn"`? -- Was passiert, wenn jemand `PoiType("bergbahn")` schreibt — funktioniert das? -- Wo könnte ein Enum an seine Grenzen stossen? \ No newline at end of file +- Welche Vorteile hat es, Queries in eigenen Dateien zu speichern? +- Warum ist `Path(__file__).parent / "queries"` besser als ein relativer Pfad `"queries/"`? +- Was passiert, wenn die `.overpassql`-Datei für einen bestimmten `PoiType` fehlt — + wie sollte `load_query()` damit umgehen? +- Welches Design-Prinzip steckt hinter dieser Änderung? + (Stichwort: *Separation of Concerns*) \ No newline at end of file diff --git a/src/overpass/main.py b/src/overpass/main.py index efb878a..8966946 100644 --- a/src/overpass/main.py +++ b/src/overpass/main.py @@ -1,6 +1,6 @@ import logging from .fetcher import load_pois, OverpassApiError -from .models import POI +from .models import POI, PoiType logging.basicConfig( level=logging.INFO, @@ -9,11 +9,13 @@ logging.basicConfig( ) logger = logging.getLogger(__name__) +poi_type = PoiType.BERGBAHN + BBOXEN = { "davos": (46.72, 9.70, 46.92, 10.00), "schweiz": (45.8, 5.9, 47.8, 10.5), } -poi_type = "bergbahn" + QUERY = """ [out:json][timeout:2][maxsize:500000]; ( diff --git a/src/overpass/models.py b/src/overpass/models.py index af727e3..1077e8e 100644 --- a/src/overpass/models.py +++ b/src/overpass/models.py @@ -1,4 +1,6 @@ from dataclasses import dataclass, field +from enum import StrEnum + @dataclass class POI: @@ -13,4 +15,9 @@ class POI: # REMARK: # Wann eine eigene Dataclass für tags? -# Nur wenn die tags strukturiert und vorhersehbar sind, was bei OSM-Daten nicht der Fall ist... \ No newline at end of file +# Nur wenn die tags strukturiert und vorhersehbar sind, was bei OSM-Daten nicht der Fall ist... + + +class PoiType(StrEnum): + BERGBAHN = "bergbahn" + RESTAURANT = "restaurant" \ No newline at end of file