Task_10: Queries auslagern
This commit is contained in:
parent
24a7051632
commit
bddf5a30cf
63
TASK.md
63
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?
|
||||
- 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*)
|
||||
@ -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];
|
||||
(
|
||||
|
||||
@ -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...
|
||||
# Nur wenn die tags strukturiert und vorhersehbar sind, was bei OSM-Daten nicht der Fall ist...
|
||||
|
||||
|
||||
class PoiType(StrEnum):
|
||||
BERGBAHN = "bergbahn"
|
||||
RESTAURANT = "restaurant"
|
||||
Loading…
x
Reference in New Issue
Block a user