commit 6413908a4bc94558c1f3e9a6f9fe366dc52985bd Author: Marco Schmid Date: Mon May 11 17:25:34 2026 +0200 Task_1: Erkunden Overpass-Query diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..124df19 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.idea +.venv +GIT_INSTRUCTOR.md +README_INSTRUCTOR.md + + +# Python +__pycache__/ +*.pyc +*.pyo +.env + + diff --git a/GIT_HINTS.md b/GIT_HINTS.md new file mode 100644 index 0000000..4c71d2b --- /dev/null +++ b/GIT_HINTS.md @@ -0,0 +1,57 @@ +# Git-Hints + +Gesamtes Repo klonen: +``` +git clone https://gitea.fhgr.ch/schmidmarco/overpass.git +``` + +Neuen Arbeitsbranch 'work' machen beim Stand 'Task 1' (alle Files): +``` +git checkout -b work Task_1 +``` + +Nur nächsten Task (nur Task.md) holen: + - holt nur die Aufgabe + - eigener Code bleibt unangetastet +``` +git checkout Task_2 -- TASK.md +``` + +Soll der Code von `main` in den `work`-Branch gemerged werden (in einem normalen Projekt ist es ja umgekehrt!), +auf den `work`-Branch wechseln und: + +``` +git merge Task_7 -> ev. zu lösende Konflikte +``` + +Bedingt durch unseren Workflow wo sowohl auf `main` als auch `work` an den gleichen Files gearbeitet wird, führt das +ziemlich sicher zu einem merge-Konflikt, welcher manuell gelöst werden muss. + + +Den ganzen Code zu einem bestimmten Tag holen (Notfall): +``` +# Vorher eigene Arbeit sichern: +git add . +git commit -m "mein Stand vor Notfall-Checkout" + +# Dann eine einzelne Datei holen: +git checkout Task_3 -- main.py + +# Oder alles auf Tag zurücksetzen (unwiderruflich!): +git reset --hard Task_3 +``` + + +Vor dem reset, besser: +``` +git log work --oneline # nochmals anschauen was verloren geht +git commit -m "mein Stand, wird jetzt verworfen" # zumindest in History sichtbar +``` + + +Immer vor dem Holen des nächsten Tasks einen eigenen `commit` machen! + +``` +git commit -m "Task xy: ..." +``` + diff --git a/README.md b/README.md new file mode 100644 index 0000000..88f88a3 --- /dev/null +++ b/README.md @@ -0,0 +1,107 @@ +# README + +Ich habe euch den `GeoService` demonstriert. Das ist ein Docker-basierter Mikroservice, welcher Fragen wie +'Zeige mir basierend auf meinem Standort die 3 per Auto nächstgelegenen Restaurants' oder 'Wieviele Schwimmbäder +befinden sich im Umkreis von 3 Kilometer um meinen jetzigen Standort' etc. + +Um den Service zu betreiben braucht es (valide) Daten. Diese kann man kaufen oder sich selbst bauen. Wir gehen hier +den zweiten Weg :-). Das Ziel für die nächsten paar Übungsstunden ist ein kleines Projekt (Miniprojekt), welches uns +diese Basisdaten mithilfe von OpenStreetMap (Overpass) für die ganze Schweiz baut. + +Es geht weniger darum, ein super End-Produkt zu bauen (inhaltlich), als vielmehr darum viele in diesem Semester +gelernte Konzepte und Techniken zu integrieren und an einem praxisnahen Beispiel miteinander zu erarbeiten und zu +festigen. + +Dies sind u.U.: + +* Zugriff mit Python auf eine API (Overpass) +* Arbeiten mit git auf Gitea (commits, clone, checkout) +* Dataclasses +* sauberer Python-Code mit Docstrings, Typehints und Logging +* Speichern der Resultate als .json in einem File und in eine Postgres-Datenbank +* Parallelisierung (multithreading) von Abfragen auf Overpass-API +* Dekorator-Pattern (für Zeitmessung) +* Schreiben von Pytests mit und ohne Mocks + +**Ziel:** + +Valide Daten für ausgewählte POI's (Points Of Interests) zu produzieren, z.B. + +```json +{ + "generated_at": "2026-03-09T23:03:40.107307+00:00", + "count": 2511, + "pois": [ + { + "id": "node/2068758717", + "type": "node", + "poi_type": "rail_station", + "name": "St. Urban Ziegelei", + "lat": 47.2271478, + "lon": 7.8361018, + "tags": { + "name": "St. Urban Ziegelei" + } + }, + { + "id": "node/2068760081", + "type": "node", + "poi_type": "rail_station", + "name": "St. Urban", + "lat": 47.2317566, + "lon": 7.8359882, + "tags": { + "name": "St. Urban" + } + } + ] +} +``` + +Für die POIs machen wir unseren eigenen Datatyp 'POI' (`dataclass`) +Ein einzelner POI: + +``` { + "id": "node/2068758717", + "type": "node", + "poi_type": "rail_station", + "name": "St. Urban Ziegelei", + "lat": 47.2271478, + "lon": 7.8361018, + "tags": { + "name": "St. Urban Ziegelei" + } +``` + +Die Daten beziehen wir von `https://overpass-turbo.eu/`. Overpass bietet nebst diesem frontend-basierten Ansatz auch eine +API-Schnittstelle (POST- und GET-Requests) an, welche wir nutzen können (`OVERPASS_URL=https://overpass-api.de/api/interpreter`). + +## Gitea + +Das Miniprojekt liegt auf `Gitea` bereit. Ziel ist es auch den Umgang mit git ein wenig zu üben. +In `GIT_HINTS.md` habe ich die wichtigsten Befehle im Zusammenhang mit diesem Miniprojekt festgehalten. + +**zu beachten**: +Der Workflow mit `git commit/pull` etc. hier ist nicht derselbe, wie in einem normalen Projekt. + +Normalerweise machen wir von `main` einen Branch, lösen auf diesem einen Task, stellen dann einen `PR` und mergen zurück in +`main`. Dann beginnt das ganze Spiel wieder von vorne... + +Hier im Miniprojekt verhält es sich ein wenig anders. Die (Muster)-Lösungen liegen schon zu Beginn auf dem `main`-Branch und +sind mit tags (z.B. TASK_1) versehen. Der main-Branch kann also zu unterschiedlichen Zeitpunkten ausgecheckt werden und +Zeit die Arbeit zu diesem Zeitpunkt. Der/die Studierende kann also zu einem bestimmten Task auschecken und dann in `Task.md` +nachlesen, was als Nächstes ansteht. Idee ist jedoch nicht, einfach die 'Lösungen' anzuschauen, sondern auf einem +paralellen Branch `work` die Übungen selbst zu programmieren. Wenn Du nicht mehr weiter weisst, kannst Du jederzeit auf +`main` zu einem Task-Tag wechseln und nachschauen. Programmiert (und commited) soll aber IMMER nur auf dem +`work`-Branch werden! + +## Code + +Aus u.a. didaktischen Gründen, beginnen wir nicht gerade mit allem möglichen in unserem Projekt, sondern arbeiten zuerst +z.B. einmal in `main.py` und nutzen `print`-Statements im Wissen, dass wir die später durch saubere `loggings` ersetzen. +Auch gibt es punktuell immer wieder Refaktorierungen des Codes (darauf werde ich jeweils in den Tasks hinweisen). + +Ziel ist am Schluss ein verständliches Miniprojekt mit einer sauberen Struktur und verständlichem Code. Das Miniprojekt +erhebt aber eben keinen Anspruch auf absolute Performanz oder Stabilität, es ist ein und bleibt ein Lernprojekt! + +Viel Spass im Projekt! \ No newline at end of file diff --git a/TASK.md b/TASK.md new file mode 100644 index 0000000..771af69 --- /dev/null +++ b/TASK.md @@ -0,0 +1,20 @@ +# TASK 1: + +Als Erstes wollen wir die Struktur und Funktionen eines einfachen +Overpass-Queries verstehen und ein wenig interaktiv damit rumspielen. + +``` + [out:json][timeout:60]; + ( + 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; +``` + +* Kopiert diesen auf `https://overpass-turbo.eu/` und führt ihn mal aus. +* Spielt mit den Zoomstufen -> bbox +* Versucht mehr über bbox herauszufinden (z.B. https://wiki.openstreetmap.org/wiki/Overpass_API) diff --git a/main.py b/main.py new file mode 100644 index 0000000..722c831 --- /dev/null +++ b/main.py @@ -0,0 +1,12 @@ +from pprint import pprint + + +def fetch_bergbahnen(bbox) -> dict: + return {} + + +if __name__ == "__main__": + + bbox = (46.72, 9.70, 46.92, 10.00) + result = fetch_bergbahnen(bbox) + pprint(result) \ No newline at end of file