python-openpublictransport 0.1.10__tar.gz → 0.1.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/PKG-INFO +1 -1
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/pyproject.toml +1 -1
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/national_rail.py +18 -9
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/PKG-INFO +1 -1
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/tests/test_national_rail_static.py +12 -1
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/setup.cfg +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/__init__.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/const.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/data/uk_stations.json +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/exceptions.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/models.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/parsers.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/__init__.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/avv.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/base.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/beg.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/bsvg.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/bvg.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/db.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/ding.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/efa_base.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/fptf_base.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/gtfsde.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/hvv.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/kvv.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/mvv.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/nta.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/nvbw.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/nwl.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/oebb.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/otp.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/otp_base.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/otp_custom.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/rejseplanen.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/rmv.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/rvv.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/sbb.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/trafiklab.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/transitous.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/trias_base.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vagfr.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vbn.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vgn.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vrn.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vrr.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vvo.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vvs.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/py.typed +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/SOURCES.txt +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/dependency_links.txt +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/requires.txt +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/top_level.txt +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/tests/test_national_rail.py +0 -0
- {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/tests/test_national_rail_parse.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-openpublictransport"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.11"
|
|
8
8
|
description = "Python library for public transport APIs (EFA, OTP2, TRIAS, FPTF, HAFAS, GTFS-RT)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -320,8 +320,11 @@ class NationalRailProvider(BaseProvider):
|
|
|
320
320
|
"""Find UK railway stations with their CRS codes.
|
|
321
321
|
|
|
322
322
|
The live Overpass API (OpenStreetMap) is the source of truth. Only if it
|
|
323
|
-
is unreachable
|
|
324
|
-
bundled offline snapshot — see
|
|
323
|
+
is unreachable or rate-limited (a *failure*, not a successful empty
|
|
324
|
+
result) do we fall back to a bundled offline snapshot — see
|
|
325
|
+
:func:`_load_static_stations`. When Overpass succeeds and legitimately
|
|
326
|
+
finds nothing, we return that empty result rather than serving
|
|
327
|
+
potentially out-of-date snapshot data.
|
|
325
328
|
|
|
326
329
|
A search term that looks like a 3-letter CRS code (e.g. "WIN", "RDG")
|
|
327
330
|
is matched directly against the CRS code; anything else is matched
|
|
@@ -332,14 +335,15 @@ class NationalRailProvider(BaseProvider):
|
|
|
332
335
|
return []
|
|
333
336
|
|
|
334
337
|
results = await self._search_overpass(term)
|
|
335
|
-
if results:
|
|
338
|
+
if results is not None:
|
|
339
|
+
# Overpass answered authoritatively (possibly with zero matches).
|
|
336
340
|
return results
|
|
337
341
|
|
|
338
|
-
# Overpass
|
|
342
|
+
# Overpass failed (unreachable / throttled) → use the offline snapshot.
|
|
339
343
|
fallback = self._search_static(term)
|
|
340
344
|
if fallback:
|
|
341
345
|
_LOGGER.info(
|
|
342
|
-
"%s: Overpass
|
|
346
|
+
"%s: Overpass unavailable for %r — served %d result(s) from the "
|
|
343
347
|
"bundled station snapshot (may be out of date)",
|
|
344
348
|
self.provider_name,
|
|
345
349
|
term,
|
|
@@ -369,8 +373,13 @@ class NationalRailProvider(BaseProvider):
|
|
|
369
373
|
break
|
|
370
374
|
return results[:10]
|
|
371
375
|
|
|
372
|
-
async def _search_overpass(self, term: str) -> List[Dict[str, Any]]:
|
|
373
|
-
"""Query the live Overpass API for UK stations matching ``term``.
|
|
376
|
+
async def _search_overpass(self, term: str) -> Optional[List[Dict[str, Any]]]:
|
|
377
|
+
"""Query the live Overpass API for UK stations matching ``term``.
|
|
378
|
+
|
|
379
|
+
Returns a (possibly empty) list on a successful query, or ``None`` if
|
|
380
|
+
the request failed (non-200 / exception) so the caller can decide
|
|
381
|
+
whether to fall back to the offline snapshot.
|
|
382
|
+
"""
|
|
374
383
|
if re.fullmatch(r"[A-Za-z]{3}", term):
|
|
375
384
|
# Direct CRS code lookup (ref:crs is stored uppercase in OSM)
|
|
376
385
|
query = f"""[out:json][timeout:15];
|
|
@@ -397,11 +406,11 @@ out 10;"""
|
|
|
397
406
|
) as resp:
|
|
398
407
|
if resp.status != 200:
|
|
399
408
|
_LOGGER.warning("%s: Overpass HTTP %s", self.provider_name, resp.status)
|
|
400
|
-
return
|
|
409
|
+
return None
|
|
401
410
|
data = await resp.json(content_type=None)
|
|
402
411
|
except Exception as exc:
|
|
403
412
|
_LOGGER.warning("%s: stop search failed: %s", self.provider_name, exc)
|
|
404
|
-
return
|
|
413
|
+
return None
|
|
405
414
|
|
|
406
415
|
results = []
|
|
407
416
|
for element in data.get("elements", []):
|
|
@@ -34,6 +34,8 @@ class _Session:
|
|
|
34
34
|
self.calls += 1
|
|
35
35
|
if self.mode == "down":
|
|
36
36
|
return _Resp(429, None)
|
|
37
|
+
if self.mode == "empty":
|
|
38
|
+
return _Resp(200, {"elements": []})
|
|
37
39
|
payload = {
|
|
38
40
|
"elements": [
|
|
39
41
|
{"tags": {"railway": "station", "ref:crs": "WIN",
|
|
@@ -45,7 +47,7 @@ class _Session:
|
|
|
45
47
|
|
|
46
48
|
def test_snapshot_loads_and_has_known_stations():
|
|
47
49
|
stations = nr._load_static_stations()
|
|
48
|
-
assert
|
|
50
|
+
assert stations # loads and is non-empty
|
|
49
51
|
by_crs = {s["crs"]: s for s in stations}
|
|
50
52
|
assert by_crs["WIN"]["name"] == "Winchester"
|
|
51
53
|
assert by_crs["RDG"]["name"] == "Reading"
|
|
@@ -73,6 +75,15 @@ async def test_overpass_success_does_not_use_fallback():
|
|
|
73
75
|
assert results[0]["name"] == "Winchester Overpass"
|
|
74
76
|
|
|
75
77
|
|
|
78
|
+
async def test_overpass_empty_result_does_not_fall_back():
|
|
79
|
+
"""A successful but empty Overpass result must NOT serve stale snapshot data."""
|
|
80
|
+
session = _Session("empty")
|
|
81
|
+
provider = NationalRailProvider(session)
|
|
82
|
+
results = await provider.search_stops("WIN")
|
|
83
|
+
assert session.calls == 1 # Overpass was queried
|
|
84
|
+
assert results == [] # authoritative "no match" — snapshot not consulted
|
|
85
|
+
|
|
86
|
+
|
|
76
87
|
async def test_falls_back_to_snapshot_when_overpass_down():
|
|
77
88
|
session = _Session("down")
|
|
78
89
|
provider = NationalRailProvider(session)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/tests/test_national_rail.py
RENAMED
|
File without changes
|
|
File without changes
|