PyTransportNSWv2 0.2.3__py3-none-any.whl → 0.3.0__py3-none-any.whl
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.2.3.dist-info → PyTransportNSWv2-0.3.0.dist-info}/LICENSE +0 -0
- {PyTransportNSWv2-0.2.3.dist-info → PyTransportNSWv2-0.3.0.dist-info}/METADATA +19 -20
- PyTransportNSWv2-0.3.0.dist-info/RECORD +7 -0
- {PyTransportNSWv2-0.2.3.dist-info → PyTransportNSWv2-0.3.0.dist-info}/WHEEL +1 -1
- TransportNSW/TransportNSW.py +55 -26
- PyTransportNSWv2-0.2.3.dist-info/RECORD +0 -8
- TransportNSW/test.py +0 -28
- {PyTransportNSWv2-0.2.3.dist-info → PyTransportNSWv2-0.3.0.dist-info}/top_level.txt +0 -0
File without changes
|
@@ -1,17 +1,16 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: PyTransportNSWv2
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0
|
4
4
|
Summary: Get detailed per-trip transport information from TransportNSW
|
5
5
|
Home-page: https://github.com/andystewart999/TransportNSW
|
6
6
|
Author: andystewart999
|
7
|
-
License: UNKNOWN
|
8
|
-
Platform: UNKNOWN
|
9
7
|
Classifier: Programming Language :: Python :: 3
|
10
8
|
Classifier: License :: OSI Approved :: MIT License
|
11
9
|
Classifier: Operating System :: OS Independent
|
12
10
|
Classifier: Intended Audience :: Developers
|
13
11
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
14
12
|
Description-Content-Type: text/markdown
|
13
|
+
License-File: LICENSE
|
15
14
|
Requires-Dist: gtfs-realtime-bindings
|
16
15
|
|
17
16
|
# TransportNSW
|
@@ -29,47 +28,47 @@ The library needs the stop ID for the source and destination, and optionally how
|
|
29
28
|
If it's available, the general occupancy level and the latitude and longitude of the selected journey's vehicle (train, bus, etc) will be returned.
|
30
29
|
|
31
30
|
### API Documentation
|
32
|
-
The source API details can be found here: https://opendata.transport.nsw.gov.au/
|
31
|
+
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
|
33
32
|
|
34
33
|
### Parameters
|
35
34
|
```python
|
36
35
|
.get_trip(origin_stop_id, destination_stop_id, api_key, [trip_wait_time = 0])
|
37
36
|
```
|
38
37
|
|
38
|
+
TransportNSW's trip planner works much better if you use the general location IDs (eg Central Station) rather than a specific platform id (eg Central Station, Platform 19). Forcing a specific platform sometimes results in much more complicated trips.
|
39
|
+
|
39
40
|
### Sample Code
|
40
|
-
The following example will return the next trip from
|
41
|
+
The following example will return the next trip from a bus stop in St. Ives to Central Station, without specifying a specific destination platform.
|
41
42
|
|
42
43
|
**Code:**
|
43
44
|
```python
|
44
45
|
from TransportNSW import TransportNSW
|
45
46
|
tnsw = TransportNSW()
|
46
|
-
journey = tnsw.get_trip('
|
47
|
+
journey = tnsw.get_trip('207537', '10101100', 'YOUR_API_KEY')
|
47
48
|
print(journey)
|
48
49
|
```
|
49
50
|
**Result:**
|
50
51
|
```python
|
51
|
-
{'due':
|
52
|
+
{'due': 23, 'origin_stop_id': '207537', 'origin_name': 'St Ives, Mona Vale Rd at Shinfield Ave', 'departure_time': '2020-06-28T10:10:00Z', 'destination_stop_id': '2000338', 'destination_name': 'Sydney, Central Station, Platform 18', 'arrival_time': '2020-06-28T11:02:00Z', 'origin_transport_type': 'Bus', 'origin_transport_name': 'Sydney Buses Network', 'origin_line_name': '195', 'origin_line_name_short': '195', 'changes': 1, 'occupancy': 'UNKNOWN', 'real_time_trip_id': '612993', 'latitude': 'n/a', 'longitude': 'n/a'}
|
52
53
|
```
|
53
54
|
|
54
|
-
* due: the time (in minutes) before the
|
55
|
+
* due: the time (in minutes) before the journey starts
|
55
56
|
* origin_stop_id: the specific departure stop id
|
56
|
-
* origin_name: the name of the
|
57
|
-
*
|
57
|
+
* origin_name: the name of the departure location
|
58
|
+
* departure_time: the departure time
|
59
|
+
* destination_stop_id: the specific destination stop id
|
60
|
+
* destination_name: the name of the destination location
|
58
61
|
* arrival_time: the arrival time at the origin
|
59
|
-
*
|
60
|
-
*
|
61
|
-
*
|
62
|
-
*
|
62
|
+
* origin_transport_type: the type of transport, eg train, bus, ferry etc
|
63
|
+
* origin_transport_name: the full name of transport providere
|
64
|
+
* origin_line_name & origin_line_name_short: the full and short names of the journey
|
65
|
+
* changes: how many transport changes are needed
|
66
|
+
* occupancy: how full the vehicle is, if available
|
63
67
|
* real_time_trip_id: the unique TransportNSW id for that specific journey
|
64
68
|
* latitude & longitude: The location of the vehicle, if available
|
65
69
|
|
66
|
-
|
67
|
-
* Add an option to filter by specific transport type, useful if the general departure and arrival ids are being used
|
68
|
-
* Add an option to show brief vs verbose information
|
70
|
+
Please note that the origin and destination detail is just that. We don't return any intermediate steps, transport change types etc other than the total number of changes. The assumption is that you'll know the details of your specified trip, you just want to know when the next departure is. If you need much more detailed information then I recommend that you use the full Transport NSW trip planner website or application.
|
69
71
|
|
70
72
|
## Thank you
|
71
73
|
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!
|
72
|
-
|
73
74
|
https://github.com/Dav0815/TransportNSW
|
74
|
-
|
75
|
-
|
@@ -0,0 +1,7 @@
|
|
1
|
+
TransportNSW/TransportNSW.py,sha256=jjuFpL2FqIKAmDE0IvgULzLqO1QZ4tE-wrUHTYs9iwY,12930
|
2
|
+
TransportNSW/__init__.py,sha256=O3iuSkUGkkDz4C7IlqvOXJHPJTxYz0q_48-94ESlkdg,86
|
3
|
+
PyTransportNSWv2-0.3.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
4
|
+
PyTransportNSWv2-0.3.0.dist-info/METADATA,sha256=86_6bT24mMIYXlUWzLlEZ97fgyG3I9gdgokDcsMy2sU,4500
|
5
|
+
PyTransportNSWv2-0.3.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
+
PyTransportNSWv2-0.3.0.dist-info/top_level.txt,sha256=C4LQEkr85VJtG9cklBu9IFpSKRaNSADPBTSPeXIYnOw,13
|
7
|
+
PyTransportNSWv2-0.3.0.dist-info/RECORD,,
|
TransportNSW/TransportNSW.py
CHANGED
@@ -46,6 +46,7 @@ class TransportNSW(object):
|
|
46
46
|
self.destination_id = None
|
47
47
|
self.api_key = None
|
48
48
|
self.trip_wait_time = None
|
49
|
+
self.transport_type = None
|
49
50
|
self.info = {
|
50
51
|
ATTR_DUE_IN : 'n/a',
|
51
52
|
ATTR_ORIGIN_STOP_ID : 'n/a',
|
@@ -65,7 +66,7 @@ class TransportNSW(object):
|
|
65
66
|
ATTR_LONGITUDE : 'n/a'
|
66
67
|
}
|
67
68
|
|
68
|
-
def get_trip(self, name_origin, name_destination , api_key, trip_wait_time = 0):
|
69
|
+
def get_trip(self, name_origin, name_destination , api_key, trip_wait_time = 0, transport_type = 0):
|
69
70
|
"""Get the latest data from Transport NSW."""
|
70
71
|
fmt = '%Y-%m-%dT%H:%M:%SZ'
|
71
72
|
|
@@ -73,12 +74,20 @@ class TransportNSW(object):
|
|
73
74
|
self.destination = name_destination
|
74
75
|
self.api_key = api_key
|
75
76
|
self.trip_wait_time = trip_wait_time
|
77
|
+
self.transport_type = transport_type
|
76
78
|
|
77
79
|
# This query always uses the current date and time - but add in any 'trip_wait_time' minutes
|
78
80
|
now_plus_wait = datetime.now() + timedelta(minutes = trip_wait_time)
|
79
81
|
itdDate = now_plus_wait.strftime('%Y%m%d')
|
80
82
|
itdTime = now_plus_wait.strftime('%H%M')
|
81
83
|
|
84
|
+
if transport_type == 0:
|
85
|
+
# We only need to retrieve one trip - a transport type filter hasn't been applied
|
86
|
+
numberOfTrips = 1
|
87
|
+
else:
|
88
|
+
# 5 trips seems like a safe number
|
89
|
+
numberOfTrips = 5
|
90
|
+
|
82
91
|
# Build the entire URL
|
83
92
|
url = \
|
84
93
|
'https://api.transport.nsw.gov.au/v1/tp/trip?' \
|
@@ -86,7 +95,9 @@ class TransportNSW(object):
|
|
86
95
|
'&depArrMacro=dep&itdDate=' + itdDate + '&itdTime=' + itdTime + \
|
87
96
|
'&type_origin=any&name_origin=' + name_origin + \
|
88
97
|
'&type_destination=any&name_destination=' + name_destination + \
|
89
|
-
'&calcNumberOfTrips=
|
98
|
+
'&calcNumberOfTrips=' + str(numberOfTrips) + \
|
99
|
+
'&TfNSWTR=true'
|
100
|
+
|
90
101
|
auth = 'apikey ' + self.api_key
|
91
102
|
header = {'Accept': 'application/json', 'Authorization': auth}
|
92
103
|
|
@@ -106,21 +117,28 @@ class TransportNSW(object):
|
|
106
117
|
|
107
118
|
# Parse the result as a JSON object
|
108
119
|
result = response.json()
|
109
|
-
print (result)
|
110
120
|
|
111
121
|
# The API will always return a valid trip, so it's just a case of grabbing what we need...
|
112
122
|
# We're only reporting on the origin and destination, it's out of scope to discuss the specifics of the ENTIRE journey
|
113
123
|
# This isn't a route planner, just a 'how long until the next journey I've specified' tool
|
114
124
|
# The assumption is that the travelee will know HOW to make the defined journey, they're just asking WHEN it's happening next
|
125
|
+
# All we potentially have to do is find the first trip that matches the transport_type filter
|
126
|
+
|
127
|
+
if transport_type == 0:
|
128
|
+
# Just grab the first (and only) trip
|
129
|
+
journey = result['journeys'][0]
|
130
|
+
else:
|
131
|
+
# Look for a trip with a matching class filter in at least one of its legs. Could possibly be more stringent here, if ANY part of the journey fits the filter, it will be returned.
|
132
|
+
journey = self.find_first_journey(result['journeys'], transport_type)
|
115
133
|
|
116
|
-
legs =
|
117
|
-
first_leg = self.find_first_leg(legs)
|
118
|
-
last_leg = self.find_last_leg(legs)
|
119
|
-
changes = self.find_changes(legs)
|
134
|
+
legs = journey['legs']
|
135
|
+
first_leg = self.find_first_leg(legs, transport_type)
|
136
|
+
last_leg = self.find_last_leg(legs, transport_type)
|
137
|
+
changes = self.find_changes(legs, transport_type)
|
120
138
|
|
121
139
|
origin = result['journeys'][0]['legs'][first_leg]['origin']
|
122
140
|
# probably tidy this up when we start to get occupancy data back
|
123
|
-
|
141
|
+
first_stop = result['journeys'][0]['legs'][first_leg]['destination']
|
124
142
|
destination = result['journeys'][0]['legs'][last_leg]['destination']
|
125
143
|
transportation = result['journeys'][0]['legs'][first_leg]['transportation']
|
126
144
|
|
@@ -155,9 +173,9 @@ class TransportNSW(object):
|
|
155
173
|
|
156
174
|
# Occupancy info, if it's there
|
157
175
|
occupancy = 'UNKNOWN'
|
158
|
-
if 'properties' in
|
159
|
-
if 'occupancy' in
|
160
|
-
occupancy =
|
176
|
+
if 'properties' in first_stop:
|
177
|
+
if 'occupancy' in first_stop['properties']:
|
178
|
+
occupancy = first_stop['properties']['occupancy']
|
161
179
|
|
162
180
|
# Now might be a good time to see if we can also find the latitude and longitude
|
163
181
|
# Using the Realtime Vehicle Positions API
|
@@ -226,43 +244,51 @@ class TransportNSW(object):
|
|
226
244
|
}
|
227
245
|
return self.info
|
228
246
|
|
247
|
+
def find_first_journey(self, journeys, journeytype):
|
248
|
+
# Find the first journey whose first leg is of the requested type
|
249
|
+
journey_count = len(journeys)
|
250
|
+
for journey in range (0, journey_count, 1):
|
251
|
+
leg = self.find_first_leg(journeys[journey]['legs'], journeytype)
|
252
|
+
if leg is not None:
|
253
|
+
return journeys[journey]
|
229
254
|
|
230
|
-
|
231
|
-
|
255
|
+
# Hmm, we didn't find one
|
256
|
+
return None
|
257
|
+
|
258
|
+
|
259
|
+
def find_first_leg(self, legs, legtype):
|
260
|
+
# Find the first leg of the requested type
|
232
261
|
leg_count = len(legs)
|
233
262
|
for leg in range (0, leg_count, 1):
|
234
263
|
leg_class = legs[leg]['transportation']['product']['class']
|
235
|
-
|
236
|
-
if leg_class
|
237
|
-
# 100 is the class for walking, anything less is a train, bus, etc
|
264
|
+
|
265
|
+
if leg_class == legtype or legtype == 0:
|
238
266
|
return leg
|
239
267
|
|
240
268
|
# Hmm, we didn't find one
|
241
269
|
return None
|
242
270
|
|
243
271
|
|
244
|
-
def find_last_leg(self, legs):
|
245
|
-
# Find the last
|
272
|
+
def find_last_leg(self, legs, legtype):
|
273
|
+
# Find the last leg of the requested type
|
246
274
|
leg_count = len(legs)
|
247
|
-
for leg in range (leg_count-1,
|
275
|
+
for leg in range (leg_count - 1, -1, -1):
|
248
276
|
leg_class = legs[leg]['transportation']['product']['class']
|
249
|
-
|
250
|
-
if leg_class
|
251
|
-
# 100 is the class for walking, anything less is a train, bus, etc
|
277
|
+
|
278
|
+
if leg_class == legtype or legtype == 0:
|
252
279
|
return leg
|
253
280
|
|
254
281
|
# Hmm, we didn't find one
|
255
282
|
return None
|
256
283
|
|
257
|
-
def find_changes(self, legs):
|
284
|
+
def find_changes(self, legs, legtype):
|
258
285
|
# Find out how often we have to change
|
259
286
|
changes = 0
|
260
287
|
leg_count = len(legs)
|
261
288
|
|
262
289
|
for leg in range (0, leg_count, 1):
|
263
290
|
leg_class = legs[leg]['transportation']['product']['class']
|
264
|
-
if leg_class
|
265
|
-
# 100 is the class for walking, anything less is a train, bus, etc
|
291
|
+
if leg_class == legtype or legtype == 0:
|
266
292
|
changes = changes + 1
|
267
293
|
|
268
294
|
return changes - 1
|
@@ -276,7 +302,10 @@ class TransportNSW(object):
|
|
276
302
|
5: "Bus",
|
277
303
|
7: "Coach",
|
278
304
|
9: "Ferry",
|
279
|
-
11: "School bus"
|
305
|
+
11: "School bus",
|
306
|
+
99: "Walk",
|
307
|
+
100: "Walk",
|
308
|
+
107: "Cycle"
|
280
309
|
}
|
281
310
|
return modes.get(iconId, None)
|
282
311
|
|
@@ -1,8 +0,0 @@
|
|
1
|
-
TransportNSW/TransportNSW.py,sha256=MMWtgjnE6-YQirVRO9O7wYABAXvys_aygg6s3dglbeA,11754
|
2
|
-
TransportNSW/__init__.py,sha256=O3iuSkUGkkDz4C7IlqvOXJHPJTxYz0q_48-94ESlkdg,86
|
3
|
-
TransportNSW/test.py,sha256=S9t1Tdz_Q1xbTPjCNgr5bFDPWgJgBHjNLMESx8xI7Ag,961
|
4
|
-
PyTransportNSWv2-0.2.3.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
5
|
-
PyTransportNSWv2-0.2.3.dist-info/METADATA,sha256=iisyfIwofXBEXQNf9aTb8lZ_xW9CpMnMtjjr8MbWAGs,3792
|
6
|
-
PyTransportNSWv2-0.2.3.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
|
7
|
-
PyTransportNSWv2-0.2.3.dist-info/top_level.txt,sha256=C4LQEkr85VJtG9cklBu9IFpSKRaNSADPBTSPeXIYnOw,13
|
8
|
-
PyTransportNSWv2-0.2.3.dist-info/RECORD,,
|
TransportNSW/test.py
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
from TransportNSW import TransportNSW
|
2
|
-
tnsw = TransportNSW()
|
3
|
-
|
4
|
-
sApiKey = 'oWwCalKSy0ZQB5JTw7sTXlcaOjv01fto1W3v'
|
5
|
-
#sStopId = '207261' #Gordon, platform 1
|
6
|
-
sStopId = '10101121' #Gordon station
|
7
|
-
#sDestId = '10101122' #Pymble station
|
8
|
-
#sStopId = '2000336' #Central, platform 16
|
9
|
-
#sDestId = '2015137' #Redfern, platform 7
|
10
|
-
#sStopId = '2015133' #Redfern, platform 11
|
11
|
-
#sStopId = '207248' # Gordon bus stop
|
12
|
-
#sDestId = '207537' # St Ives stop
|
13
|
-
#sDestId = '2073161' #Pymble station
|
14
|
-
#sStopId = '2000225' # Circular Quay Wharf 4
|
15
|
-
#sDestId = '20883' # Taronga Zoo Wharf
|
16
|
-
#sStopId = '20461' # Abbotsford
|
17
|
-
#sDestId = '2137186' # Cabarita
|
18
|
-
sDestId = '10101100' # Central
|
19
|
-
#sDestId = '10101421' # Redfern
|
20
|
-
|
21
|
-
sStopId = 'streetID:1500000021:8:95330012:1:Coree Pl:St Ives:Coree Pl::Coree Pl:2075:ANY:DIVA_SINGLEHOUSE:4885970:3740665:GDAV:nsw'
|
22
|
-
sDestId = '10101100'
|
23
|
-
|
24
|
-
nMinDueTime = 0
|
25
|
-
|
26
|
-
journey = tnsw.get_trip(sStopId, sDestId, sApiKey, nMinDueTime)
|
27
|
-
print (' ')
|
28
|
-
print(journey)
|
File without changes
|