Task_6: Adapter, load- und fetch-Funktionen

This commit is contained in:
Marco Schmid 2026-05-11 18:13:06 +02:00
parent 3ae4f2aead
commit e341a65204
4 changed files with 78 additions and 41 deletions

42
TASK.md
View File

@ -1,31 +1,21 @@
# TASK 5:
# TASK 6:
Als Nächstes versuchen wir unsere `main.py` von Businesslogik zu befreien und verlagern diese in ein eigenes Modul.
Wir arbeiten nun intern direkt mit den Daten von Overpass, will heissen `results` hat die gleiche Struktur wie die Daten,
welche von Overpass kommen. Macht das Sinn? Warum vielleicht nicht?
* verlagert dazu die Logik von 'fetch_bergbahnen' in ein eigenes Modul `overpass.py` aus.
* nennt die Funktion allgemeiner `fetch_overpass` (anstelle `fetch_bergbahnen`) -> somit würde es Sinn
machen, wenn wir den Query der Funktion als Argument mitgeben könnten (ist genereller).
* Erstellt in diesem `main.py` eine eigene 'main-Funktion', welche nur die Hauptlogik beinhalten und somit `fetch_overpass`
importiert und aufruft
* Wir versuchen einen Adapter zu bauen. Intern wollen wir mit einer eigenen Dataclass `POI` arbeiten. Wir bauen also dazu eine
Funktion `load_pois`, welche einerseits die Daten fetched und andererseits auch parsed. Den Fetching-Teil haben wir
bereits (`fetch_overpass`), den Pasing-Teil haben wir noch nicht.
Schreibt bitte eine eigene Dataclass`Poi` in welche die gefetchten Daten 'abgefüllt' werden können.
* Die Datenklasse `POI` könnt ihr in einem neuen Modul `models.py` ablegen.
* Die Struktur von `POI` sieht z.B. wie folgt aus:
```
overpass/
├── src/
│ └── overpass/
│ ├── __init__.py
│ ├── main.py
│ ├── overpass.py
├── tests/
│ └── test_...py
├── .env
├── .gitignore
├── requirements.txt
└── pyproject.toml
class POI:
id: str
type: str
poi_type: str
lat: float
lon: float
tags: dict
```
**Anmerkungen:**
* `requirements.txt` ist nicht falsch, aber `pyproject.toml` ist seit PEP 517/518 der aktuelle
Standard — auch für einfache Projekte
* `.env` beinhaltet später unsere (geschützten) Environment-Variablen. Diese sollen aus sicherheitsgründen
NIE auf git gepushed werden und werden deshalb auch in `.gitignore` vermerkt.

0
src/overpass/__init__.py Normal file
View File

40
src/overpass/main.py Normal file
View File

@ -0,0 +1,40 @@
from overpass import fetch_overpass, OverpassApiError
# ---------------------------------------------------------------------------
# Konfiguration
# ---------------------------------------------------------------------------
BBOXEN = {
"davos": (46.72, 9.70, 46.92, 10.00),
"schweiz": (45.8, 5.9, 47.8, 10.5),
}
QUERY = """
[out:json][timeout:2][maxsize:500000];
(
node["aerialway"="station"]({bbox});
way["aerialway"="station"]({bbox});
node["railway"="funicular"]({bbox});
way["railway"="funicular"]({bbox});
node["railway"="station"]["funicular"="yes"]({bbox});
);
out center body;
"""
# ---------------------------------------------------------------------------
# Hauptlogik
# ---------------------------------------------------------------------------
def main() -> None:
for name, bbox in BBOXEN.items():
try:
result = fetch_overpass(overpass_query=QUERY, bbox=bbox)
except OverpassApiError as exc:
print(f" Fehler : {exc}")
continue
elements = result.get("elements", [])
print(elements)
if __name__ == "__main__":
main()

View File

@ -4,29 +4,23 @@ from pprint import pprint
OVERPASS_URL = "https://overpass-api.de/api/interpreter"
BERGBAHN_QUERY = """
[out:json][timeout:3][maxsize:500000];
(
node["aerialway"="station"]({bbox});
way["aerialway"="station"]({bbox});
node["railway"="funicular"]({bbox});
way["railway"="funicular"]({bbox});
node["railway"="station"]["funicular"="yes"]({bbox});
);
out center body;
"""
class OverpassApiError(Exception):
pass
def fetch_bergbahnen(bbox: tuple) -> dict:
def fetch_overpass(overpass_query: str, bbox: tuple) -> dict:
"""
Fragt die Overpass API nach Bergbahnen in der angegebenen Bounding Box ab.
Sendet einen HTTP-POST-Request an die Overpass API und gibt die geparste
JSON-Antwort zurück.
Args:
overpass_query (str): Overpass-QL-Query mit dem Platzhalter {bbox}.
Beispiel:
'[out:json][timeout:5];
(node["aerialway"="station"]({bbox}););
out center body;'
bbox (tuple): Bounding Box als 4-Tuple in Dezimalgrad:
(south, west, north, east)
Beispiel Davos: (46.72, 9.70, 46.92, 10.00)
@ -59,7 +53,7 @@ def fetch_bergbahnen(bbox: tuple) -> dict:
"""
bbox_str = ",".join(map(str, bbox))
query = BERGBAHN_QUERY.format(bbox=bbox_str)
query = overpass_query.format(bbox=bbox_str)
try:
response = requests.post(
@ -78,6 +72,19 @@ def fetch_bergbahnen(bbox: tuple) -> dict:
if __name__ == "__main__":
BERGBAHN_QUERY = """
[out:json][timeout:2][maxsize:500000];
(
node["aerialway"="station"]({bbox});
way["aerialway"="station"]({bbox});
node["railway"="funicular"]({bbox});
way["railway"="funicular"]({bbox});
node["railway"="station"]["funicular"="yes"]({bbox});
);
out center body;
"""
bbox = (46.72, 9.70, 46.92, 10.00)
result = fetch_bergbahnen(bbox)
# bbox = (45.8, 5.9, 47.8, 10.5)
result = fetch_overpass(overpass_query=BERGBAHN_QUERY, bbox=bbox)
pprint(result)