koleo-cli 0.2.137.16__py3-none-any.whl → 0.2.137.18__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.

Potentially problematic release.


This version of koleo-cli might be problematic. Click here for more details.

koleo/cli.py DELETED
@@ -1,550 +0,0 @@
1
- import re
2
- from argparse import ArgumentParser
3
- from datetime import datetime, timedelta
4
-
5
- from rich.console import Console
6
-
7
- from .api import KoleoAPI
8
- from .storage import DEFAULT_CONFIG_PATH, Storage
9
- from .types import ExtendedBaseStationInfo, TrainDetailResponse, TrainOnStationInfo, TrainCalendar
10
- from .utils import RemainderString, arr_dep_to_dt, convert_platform_number, name_to_slug, parse_datetime
11
-
12
-
13
- class CLI:
14
- def __init__(
15
- self,
16
- no_color: bool = False,
17
- client: KoleoAPI | None = None,
18
- storage: Storage | None = None,
19
- ) -> None:
20
- self._client = client
21
- self._storage = storage
22
- self.no_color = no_color
23
- self.console = Console(color_system="standard", no_color=no_color, highlight=False)
24
-
25
- def print(self, text, *args, **kwargs):
26
- if self.no_color:
27
- result = re.sub(r"\[[^\]]*\]", "", text)
28
- print(result)
29
- else:
30
- self.console.print(text, *args, **kwargs)
31
-
32
- @property
33
- def client(self) -> KoleoAPI:
34
- if not self._client:
35
- raise ValueError("Client not set!")
36
- return self._client
37
-
38
- @client.setter
39
- def client(self, client: KoleoAPI):
40
- self._client = client
41
-
42
- @property
43
- def storage(self) -> Storage:
44
- if not self._storage:
45
- raise ValueError("Storage not set!")
46
- return self._storage
47
-
48
- @storage.setter
49
- def storage(self, storage: Storage):
50
- self._storage = storage
51
-
52
- def get_departures(self, station_id: int, date: datetime):
53
- cache_id = f"dep-{station_id}-{date.strftime("%Y-%m-%d")}"
54
- trains = self.storage.get_cache(cache_id) or self.storage.set_cache(
55
- cache_id, self.client.get_departures(station_id, date)
56
- )
57
- trains = [
58
- i
59
- for i in trains
60
- if datetime.fromisoformat(i["departure"]).timestamp() > date.timestamp() # type: ignore
61
- ]
62
- table = self.trains_on_station_table(trains)
63
- self.print(table)
64
- return table
65
-
66
- def get_arrivals(self, station_id: int, date: datetime):
67
- cache_id = f"arr-{station_id}-{date.strftime("%Y-%m-%d")}"
68
- trains = self.storage.get_cache(cache_id) or self.storage.set_cache(
69
- cache_id, self.client.get_arrivals(station_id, date)
70
- )
71
- trains = [
72
- i
73
- for i in trains
74
- if datetime.fromisoformat(i["arrival"]).timestamp() > date.timestamp() # type: ignore
75
- ]
76
- table = self.trains_on_station_table(trains, type=2)
77
- self.print(table)
78
- return table
79
-
80
- def full_departures(self, station: str, date: datetime):
81
- st = self.get_station(station)
82
- station_info = f"[bold blue][link=https://koleo.pl/dworzec-pkp/{st["name_slug"]}/{date.strftime("%Y-%m-%d")}]{st["name"]} at {date.strftime("%d-%m %H:%M")}[/bold blue] ID: {st["id"]}[/link]"
83
- self.print(station_info)
84
- self.get_departures(st["id"], date)
85
-
86
- def full_arrivals(self, station: str, date: datetime):
87
- st = self.get_station(station)
88
- station_info = f"[bold blue][link=https://koleo.pl/dworzec-pkp/{st["name_slug"]}/{date.strftime("%Y-%m-%d")}]{st["name"]} at {date.strftime("%d-%m %H:%M")}[/bold blue] ID: {st["id"]}[/link]"
89
- self.print(station_info)
90
- self.get_arrivals(st["id"], date)
91
-
92
- def all_trains(self, station: str, date: datetime):
93
- st = self.get_station(station)
94
- station_info = f"[bold blue][link=https://koleo.pl/dworzec-pkp/{st["name_slug"]}/{date.strftime("%Y-%m-%d")}]{st["name"]} at {date.strftime("%d-%m %H:%M")}[/bold blue] ID: {st["id"]}[/link]"
95
- self.print(station_info)
96
- arr_cache_id = f"arr-{st['id']}-{date.strftime("%Y-%m-%d")}"
97
- dep_cache_id = f"dep-{st['id']}-{date.strftime("%Y-%m-%d")}"
98
- arrivals = self.storage.get_cache(arr_cache_id) or self.storage.set_cache(
99
- arr_cache_id, self.client.get_arrivals(st["id"], date)
100
- )
101
- departures = self.storage.get_cache(dep_cache_id) or self.storage.set_cache(
102
- dep_cache_id, self.client.get_departures(st["id"], date)
103
- )
104
- trains = sorted(
105
- [(i, 1) for i in departures] + [(i, 2) for i in arrivals],
106
- key=lambda train: datetime.fromisoformat(
107
- train[0]["departure"] if train[1] == 1 else train[0]["arrival"]
108
- ).timestamp(),
109
- )
110
- trains = [
111
- (i, type)
112
- for i, type in trains
113
- if datetime.fromisoformat(i["departure"] if type == 1 else i["arrival"]).timestamp() > date.timestamp() # type: ignore
114
- ]
115
- brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
116
- parts = []
117
- for train, type in trains:
118
- time = (
119
- f"[bold green]{train['departure'][11:16]}[/bold green]"
120
- if type == 1
121
- else f"[bold yellow]{train['arrival'][11:16]}[/bold yellow]"
122
- )
123
- brand = next(iter(i for i in brands if i["id"] == train["brand_id"]), {}).get("logo_text")
124
- parts.append(
125
- f"{time} [red]{brand}[/red] {train["train_full_name"]}[purple] {train["stations"][0]["name"]} {self.format_position(train["platform"], train["track"])}[/purple]"
126
- )
127
- self.print("\n".join(parts))
128
-
129
- def find_station(self, query: str | None):
130
- if query:
131
- stations = self.client.find_station(query)
132
- else:
133
- stations = self.storage.get_cache("stations") or self.storage.set_cache(
134
- "stations", self.client.get_stations()
135
- )
136
- for st in stations:
137
- self.print(
138
- f"[bold blue][link=https://koleo.pl/dworzec-pkp/{st["name_slug"]}]{st["name"]}[/bold blue] ID: {st["id"]}[/link]"
139
- )
140
-
141
- def get_train_calendars(self, brand: str, name: str) -> list[TrainCalendar]:
142
- brand = brand.upper().strip()
143
- name_parts = name.split(" ")
144
- if len(name_parts) == 1 and name_parts[0].isnumeric():
145
- number = int(name_parts[0])
146
- train_name = ""
147
- elif len(name) > 1:
148
- number = int(name_parts.pop(0))
149
- train_name = " ".join(name_parts)
150
- else:
151
- raise ValueError("Invalid train name!")
152
- brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
153
- if brand not in [i["name"] for i in brands]:
154
- res = {i["logo_text"]: i["name"] for i in brands}.get(brand)
155
- if not res:
156
- raise ValueError("Invalid brand name!")
157
- brand = res
158
- cache_id = f"tc-{brand}-{number}-{name}"
159
- try:
160
- train_calendars = self.storage.get_cache(cache_id) or self.storage.set_cache(
161
- cache_id, self.client.get_train_calendars(brand, number, train_name)
162
- )
163
- except self.client.errors.KoleoNotFound:
164
- self.print(f'[bold red]Train not found: nr={number}, name="{train_name}"[/bold red]')
165
- exit(2)
166
- return train_calendars["train_calendars"]
167
-
168
- def train_calendar(self, brand: str, name: str):
169
- train_calendars = self.get_train_calendars(brand, name)
170
- brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
171
- for calendar in train_calendars:
172
- brand = next(iter(i for i in brands if i["id"] == calendar["trainBrand"]), {}).get("logo_text", "")
173
- parts = [
174
- f"[red]{brand}[/red] [bold blue]{calendar['train_nr']}{" "+ v if (v:=calendar.get("train_name")) else ""}[/bold blue]:"
175
- ]
176
- for k, v in calendar["date_train_map"].items():
177
- parts.append(f" [bold green]{k}[/bold green]: [purple]{v}[/purple]")
178
- self.print("\n".join(parts))
179
-
180
- def train_info(self, brand: str, name: str, date: datetime):
181
- train_calendars = self.get_train_calendars(brand, name)
182
- if not (train_id := train_calendars[0]["date_train_map"].get(date.strftime("%Y-%m-%d"))):
183
- self.print(f"[bold red]This train doesn't run on the selected date: {date.strftime("%Y-%m-%d")}[/bold red]")
184
- exit(2)
185
- self.train_detail(train_id)
186
-
187
- def train_detail(self, train_id: int):
188
- train_details = self.client.get_train(train_id)
189
- brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
190
- brand = next(iter(i for i in brands if i["id"] == train_details["train"]["brand_id"]), {}).get("logo_text", "")
191
-
192
- parts = [f"[red]{brand}[/red] [bold blue]{train_details["train"]["train_full_name"]}[/bold blue]"]
193
- if train_details["train"]["run_desc"]:
194
- parts.append(f" {train_details["train"]["run_desc"]}")
195
-
196
- route_start = arr_dep_to_dt(train_details["stops"][0]["departure"])
197
- route_end = arr_dep_to_dt(train_details["stops"][-1]["arrival"])
198
-
199
- if route_end.hour < route_start.hour or (
200
- route_end.hour == route_start.hour and route_end.minute < route_end.minute
201
- ):
202
- route_end += timedelta(days=1)
203
-
204
- travel_time = route_end - route_start
205
- speed = train_details["stops"][-1]["distance"] / 1000 / travel_time.seconds * 3600
206
- parts.append(
207
- f"[white] {travel_time.seconds//3600}h{(travel_time.seconds % 3600)/60:.0f}m {speed:^4.1f}km/h [/white]"
208
- )
209
-
210
- vehicle_types: dict[str, str] = {
211
- stop["station_display_name"]: stop["vehicle_type"]
212
- for stop in train_details["stops"]
213
- if stop["vehicle_type"]
214
- }
215
- if vehicle_types:
216
- keys = list(vehicle_types.keys())
217
- start = keys[0]
218
- for i in range(1, len(keys)):
219
- if vehicle_types[keys[i]] != vehicle_types[start]:
220
- parts.append(f" {start} - {keys[i]}: [bold green]{vehicle_types[start]}[/bold green]")
221
- start = keys[i]
222
- parts.append(f" {start} - {keys[-1]}: [bold green]{vehicle_types[start]}[/bold green]")
223
- self.print("\n".join(parts))
224
- self.print(self.train_route_table(train_details))
225
-
226
- def connections(
227
- self, start: str, end: str, date: datetime, brands: list[str], direct: bool, purchasable: bool, length: int = 1
228
- ):
229
- start_station = self.get_station(start)
230
- end_station = self.get_station(end)
231
- brands = [i.lower().strip() for i in brands]
232
- api_brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
233
- if not brands:
234
- connection_brands = {i["name"]: i["id"] for i in api_brands}
235
- else:
236
- connection_brands = {
237
- i["name"]: i["id"]
238
- for i in api_brands
239
- if i["name"].lower().strip() in brands or i["logo_text"].lower().strip() in brands
240
- }
241
- if not connection_brands:
242
- self.print(f'[bold red]No brands match: "{', '.join(brands)}"[/bold red]')
243
- exit(2)
244
- results = []
245
- fetch_date = date
246
- while len(results) < length:
247
- connections = self.client.get_connections(
248
- start_station["name_slug"],
249
- end_station["name_slug"],
250
- list(connection_brands.values()),
251
- fetch_date,
252
- direct,
253
- purchasable,
254
- )
255
- if connections:
256
- fetch_date = arr_dep_to_dt(connections[-1]["departure"]) + timedelta(seconds=(30 * 60) + 1) # wtf
257
- results.extend(connections)
258
- else:
259
- break
260
- link = (
261
- f"https://koleo.pl/rozklad-pkp/{start_station["name_slug"]}/{end_station["name_slug"]}"
262
- + f"/{date.strftime("%d-%m-%Y_%H:%M")}"
263
- + f"{"all" if not direct else "direct"}/{"-".join(connection_brands.keys()) if brands else "all"}"
264
- )
265
- parts = [
266
- f"[bold blue][link={link}]{start_station["name"]} → {end_station["name"]} at {date.strftime("%H:%M %d-%m")}[/link][/bold blue]"
267
- ]
268
- for i in results:
269
- arr = arr_dep_to_dt(i["arrival"])
270
- dep = arr_dep_to_dt(i["departure"])
271
- travel_time = (arr - dep).seconds
272
- date_part = f"{arr.strftime("%d-%m")} " if arr.date() != date.date() else ""
273
- parts.append(
274
- f"[bold green][link=https://koleo.pl/travel-options/{i["id"]}]{date_part}{dep.strftime("%H:%M")} - {arr.strftime("%H:%M")}[/bold green] {travel_time//3600}h{(travel_time % 3600)/60:.0f}m {i['distance']}km:[/link]"
275
- )
276
- if len(i["trains"]) == 1:
277
- train = i["trains"][0]
278
- stop = next(iter(i for i in train["stops"] if i["station_id"] == train["start_station_id"]), {})
279
- stop_station = (
280
- start_station
281
- if stop["station_id"] == start_station["id"]
282
- else self.storage.get_cache(f"st-{stop['station_id']}")
283
- or self.storage.set_cache(
284
- f"st-{stop['station_id']}", self.client.get_station_by_id(stop["station_id"])
285
- )
286
- )
287
- brand = next(iter(i for i in api_brands if i["id"] == train["brand_id"]), {}).get("logo_text")
288
- s = f" [red]{brand}[/red] {train["train_full_name"]}[purple] {stop_station['name']} {self.format_position(stop["platform"], stop["track"])}[/purple]"
289
- parts[-1] += (
290
- f" [red]{brand}[/red] {train["train_full_name"]}[purple] {stop_station['name']} {self.format_position(stop["platform"], stop["track"])}[/purple]"
291
- )
292
- for constriction in i["constriction_info"]:
293
- parts.append(f" [bold red]- {constriction}[/bold red]")
294
- else:
295
- for constriction in i["constriction_info"]:
296
- parts.append(f" [bold red]- {constriction}[/bold red]")
297
- previous_arrival: datetime | None = None
298
- for train in i["trains"]:
299
- brand = next(iter(i for i in api_brands if i["id"] == train["brand_id"]), {}).get("logo_text")
300
-
301
- fs = next(iter(i for i in train["stops"] if i["station_id"] == train["start_station_id"]), {})
302
- fs_station = (
303
- start_station
304
- if fs["station_id"] == start_station["id"]
305
- else self.storage.get_cache(f"st-{fs['station_id']}")
306
- or self.storage.set_cache(
307
- f"st-{fs['station_id']}", self.client.get_station_by_id(fs["station_id"])
308
- )
309
- )
310
- # fs_arr = arr_dep_to_dt(fs["arrival"])
311
- fs_dep = arr_dep_to_dt(fs["departure"])
312
- fs_info = f"[bold green]{fs_dep.strftime("%H:%M")} [/bold green][purple]{fs_station['name']} {self.format_position(fs["platform"], fs["track"])}[/purple]"
313
-
314
- ls = next(iter(i for i in train["stops"] if i["station_id"] == train["end_station_id"]), {})
315
- ls_station = (
316
- start_station
317
- if ls["station_id"] == start_station["id"]
318
- else self.storage.get_cache(f"st-{ls['station_id']}")
319
- or self.storage.set_cache(
320
- f"st-{ls['station_id']}", self.client.get_station_by_id(ls["station_id"])
321
- )
322
- )
323
- ls_arr = arr_dep_to_dt(ls["arrival"])
324
- # ls_dep = arr_dep_to_dt(ls["departure"])
325
- ls_info = f"[bold green]{ls_arr.strftime("%H:%M")} [/bold green][purple]{ls_station['name']} {self.format_position(ls["platform"], ls["track"])}[/purple]"
326
- connection_time = (fs_dep - previous_arrival).seconds if previous_arrival else ""
327
- previous_arrival = ls_arr
328
- if connection_time:
329
- parts.append(
330
- f" {connection_time//3600}h{(connection_time % 3600)/60:.0f}m at [purple]{fs_station['name']}[/purple]"
331
- )
332
- parts.append(f" [red]{brand}[/red] {train["train_full_name"]} {fs_info} - {ls_info}")
333
- self.print("\n".join(parts))
334
-
335
- def trains_on_station_table(self, trains: list[TrainOnStationInfo], type: int = 1):
336
- parts = []
337
- brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
338
- for train in trains:
339
- time = train["departure"] if type == 1 else train["arrival"]
340
- assert time
341
- brand = next(iter(i for i in brands if i["id"] == train["brand_id"]), {}).get("logo_text")
342
- parts.append(
343
- f"[bold green]{time[11:16]}[/bold green] [red]{brand}[/red] {train["train_full_name"]}[purple] {train["stations"][0]["name"]} {self.format_position(train["platform"], train["track"])}[/purple]"
344
- )
345
- return "\n".join(parts)
346
-
347
- def train_route_table(self, train: TrainDetailResponse):
348
- parts = []
349
- for stop in train["stops"]:
350
- arr = arr_dep_to_dt(stop["arrival"])
351
- dep = arr_dep_to_dt(stop["departure"])
352
- parts.append(
353
- f"[white underline]{stop["distance"] / 1000:^5.1f}km[/white underline] [bold green]{arr.strftime("%H:%M")}[/bold green] - [bold red]{dep.strftime("%H:%M")}[/bold red] [purple]{stop["station_display_name"]} {self.format_position(stop["platform"])} [/purple]"
354
- )
355
- return "\n".join(parts)
356
-
357
- def format_position(self, platform: str, track: str | None = None):
358
- res = str(convert_platform_number(platform) or "" if not self.storage.use_roman_numerals else platform)
359
- if track is not None and track != "":
360
- res += f"/{track}"
361
- return res
362
-
363
- def get_station(self, station: str) -> ExtendedBaseStationInfo:
364
- slug = name_to_slug(station)
365
- try:
366
- return self.storage.get_cache(f"st-{slug}") or self.storage.set_cache(
367
- f"st-{slug}", self.client.get_station_by_slug(slug)
368
- )
369
- except self.client.errors.KoleoNotFound:
370
- self.print(f'[bold red]Station not found: "{station}"[/bold red]')
371
- exit(2)
372
-
373
-
374
- def main():
375
- cli = CLI()
376
-
377
- parser = ArgumentParser("koleo", description="Koleo CLI")
378
- parser.add_argument("-c", "--config", help="Custom config path.", default=DEFAULT_CONFIG_PATH)
379
- parser.add_argument("--nocolor", help="Disable color output and formatting", action="store_true", default=False)
380
- subparsers = parser.add_subparsers(title="actions", required=False) # type: ignore
381
-
382
- departures = subparsers.add_parser(
383
- "departures", aliases=["d", "dep", "odjazdy", "o"], help="Allows you to list station departures"
384
- )
385
- departures.add_argument(
386
- "station",
387
- help="The station name",
388
- default=None,
389
- nargs="*",
390
- action=RemainderString,
391
- )
392
- departures.add_argument(
393
- "-d",
394
- "--date",
395
- help="the departure date",
396
- type=lambda s: parse_datetime(s),
397
- default=datetime.now(),
398
- )
399
- departures.add_argument("-s", "--save", help="save the station as your default one", action="store_true")
400
- departures.set_defaults(func=cli.full_departures, pass_=["station", "date"])
401
-
402
- arrivals = subparsers.add_parser(
403
- "arrivals", aliases=["a", "arr", "przyjazdy", "p"], help="Allows you to list station departures"
404
- )
405
- arrivals.add_argument(
406
- "station",
407
- help="The station name",
408
- default=None,
409
- nargs="*",
410
- action=RemainderString,
411
- )
412
- arrivals.add_argument(
413
- "-d",
414
- "--date",
415
- help="the arrival date",
416
- type=lambda s: parse_datetime(s),
417
- default=datetime.now(),
418
- )
419
- arrivals.add_argument("-s", "--save", help="save the station as your default one", action="store_true")
420
- arrivals.set_defaults(func=cli.full_arrivals, pass_=["station", "date"])
421
-
422
- all_trains = subparsers.add_parser(
423
- "all", aliases=["w", "wszystkie", "all_trains", "pociagi"], help="Allows you to list all station trains"
424
- )
425
- all_trains.add_argument(
426
- "station",
427
- help="The station name",
428
- default=None,
429
- nargs="*",
430
- action=RemainderString,
431
- )
432
- all_trains.add_argument(
433
- "-d",
434
- "--date",
435
- help="the date",
436
- type=lambda s: parse_datetime(s),
437
- default=datetime.now(),
438
- )
439
- all_trains.add_argument("-s", "--save", help="save the station as your default one", action="store_true")
440
- all_trains.set_defaults(func=cli.all_trains, pass_=["station", "date"])
441
-
442
- train_route = subparsers.add_parser(
443
- "trainroute",
444
- aliases=["r", "tr", "t", "poc", "pociąg"],
445
- help="Allows you to check the train's route",
446
- )
447
- train_route.add_argument("brand", help="The brand name", type=str)
448
- train_route.add_argument("name", help="The train name", nargs="+", action=RemainderString)
449
- train_route.add_argument(
450
- "-d",
451
- "--date",
452
- help="the date",
453
- type=lambda s: parse_datetime(s),
454
- default=datetime.now(),
455
- )
456
- train_route.set_defaults(func=cli.train_info, pass_=["brand", "name", "date"])
457
-
458
- train_calendar = subparsers.add_parser(
459
- "traincalendar",
460
- aliases=["kursowanie", "tc", "k"],
461
- help="Allows you to check what days the train runs on",
462
- )
463
- train_calendar.add_argument("brand", help="The brand name", type=str)
464
- train_calendar.add_argument("name", help="The train name", nargs="+", action=RemainderString)
465
- train_calendar.set_defaults(func=cli.train_calendar, pass_=["brand", "name"])
466
-
467
- train_detail = subparsers.add_parser(
468
- "traindetail",
469
- aliases=["td", "tid", "id", "idpoc"],
470
- help="Allows you to show the train's route given it's koleo ID",
471
- )
472
- train_detail.add_argument("train_id", help="The koleo ID", type=int)
473
- train_detail.set_defaults(func=cli.train_detail, pass_=["train_id"])
474
-
475
- stations = subparsers.add_parser(
476
- "stations", aliases=["s", "find", "f", "stacje", "ls", "q"], help="Allows you to find stations by their name"
477
- )
478
- stations.add_argument(
479
- "query",
480
- help="The station name",
481
- default=None,
482
- nargs="*",
483
- action=RemainderString,
484
- )
485
- stations.set_defaults(func=cli.find_station, pass_=["query"])
486
-
487
- connections = subparsers.add_parser(
488
- "connections",
489
- aliases=["do", "z", "szukaj", "path"],
490
- help="Allows you to search for connections from a to b",
491
- )
492
- connections.add_argument("start", help="The starting station", type=str)
493
- connections.add_argument("end", help="The end station", type=str)
494
- connections.add_argument(
495
- "-d",
496
- "--date",
497
- help="the date",
498
- type=lambda s: parse_datetime(s),
499
- default=datetime.now(),
500
- )
501
- connections.add_argument(
502
- "-b", "--brands", help="Brands to include", action="extend", nargs="+", type=str, default=[]
503
- )
504
- connections.add_argument(
505
- "-f",
506
- "--direct",
507
- help="whether or not the result should only include direct trains",
508
- action="store_true",
509
- default=False,
510
- )
511
- connections.add_argument(
512
- "-p",
513
- "--purchasable",
514
- help="whether or not the result should only trains purchasable on koleo",
515
- action="store_true",
516
- default=False,
517
- )
518
- connections.add_argument(
519
- "-l",
520
- "--length",
521
- help="fetch at least n connections",
522
- type=int,
523
- default=1,
524
- )
525
- connections.set_defaults(
526
- func=cli.connections, pass_=["start", "end", "brands", "date", "direct", "purchasable", "length"]
527
- )
528
-
529
- args = parser.parse_args()
530
-
531
- storage = Storage.load(path=args.config)
532
- client = KoleoAPI()
533
- cli.client, cli.storage = client, storage
534
- cli.console.no_color = args.nocolor
535
- cli.no_color = args.nocolor
536
- if hasattr(args, "station") and args.station is None:
537
- args.station = storage.favourite_station
538
- elif hasattr(args, "station") and args.save:
539
- storage.favourite_station = args.station
540
- if not hasattr(args, "func"):
541
- if storage.favourite_station:
542
- cli.full_departures(storage.favourite_station, datetime.now())
543
- else:
544
- parser.print_help()
545
- exit()
546
- else:
547
- args.func(**{k: v for k, v in args.__dict__.items() if k in getattr(args, "pass_", [])})
548
-
549
- if storage._dirty:
550
- storage.save()