PyTransportNSWv2 0.8.5__tar.gz → 0.8.7__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.5 → PyTransportNSWv2-0.8.7}/PKG-INFO +2 -2
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/PyTransportNSWv2.egg-info/PKG-INFO +2 -2
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/README.md +1 -1
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/TransportNSWv2/TransportNSWv2.py +84 -54
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/setup.py +1 -1
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/LICENSE +0 -0
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/PyTransportNSWv2.egg-info/SOURCES.txt +0 -0
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/PyTransportNSWv2.egg-info/dependency_links.txt +0 -0
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/PyTransportNSWv2.egg-info/requires.txt +0 -0
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/PyTransportNSWv2.egg-info/top_level.txt +0 -0
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/TransportNSWv2/__init__.py +0 -0
- {PyTransportNSWv2-0.8.5 → PyTransportNSWv2-0.8.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: PyTransportNSWv2
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.7
|
4
4
|
Summary: Get detailed per-trip transport information from TransportNSW
|
5
5
|
Home-page: https://github.com/andystewart999/TransportNSW
|
6
6
|
Author: andystewart999
|
@@ -148,7 +148,7 @@ Description: # TransportNSWv2
|
|
148
148
|
Also note that the 'transport_type' filter, if present, only makes sure that at least **one** leg of the journey includes that transport type unless ```strict_transport_type``` is True, in which case the **first** leg must be of the requested type to be returned.
|
149
149
|
|
150
150
|
### Rate limits ###
|
151
|
-
By default the TransportNSW API allows each API key to make 60,000 calls in a day and up to 5 calls per second.
|
151
|
+
By default the TransportNSW API allows each API key to make 60,000 calls in a day and up to 5 calls per second. From version 0.8.7 I found a TransportNSW-maintained CSV that contains mappings of bus agency IDs to URLs so I'm using that, plus adding in a 0.75 second delay between API calls.
|
152
152
|
|
153
153
|
## Thank you
|
154
154
|
Thank you Dav0815 for your TransportNSW library that the vast majority of this fork is based on. I couldn't have done it without you!
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: PyTransportNSWv2
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.7
|
4
4
|
Summary: Get detailed per-trip transport information from TransportNSW
|
5
5
|
Home-page: https://github.com/andystewart999/TransportNSW
|
6
6
|
Author: andystewart999
|
@@ -148,7 +148,7 @@ Description: # TransportNSWv2
|
|
148
148
|
Also note that the 'transport_type' filter, if present, only makes sure that at least **one** leg of the journey includes that transport type unless ```strict_transport_type``` is True, in which case the **first** leg must be of the requested type to be returned.
|
149
149
|
|
150
150
|
### Rate limits ###
|
151
|
-
By default the TransportNSW API allows each API key to make 60,000 calls in a day and up to 5 calls per second.
|
151
|
+
By default the TransportNSW API allows each API key to make 60,000 calls in a day and up to 5 calls per second. From version 0.8.7 I found a TransportNSW-maintained CSV that contains mappings of bus agency IDs to URLs so I'm using that, plus adding in a 0.75 second delay between API calls.
|
152
152
|
|
153
153
|
## Thank you
|
154
154
|
Thank you Dav0815 for your TransportNSW library that the vast majority of this fork is based on. I couldn't have done it without you!
|
@@ -140,7 +140,7 @@ Note also that the origin and destination details are just that - information ab
|
|
140
140
|
Also note that the 'transport_type' filter, if present, only makes sure that at least **one** leg of the journey includes that transport type unless ```strict_transport_type``` is True, in which case the **first** leg must be of the requested type to be returned.
|
141
141
|
|
142
142
|
### Rate limits ###
|
143
|
-
By default the TransportNSW API allows each API key to make 60,000 calls in a day and up to 5 calls per second.
|
143
|
+
By default the TransportNSW API allows each API key to make 60,000 calls in a day and up to 5 calls per second. From version 0.8.7 I found a TransportNSW-maintained CSV that contains mappings of bus agency IDs to URLs so I'm using that, plus adding in a 0.75 second delay between API calls.
|
144
144
|
|
145
145
|
## Thank you
|
146
146
|
Thank you Dav0815 for your TransportNSW library that the vast majority of this fork is based on. I couldn't have done it without you!
|
@@ -115,8 +115,8 @@ class TransportNSWv2(object):
|
|
115
115
|
|
116
116
|
# Send the query and return an error if something goes wrong
|
117
117
|
try:
|
118
|
-
response = requests.get(url, headers=header, timeout=
|
119
|
-
except:
|
118
|
+
response = requests.get(url, headers=header, timeout=5)
|
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
|
|
@@ -157,7 +157,7 @@ class TransportNSWv2(object):
|
|
157
157
|
# Send the query and return an error if something goes wrong
|
158
158
|
# Otherwise store the response
|
159
159
|
try:
|
160
|
-
response = requests.get(url, headers=header, timeout=
|
160
|
+
response = requests.get(url, headers=header, timeout=10)
|
161
161
|
except:
|
162
162
|
logger.error("Network or timeout error")
|
163
163
|
return None
|
@@ -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
|
-
|
296
|
-
# We found it, so flag it and break out
|
297
|
-
bFoundTripID = True
|
298
|
-
break
|
299
273
|
|
300
|
-
|
301
|
-
|
302
|
-
|
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
|
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,21 +522,50 @@ class TransportNSWv2(object):
|
|
521
522
|
return alert_priorities.get(alert_priority, 99)
|
522
523
|
|
523
524
|
|
524
|
-
def
|
525
|
-
"""
|
526
|
-
|
527
|
-
|
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
|
+
"""
|
528
530
|
|
529
|
-
|
530
|
-
|
531
|
-
"
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
531
|
+
if mode in ["Bus", "Coach", "School bus"]:
|
532
|
+
# Use the API to determine the appropriate URL
|
533
|
+
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"
|
534
|
+
|
535
|
+
# Send the query and return an error if something goes wrong
|
536
|
+
try:
|
537
|
+
response = requests.get(url, timeout=5)
|
538
|
+
except Exception as ex:
|
539
|
+
logger.error("Error " + str(ex) + " querying GTFS URL datastore")
|
540
|
+
return None
|
541
|
+
|
542
|
+
# If we get bad status code, log error and return with None
|
543
|
+
if response.status_code != 200:
|
544
|
+
if response.status_code == 429:
|
545
|
+
logger.error("Error " + str(response.status_code) + " calling /v1/tp/stop_finder API; rate limit exceeded")
|
546
|
+
else:
|
547
|
+
logger.error("Error " + str(response.status_code) + " calling /v1/tp/stop_finder API; check api key")
|
548
|
+
|
549
|
+
return None
|
550
|
+
|
551
|
+
# Parse the result as JSON
|
552
|
+
result = response.json()
|
553
|
+
if 'records' in result['result'] and len(result['result']['records']) > 0:
|
554
|
+
mode_path = result['result']['records'][0]['For Realtime parameter']
|
555
|
+
else:
|
556
|
+
return None
|
557
|
+
|
558
|
+
bus_list = ["/" + mode_path]
|
559
|
+
return bus_list
|
560
|
+
else:
|
561
|
+
# Handle the other modes
|
562
|
+
url_options = {
|
563
|
+
"Train" : ["/sydneytrains"],
|
564
|
+
"Metro" : ["/metro"],
|
565
|
+
"Light rail" : ["/lightrail/innerwest", "/lightrail/cbdandsoutheast", "/lightrail/newcastle"],
|
566
|
+
"Ferry" : ["/ferries/sydneyferries"]
|
567
|
+
}
|
568
|
+
return url_options.get(mode, None)
|
539
569
|
|
540
570
|
|
541
571
|
def get_due(self, estimated):
|
@@ -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.7",
|
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.5 → PyTransportNSWv2-0.8.7}/PyTransportNSWv2.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|