PyTransportNSWv2 0.8.5__tar.gz → 0.8.6__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyTransportNSWv2
3
- Version: 0.8.5
3
+ Version: 0.8.6
4
4
  Summary: Get detailed per-trip transport information from TransportNSW
5
5
  Home-page: https://github.com/andystewart999/TransportNSW
6
6
  Author: andystewart999
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyTransportNSWv2
3
- Version: 0.8.5
3
+ Version: 0.8.6
4
4
  Summary: Get detailed per-trip transport information from TransportNSW
5
5
  Home-page: https://github.com/andystewart999/TransportNSW
6
6
  Author: andystewart999
@@ -116,7 +116,7 @@ class TransportNSWv2(object):
116
116
  # Send the query and return an error if something goes wrong
117
117
  try:
118
118
  response = requests.get(url, headers=header, timeout=20)
119
- except:
119
+ except Exception as ex:
120
120
  logger.error("Network or Timeout error when calling /v1/tp/stop_finder API")
121
121
  return None
122
122
 
@@ -240,6 +240,9 @@ class TransportNSWv2(object):
240
240
  if 'RealtimeTripId' in transportation['properties']:
241
241
  realtimetripid = transportation['properties']['RealtimeTripId']
242
242
 
243
+ # We're also going to need the agency_id
244
+ agencyid = transportation['operator']['id']
245
+
243
246
  # Line info
244
247
  origin_line_name_short = "unknown"
245
248
  if 'disassembledName' in transportation:
@@ -267,44 +270,42 @@ class TransportNSWv2(object):
267
270
  if ((realtimetripid != 'n/a') and (self.include_realtime_location) == True):
268
271
  # See if we can get the latitute and longitude via the Realtime Vehicle Positions API
269
272
  # Build the URL(s) - some modes have multiple GTFS sources, unforunately
270
- url_path = self.get_url(origin_mode)
271
- url_list = self.get_url_path(origin_mode)
272
- bFoundTripID = False
273
-
274
- auth = 'apikey ' + self.api_key
275
- header = {'Authorization': auth}
276
-
277
- for mode_url in url_list:
278
- url = url_path + mode_url
279
-
280
- response = requests.get(url, headers=header, timeout=10)
281
-
282
- # Only try and process the results if we got a good return code
283
- if response.status_code == 200:
284
- # Search the feed and see if we can match realtimetripid to trip_id
285
- # If we do, capture the latitude and longitude
286
- feed = gtfs_realtime_pb2.FeedMessage()
287
- feed.ParseFromString(response.content)
288
-
289
- reg = re.compile(realtimetripid)
290
-
291
- for entity in feed.entity:
292
- if bool(re.match(reg, entity.vehicle.trip.trip_id)):
293
- latitude = entity.vehicle.position.latitude
294
- longitude = entity.vehicle.position.longitude
295
273
 
296
- # We found it, so flag it and break out
297
- bFoundTripID = True
298
- break
299
-
300
- if bFoundTripID == True:
301
- # No need to look any further
302
- break
303
-
304
- # Put in a quick pause here to try and make sure we stay under the 5 API calls/second limit
305
- # Not usually an issue but if multiple processes are running multiple calls we might hit it
306
- time.sleep(0.5)
274
+ url_base_path = self.get_base_url(origin_mode)
275
+ url_mode_list = self.get_mode_list(origin_mode, agencyid)
276
+ bFoundTripID = False
307
277
 
278
+ #auth = 'apikey ' + self.api_key
279
+ #header = {'Authorization': auth}
280
+
281
+ if not url_mode_list is None:
282
+ for mode_url in url_mode_list:
283
+ url = url_base_path + mode_url
284
+ response = requests.get(url, headers=header, timeout=10)
285
+ # Only try and process the results if we got a good return code
286
+ if response.status_code == 200:
287
+ # Search the feed and see if we can match realtimetripid to trip_id
288
+ # If we do, capture the latitude and longitude
289
+ feed = gtfs_realtime_pb2.FeedMessage()
290
+ feed.ParseFromString(response.content)
291
+ reg = re.compile(realtimetripid)
292
+
293
+ for entity in feed.entity:
294
+ if bool(re.match(reg, entity.vehicle.trip.trip_id)):
295
+ latitude = entity.vehicle.position.latitude
296
+ longitude = entity.vehicle.position.longitude
297
+
298
+ # We found it, so flag it and break out
299
+ bFoundTripID = True
300
+ break
301
+
302
+ if bFoundTripID == True:
303
+ # No need to look any further
304
+ break
305
+
306
+ # Put in a quick pause here to try and make sure we stay under the 5 API calls/second limit
307
+ # Not usually an issue but if multiple processes are running multiple calls we might hit it
308
+ time.sleep(0.75)
308
309
 
