PyTransportNSWv2 0.8.4__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.
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/PKG-INFO +1 -1
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/PyTransportNSWv2.egg-info/PKG-INFO +1 -1
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/TransportNSWv2/TransportNSWv2.py +84 -51
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/setup.py +1 -1
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/LICENSE +0 -0
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/PyTransportNSWv2.egg-info/SOURCES.txt +0 -0
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/PyTransportNSWv2.egg-info/dependency_links.txt +0 -0
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/PyTransportNSWv2.egg-info/requires.txt +0 -0
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/PyTransportNSWv2.egg-info/top_level.txt +0 -0
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/README.md +0 -0
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/TransportNSWv2/__init__.py +0 -0
- {PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/setup.cfg +0 -0
@@ -8,8 +8,9 @@ import requests.exceptions
|
|
8
8
|
import requests
|
9
9
|
import logging
|
10
10
|
import re
|
11
|
-
import json
|
11
|
+
import json #For the output
|
12
12
|
import time
|
13
|
+
#from ratelimit import limits, sleep_and_retry # API rate limiting
|
13
14
|
|
14
15
|
ATTR_DUE_IN = 'due'
|
15
16
|
|
@@ -115,11 +116,11 @@ class TransportNSWv2(object):
|
|
115
116
|
# Send the query and return an error if something goes wrong
|
116
117
|
try:
|
117
118
|
response = requests.get(url, headers=header, timeout=20)
|
118
|
-
except:
|
119
|
+
except Exception as ex:
|
119
120
|
logger.error("Network or Timeout error when calling /v1/tp/stop_finder API")
|
120
121
|
return None
|
121
122
|
|
122
|
-
# If we get bad status code, log error and return with
|
123
|
+
# If we get bad status code, log error and return with None
|
123
124
|
if response.status_code != 200:
|
124
125
|
if response.status_code == 429:
|
125
126
|
logger.error("Error " + str(response.status_code) + " calling /v1/tp/stop_finder API; rate limit exceeded")
|
@@ -135,9 +136,9 @@ class TransportNSWv2(object):
|
|
135
136
|
if 'systemMessages' in result:
|
136
137
|
logger.error("Stop ID " + stop + " does not exist")
|
137
138
|
|
138
|
-
# Put in a
|
139
|
+
# Put in a pause here to try and make sure we stay under the 5 API calls/second limit
|
139
140
|
# Not usually an issue but if multiple processes are running multiple calls we might hit it
|
140
|
-
time.sleep(0
|
141
|
+
time.sleep(1.0)
|
141
142
|
|
142
143
|
# We don't control how many journeys are returned any more, so need to be careful of running out of valid journeys if there is a filter in place, particularly a strict filter
|
143
144
|
# It would be more efficient to return one journey, check if the filter is met and then retrieve the next one via a new query if not, but for now we'll only be making use of the journeys we've been given
|
@@ -158,13 +159,17 @@ class TransportNSWv2(object):
|
|
158
159
|
try:
|
159
160
|
response = requests.get(url, headers=header, timeout=20)
|
160
161
|
except:
|
161
|
-
logger.error("Network or
|
162
|
+
logger.error("Network or timeout error")
|
162
163
|
return None
|
163
164
|
|
164
165
|
# If we get bad status code, log error and return with n/a or an empty string
|
165
166
|
if response.status_code != 200:
|
166
|
-
|
167
|
-
|
167
|
+
if response.status_code == 429:
|
168
|
+
logger.error("Error " + str(response.status_code) + " calling /v1/tp/stop_finder API; rate limit exceeded")
|
169
|
+
else:
|
170
|
+
logger.error("Error " + str(response.status_code) + " calling /v1/tp/stop_finder API; check api key")
|
171
|
+
|
172
|
+
return None
|
168
173
|
|
169
174
|
# Parse the result as a JSON object
|
170
175
|
result = response.json()
|
@@ -235,6 +240,9 @@ class TransportNSWv2(object):
|
|
235
240
|
if 'RealtimeTripId' in transportation['properties']:
|
236
241
|
realtimetripid = transportation['properties']['RealtimeTripId']
|
237
242
|
|
243
|
+
# We're also going to need the agency_id
|
244
|
+
agencyid = transportation['operator']['id']
|
245
|
+
|
238
246
|
# Line info
|
239
247
|
origin_line_name_short = "unknown"
|
240
248
|
if 'disassembledName' in transportation:
|
@@ -262,46 +270,42 @@ class TransportNSWv2(object):
|
|
262
270
|
if ((realtimetripid != 'n/a') and (self.include_realtime_location) == True):
|
263
271
|
# See if we can get the latitute and longitude via the Realtime Vehicle Positions API
|
264
272
|
# Build the URL(s) - some modes have multiple GTFS sources, unforunately
|
265
|
-
url_path = self.get_url(origin_mode)
|
266
|
-
url_list = self.get_url_path(origin_mode)
|
267
|
-
bFoundTripID = False
|
268
|
-
|
269
|
-
for mode_url in url_list:
|
270
|
-
url = url_path + mode_url
|
271
|
-
auth = 'apikey ' + self.api_key
|
272
|
-
header = {'Authorization': auth}
|
273
|
-
|
274
|
-
response = requests.get(url, headers=header, timeout=10)
|
275
|
-
|
276
|
-
# Only try and process the results if we got a good return code
|
277
|
-
if response.status_code == 200:
|
278
|
-
# Search the feed and see if we can match realtimetripid to trip_id
|
279
|
-
# If we do, capture the latitude and longitude
|
280
|
-
feed = gtfs_realtime_pb2.FeedMessage()
|
281
|
-
feed.ParseFromString(response.content)
|
282
|
-
|
283
|
-
reg = re.compile(realtimetripid)
|
284
|
-
|
285
|
-
for entity in feed.entity:
|
286
|
-
if bool(re.match(reg, entity.vehicle.trip.trip_id)):
|
287
|
-
latitude = entity.vehicle.position.latitude
|
288
|
-
longitude = entity.vehicle.position.longitude
|
289
|
-
|
290
|
-
# We found it, so flag it and break out
|
291
|
-
bFoundTripID = True
|
292
|
-
break
|
293
|
-
|
294
|
-
if bFoundTripID == True:
|
295
|
-
# No need to look any further
|
296
|
-
break
|
297
|
-
|
298
|
-
|
299
|
-
# Put in a quick pause here to try and make sure we stay under the 5 minute calls/second limit
|
300
|
-
# Not usually an issue but if multiple processes are running multiple calls we might hit it
|
301
|
-
time.sleep(0.5)
|
302
|
-
|
303
273
|
|
274
|
+
url_base_path = self.get_base_url(origin_mode)
|
275
|
+
url_mode_list = self.get_mode_list(origin_mode, agencyid)
|
276
|
+
bFoundTripID = False
|
304
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)
|
305
309
|
|
306
310
|
self.info = {
|
307
311
|
ATTR_DUE_IN: due,
|
@@ -487,7 +491,7 @@ class TransportNSWv2(object):
|
|
487
491
|
}
|
488
492
|
return modes.get(iconId, None)
|
489
493
|
|
490
|
-
def
|
494
|
+
def get_base_url(self, mode):
|
491
495
|
"""Map the journey mode to the proper base real time location URL """
|
492
496
|
v1_url = "https://api.transport.nsw.gov.au/v1/gtfs/vehiclepos"
|
493
497
|
v2_url = "https://api.transport.nsw.gov.au/v2/gtfs/vehiclepos"
|
@@ -518,10 +522,39 @@ class TransportNSWv2(object):
|
|
518
522
|
return alert_priorities.get(alert_priority, 99)
|
519
523
|
|
520
524
|
|
521
|
-
def
|
522
|
-
"""
|
523
|
-
|
524
|
-
|
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]
|
525
558
|
|
526
559
|
url_options = {
|
527
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.
|
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",
|
File without changes
|
File without changes
|
{PyTransportNSWv2-0.8.4 → PyTransportNSWv2-0.8.6}/PyTransportNSWv2.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|