MBTAclient 0.2.0__tar.gz → 0.2.1__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.
Files changed (25) hide show
  1. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/PKG-INFO +1 -1
  2. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/pyproject.toml +1 -1
  3. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/MBTAclient.egg-info/PKG-INFO +1 -1
  4. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/base_handler.py +130 -98
  5. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/journey.py +20 -4
  6. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/journey_stop.py +23 -14
  7. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/journeys_handler.py +13 -9
  8. mbtaclient-0.2.1/src/main.py +171 -0
  9. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/mbta_alert.py +1 -1
  10. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/mbta_client.py +6 -6
  11. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/mbta_prediction.py +1 -1
  12. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/mbta_schedule.py +1 -1
  13. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/mbta_stop.py +1 -1
  14. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/mbta_trip.py +1 -1
  15. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/mbta_utils.py +2 -7
  16. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/trip_handler.py +24 -30
  17. mbtaclient-0.2.0/src/main.py +0 -173
  18. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/LICENSE +0 -0
  19. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/README.md +0 -0
  20. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/setup.cfg +0 -0
  21. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/MBTAclient.egg-info/SOURCES.txt +0 -0
  22. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/MBTAclient.egg-info/dependency_links.txt +0 -0
  23. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/MBTAclient.egg-info/top_level.txt +0 -0
  24. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/__init__.py +0 -0
  25. {mbtaclient-0.2.0 → mbtaclient-0.2.1}/src/mbta_route.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: MBTAclient
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: A Python client for interacting with the MBTA API
5
5
  Author-email: Luca Chiabrera <luca.chiabrera@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/chiabre/MBTAclient
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "MBTAclient"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  authors = [
5
5
  { name="Luca Chiabrera", email="luca.chiabrera@gmail.com" },
6
6
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: MBTAclient
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: A Python client for interacting with the MBTA API
5
5
  Author-email: Luca Chiabrera <luca.chiabrera@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/chiabre/MBTAclient
@@ -17,14 +17,22 @@ from mbta_alert import MBTAAlert
17
17
 
18
18
 
19
19
  class BaseHandler:
20
- """Base class for handling MBTA data."""
20
+ """Base class for handling MBTA journeys."""
21
21
 
22
- def __init__(self, session: aiohttp.ClientSession, api_key: str, depart_from_name: str , arrive_at_name: str) -> None:
23
-
22
+ def __init__(self, session: aiohttp.ClientSession, logger: logging.Logger, depart_from_name: str , arrive_at_name: str, api_key: str = None) -> None:
24
23
 
25
- self.mbta_client = MBTAClient(session, api_key)
26
- self.depart_from_name = depart_from_name
27
- self.arrive_at_name = arrive_at_name
24
+ self.depart_from = {
25
+ 'name' : depart_from_name,
26
+ 'stops' : None,
27
+ 'ids' : None
28
+ }
29
+ self.arrive_at = {
30
+ 'name' : arrive_at_name,
31
+ 'stops' : None,
32
+ 'ids' : None
33
+ }
34
+ self.mbta_client = MBTAClient(session,logger, api_key=api_key)
35
+
28
36
  self.journeys: dict[str, Journey] = {}
29
37
 
30
38
  # Caches
@@ -33,14 +41,24 @@ class BaseHandler:
33
41
  self._schedules_cache_date: Optional[date] = None
34
42
  self._trip_cache: dict[str, MBTATrip] = {}
35
43
  self._route_cache: dict[str, MBTARoute] = {}
36
- self._stop_name_cache: dict[str, list[MBTAStop]] = {}
44
+
45
+ # Logger
46
+ self.logger: logging.Logger = logger
47
+
48
+ def __repr__(self) -> str:
49
+ return (f"BaseHandler(depart_from_name={self.depart_from['name']}, arrive_at_name={self.arrive_at['name']})")
50
+
51
+
52
+ async def _async_init(self):
53
+ stops = await self.__fetch_stops()
54
+ self.__process_stops(stops)
37
55
 
38
- async def _fetch_stops(self, params: dict = None) -> list[MBTAStop]:
56
+ async def __fetch_stops(self, params: dict = None) -> list[MBTAStop]:
39
57
  """Retrieve and process stops with a non-expiring cache."""
58
+ self.logger.debug("Fetching MBTA stops")
40
59
 
41
60
  # Check if stops are already cached
42
61
  if self._stops_cache is not None:
43
- logging.info("Returning cached stops")
44
62
  return self._stops_cache
45
63
 
46
64
  # Cache is empty, so we fetch the stops from the API
@@ -51,70 +69,68 @@ class BaseHandler:
51
69
 
52
70
  try:
53
71
  stops: list[MBTAStop] = await self.mbta_client.list_stops(base_params)
54
- # Update the cache
72
+ self.logger.debug("Updating cached stops")
55
73
  self._stops_cache = stops
56
74
  return stops
57
75
 
58
76
  except Exception as e:
59
- logging.error(f"Error fetching stops: {e}")
77
+ self.logger.error(f"Error fetching stops: {e}")
60
78
  traceback.print_exc()
61
79
  return []
62
-
63
- async def _get_stops_ids(self) -> list[str]:
64
- departure_stop_ids = await self.__get_stops_ids_by_name(self.depart_from_name)
65
- arrival_stop_ids = await self.__get_stops_ids_by_name(self.arrive_at_name)
66
- return departure_stop_ids + arrival_stop_ids
67
-
68
- async def __get_stops_ids_by_name(self, stop_name: str ) -> list[str]:
69
- stops = await self.__get_stops_by_name(stop_name)
70
- stop_ids = [stop.id for stop in stops]
71
- return stop_ids
72
-
73
- async def _get_stops(self) -> list['MBTAStop']:
74
- departure_stops = await self.__get_stops_by_name(self.depart_from_name)
75
- arrival_stops = await self.__get_stops_by_name(self.arrive_at_name)
76
- return departure_stops + arrival_stops
77
-
78
- async def __get_stops_by_name(self, stop_name: str) -> list[MBTAStop]:
79
- # Check if the stops for the stop_name are already cached
80
- if stop_name.lower() in self._stop_name_cache:
81
- logging.info(f"Returning cached stops for stop_name: {stop_name}")
82
- return self._stop_name_cache[stop_name.lower()]
83
-
84
- # Fetch all stops (assuming _fetch_stops is asynchronous)
85
- stops = await self._fetch_stops()
86
-
87
- # Filter stops by the given name
88
- matching_stops = [stop for stop in stops if stop.name.lower() == stop_name.lower()]
89
-
90
- # Cache the result
91
- self._stop_name_cache[stop_name.lower()] = matching_stops
92
-
93
- return matching_stops
94
-
95
- async def _get_stop_by_id(self, stop_id: str) -> MBTAStop:
96
-
97
- # Fetch all stops (assuming _fetch_stops is asynchronous)
98
- stops = await self._fetch_stops()
99
-
100
- # Find the first stop that matches the given stop_id
80
+
81
+ def __process_stops(self, stops: list[MBTAStop]):
82
+ depart_from_stops = []
83
+ depart_from_ids = []
84
+ arrive_at_stops = []
85
+ arrive_at_ids = []
101
86
  for stop in stops:
87
+ if stop.name.lower() == self.depart_from['name'].lower():
88
+ depart_from_stops.append(stop)
89
+ depart_from_ids.append(stop.id)
90
+ if stop.name.lower() == self.arrive_at['name'].lower():
91
+ arrive_at_stops.append(stop)
92
+ arrive_at_ids.append(stop.id)
93
+
94
+ if len(depart_from_stops) == 0:
95
+ self.logger.error(f"Error fetching MBTA stop data for {self.depart_from['name']}")
96
+ raise ValueError(f"Invalid stop name: {self.depart_from['name']}")
97
+
98
+ if len(arrive_at_stops) == 0:
99
+ self.logger.error(f"Error fetching MBTA stop data for {self.arrive_at['name']}")
100
+ raise ValueError(f"Invalid stop name: {self.arrive_at['name']}")
101
+ else:
102
+ self.depart_from['stops'] = depart_from_stops
103
+ self.depart_from['ids'] = depart_from_ids
104
+ self.arrive_at['stops'] = arrive_at_stops
105
+ self.arrive_at['ids'] = arrive_at_ids
106
+
107
+ def __get_stop_by_id(self, stop_id: str) -> Optional[MBTAStop]:
108
+ for stop in (self.depart_from['stops'] + self.arrive_at['stops']):
102
109
  if stop.id == stop_id:
103
110
  return stop
104
-
105
- # Return None if no matching stop is found
106
111
  return None
107
-
112
+
113
+ def _get_stops_ids(self) -> list[str]:
114
+ return self.depart_from['ids'] + self.arrive_at['ids']
115
+
116
+ def __get_stops_ids_by_stop_type(self, stop_type: str) -> Optional[list[str]]:
117
+ if stop_type == 'departure':
118
+ return self.depart_from['ids']
119
+ elif stop_type == 'arrival':
120
+ return self.arrive_at['ids']
121
+ return None
122
+
108
123
  async def _fetch_schedules(self, params: Optional[dict] = None) -> list[MBTASchedule]:
109
124
  """Retrieve and process schedules for today."""
110
-
125
+ self.logger.debug("Fetching MBTA schedules")
126
+
111
127
  # Check if the cache is outdated
112
128
  if self._schedules_cache_date is not None and self._schedules_cache_date == date.today():
113
- logging.info("Returning cached schedules")
129
+ self.logger.debug("Returning cached schedules")
114
130
  return self._schedules_cache
115
131
 
116
132
  base_params = {
117
- 'filter[stop]': ','.join(await self._get_stops_ids()),
133
+ 'filter[stop]': ','.join(self._get_stops_ids()),
118
134
  'sort': 'departure_time'
119
135
  }
120
136
  if params is not None:
@@ -123,15 +139,17 @@ class BaseHandler:
123
139
  try:
124
140
  schedules: list[MBTASchedule] = await self.mbta_client.list_schedules(base_params)
125
141
  # Update the cache with new data and timestamp
142
+ self.logger.debug("Updating cached schedules")
126
143
  self._schedules_cache = schedules
127
144
  self._schedules_cache_date = date.today()
128
145
  return schedules
129
146
  except Exception as e:
130
- logging.error(f"Error fetching schedules: {e}")
147
+ self.logger.error(f"Error fetching schedules: {e}")
131
148
  traceback.print_exc()
132
149
  return []
133
150
 
134
151
  async def _process_schedules(self, schedules: list[MBTASchedule]):
152
+ self.logger.debug("Processing schedules")
135
153
 
136
154
  for schedule in schedules:
137
155
 
@@ -142,21 +160,22 @@ class BaseHandler:
142
160
  # add the journey to the journeys dict using the trip_id as key
143
161
  self.journeys[schedule.trip_id] = journey
144
162
 
145
- stop: MBTAStop = await self._get_stop_by_id(schedule.stop_id)
146
- departure_stop_ids = await self.__get_stops_ids_by_name(self.depart_from_name)
147
- arrival_stop_id = await self.__get_stops_ids_by_name(self.arrive_at_name)
163
+ stop: MBTAStop = self.__get_stop_by_id(schedule.stop_id)
164
+ departure_stops_ids = self.__get_stops_ids_by_stop_type('departure')
165
+ arrival_stops_ids = self.__get_stops_ids_by_stop_type('arrival')
148
166
 
149
- if schedule.stop_id in departure_stop_ids:
167
+ if schedule.stop_id in departure_stops_ids:
150
168
  self.journeys[schedule.trip_id].add_stop('departure',schedule,stop,'SCHEDULED')
151
- elif schedule.stop_id in arrival_stop_id:
169
+ elif schedule.stop_id in arrival_stops_ids:
152
170
  self.journeys[schedule.trip_id].add_stop('arrival',schedule, stop,'SCHEDULED')
153
171
 
154
172
 
155
173
  async def _fetch_predictions(self, params: str = None) -> list[MBTAPrediction]:
156
174
  """Retrieve and process predictions based on the provided stop IDs and route ID."""
157
-
175
+ self.logger.debug("Fetching MBTA predictions")
176
+
158
177
  base_params = {
159
- 'filter[stop]': ','.join(await self._get_stops_ids()),
178
+ 'filter[stop]': ','.join(self._get_stops_ids()),
160
179
  'filter[revenue]': 'REVENUE',
161
180
  'sort': 'departure_time'
162
181
  }
@@ -169,11 +188,12 @@ class BaseHandler:
169
188
  return predictions
170
189
 
171
190
  except Exception as e:
172
- logging.error(f"Error fetching predictions: {e}")
191
+ self.logger.error(f"Error fetching predictions: {e}")
173
192
  traceback.print_exc()
174
193
 
175
194
  async def _process_predictions (self, predictions: list[MBTAPrediction]):
176
-
195
+ self.logger.debug("Processing predictions")
196
+
177
197
  for prediction in predictions:
178
198
 
179
199
  # if the trip of the prediciton is not in the journeys dict
@@ -183,29 +203,27 @@ class BaseHandler:
183
203
  # add the journey to the journeys dict using the trip_id as key
184
204
  self.journeys[prediction.trip_id] = journey
185
205
 
186
- stop: MBTAStop = await self._get_stop_by_id(prediction.stop_id)
187
- departure_stop_ids = await self.__get_stops_ids_by_name(self.depart_from_name)
188
- arrival_stop_id = await self.__get_stops_ids_by_name(self.arrive_at_name)
206
+ stop: MBTAStop = self.__get_stop_by_id(prediction.stop_id)
207
+ departure_stops_ids = self.__get_stops_ids_by_stop_type('departure')
208
+ arrival_stops_ids = self.__get_stops_ids_by_stop_type('arrival')
189
209
 
190
210
  if prediction.schedule_relationship is None:
191
- prediction.schedule_relationship = 'DELAYED'
211
+ prediction.schedule_relationship = 'PREDICTED'
192
212
 
193
213
  # if the prediction stop id is in the departure stop ids
194
- if prediction.stop_id in departure_stop_ids:
195
-
214
+ if prediction.stop_id in departure_stops_ids:
196
215
  self.journeys[prediction.trip_id].add_stop('departure',prediction,stop,prediction.schedule_relationship)
197
-
198
216
  # if the prediction stop id is in the arrival stop ids
199
- if prediction.stop_id in arrival_stop_id:
200
-
217
+ if prediction.stop_id in arrival_stops_ids:
201
218
  self.journeys[prediction.trip_id].add_stop('arrival',prediction,stop,prediction.schedule_relationship)
202
219
 
203
220
  async def _fetch_alerts(self,params: str = None) -> list[MBTAAlert]:
204
221
  """Retrieve and associate alerts with the relevant journeys."""
205
-
222
+ self.logger.debug("Fetching MBTA alerts")
223
+
206
224
  # Prepare filter parameters
207
225
  base_params = {
208
- 'filter[stop]': ','.join(await self._get_stops_ids()),
226
+ 'filter[stop]': ','.join(self._get_stops_ids()),
209
227
  'filter[activity]': 'BOARD,EXIT,RIDE',
210
228
  'filter[datetime]': 'NOW'
211
229
  }
@@ -217,23 +235,24 @@ class BaseHandler:
217
235
  alerts: list[MBTAAlert] = await self.mbta_client.list_alerts(base_params)
218
236
  return alerts
219
237
  except Exception as e:
220
- logging.error(f"Error fetching alerts: {e}")
238
+ self.logger.error(f"Error fetching alerts: {e}")
221
239
  traceback.print_exc()
222
240
 
223
241
  def _process_alerts(self, alerts: list[MBTAAlert]):
242
+ self.logger.debug("Processing alerts")
224
243
 
225
- for alert in alerts:
226
-
227
- # Iterate through each journey and associate relevant alerts
228
- for journey in self.journeys.values():
229
- if alert in journey.alerts:
230
- continue # Skip if alert is already associated
244
+ for alert in alerts:
245
+
246
+ # Iterate through each journey and associate relevant alerts
247
+ for journey in self.journeys.values():
248
+ if alert in journey.alerts:
249
+ continue # Skip if alert is already associated
231
250
 
232
- # Check if the alert is relevant to the journey
233
- if self._is_alert_relevant(alert, journey):
234
- journey.alerts.append(alert)
251
+ # Check if the alert is relevant to the journey
252
+ if self.__is_alert_relevant(alert, journey):
253
+ journey.alerts.append(alert)
235
254
 
236
- def _is_alert_relevant(self, alert: MBTAAlert, journey: Journey) -> bool:
255
+ def __is_alert_relevant(self, alert: MBTAAlert, journey: Journey) -> bool:
237
256
  """Check if an alert is relevant to a given journey."""
238
257
  for informed_entity in alert.informed_entities:
239
258
  # Check informed entity stop relevance
@@ -246,12 +265,12 @@ class BaseHandler:
246
265
  if informed_entity.get('route') and informed_entity['route'] != journey.route.id:
247
266
  continue
248
267
  # Check activities relevance based on departure or arrival
249
- if not self._is_alert_activity_relevant(informed_entity, journey):
268
+ if not self.__is_alert_activity_relevant(informed_entity, journey):
250
269
  continue
251
270
  return True # Alert is relevant if all checks pass
252
271
  return False # Alert is not relevant
253
272
 
254
- def _is_alert_activity_relevant(self, informed_entity: dict, journey: Journey) -> bool:
273
+ def __is_alert_activity_relevant(self, informed_entity: dict, journey: Journey) -> bool:
255
274
  """Check if the activities of the informed entity are relevant to the journey."""
256
275
  departure_stop_id = journey.get_stop_id('departure')
257
276
  arrival_stop_id = journey.get_stop_id('arrival')
@@ -262,42 +281,55 @@ class BaseHandler:
262
281
  return False
263
282
  return True
264
283
 
265
- async def _fetch_trip(self, trip_id: str, params: dict = None) -> MBTATrip:
284
+ async def _fetch_trip(self, trip_id: str, params: dict = None) -> Optional[MBTATrip]:
266
285
  """Retrieve and process a trip with a non-expiring cache based on trip_id."""
286
+ self.logger.debug(f"Fetching MBTA trip: {trip_id} ")
267
287
 
268
288
  # Check if the trip is already cached
269
289
  if trip_id in self._trip_cache:
270
- logging.info(f"Returning cached trip for trip_id: {trip_id}")
290
+ self.logger.debug(f"Returning cached trip: {trip_id}")
271
291
  return self._trip_cache[trip_id]
272
292
 
273
293
  # Trip is not in the cache, so fetch it from the API
274
294
  try:
275
295
  trip: MBTATrip = await self.mbta_client.get_trip(trip_id, params)
276
- # Update the cache
296
+ self.logger.debug(f"Updating cached trip: {trip_id}")
277
297
  self._trip_cache[trip_id] = trip
278
298
  return trip
279
299
 
280
300
  except Exception as e:
281
- logging.error(f"Error fetching trip: {e}")
301
+ self.logger.error(f"Error fetching trip: {e}")
282
302
  traceback.print_exc()
283
303
  return None
284
304
 
285
- async def _fetch_route(self, route_id: str, params: dict = None) -> MBTARoute:
305
+ async def _fetch_route(self, route_id: str, params: dict = None) -> Optional[MBTARoute]:
286
306
  """Retrieve and process a route with a non-expiring cache based on route_id."""
307
+ self.logger.debug(f"Fetching MBTA route: {route_id} ")
287
308
 
288
309
  # Check if the trip is already cached
289
310
  if route_id in self._route_cache:
290
- logging.info(f"Returning cached trip for route_id: {route_id}")
291
311
  return self._route_cache[route_id]
292
312
 
293
313
  # Trip is not in the cache, so fetch it from the API
294
314
  try:
295
315
  route: MBTARoute = await self.mbta_client.get_route(route_id, params)
296
316
  # Update the cache
317
+ self.logger.debug(f"Updating cached route: {route_id}")
297
318
  self._route_cache[route_id] = route
298
319
  return route
299
320
 
300
321
  except Exception as e:
301
- logging.error(f"Error fetching route: {e}")
322
+ self.logger.error(f"Error fetching route: {e}")
302
323
  traceback.print_exc()
303
- return None
324
+ return None
325
+
326
+ async def _fetch_trips(self, params: dict = None) -> Optional[MBTARoute]:
327
+ self.logger.debug("Fetching MBTA trips")
328
+ try:
329
+ trips: list[MBTATrip] = await self.mbta_client.list_trips(params)
330
+ return trips
331
+ except Exception as e:
332
+ self.logger.error(f"Error fetching route: {e}")
333
+ traceback.print_exc()
334
+ return None
335
+
@@ -1,11 +1,14 @@
1
- from typing import Optional
1
+ from typing import Union, Optional
2
2
  from datetime import datetime
3
3
 
4
4
  from journey_stop import JourneyStop
5
+ from mbta_schedule import MBTASchedule
6
+ from mbta_prediction import MBTAPrediction
5
7
  from mbta_stop import MBTAStop
6
8
  from mbta_route import MBTARoute
7
9
  from mbta_trip import MBTATrip
8
10
  from mbta_alert import MBTAAlert
11
+ from mbta_utils import MBTAUtils
9
12
 
10
13
  class Journey:
11
14
  """A class to manage a journey with multiple stops."""
@@ -15,6 +18,7 @@ class Journey:
15
18
  Initialize a Journey with optional route, trip, and alert information.
16
19
  Departure and arrival stops are also initialized as None.
17
20
  """
21
+ self.duration = None
18
22
  self.route: Optional[MBTARoute] = None
19
23
  self.trip: Optional[MBTATrip] = None
20
24
  self.alerts: list[MBTAAlert] = []
@@ -24,9 +28,9 @@ class Journey:
24
28
  }
25
29
 
26
30
  def __repr__(self) -> str:
27
- return f"Journey(departure={self.stops['departure']}, arrival={self.stops['arrival']})"
31
+ return f"Journey(depart_from={self.stops['departure']}, arrive_at={self.stops['arrival']})"
28
32
 
29
- def add_stop(self, stop_type: str, scheduling_data, stop: MBTAStop, status) -> None:
33
+ def add_stop(self, stop_type: str, scheduling_data: Union[MBTASchedule,MBTAPrediction], stop: MBTAStop, status) -> None:
30
34
  """Add or update a stop to the journey."""
31
35
 
32
36
  if self.stops[stop_type] is None:
@@ -52,7 +56,9 @@ class Journey:
52
56
  status
53
57
  )
54
58
 
55
-
59
+ if self.stops['departure'] and self.stops['arrival']:
60
+ self.duration = MBTAUtils.calculate_time_difference(self.stops['arrival'].get_time(),self.stops['departure'].get_time())
61
+
56
62
  def get_stop(self, stop_type: str) -> Optional[JourneyStop]:
57
63
  """Return the specified stop or None if not set."""
58
64
  if stop_type in self.stops:
@@ -107,6 +113,11 @@ class Journey:
107
113
  trip_direction = self.trip.direction_id
108
114
  return self.route.direction_names[trip_direction]
109
115
  return None
116
+
117
+ def get_trip_duration(self) -> Optional[str]:
118
+ if self.duration:
119
+ return self.duration
120
+ return None
110
121
 
111
122
  def get_stop_name(self, stop_type: str) -> Optional[str]:
112
123
  """Return the stop name for the specified stop type."""
@@ -128,6 +139,11 @@ class Journey:
128
139
  stop = self.get_stop(stop_type)
129
140
  return stop.get_delay() if stop else None
130
141
 
142
+ def get_stop_status(self, stop_type: str) -> Optional[float]:
143
+ """Return the stop delay for the specified stop type."""
144
+ stop = self.get_stop(stop_type)
145
+ return stop.status if stop else None
146
+
131
147
  def get_stop_time_to(self, stop_type: str) -> Optional[float]:
132
148
  """Return the time to for the specified stop type."""
133
149
  stop = self.get_stop(stop_type)
@@ -15,32 +15,41 @@ class JourneyStop:
15
15
 
16
16
  self.arrival_time = MBTAUtils.parse_datetime(arrival_time)
17
17
  self.real_arrival_time = None
18
- self.arrival_delay = 0
18
+ self.arrival_delay = None
19
19
 
20
20
  self.departure_time = MBTAUtils.parse_datetime(departure_time)
21
21
  self.real_departure_time = None
22
- self.departure_delay = 0
22
+ self.departure_delay = None
23
23
 
24
24
  self.status = status
25
25
  self.stop_sequence = stop_sequence
26
26
 
27
27
  def __repr__(self) -> str:
28
- return (f"JourneyStop(stop={self.stop.id})")
28
+ return (f"JourneyStop(stop={self.stop.name})")
29
29
 
30
- def update_stop(self, stop: MBTAStop, arrival_time: str, departure_time: str, stop_sequence:str, status: str) -> None:
30
+ def update_stop(self, stop: MBTAStop, arrival_time: str, departure_time: str, stop_sequence: str, status: str) -> None:
31
31
  """Update the stop details, including real arrival and departure times, uncertainties, and delays."""
32
-
33
- self.stop: MBTAStop = stop
32
+
33
+ self.stop = stop
34
34
  self.stop_sequence = stop_sequence
35
35
  self.status = status
36
- if arrival_time is not None:
37
- self.real_arrival_time = MBTAUtils.parse_datetime(arrival_time)
38
- if self.arrival_time is not None:
39
- self.arrival_delay = MBTAUtils.calculate_time_difference(self.real_arrival_time, self.arrival_time)
40
- if departure_time is not None:
41
- self.real_departure_time = MBTAUtils.parse_datetime(departure_time)
42
- if self.departure_time is not None:
43
- self.departure_delay = MBTAUtils.calculate_time_difference(self.real_departure_time, self.departure_time)
36
+
37
+ if arrival_time is None and departure_time is None:
38
+ self.arrival_time = None
39
+ self.real_arrival_time = None
40
+ self.arrival_delay = None
41
+ self.departure_time = None
42
+ self.real_departure_time = None
43
+ self.departure_delay = None
44
+ else:
45
+ if arrival_time is not None:
46
+ self.real_arrival_time = MBTAUtils.parse_datetime(arrival_time)
47
+ if self.arrival_time is not None:
48
+ self.arrival_delay = MBTAUtils.calculate_time_difference(self.real_arrival_time, self.arrival_time)
49
+ if departure_time is not None:
50
+ self.real_departure_time = MBTAUtils.parse_datetime(departure_time)
51
+ if self.departure_time is not None:
52
+ self.departure_delay = MBTAUtils.calculate_time_difference(self.real_departure_time, self.departure_time)
44
53
 
45
54
  def get_time(self) -> Optional[datetime]:
46
55
  """Return the most relevant time for the stop."""
@@ -1,4 +1,5 @@
1
1
  import aiohttp
2
+ import logging
2
3
 
3
4
  from datetime import datetime
4
5
 
@@ -12,17 +13,20 @@ from mbta_schedule import MBTASchedule
12
13
  class JourneysHandler(BaseHandler):
13
14
  """Handler for managing a specific journey."""
14
15
 
15
- def __init__(self, session: aiohttp.ClientSession, api_key: str, depart_from_name: str, arrive_at_name: str, max_journeys: int):
16
- super().__init__(session, api_key,depart_from_name,arrive_at_name)
16
+ def __init__(self, session: aiohttp.ClientSession, logger: logging.Logger, depart_from_name: str, arrive_at_name: str, max_journeys: int, api_key:str = None) :
17
+ super().__init__(session, logger, depart_from_name,arrive_at_name, api_key)
17
18
  self.max_journeys = max_journeys
18
19
 
19
- async def fetch_journeys(self) -> list[Journey]:
20
+ async def async_init(self):
21
+ await super()._async_init()
22
+
23
+ async def update(self) -> list[Journey]:
20
24
 
21
25
  schedules = await self.__fetch_schedules()
22
- await self._process_schedules(schedules)
26
+ await super()._process_schedules(schedules)
23
27
 
24
28
  predictions = await self._fetch_predictions()
25
- await self._process_predictions(predictions)
29
+ await super()._process_predictions(predictions)
26
30
 
27
31
  self.__sort_and_clean()
28
32
 
@@ -31,7 +35,7 @@ class JourneysHandler(BaseHandler):
31
35
  await self.__fetch_routes()
32
36
 
33
37
  alerts = await self._fetch_alerts()
34
- self._process_alerts(alerts)
38
+ super()._process_alerts(alerts)
35
39
 
36
40
  return list(self.journeys.values())
37
41
 
@@ -40,7 +44,7 @@ class JourneysHandler(BaseHandler):
40
44
  now = datetime.now().astimezone()
41
45
 
42
46
  params = {
43
- 'filter[stop]': ','.join(await self._get_stops_ids()),
47
+ 'filter[stop]': ','.join(super()._get_stops_ids()),
44
48
  'filter[min_time]': now.strftime('%H:%M'),
45
49
  }
46
50
 
@@ -74,12 +78,12 @@ class JourneysHandler(BaseHandler):
74
78
  async def __fetch_trips(self):
75
79
  """Retrieve trip details for each journey."""
76
80
  for trip_id, journey in self.journeys.items():
77
- trip: MBTATrip = await self._fetch_trip(trip_id)
81
+ trip: MBTATrip = await super()._fetch_trip(trip_id)
78
82
  journey.trip = trip
79
83
 
80
84
  async def __fetch_routes(self):
81
85
  """Retrieve route details for each journey."""
82
86
  for journey in self.journeys.values():
83
87
  if journey.trip and journey.trip.route_id:
84
- route: MBTARoute = await self._fetch_route(journey.trip.route_id)
88
+ route: MBTARoute = await super()._fetch_route(journey.trip.route_id)
85
89
  journey.route = route
@@ -0,0 +1,171 @@
1
+ import aiohttp
2
+ import logging
3
+ from trip_handler import TripHandler
4
+ from journeys_handler import JourneysHandler
5
+ from journey import Journey
6
+
7
+ _LOGGER = logging.getLogger("MBTAClient")
8
+
9
+ logging.basicConfig(level=logging.INFO, # Set the logging level to DEBUG
10
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
11
+
12
+ API_KEY = ''
13
+ MAX_JOURNEYS = 1
14
+
15
+ # DEPART_FROM = 'South Station'
16
+ # ARRIVE_AT = 'Wellesley Square'
17
+
18
+ # DEPART_FROM = 'Wellesley Square'
19
+ # ARRIVE_AT = 'South Station'
20
+
21
+ # DEPART_FROM = 'South Station'
22
+ # ARRIVE_AT = 'Braintree'
23
+
24
+ # DEPART_FROM = 'Copley'
25
+ # ARRIVE_AT = 'Park Street'
26
+
27
+ # DEPART_FROM = 'North Station'
28
+ # ARRIVE_AT = 'Swampscott'
29
+
30
+ # DEPART_FROM = 'Dorchester Ave @ Valley Rd'
31
+ # ARRIVE_AT = 'River St @ Standard St'
32
+
33
+ # DEPART_FROM = 'Back Bay'
34
+ # ARRIVE_AT = 'Huntington Ave @ Opera Pl'
35
+
36
+ # DEPART_FROM = 'Charlestown Navy Yard'
37
+ # ARRIVE_AT = 'Long Wharf (South)'
38
+
39
+ # DEPART_FROM = 'North Billerica'
40
+ # ARRIVE_AT = 'North Station'
41
+
42
+ # DEPART_FROM = 'Back Bay'
43
+ # ARRIVE_AT = 'South Station'
44
+
45
+ # DEPART_FROM = 'Pemberton Point'
46
+ # ARRIVE_AT = 'Summer St from Cushing Way to Water St (FLAG)'
47
+
48
+ TRIP = '518'
49
+ DEPART_FROM = 'Wellesley Square'
50
+ ARRIVE_AT = 'South Station'
51
+
52
+
53
+ def print_journey(journey: Journey):
54
+ route_type = journey.get_route_type()
55
+
56
+ # if subway or ferry
57
+ if route_type in [0, 1, 4]:
58
+
59
+ _LOGGER.info("###########")
60
+ _LOGGER.info("Line: %s", journey.get_route_long_name())
61
+ _LOGGER.info("Type: %s", journey.get_route_description())
62
+ _LOGGER.info("Color: %s", journey.get_route_color())
63
+ _LOGGER.info("**********")
64
+ _LOGGER.info("Direction: %s to %s", journey.get_trip_direction(), journey.get_trip_destination())
65
+ _LOGGER.info("Destination: %s", journey.get_trip_headsign())
66
+ _LOGGER.info("Duration: %s", journey.get_trip_duration())
67
+ _LOGGER.info("**********")
68
+ _LOGGER.info("Departure Station: %s", journey.get_stop_name('departure'))
69
+ _LOGGER.info("Departure Platform: %s", journey.get_platform_name('departure'))
70
+ _LOGGER.info("Departure Time: %s", journey.get_stop_time('departure'))
71
+ _LOGGER.info("Departure Delay: %s", journey.get_stop_delay('departure'))
72
+ _LOGGER.info("Departure Time To: %s", journey.get_stop_time_to('departure'))
73
+ _LOGGER.info("%s", journey.get_stop_status('departure'))
74
+ _LOGGER.info("**********")
75
+ _LOGGER.info("Arrival Station: %s", journey.get_stop_name('arrival'))
76
+ _LOGGER.info("Arrival Platform: %s", journey.get_platform_name('arrival'))
77
+ _LOGGER.info("Arrival Time: %s", journey.get_stop_time('arrival'))
78
+ _LOGGER.info("Arrival Delay: %s", journey.get_stop_delay('arrival'))
79
+ _LOGGER.info("Arrival Time To: %s", journey.get_stop_time_to('arrival'))
80
+ _LOGGER.info("%s", journey.get_stop_status('arrival'))
81
+ _LOGGER.info("**********")
82
+ for j in range(len(journey.alerts)):
83
+ _LOGGER.info("Alert: %s", journey.get_alert_header(j))
84
+
85
+ # if train
86
+ elif route_type == 2:
87
+
88
+ _LOGGER.info("###########")
89
+ _LOGGER.info("Line: %s", journey.get_route_long_name())
90
+ _LOGGER.info("Type: %s", journey.get_route_description())
91
+ _LOGGER.info("Color: %s", journey.get_route_color())
92
+ _LOGGER.info("Train Number: %s", journey.get_trip_name())
93
+ _LOGGER.info("**********")
94
+ _LOGGER.info("Direction: %s to %s", journey.get_trip_direction(), journey.get_trip_destination())
95
+ _LOGGER.info("Destination: %s", journey.get_trip_headsign())
96
+ _LOGGER.info("Duration: %s", journey.get_trip_duration())
97
+ _LOGGER.info("**********")
98
+ _LOGGER.info("Departure Station: %s", journey.get_stop_name('departure'))
99
+ _LOGGER.info("Departure Platform: %s", journey.get_platform_name('departure'))
100
+ _LOGGER.info("Departure Time: %s", journey.get_stop_time('departure'))
101
+ _LOGGER.info("Departure Delay: %s", journey.get_stop_delay('departure'))
102
+ _LOGGER.info("Departure Time To: %s", journey.get_stop_time_to('departure'))
103
+ _LOGGER.info("%s", journey.get_stop_status('departure'))
104
+ _LOGGER.info("**********")
105
+ _LOGGER.info("Arrival Station: %s", journey.get_stop_name('arrival'))
106
+ _LOGGER.info("Arrival Platform: %s", journey.get_platform_name('arrival'))
107
+ _LOGGER.info("Arrival Time: %s", journey.get_stop_time('arrival'))
108
+ _LOGGER.info("Arrival Delay: %s", journey.get_stop_delay('arrival'))
109
+ _LOGGER.info("Arrival Time To: %s", journey.get_stop_time_to('arrival'))
110
+ _LOGGER.info("%s", journey.get_stop_status('arrival'))
111
+ _LOGGER.info("**********")
112
+ for j in range(len(journey.alerts)):
113
+ _LOGGER.info("Alert: %s", journey.get_alert_header(j))
114
+
115
+ # if bus
116
+ elif route_type == 3:
117
+
118
+ _LOGGER.info("###########")
119
+ _LOGGER.info("Line: %s", journey.get_route_short_name())
120
+ _LOGGER.info("Type: %s", journey.get_route_description())
121
+ _LOGGER.info("Color: %s", journey.get_route_color())
122
+ _LOGGER.info("**********")
123
+ _LOGGER.info("Direction: %s to %s", journey.get_trip_direction(), journey.get_trip_destination())
124
+ _LOGGER.info("Destination: %s", journey.get_trip_headsign())
125
+ _LOGGER.info("Duration: %s", journey.get_trip_duration())
126
+ _LOGGER.info("**********")
127
+ _LOGGER.info("Departure Stop: %s", journey.get_stop_name('departure'))
128
+ _LOGGER.info("Departure Time: %s", journey.get_stop_time('departure'))
129
+ _LOGGER.info("Departure Delay: %s", journey.get_stop_delay('departure'))
130
+ _LOGGER.info("Departure Time To: %s", journey.get_stop_time_to('departure'))
131
+ _LOGGER.info("%s", journey.get_stop_status('departure'))
132
+ _LOGGER.info("**********")
133
+ _LOGGER.info("Arrival Stop: %s", journey.get_stop_name('arrival'))
134
+ _LOGGER.info("Arrival Time: %s", journey.get_stop_time('arrival'))
135
+ _LOGGER.info("Arrival Delay: %s", journey.get_stop_delay('arrival'))
136
+ _LOGGER.info("Arrival Time To: %s", journey.get_stop_time_to('arrival'))
137
+ _LOGGER.info("%s", journey.get_stop_status('arrival'))
138
+ _LOGGER.info("**********")
139
+ for j in range(len(journey.alerts)):
140
+ _LOGGER.info("Alert: %s", journey.get_alert_header(j))
141
+
142
+ else:
143
+ _LOGGER.error('ARGH!')
144
+
145
+
146
+ async def main():
147
+ async with aiohttp.ClientSession() as session:
148
+
149
+ trip_hadler = TripHandler(session, _LOGGER, DEPART_FROM, ARRIVE_AT, TRIP, API_KEY)
150
+
151
+ await trip_hadler.async_init()
152
+
153
+ trips = await trip_hadler.update()
154
+
155
+ for trip in trips:
156
+ print_journey(trip)
157
+
158
+ journeys_handler = JourneysHandler(session, _LOGGER, DEPART_FROM, ARRIVE_AT, MAX_JOURNEYS, API_KEY)
159
+
160
+ await journeys_handler.async_init()
161
+
162
+ journeys = await journeys_handler.update()
163
+
164
+ for journey in journeys:
165
+ print_journey(journey)
166
+
167
+
168
+
169
+ # Run the main function
170
+ import asyncio
171
+ asyncio.run(main())
@@ -32,7 +32,7 @@ class MBTAAlert:
32
32
  ]
33
33
 
34
34
  def __repr__(self) -> str:
35
- return (f"MBTAalert(id={self.alert_id}, header_text={self.header_text})")
35
+ return (f"MBTAalert(id={self.alert_id})")
36
36
 
37
37
  def get_informed_stops(self) -> list[str]:
38
38
  """Retrieve a list of unique stops from informed entities."""
@@ -23,10 +23,10 @@ ENDPOINTS = {
23
23
  class MBTAClient:
24
24
  """Class to interact with the MBTA v3 API."""
25
25
 
26
- def __init__(self, session: aiohttp.ClientSession, api_key: Optional[str] = None) -> None:
26
+ def __init__(self, session: aiohttp.ClientSession, logger: logging.Logger, api_key: Optional[str] = None)-> None:
27
27
  self._session = session
28
28
  self._api_key = api_key
29
-
29
+ self.logger: logging.Logger = logger
30
30
 
31
31
  async def get_route(self, id: str, params: Optional[dict[str, Any]] = None) -> MBTARoute:
32
32
  """Get a route by its ID."""
@@ -82,7 +82,7 @@ class MBTAClient:
82
82
  raise ValueError("Unexpected response format")
83
83
  return data
84
84
  except Exception as error:
85
- logging.error(f"Error fetching data: {error}")
85
+ self.logger.error(f"Error fetching data: {error}")
86
86
  raise
87
87
 
88
88
  async def request(
@@ -106,13 +106,13 @@ class MBTAClient:
106
106
  return response
107
107
 
108
108
  except ClientConnectionError as error:
109
- logging.error(f"Connection error: {error}")
109
+ self.logger.error(f"Connection error: {error}")
110
110
  raise
111
111
  except ClientResponseError as error:
112
- logging.error(f"Client response error: {error.status} - {str(error)}")
112
+ self.logger.error(f"Client response error: {error.status} - {str(error)}")
113
113
  raise
114
114
  except Exception as error:
115
- logging.error(f"An unexpected error occurred: {error}")
115
+ self.logger.error(f"An unexpected error occurred: {error}")
116
116
  raise
117
117
 
118
118
 
@@ -27,6 +27,6 @@ class MBTAPrediction:
27
27
  self.trip_id: str = prediction.get('relationships', {}).get('trip', {}).get('data', {}).get('id', '')
28
28
 
29
29
  def __repr__(self) -> str:
30
- return (f"MBTAprediction(id={self.id}, route_id={self.route_id}, stop_id={self.stop_id}, trip_id={self.trip_id})")
30
+ return (f"MBTAprediction(id={self.id})")
31
31
 
32
32
 
@@ -22,5 +22,5 @@ class MBTASchedule:
22
22
  self.trip_id: str = relationships.get('trip', {}).get('data', {}).get('id', '')
23
23
 
24
24
  def __repr__(self) -> str:
25
- return (f"MBTAschedule(id={self.id}, route_id={self.route_id}, stop_id={self.stop_id}, trip_id={self.trip_id})")
25
+ return (f"MBTAschedule(id={self.id})")
26
26
 
@@ -22,5 +22,5 @@ class MBTAStop:
22
22
  self.wheelchair_boarding: int = attributes.get('wheelchair_boarding', 0)
23
23
 
24
24
  def __repr__(self) -> str:
25
- return (f"MBTAstop(id={self.id}, name={self.name})")
25
+ return (f"MBTAstop(id={self.id})")
26
26
 
@@ -23,7 +23,7 @@ class MBTATrip:
23
23
 
24
24
 
25
25
  def __repr__(self) -> str:
26
- return (f"MBTAtrip(id={self.id}, route_id={self.route_id})")
26
+ return (f"MBTAtrip(id={self.id})")
27
27
 
28
28
 
29
29
 
@@ -1,5 +1,4 @@
1
1
  from datetime import datetime
2
- import logging
3
2
  from typing import Optional
4
3
 
5
4
  class MBTAUtils:
@@ -46,10 +45,6 @@ class MBTAUtils:
46
45
  @staticmethod
47
46
  def parse_datetime(time_str: str) -> Optional[datetime]:
48
47
  """Parse a string in ISO 8601 format to a datetime object."""
49
- if time_str is None:
48
+ if not isinstance(time_str, str):
50
49
  return None
51
- try:
52
- return datetime.fromisoformat(time_str)
53
- except ValueError as e:
54
- logging.error(f"Error parsing datetime: {e}")
55
- return None
50
+ return datetime.fromisoformat(time_str)
@@ -1,3 +1,5 @@
1
+ from typing import Optional
2
+ import traceback
1
3
  import aiohttp
2
4
 
3
5
  from base_handler import BaseHandler
@@ -10,46 +12,41 @@ from mbta_prediction import MBTAPrediction
10
12
  class TripHandler(BaseHandler):
11
13
  """Handler for managing a specific trip."""
12
14
 
13
- def __init__(self, session: aiohttp.ClientSession, api_key: str, depart_from_name: str, arrive_at_name: str, trip_name: str):
14
- super().__init__(session, api_key,depart_from_name,arrive_at_name)
15
+ def __init__(self, session: aiohttp.ClientSession, logger, depart_from_name: str, arrive_at_name: str, trip_name: str, api_key:str = None ) :
16
+ super().__init__(session, logger, depart_from_name, arrive_at_name, api_key)
15
17
  self.trip_name = trip_name
16
18
 
17
- async def fetch_trip(self):
18
-
19
- await self.trip_init()
20
-
21
- schedules = await self.__fetch_schedules()
22
- await self._process_schedules(schedules)
23
-
24
- predictions = await self.__fetch_predictions()
25
- await self._process_predictions(predictions)
26
-
27
- alerts = await self.__fetch_alerts()
28
- self._process_alerts(alerts)
29
-
30
- return next(iter(self.journeys.values()))
31
-
32
-
33
- async def trip_init(self):
34
-
19
+
20
+ async def async_init(self):
21
+ await super()._async_init()
22
+
35
23
  params = {
36
24
  'filter[revenue]' :'REVENUE',
37
25
  'filter[name]' : self.trip_name
38
26
  }
39
-
40
- trips: list[MBTATrip] = await self.mbta_client.list_trips(params)
27
+ trips: list[MBTATrip] = await super()._fetch_trips(params)
41
28
 
42
29
  journey = Journey()
43
-
44
30
  journey.trip = trips[0]
45
31
 
46
- route: MBTARoute = await self.mbta_client.get_route(journey.trip.route_id)
32
+ route: MBTARoute = await super()._fetch_route(journey.trip.route_id)
47
33
 
48
34
  journey.route = route
49
-
50
35
  self.journeys[trips[0].id] = journey
51
-
52
-
36
+
37
+ async def update(self) -> list[Journey]:
38
+
39
+ schedules = await self.__fetch_schedules()
40
+ await super()._process_schedules(schedules)
41
+
42
+ predictions = await self.__fetch_predictions()
43
+ await super()._process_predictions(predictions)
44
+
45
+ alerts = await self.__fetch_alerts()
46
+ super()._process_alerts(alerts)
47
+ return list(self.journeys.values())
48
+
49
+
53
50
  async def __fetch_schedules(self) -> list[MBTASchedule]:
54
51
 
55
52
  jounrey = next(iter(self.journeys.values()))
@@ -60,7 +57,6 @@ class TripHandler(BaseHandler):
60
57
  }
61
58
 
62
59
  schedules = await super()._fetch_schedules(params)
63
-
64
60
  return schedules
65
61
 
66
62
 
@@ -74,7 +70,6 @@ class TripHandler(BaseHandler):
74
70
  }
75
71
 
76
72
  predictions = await super()._fetch_predictions(params)
77
-
78
73
  return predictions
79
74
 
80
75
 
@@ -88,5 +83,4 @@ class TripHandler(BaseHandler):
88
83
  }
89
84
 
90
85
  alerts = await super()._fetch_alerts(params)
91
-
92
86
  return alerts
@@ -1,173 +0,0 @@
1
- import aiohttp
2
- from trip_handler import TripHandler
3
- from journeys_handler import JourneysHandler
4
-
5
-
6
- API_KEY = ''
7
- MAX_JOURNEYS = 5
8
-
9
-
10
- # DEPART_FROM = 'South Station'
11
- # ARRIVE_AT = 'Wellesley Square'
12
-
13
-
14
- # DEPART_FROM = 'Wellesley Square'
15
- # ARRIVE_AT = 'South Station'
16
-
17
-
18
- # DEPART_FROM = 'South Station'
19
- # ARRIVE_AT = 'Braintree'
20
-
21
-
22
- # DEPART_FROM = 'Copley'
23
- # ARRIVE_AT = 'Park Street'
24
-
25
-
26
- # DEPART_FROM = 'North Station'
27
- # ARRIVE_AT = 'Swampscott'
28
-
29
-
30
- # DEPART_FROM = 'Dorchester Ave @ Valley Rd'
31
- # ARRIVE_AT = 'River St @ Standard St'
32
-
33
-
34
- # DEPART_FROM = 'Back Bay'
35
- # ARRIVE_AT = 'Huntington Ave @ Opera Pl'
36
-
37
- # DEPART_FROM = 'Charlestown Navy Yard'
38
- # ARRIVE_AT = 'Long Wharf (South)'
39
-
40
-
41
-
42
- # DEPART_FROM = 'North Billerica'
43
- # ARRIVE_AT = 'North Station'
44
-
45
- # DEPART_FROM = 'Back Bay'
46
- # ARRIVE_AT = 'South Station'
47
-
48
- # DEPART_FROM = 'Pemberton Point'
49
- # ARRIVE_AT = 'Summer St from Cushing Way to Water St (FLAG)'
50
-
51
- TRIP = '518'
52
- DEPART_FROM = 'Wellesley Square'
53
- ARRIVE_AT = 'South Station'
54
-
55
-
56
- def print_journey(journey):
57
- route_type = journey.get_route_type()
58
-
59
- # if subway or ferry
60
- if route_type == 0 or route_type == 1 or route_type == 4:
61
-
62
- print("###########")
63
- print()
64
- print("Line:", journey.get_route_long_name())
65
- print("Type:", journey.get_route_description())
66
- print("Color:", journey.get_route_color())
67
- print()
68
- print("Direction:", journey.get_trip_direction()+" to "+journey.get_trip_destination())
69
- print("Destination:", journey.get_trip_headsign())
70
- print()
71
- # Print departure information
72
- print("Departure Station:", journey.get_stop_name('departure'))
73
- print("Departure Platform:", journey.get_platform_name('departure'))
74
- print("Departure Time:", journey.get_stop_time('departure'))
75
- print("Departure Delay:", journey.get_stop_delay('departure'))
76
- print("Departure Time To:", journey.get_stop_time_to('departure'))
77
- print()
78
- # Print arrival information
79
- print("Arrival Station:", journey.get_stop_name('arrival'))
80
- print("Arrival Platform:", journey.get_platform_name('arrival'))
81
- print("Arrival Time:", journey.get_stop_time('arrival'))
82
- print("Arrival Delay:", journey.get_stop_delay('arrival'))
83
- print("Arrival Time To:", journey.get_stop_time_to('arrival'))
84
- print()
85
- for j in range(len(journey.alerts)):
86
- print("Alert:" , journey.get_alert_header(j))
87
- print()
88
-
89
- # if train
90
- elif route_type == 2:
91
-
92
- print("###########")
93
- print()
94
- print("Line:", journey.get_route_long_name())
95
- print("Type:", journey.get_route_description())
96
- print("Color:", journey.get_route_color())
97
- print()
98
- print("Train Number:", journey.get_trip_name())
99
- print("Direction:", journey.get_trip_direction()+" to "+journey.get_trip_destination())
100
- print("Destination:", journey.get_trip_headsign())
101
- print()
102
- # Print departure information
103
- print("Departure Station:", journey.get_stop_name('departure'))
104
- print("Departure Platform:", journey.get_platform_name('departure'))
105
- print("Departure Time:", journey.get_stop_time('departure'))
106
- print("Departure Delay:", journey.get_stop_delay('departure'))
107
- print("Departure Time To:", journey.get_stop_time_to('departure'))
108
- print()
109
- # Print arrival information
110
- print("Arrival Station:", journey.get_stop_name('arrival'))
111
- print("Arrival Platform:", journey.get_platform_name('arrival'))
112
- print("Arrival Time:", journey.get_stop_time('arrival'))
113
- print("Arrival Delay:", journey.get_stop_delay('arrival'))
114
- print("Arrival Time To:", journey.get_stop_time_to('arrival'))
115
- print()
116
-
117
- for j in range(len(journey.alerts)):
118
- print("Alert:" , journey.get_alert_header(j))
119
- print()
120
-
121
- #if bus
122
- elif route_type == 3:
123
-
124
- print("###########")
125
- print()
126
- print("Line:", journey.get_route_short_name())
127
- print("Type:", journey.get_route_description())
128
- print("Color:", journey.get_route_color())
129
- print()
130
- print("Direction:", journey.get_trip_direction()+" to "+journey.get_trip_destination())
131
- print("Destination:", journey.get_trip_headsign())
132
- # Print departure information
133
- print("Departure Stop:", journey.get_stop_name('departure'))
134
- print("Departure Time:", journey.get_stop_time('departure'))
135
- print("Departure Delay:", journey.get_stop_delay('departure'))
136
- print("Departure Time To:", journey.get_stop_time_to('departure'))
137
- print()
138
- # Print arrival information
139
- print("Arrival Stop:", journey.get_stop_name('arrival'))
140
- print("Arrival Time:", journey.get_stop_time('arrival'))
141
- print("Arrival Delay:", journey.get_stop_delay('arrival'))
142
- print("Arrival Time To:", journey.get_stop_time_to('arrival'))
143
- print()
144
- for j in range(len(journey.alerts)):
145
- print("Alert:" , journey.get_alert_header(j))
146
- print()
147
-
148
- else:
149
-
150
- print('ARGH!')
151
-
152
-
153
- async def main():
154
- async with aiohttp.ClientSession() as session:
155
-
156
- trip_hadler = TripHandler(session, API_KEY, DEPART_FROM, ARRIVE_AT, TRIP)
157
-
158
- trip = await trip_hadler.fetch_trip()
159
-
160
- print_journey(trip)
161
-
162
- journeys_handler = JourneysHandler(session, API_KEY, DEPART_FROM, ARRIVE_AT, MAX_JOURNEYS)
163
-
164
- journeys = await journeys_handler.fetch_journeys()
165
-
166
- for journey in journeys:
167
- print_journey(journey)
168
-
169
-
170
-
171
- # Run the main function
172
- import asyncio
173
- asyncio.run(main())
File without changes
File without changes
File without changes
File without changes
File without changes