PyTransportNSWv2 0.9.0__tar.gz → 0.9.2__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.9.0 → PyTransportNSWv2-0.9.2}/PKG-INFO +46 -3
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/PyTransportNSWv2.egg-info/PKG-INFO +46 -3
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/PyTransportNSWv2.egg-info/requires.txt +0 -1
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/README.md +45 -2
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/TransportNSWv2/TransportNSWv2.py +141 -60
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/setup.py +2 -3
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/LICENSE +0 -0
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/PyTransportNSWv2.egg-info/SOURCES.txt +0 -0
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/PyTransportNSWv2.egg-info/TransportNSWv2.py +0 -0
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/PyTransportNSWv2.egg-info/dependency_links.txt +0 -0
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/PyTransportNSWv2.egg-info/top_level.txt +0 -0
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/TransportNSWv2/__init__.py +0 -0
- {PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: PyTransportNSWv2
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.2
|
4
4
|
Summary: Get detailed per-trip transport information from TransportNSW
|
5
5
|
Home-page: https://github.com/andystewart999/TransportNSW
|
6
6
|
Author: andystewart999
|
@@ -23,8 +23,51 @@ Description: # TransportNSWv2
|
|
23
23
|
### API Documentation
|
24
24
|
The source API details can be found here: https://opendata.transport.nsw.gov.au/sites/default/files/2023-08/Trip%20Planner%20API%20manual-opendataproduction%20v3.2.pdf
|
25
25
|
|
26
|
-
###
|
27
|
-
|
26
|
+
### Exposed functions
|
27
|
+
Two functions are available:
|
28
|
+
```get_trip()``` returns trip information between two stop IDs
|
29
|
+
```check_stops()``` lets you confirm that the two stop IDs are valid, plus it returns all the stop ID metadata. Note that ```get_trip()``` calls this function internally and fails relatively gracefully if either of the stop IDs are invalid, so there's no specific need to call ```check_stops()``` unless you want the stop ID metadata.
|
30
|
+
|
31
|
+
### check_stops() parameters
|
32
|
+
All parameters are mandatory. Note that ```stop_list``` can be a single string or a list of strings:
|
33
|
+
```.check_stops(api_key, stop_list)```
|
34
|
+
|
35
|
+
The return is a JSON-compatible Python object as per the example here:
|
36
|
+
```
|
37
|
+
{
|
38
|
+
"all_stops_valid": true,
|
39
|
+
"stop_list": [
|
40
|
+
{
|
41
|
+
"stop_id": "200060",
|
42
|
+
"valid": true,
|
43
|
+
"error_code": 0,
|
44
|
+
"stop_detail": {
|
45
|
+
"id": "200060",
|
46
|
+
"name": "Central Station, Sydney",
|
47
|
+
"disassembledName": "Central Station",
|
48
|
+
<etc, as per the Transport NSW API>
|
49
|
+
}
|
50
|
+
}
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"stop_id": "229310",
|
54
|
+
"valid": true,
|
55
|
+
"error_code": 0,
|
56
|
+
"stop_detail": {
|
57
|
+
"id": "229310",
|
58
|
+
"name": "Newcastle Interchange, Wickham",
|
59
|
+
"disassembledName": "Newcastle Interchange",
|
60
|
+
<etc, as per the Transport NSW API>
|
61
|
+
}
|
62
|
+
}
|
63
|
+
]
|
64
|
+
}
|
65
|
+
```
|
66
|
+
Most of the top-level properties are pretty self-explanatory. If all you want to do is get a general yes/no then ```all_stops_valid``` is the quickest check. If any of the stops are invalid or there was an error calling the stop-finder API then ```error_code``` will point you to the issue. If the API call was successful then ```stop_detail``` will contain everything that the API sent back for the closest match it found.
|
67
|
+
|
68
|
+
|
69
|
+
### get_trip() parameters
|
70
|
+
Only the first three parameters are mandatory, the rest are optional. All parameters and their defaults are as follows:
|
28
71
|
```python
|
29
72
|
.get_trip(origin_stop_id, destination_stop_id, api_key, trip_wait_time = 0, transport_type = 0, strict_transport_type = False, raw_output = False, journeys_to_return = 1, route_filter = '', include_realtime_location = True, include_alerts = 'none', alert_type = 'all', check_stop_ids = True, forced_gtfs_uri = [])
|
30
73
|
```
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: PyTransportNSWv2
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.2
|
4
4
|
Summary: Get detailed per-trip transport information from TransportNSW
|
5
5
|
Home-page: https://github.com/andystewart999/TransportNSW
|
6
6
|
Author: andystewart999
|
@@ -23,8 +23,51 @@ Description: # TransportNSWv2
|
|
23
23
|
### API Documentation
|
24
24
|
The source API details can be found here: https://opendata.transport.nsw.gov.au/sites/default/files/2023-08/Trip%20Planner%20API%20manual-opendataproduction%20v3.2.pdf
|
25
25
|
|
26
|
-
###
|
27
|
-
|
26
|
+
### Exposed functions
|
27
|
+
Two functions are available:
|
28
|
+
```get_trip()``` returns trip information between two stop IDs
|
29
|
+
```check_stops()``` lets you confirm that the two stop IDs are valid, plus it returns all the stop ID metadata. Note that ```get_trip()``` calls this function internally and fails relatively gracefully if either of the stop IDs are invalid, so there's no specific need to call ```check_stops()``` unless you want the stop ID metadata.
|
30
|
+
|
31
|
+
### check_stops() parameters
|
32
|
+
All parameters are mandatory. Note that ```stop_list``` can be a single string or a list of strings:
|
33
|
+
```.check_stops(api_key, stop_list)```
|
34
|
+
|
35
|
+
The return is a JSON-compatible Python object as per the example here:
|
36
|
+
```
|
37
|
+
{
|
38
|
+
"all_stops_valid": true,
|
39
|
+
"stop_list": [
|
40
|
+
{
|
41
|
+
"stop_id": "200060",
|
42
|
+
"valid": true,
|
43
|
+
"error_code": 0,
|
44
|
+
"stop_detail": {
|
45
|
+
"id": "200060",
|
46
|
+
"name": "Central Station, Sydney",
|
47
|
+
"disassembledName": "Central Station",
|
48
|
+
<etc, as per the Transport NSW API>
|
49
|
+
}
|
50
|
+
}
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"stop_id": "229310",
|
54
|
+
"valid": true,
|
55
|
+
"error_code": 0,
|
56
|
+
"stop_detail": {
|
57
|
+
"id": "229310",
|
58
|
+
"name": "Newcastle Interchange, Wickham",
|
59
|
+
"disassembledName": "Newcastle Interchange",
|
60
|
+
<etc, as per the Transport NSW API>
|
61
|
+
}
|
62
|
+
}
|
63
|
+
]
|
64
|
+
}
|
65
|
+
```
|
66
|
+
Most of the top-level properties are pretty self-explanatory. If all you want to do is get a general yes/no then ```all_stops_valid``` is the quickest check. If any of the stops are invalid or there was an error calling the stop-finder API then ```error_code``` will point you to the issue. If the API call was successful then ```stop_detail``` will contain everything that the API sent back for the closest match it found.
|
67
|
+
|
68
|
+
|
69
|
+
### get_trip() parameters
|
70
|
+
Only the first three parameters are mandatory, the rest are optional. All parameters and their defaults are as follows:
|
28
71
|
```python
|
29
72
|
.get_trip(origin_stop_id, destination_stop_id, api_key, trip_wait_time = 0, transport_type = 0, strict_transport_type = False, raw_output = False, journeys_to_return = 1, route_filter = '', include_realtime_location = True, include_alerts = 'none', alert_type = 'all', check_stop_ids = True, forced_gtfs_uri = [])
|
30
73
|
```
|
@@ -15,8 +15,51 @@ If it's available, the general occupancy level and the latitude and longitude of
|
|
15
15
|
### API Documentation
|
16
16
|
The source API details can be found here: https://opendata.transport.nsw.gov.au/sites/default/files/2023-08/Trip%20Planner%20API%20manual-opendataproduction%20v3.2.pdf
|
17
17
|
|
18
|
-
###
|
19
|
-
|
18
|
+
### Exposed functions
|
19
|
+
Two functions are available:
|
20
|
+
```get_trip()``` returns trip information between two stop IDs
|
21
|
+
```check_stops()``` lets you confirm that the two stop IDs are valid, plus it returns all the stop ID metadata. Note that ```get_trip()``` calls this function internally and fails relatively gracefully if either of the stop IDs are invalid, so there's no specific need to call ```check_stops()``` unless you want the stop ID metadata.
|
22
|
+
|
23
|
+
### check_stops() parameters
|
24
|
+
All parameters are mandatory. Note that ```stop_list``` can be a single string or a list of strings:
|
25
|
+
```.check_stops(api_key, stop_list)```
|
26
|
+
|
27
|
+
The return is a JSON-compatible Python object as per the example here:
|
28
|
+
```
|
29
|
+
{
|
30
|
+
"all_stops_valid": true,
|
31
|
+
"stop_list": [
|
32
|
+
{
|
33
|
+
"stop_id": "200060",
|
34
|
+
"valid": true,
|
35
|
+
"error_code": 0,
|
36
|
+
"stop_detail": {
|
37
|
+
"id": "200060",
|
38
|
+
"name": "Central Station, Sydney",
|
39
|
+
"disassembledName": "Central Station",
|
40
|
+
<etc, as per the Transport NSW API>
|
41
|
+
}
|
42
|
+
}
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"stop_id": "229310",
|
46
|
+
"valid": true,
|
47
|
+
"error_code": 0,
|
48
|
+
"stop_detail": {
|
49
|
+
"id": "229310",
|
50
|
+
"name": "Newcastle Interchange, Wickham",
|
51
|
+
"disassembledName": "Newcastle Interchange",
|
52
|
+
<etc, as per the Transport NSW API>
|
53
|
+
}
|
54
|
+
}
|
55
|
+
]
|
56
|
+
}
|
57
|
+
```
|
58
|
+
Most of the top-level properties are pretty self-explanatory. If all you want to do is get a general yes/no then ```all_stops_valid``` is the quickest check. If any of the stops are invalid or there was an error calling the stop-finder API then ```error_code``` will point you to the issue. If the API call was successful then ```stop_detail``` will contain everything that the API sent back for the closest match it found.
|
59
|
+
|
60
|
+
|
61
|
+
### get_trip() parameters
|
62
|
+
Only the first three parameters are mandatory, the rest are optional. All parameters and their defaults are as follows:
|
20
63
|
```python
|
21
64
|
.get_trip(origin_stop_id, destination_stop_id, api_key, trip_wait_time = 0, transport_type = 0, strict_transport_type = False, raw_output = False, journeys_to_return = 1, route_filter = '', include_realtime_location = True, include_alerts = 'none', alert_type = 'all', check_stop_ids = True, forced_gtfs_uri = [])
|
22
65
|
```
|
@@ -4,8 +4,9 @@
|
|
4
4
|
|
5
5
|
from datetime import datetime, timedelta
|
6
6
|
from google.transit import gtfs_realtime_pb2
|
7
|
-
|
7
|
+
|
8
8
|
import requests
|
9
|
+
|
9
10
|
import logging
|
10
11
|
import re
|
11
12
|
import json #For the output
|
@@ -76,6 +77,110 @@ class TransportNSWv2(object):
|
|
76
77
|
ATTR_ALERTS: '[]'
|
77
78
|
}
|
78
79
|
|
80
|
+
|
81
|
+
def check_stops(self, api_key, stops):
|
82
|
+
# Check the list of stops and return a JSON array of the stop details, plus if all the checked stops existed
|
83
|
+
# Return a JSON array of the results
|
84
|
+
|
85
|
+
# Sanity checking
|
86
|
+
if isinstance(stops, str):
|
87
|
+
# If it's a single string, convert it to a list
|
88
|
+
stops = [stops]
|
89
|
+
|
90
|
+
auth = 'apikey ' + api_key
|
91
|
+
header = {'Accept': 'application/json', 'Authorization': auth}
|
92
|
+
|
93
|
+
#Prepare the output string
|
94
|
+
all_stops_valid = True
|
95
|
+
stop_list = []
|
96
|
+
skip_api_calls = False
|
97
|
+
|
98
|
+
for stop in stops:
|
99
|
+
url = \
|
100
|
+
'https://api.transport.nsw.gov.au/v1/tp/stop_finder?' \
|
101
|
+
'outputFormat=rapidJSON&coordOutputFormat=EPSG%3A4326' \
|
102
|
+
'&type_sf=stop&name_sf=' + stop + \
|
103
|
+
'&TfNSWSF=true'
|
104
|
+
|
105
|
+
# Send the query
|
106
|
+
try:
|
107
|
+
url = 'https://api.transport.nsw.gov.au/v1/tp/stop_finder?outputFormat=rapidJSON&coordOutputFormat=EPSG%3A4326&type_sf=stop&name_sf=' + stop + '&TfNSWSF=true'
|
108
|
+
error_code = 0
|
109
|
+
|
110
|
+
if not skip_api_calls:
|
111
|
+
response = requests.get(url, headers=header, timeout=5)
|
112
|
+
else:
|
113
|
+
# An earlier call resulted in an API key error so no point trying again
|
114
|
+
response.status_code = 401
|
115
|
+
|
116
|
+
# If we get bad status code, handle it depending on the error type
|
117
|
+
if response.status_code != 200:
|
118
|
+
# We can't be sure that all the stops are valid
|
119
|
+
error_code = response.status_code
|
120
|
+
stop_detail = []
|
121
|
+
|
122
|
+
if response.status_code == 401:
|
123
|
+
# API key issue - log that, and don't bother with the other calls as they will all fail
|
124
|
+
skip_api_calls = True
|
125
|
+
all_stops_valid = False
|
126
|
+
logger.error(f"Error {str(response.status_code)} calling /v1/tp/stop_finder API; invalid API key")
|
127
|
+
|
128
|
+
elif response.status_code == 403 or response.status_code == 429:
|
129
|
+
# We've exceeded the rate limit but that doesn't mean the stop isn't valid
|
130
|
+
# So let's assume that the stop ID is probably ok but we'll still raise a warning
|
131
|
+
logger.warn(f"Error {str(response.status_code)} calling /v1/tp/stop_finder API; rate limit exceeded - assuming stop is valid")
|
132
|
+
|
133
|
+
else:
|
134
|
+
# A misc error - log it
|
135
|
+
all_stops_valid = False
|
136
|
+
logger.error(f"Error {str(response.status_code)} calling /v1/tp/stop_finder API")
|
137
|
+
else:
|
138
|
+
# Parse the result as a JSON object
|
139
|
+
stop_detail = response.json()
|
140
|
+
|
141
|
+
# Just a quick check - the presence of systemMessages signifies an error, otherwise we assume it's ok
|
142
|
+
if 'systemMessages' in stop_detail:
|
143
|
+
all_stops_valid = False
|
144
|
+
error_code = stop_detail['systemMessages'][0]['code']
|
145
|
+
error_text = stop_detail['systemMessages'][0]['text']
|
146
|
+
stop_detail = []
|
147
|
+
|
148
|
+
logger.error(f"Error {error_code} calling /v1/tp/stop_finder API; {error_text} for Stop ID {stop}")
|
149
|
+
|
150
|
+
# Put in a pause here to try and make sure we stay under the 5 API calls/second limit
|
151
|
+
# Not usually an issue but if multiple processes are running multiple calls we might hit it
|
152
|
+
time.sleep(1.0)
|
153
|
+
|
154
|
+
except Exception as ex:
|
155
|
+
# Some other kind of error, we should assume that the stop is invalid
|
156
|
+
error_code = 999
|
157
|
+
stop_detail = []
|
158
|
+
|
159
|
+
logger.error(f"Error {str(ex)} calling /v1/tp/stop_finder API; assuming stop is invalid")
|
160
|
+
|
161
|
+
finally:
|
162
|
+
# Append the results to the JSON output - only return the 'isBest' location entry if there's more than one
|
163
|
+
if stop_detail != []:
|
164
|
+
stop_valid = True
|
165
|
+
for location in stop_detail['locations']:
|
166
|
+
if location['isBest']:
|
167
|
+
stop_detail = location
|
168
|
+
|
169
|
+
break
|
170
|
+
|
171
|
+
else:
|
172
|
+
stop_valid = False
|
173
|
+
|
174
|
+
#Add it to the list
|
175
|
+
data = {"stop_id": stop, "valid": stop_valid, "error_code": error_code, "stop_detail": stop_detail}
|
176
|
+
stop_list.append (data)
|
177
|
+
|
178
|
+
# Complete the JSON output and return it
|
179
|
+
data = {"all_stops_valid": all_stops_valid, "stop_list": stop_list}
|
180
|
+
#return json.dumps(data)
|
181
|
+
return data
|
182
|
+
|
183
|
+
|
79
184
|
def get_trip(self, name_origin, name_destination , api_key, journey_wait_time = 0, transport_type = 0, \
|
80
185
|
strict_transport_type = False, raw_output = False, journeys_to_return = 1, route_filter = '', \
|
81
186
|
include_realtime_location = True, include_alerts = 'none', alert_type = 'all', check_stop_ids = True, forced_gtfs_uri = []):
|
@@ -108,44 +213,18 @@ class TransportNSWv2(object):
|
|
108
213
|
# First, check if the source and dest stops are valid unless we've been told not to
|
109
214
|
if check_stop_ids:
|
110
215
|
stop_list = [name_origin, name_destination]
|
216
|
+
data = self.check_stops(api_key, stop_list)
|
111
217
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
218
|
+
if not data['all_stops_valid']:
|
219
|
+
# One or both of those stops was invalid - log an error and exit
|
220
|
+
stop_error = ""
|
221
|
+
for stop in data['stop_list']:
|
222
|
+
if not stop['valid']:
|
223
|
+
stop_error += stop['stop_id']+ ", "
|
118
224
|
|
119
|
-
|
120
|
-
|
121
|
-
response = requests.get(url, headers=header, timeout=5)
|
122
|
-
|
123
|
-
# If we get bad status code, log error and return with None
|
124
|
-
if response.status_code != 200:
|
125
|
-
if response.status_code == 429:
|
126
|
-
# We've exceeded the rate limit but that doesn't mean future calls won't work
|
127
|
-
# So let's assume that the stop ID is ok but we'll still raise a warning
|
128
|
-
logger.warn(f"Error {str(response.status_code)} calling /v1/tp/stop_finder API; rate limit exceeded - assuming stop is valid")
|
129
|
-
else:
|
130
|
-
# If it's an API key issue there's no point in continuing, hence returning None
|
131
|
-
logger.error(f"Error {str(response.status_code)} calling /v1/tp/stop_finder API; check API key")
|
132
|
-
return None
|
133
|
-
else:
|
134
|
-
# Parse the result as a JSON object
|
135
|
-
result = response.json()
|
136
|
-
|
137
|
-
# Just a quick check - the presence of systemMessages signifies an error, otherwise we assume it's ok
|
138
|
-
if 'systemMessages' in result:
|
139
|
-
logger.error(f"Error - Stop ID {stop} doesn't exist")
|
140
|
-
return None
|
141
|
-
|
142
|
-
# Put in a pause here to try and make sure we stay under the 5 API calls/second limit
|
143
|
-
# Not usually an issue but if multiple processes are running multiple calls we might hit it
|
144
|
-
time.sleep(1.0)
|
225
|
+
logger.error(f"Stop ID(s) {stop_error[:-2]} do not exist - exiting")
|
226
|
+
return None
|
145
227
|
|
146
|
-
except Exception as ex:
|
147
|
-
logger.error(f"Error {str(ex)} calling /v1/tp/stop_finder API; assuming stop is valid")
|
148
|
-
return None
|
149
228
|
|
150
229
|
# 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
|
151
230
|
# 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
|
@@ -164,6 +243,8 @@ class TransportNSWv2(object):
|
|
164
243
|
# Otherwise store the response for the next steps
|
165
244
|
try:
|
166
245
|
response = requests.get(url, headers=header, timeout=10)
|
246
|
+
|
247
|
+
|
167
248
|
except Exception as ex:
|
168
249
|
logger.error(f"Error {str(ex)} calling /v1/tp/trip API")
|
169
250
|
return None
|
@@ -207,17 +288,17 @@ class TransportNSWv2(object):
|
|
207
288
|
|
208
289
|
for current_journey_index in range (0, retrieved_journeys, 1):
|
209
290
|
# Look for a trip with a matching transport type filter in at least one of its legs. Either ANY, or the first leg, depending on how strict we're being
|
210
|
-
journey, next_journey_index = self.
|
291
|
+
journey, next_journey_index = self._find_next_journey(result['journeys'], current_journey_index, transport_type, strict_transport_type, route_filter)
|
211
292
|
|
212
293
|
if ((journey is None) or (journey['legs']) is None):
|
213
294
|
pass
|
214
295
|
else:
|
215
296
|
legs = journey['legs']
|
216
|
-
first_leg = self.
|
297
|
+
first_leg = self._find_first_leg(legs, transport_type, strict_transport_type, route_filter)
|
217
298
|
|
218
299
|
#Executive decision - don't be strict on the last leg, there's often some walking (transport type 100) involved.
|
219
|
-
last_leg = self.
|
220
|
-
changes = self.
|
300
|
+
last_leg = self._find_last_leg(legs, transport_type, False)
|
301
|
+
changes = self._find_changes(legs, transport_type)
|
221
302
|
|
222
303
|
origin = first_leg['origin']
|
223
304
|
first_stop = first_leg['destination']
|
@@ -235,7 +316,7 @@ class TransportNSWv2(object):
|
|
235
316
|
delay = int((t1-t2) / 60)
|
236
317
|
|
237
318
|
# How long until it leaves?
|
238
|
-
due = self.
|
319
|
+
due = self._get_due(datetime.strptime(origin_departure_time, fmt))
|
239
320
|
|
240
321
|
# Destination info
|
241
322
|
destination_stop_id = destination['id']
|
@@ -243,7 +324,7 @@ class TransportNSWv2(object):
|
|
243
324
|
destination_arrival_time = destination['arrivalTimeEstimated']
|
244
325
|
|
245
326
|
# Origin type info - train, bus, etc
|
246
|
-
origin_mode = self.
|
327
|
+
origin_mode = self._get_mode(transportation['product']['class'])
|
247
328
|
origin_mode_name = transportation['product']['name']
|
248
329
|
|
249
330
|
# RealTimeTripID info so we can try and get the current location later
|
@@ -272,7 +353,7 @@ class TransportNSWv2(object):
|
|
272
353
|
if self.include_alerts != 'none':
|
273
354
|
# We'll be adding these to the returned JSON string as an array
|
274
355
|
# Only include alerts of the specified priority or greater, and of the specified type
|
275
|
-
alerts = self.
|
356
|
+
alerts = self._find_alerts(legs, self.include_alerts, self.alert_type)
|
276
357
|
|
277
358
|
latitude = 'n/a'
|
278
359
|
longitude = 'n/a'
|
@@ -284,11 +365,11 @@ class TransportNSWv2(object):
|
|
284
365
|
# ie it's been determined elsewhere then it can be forced
|
285
366
|
|
286
367
|
bFoundTripID = False
|
287
|
-
url_base_path = self.
|
368
|
+
url_base_path = self._get_base_url(origin_mode)
|
288
369
|
|
289
370
|
# Check for a forced URI
|
290
371
|
if not forced_gtfs_uri:
|
291
|
-
url_mode_list = self.
|
372
|
+
url_mode_list = self._get_mode_list(origin_mode, agencyid)
|
292
373
|
else:
|
293
374
|
# We've been forced to use a specific URI!
|
294
375
|
url_mode_list = forced_gtfs_uri
|
@@ -370,8 +451,8 @@ class TransportNSWv2(object):
|
|
370
451
|
return json_output
|
371
452
|
|
372
453
|
|
373
|
-
def
|
374
|
-
#
|
454
|
+
def _find_next_journey(self, journeys, start_journey_index, journeytype, strict, route_filter):
|
455
|
+
# Find the next journey that has a leg of the requested type, and/or that satisfies the route filter
|
375
456
|
journey_count = len(journeys)
|
376
457
|
|
377
458
|
# Some basic error checking
|
@@ -379,7 +460,7 @@ class TransportNSWv2(object):
|
|
379
460
|
return None, None
|
380
461
|
|
381
462
|
for journey_index in range (start_journey_index, journey_count, 1):
|
382
|
-
leg = self.
|
463
|
+
leg = self._find_first_leg(journeys[journey_index]['legs'], journeytype, strict, route_filter)
|
383
464
|
if leg is not None:
|
384
465
|
return journeys[journey_index], journey_index + 1
|
385
466
|
else:
|
@@ -389,7 +470,7 @@ class TransportNSWv2(object):
|
|
389
470
|
return None, None
|
390
471
|
|
391
472
|
|
392
|
-
def
|
473
|
+
def _find_first_leg(self, legs, legtype, strict, route_filter):
|
393
474
|
# Find the first leg of the requested type
|
394
475
|
leg_count = len(legs)
|
395
476
|
for leg_index in range (0, leg_count, 1):
|
@@ -419,7 +500,7 @@ class TransportNSWv2(object):
|
|
419
500
|
return None
|
420
501
|
|
421
502
|
|
422
|
-
def
|
503
|
+
def _find_last_leg(self, legs, legtype, strict):
|
423
504
|
# Find the last leg of the requested type
|
424
505
|
leg_count = len(legs)
|
425
506
|
for leg_index in range (leg_count - 1, -1, -1):
|
@@ -441,7 +522,7 @@ class TransportNSWv2(object):
|
|
441
522
|
return None
|
442
523
|
|
443
524
|
|
444
|
-
def
|
525
|
+
def _find_changes(self, legs, legtype):
|
445
526
|
# Find out how often we have to change
|
446
527
|
changes = 0
|
447
528
|
leg_count = len(legs)
|
@@ -454,11 +535,11 @@ class TransportNSWv2(object):
|
|
454
535
|
return changes - 1
|
455
536
|
|
456
537
|
|
457
|
-
def
|
538
|
+
def _find_alerts(self, legs, priority_filter, alert_type):
|
458
539
|
# Return an array of all the alerts on this trip that meet the priority level and alert type
|
459
540
|
leg_count = len(legs)
|
460
541
|
found_alerts = []
|
461
|
-
priority_minimum = self.
|
542
|
+
priority_minimum = self._get_alert_priority(priority_filter)
|
462
543
|
alert_list = alert_type.split("|")
|
463
544
|
|
464
545
|
for leg_index in range (0, leg_count, 1):
|
@@ -466,14 +547,14 @@ class TransportNSWv2(object):
|
|
466
547
|
if 'infos' in current_leg:
|
467
548
|
alerts = current_leg['infos']
|
468
549
|
for alert in alerts:
|
469
|
-
if (self.
|
550
|
+
if (self._get_alert_priority(alert['priority'])) >= priority_minimum:
|
470
551
|
if (alert_type == 'all') or (alert['type'].lower() in alert_list):
|
471
552
|
found_alerts.append (alert)
|
472
553
|
|
473
554
|
return json.dumps(found_alerts)
|
474
555
|
|
475
556
|
|
476
|
-
def
|
557
|
+
def _find_hints(self, legs, legtype, priority):
|
477
558
|
# Return an array of all the hints on this trip that meet the priority type
|
478
559
|
leg_count = len(legs)
|
479
560
|
|
@@ -484,7 +565,7 @@ class TransportNSWv2(object):
|
|
484
565
|
hints = current_leg['hints']
|
485
566
|
|
486
567
|
|
487
|
-
def
|
568
|
+
def _get_mode(self, iconId):
|
488
569
|
"""Map the iconId to a full text string"""
|
489
570
|
modes = {
|
490
571
|
1 : "Train",
|
@@ -501,7 +582,7 @@ class TransportNSWv2(object):
|
|
501
582
|
|
502
583
|
return modes.get(iconId, None)
|
503
584
|
|
504
|
-
def
|
585
|
+
def _get_base_url(self, mode):
|
505
586
|
# Map the journey mode to the proper base real time location URL
|
506
587
|
v1_url = "https://api.transport.nsw.gov.au/v1/gtfs/vehiclepos"
|
507
588
|
v2_url = "https://api.transport.nsw.gov.au/v2/gtfs/vehiclepos"
|
@@ -519,7 +600,7 @@ class TransportNSWv2(object):
|
|
519
600
|
return url_options.get(mode, None)
|
520
601
|
|
521
602
|
|
522
|
-
def
|
603
|
+
def _get_alert_priority(self, alert_priority):
|
523
604
|
# Map the alert priority to a number so we can filter later
|
524
605
|
|
525
606
|
alert_priorities = {
|
@@ -533,7 +614,7 @@ class TransportNSWv2(object):
|
|
533
614
|
return alert_priorities.get(alert_priority.lower(), 4)
|
534
615
|
|
535
616
|
|
536
|
-
def
|
617
|
+
def _get_mode_list(self, mode, agencyid):
|
537
618
|
"""
|
538
619
|
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
|
539
620
|
which will give us the appropriate URL to call later - we still have to do light rail the old-fashioned, brute-force way though
|
@@ -581,7 +662,7 @@ class TransportNSWv2(object):
|
|
581
662
|
return url_options.get(mode, None)
|
582
663
|
|
583
664
|
|
584
|
-
def
|
665
|
+
def _get_due(self, estimated):
|
585
666
|
# Minutes until departure
|
586
667
|
due = 0
|
587
668
|
if estimated > datetime.utcnow():
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
|
|
5
5
|
|
6
6
|
setuptools.setup(
|
7
7
|
name="PyTransportNSWv2",
|
8
|
-
version="0.9.
|
8
|
+
version="0.9.2",
|
9
9
|
author="andystewart999",
|
10
10
|
author_email="andy.stewart@live.com",
|
11
11
|
description="Get detailed per-trip transport information from TransportNSW",
|
@@ -14,8 +14,7 @@ setuptools.setup(
|
|
14
14
|
url="https://github.com/andystewart999/TransportNSW",
|
15
15
|
packages=setuptools.find_packages(),
|
16
16
|
install_requires=[
|
17
|
-
'gtfs-realtime-bindings'
|
18
|
-
'httpx',
|
17
|
+
'gtfs-realtime-bindings'
|
19
18
|
],
|
20
19
|
classifiers=[
|
21
20
|
"Programming Language :: Python :: 3",
|
File without changes
|
File without changes
|
{PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/PyTransportNSWv2.egg-info/TransportNSWv2.py
RENAMED
File without changes
|
{PyTransportNSWv2-0.9.0 → PyTransportNSWv2-0.9.2}/PyTransportNSWv2.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|