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.
@@ -1,17 +1,16 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyTransportNSWv2
3
- Version: 0.2.3
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/node/601/exploreapi
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 Gordon Station to Pymble Station, without specifying a platform.
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('10101121', '10101123', 'YOUR_API_KEY')
47
+ journey = tnsw.get_trip('207537', '10101100', 'YOUR_API_KEY')
47
48
  print(journey)
48
49
  ```
49
50
  **Result:**
50
51
  ```python
51
- {'due': 5, 'origin_stop_id': '207263', 'origin_name': 'Gordon Station', 'origin_detail': 'Platform 3', 'departure_time': '2020-06-14T10:21:30Z', 'destination_stop_id': '2073162', 'destination_name': 'Pymble Station', 'destination_detail': 'Platform 2', 'arrival_time': '2020-06-14T10:23:30Z', 'transport_type': 'Train', 'transport_name': 'Sydney Trains Network', 'line_name': 'T1 North Shore & Western Line', 'line_name_short': 'T1', 'occupancy': 'UNKNOWN', 'real_time_trip_id': '104P.1379.110.128.T.8.61720413', 'latitude': -33.76505661010742, 'longitude': 151.1614227294922}
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 vehicle arrives
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 general departure location
57
- * origin_detail: the specific departure location
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
- * transport_type: the type of transport, eg train, bus, ferry etc
60
- * transport_name: the full name of transport providere
61
- * line_name & line_name_short: the full and short names of the journey
62
- * occupancy: how full the vehicle is
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
- ### To do:
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.34.2)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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=1&TfNSWDM=true&version=10.2.1.42'
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 = result['journeys'][0]['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
- first_destination = result['journeys'][0]['legs'][first_leg]['destination']
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 first_destination:
159
- if 'occupancy' in first_destination['properties']:
160
- occupancy = first_destination['properties']['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
- def find_first_leg(self, legs):
231
- # Find the first non-footpath leg
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
- #print (leg_class)
236
- if leg_class < 100:
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 non-footpath leg
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, 0, -1):
275
+ for leg in range (leg_count - 1, -1, -1):
248
276
  leg_class = legs[leg]['transportation']['product']['class']
249
- #print (leg_class)
250
- if leg_class < 100:
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 < 100:
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)