309
310
  self.info = {
310
311
  ATTR_DUE_IN: due,
@@ -490,7 +491,7 @@ class TransportNSWv2(object):
490
491
  }
491
492
  return modes.get(iconId, None)
492
493
 
493
- def get_url(self, mode):
494
+ def get_base_url(self, mode):
494
495
  """Map the journey mode to the proper base real time location URL """
495
496
  v1_url = "https://api.transport.nsw.gov.au/v1/gtfs/vehiclepos"
496
497
  v2_url = "https://api.transport.nsw.gov.au/v2/gtfs/vehiclepos"
@@ -521,10 +522,39 @@ class TransportNSWv2(object):
521
522
  return alert_priorities.get(alert_priority, 99)
522
523
 
523
524
 
524
- def get_url_path(self, mode):
525
- """Map the journey mode to the proper modifier URL """
526
- # There's probably a better way of mapping the bus route/stop/line number to the correct URL to call in the GTFS API, but as of now I don't know it... hence the brute force approach, although I hate the lack of elegance
527
- bus_list = ["/buses", "/regionbuses/centralwestandorana", "/regionbuses/centralwestandorana2", "/regionbuses/newenglandnorthwest", "/regionbuses/northcoast", "/regionbuses/northcoast2", "/regionbuses/northcoast3", "/regionbuses/riverinamurray", "/regionbuses/riverinamurray2", "/regionbuses/southeasttablelands", "/regionbuses/southeasttablelands2", "/regionbuses/sydneysurrounds", "/regionbuses/newcastlehunter", "/regionbuses/farwest"]
525
+ def get_mode_list(self, mode, agencyid):
526
+ """
527
+ Map the journey mode to the proper modifier URL. If the mode is Bus, Coach or School bus then use the agency ID to invoke the GTFS datastore search API
528
+ which will give us the appropriate URL to call later - we still have to do light rail the old-fashioned, brute-force way though
529
+ """
530
+ if mode in ["Bus", "Coach", "School bus"]:
531
+ # Use the API to determine the appropriate URL
532
+ url = "https://opendata.transport.nsw.gov.au/data/api/action/datastore_search?resource_id=30b850b7-f439-4e30-8072-e07ef62a2a36&filters={%22For%20Realtime%20GTFS%20agency_id%22:%22" + agencyid + "%22}&limit=1"
533
+
534
+ # Send the query and return an error if something goes wrong
535
+ try:
536
+ response = requests.get(url, timeout=20)
537
+ except Exception as ex:
538
+ logger.error("Error " + str(ex) + " querying GTFS URL datastore")
539
+ return None
540
+
541
+ # If we get bad status code, log error and return with None
542
+ if response.status_code != 200:
543
+ if response.status_code == 429:
544
+ logger.error("Error " + str(response.status_code) + " calling /v1/tp/stop_finder API; rate limit exceeded")
545
+ else:
546
+ logger.error("Error " + str(response.status_code) + " calling /v1/tp/stop_finder API; check api key")
547
+
548
+ return None
549
+
550
+ # Parse the result as JSON
551
+ result = response.json()
552
+ if 'records' in result['result'] and len(result['result']['records']) > 0:
553
+ mode_path = result['result']['records'][0]['For Realtime parameter']
554
+ else:
555
+ return None
556
+
557
+ bus_list = ["/" + mode_path]
528
558
 
529
559
  url_options = {
530
560
  "Train" : ["/sydneytrains"],
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="PyTransportNSWv2",
8
- version="0.8.5",
8
+ version="0.8.6",
9
9
  author="andystewart999",
10
10
  author_email="andy.stewart@live.com",
11
11
  description="Get detailed per-trip transport information from TransportNSW",