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.
Files changed (54) hide show
  1. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/PKG-INFO +1 -1
  2. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/pyproject.toml +1 -1
  3. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/national_rail.py +18 -9
  4. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/PKG-INFO +1 -1
  5. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/tests/test_national_rail_static.py +12 -1
  6. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/setup.cfg +0 -0
  7. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/__init__.py +0 -0
  8. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/const.py +0 -0
  9. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/data/uk_stations.json +0 -0
  10. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/exceptions.py +0 -0
  11. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/models.py +0 -0
  12. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/parsers.py +0 -0
  13. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/__init__.py +0 -0
  14. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/avv.py +0 -0
  15. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/base.py +0 -0
  16. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/beg.py +0 -0
  17. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/bsvg.py +0 -0
  18. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/bvg.py +0 -0
  19. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/db.py +0 -0
  20. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/ding.py +0 -0
  21. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/efa_base.py +0 -0
  22. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/fptf_base.py +0 -0
  23. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/gtfsde.py +0 -0
  24. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/hvv.py +0 -0
  25. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/kvv.py +0 -0
  26. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/mvv.py +0 -0
  27. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/nta.py +0 -0
  28. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/nvbw.py +0 -0
  29. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/nwl.py +0 -0
  30. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/oebb.py +0 -0
  31. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/otp.py +0 -0
  32. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/otp_base.py +0 -0
  33. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/otp_custom.py +0 -0
  34. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/rejseplanen.py +0 -0
  35. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/rmv.py +0 -0
  36. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/rvv.py +0 -0
  37. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/sbb.py +0 -0
  38. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/trafiklab.py +0 -0
  39. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/transitous.py +0 -0
  40. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/trias_base.py +0 -0
  41. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vagfr.py +0 -0
  42. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vbn.py +0 -0
  43. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vgn.py +0 -0
  44. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vrn.py +0 -0
  45. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vrr.py +0 -0
  46. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vvo.py +0 -0
  47. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/providers/vvs.py +0 -0
  48. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/openpublictransport/py.typed +0 -0
  49. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/SOURCES.txt +0 -0
  50. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/dependency_links.txt +0 -0
  51. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/requires.txt +0 -0
  52. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/src/python_openpublictransport.egg-info/top_level.txt +0 -0
  53. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/tests/test_national_rail.py +0 -0
  54. {python_openpublictransport-0.1.10 → python_openpublictransport-0.1.11}/tests/test_national_rail_parse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-openpublictransport
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: Python library for public transport APIs (EFA, OTP2, TRIAS, FPTF, HAFAS, GTFS-RT)
5
5
  License: MIT
6
6
  Requires-Python: >=3.11
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-openpublictransport"
7
- version = "0.1.10"
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, rate-limited, or returns nothing do we fall back to a
324
- bundled offline snapshot — see :func:`_load_static_stations`.
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 down / throttled / empty → use the offline snapshot.
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 returned nothing for %r — served %d result(s) from the "
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", []):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-openpublictransport
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: Python library for public transport APIs (EFA, OTP2, TRIAS, FPTF, HAFAS, GTFS-RT)
5
5
  License: MIT
6
6
  Requires-Python: >=3.11
@@ -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 len(stations) > 2000
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)