koleo-cli 0.2.137.8__py3-none-any.whl → 0.2.137.10__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 CHANGED
@@ -6,7 +6,7 @@ from rich.console import Console
6
6
 
7
7
  from .api import KoleoAPI
8
8
  from .storage import DEFAULT_CONFIG_PATH, Storage
9
- from .types import ExtendedBaseStationInfo, TrainDetailResponse, TrainOnStationInfo
9
+ from .types import ExtendedBaseStationInfo, TrainDetailResponse, TrainOnStationInfo, TrainCalendar
10
10
  from .utils import RemainderString, arr_dep_to_dt, convert_platform_number, name_to_slug, parse_datetime
11
11
 
12
12
 
@@ -89,6 +89,37 @@ class CLI:
89
89
  self.print(station_info)
90
90
  self.get_arrivals(st["id"], date)
91
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(train[0]["departure"] if train[1] == 1 else train[0]["arrival"]).timestamp()
107
+ )
108
+ trains = [
109
+ (i, type)
110
+ for i, type in trains
111
+ if datetime.fromisoformat(i["departure"] if type == 1 else i["arrival"]).timestamp() > date.timestamp() # type: ignore
112
+ ]
113
+ brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
114
+ parts = []
115
+ for train, type in trains:
116
+ time = f"[bold green]{train['departure'][11:16]}[/bold green]" if type == 1 else f"[bold yellow]{train['arrival'][11:16]}[/bold yellow]"
117
+ brand = next(iter(i for i in brands if i["id"] == train["brand_id"]), {}).get("logo_text")
118
+ parts.append(
119
+ f"{time} [red]{brand}[/red] {train["train_full_name"]}[purple] {train["stations"][0]["name"]} {self.format_position(train["platform"], train["track"])}[/purple]"
120
+ )
121
+ self.print("\n".join(parts))
122
+
92
123
  def find_station(self, query: str | None):
93
124
  if query:
94
125
  stations = self.client.find_station(query)
@@ -101,7 +132,7 @@ class CLI:
101
132
  f"[bold blue][link=https://koleo.pl/dworzec-pkp/{st["name_slug"]}]{st["name"]}[/bold blue] ID: {st["id"]}[/link]"
102
133
  )
103
134
 
104
- def train_info(self, brand: str, name: str, date: datetime):
135
+ def get_train_calendars(self, brand: str, name: str) -> list[TrainCalendar]:
105
136
  brand = brand.upper().strip()
106
137
  name_parts = name.split(" ")
107
138
  if len(name_parts) == 1 and name_parts[0].isnumeric():
@@ -126,21 +157,47 @@ class CLI:
126
157
  except self.client.errors.KoleoNotFound:
127
158
  self.print(f'[bold red]Train not found: nr={number}, name="{train_name}"[/bold red]')
128
159
  exit(2)
129
- train_id = train_calendars["train_calendars"][0]["date_train_map"][date.strftime("%Y-%m-%d")]
160
+ return train_calendars["train_calendars"]
161
+
162
+ def train_calendar(self, brand: str, name: str):
163
+ train_calendars = self.get_train_calendars(brand, name)
164
+ brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
165
+ for calendar in train_calendars:
166
+ brand = next(iter(i for i in brands if i["id"] == calendar["trainBrand"]), {}).get("logo_text", "")
167
+ parts = [f"[red]{brand}[/red] [bold blue]{calendar['train_nr']}{" "+ v if (v:=calendar.get("train_name")) else ""}[/bold blue]:"]
168
+ for k, v in calendar["date_train_map"].items():
169
+ parts.append(f" [bold green]{k}[/bold green]: [purple]{v}[/purple]")
170
+ self.print("\n".join(parts))
171
+
172
+ def train_info(self, brand: str, name: str, date: datetime):
173
+ train_calendars = self.get_train_calendars(brand, name)
174
+ if not (train_id:=train_calendars[0]["date_train_map"].get(date.strftime("%Y-%m-%d"))):
175
+ self.print(f"[bold red]This train doesn't run on the selected date: {date.strftime("%Y-%m-%d")}[/bold red]")
176
+ exit(2)
177
+ self.train_detail(train_id)
178
+
179
+ def train_detail(self, train_id: int):
130
180
  train_details = self.client.get_train(train_id)
181
+ brands = self.storage.get_cache("brands") or self.storage.set_cache("brands", self.client.get_brands())
131
182
  brand = next(iter(i for i in brands if i["id"] == train_details["train"]["brand_id"]), {}).get("logo_text", "")
183
+
132
184
  parts = [f"[red]{brand}[/red] [bold blue]{train_details["train"]["train_full_name"]}[/bold blue]"]
185
+ parts.append(f" {train_details["train"]["run_desc"]}")
186
+
133
187
  route_start = arr_dep_to_dt(train_details["stops"][0]["departure"])
134
188
  route_end = arr_dep_to_dt(train_details["stops"][-1]["arrival"])
189
+
135
190
  if route_end.hour < route_start.hour or (
136
191
  route_end.hour == route_start.hour and route_end.minute < route_end.minute
137
192
  ):
138
193
  route_end += timedelta(days=1)
194
+
139
195
  travel_time = route_end - route_start
140
196
  speed = train_details["stops"][-1]["distance"] / 1000 / travel_time.seconds * 3600
141
197
  parts.append(
142
198
  f"[white] {travel_time.seconds//3600}h{(travel_time.seconds % 3600)/60:.0f}m {speed:^4.1f}km/h [/white]"
143
199
  )
200
+
144
201
  vehicle_types: dict[str, str] = {
145
202
  stop["station_display_name"]: stop["vehicle_type"]
146
203
  for stop in train_details["stops"]
@@ -330,10 +387,30 @@ def main():
330
387
  arrivals.add_argument("-s", "--save", help="save the station as your default one", action="store_true")
331
388
  arrivals.set_defaults(func=cli.full_arrivals, pass_=["station", "date"])
332
389
 
390
+ all_trains = subparsers.add_parser(
391
+ "all", aliases=["w", "wszystkie", "all_trains", "pociagi"], help="Allows you to list all station trains"
392
+ )
393
+ all_trains.add_argument(
394
+ "station",
395
+ help="The station name",
396
+ default=None,
397
+ nargs="*",
398
+ action=RemainderString,
399
+ )
400
+ all_trains.add_argument(
401
+ "-d",
402
+ "--date",
403
+ help="the date",
404
+ type=lambda s: parse_datetime(s),
405
+ default=datetime.now(),
406
+ )
407
+ all_trains.add_argument("-s", "--save", help="save the station as your default one", action="store_true")
408
+ all_trains.set_defaults(func=cli.all_trains, pass_=["station", "date"])
409
+
333
410
  train_route = subparsers.add_parser(
334
411
  "trainroute",
335
412
  aliases=["r", "tr", "t", "poc", "pociąg"],
336
- help="Allows you to show the train's route",
413
+ help="Allows you to check the train's route",
337
414
  )
338
415
  train_route.add_argument("brand", help="The brand name", type=str)
339
416
  train_route.add_argument("name", help="The train name", nargs="+", action=RemainderString)
@@ -346,6 +423,23 @@ def main():
346
423
  )
347
424
  train_route.set_defaults(func=cli.train_info, pass_=["brand", "name", "date"])
348
425
 
426
+ train_calendar = subparsers.add_parser(
427
+ "traincalendar",
428
+ aliases=["kursowanie", "tc", "k"],
429
+ help="Allows you to check what days the train runs on",
430
+ )
431
+ train_calendar.add_argument("brand", help="The brand name", type=str)
432
+ train_calendar.add_argument("name", help="The train name", nargs="+", action=RemainderString)
433
+ train_calendar.set_defaults(func=cli.train_calendar, pass_=["brand", "name"])
434
+
435
+ train_detail = subparsers.add_parser(
436
+ "traindetail",
437
+ aliases=["td", "tid", "id", "idpoc"],
438
+ help="Allows you to show the train's route given it's koleo ID",
439
+ )
440
+ train_detail.add_argument("train_id", help="The koleo ID", type=int)
441
+ train_detail.set_defaults(func=cli.train_detail, pass_=["train_id"])
442
+
349
443
  stations = subparsers.add_parser(
350
444
  "stations", aliases=["s", "find", "f", "stacje", "ls", "q"], help="Allows you to find stations by their name"
351
445
  )
@@ -402,7 +496,6 @@ def main():
402
496
  args.station = storage.favourite_station
403
497
  elif hasattr(args, "station") and args.save:
404
498
  storage.favourite_station = args.station
405
- storage.save()
406
499
  if not hasattr(args, "func"):
407
500
  if storage.favourite_station:
408
501
  cli.full_departures(storage.favourite_station, datetime.now())
@@ -411,3 +504,6 @@ def main():
411
504
  exit()
412
505
  else:
413
506
  args.func(**{k: v for k, v in args.__dict__.items() if k in getattr(args, "pass_", [])})
507
+
508
+ if storage._dirty:
509
+ storage.save()
koleo/storage.py CHANGED
@@ -33,6 +33,7 @@ class Storage:
33
33
 
34
34
  def __post_init__(self):
35
35
  self._path: str
36
+ self._dirty = False
36
37
 
37
38
  @classmethod
38
39
  def load(cls, *, path: str = DEFAULT_CONFIG_PATH) -> t.Self:
@@ -57,13 +58,13 @@ class Storage:
57
58
  return item
58
59
  else:
59
60
  self.cache.pop(id)
60
- self.save()
61
+ self._dirty = True
61
62
 
62
63
  def set_cache(self, id: str, item: T, ttl: int = 86400) -> T:
63
64
  if self.disable_cache:
64
65
  return item
65
66
  self.cache[id] = (int(time() + ttl), item)
66
- self.save()
67
+ self._dirty = True
67
68
  return item
68
69
 
69
70
  def save(self):
@@ -72,4 +73,12 @@ class Storage:
72
73
  if not ospath.exists(dir):
73
74
  makedirs(dir)
74
75
  with open(self._path, "w+") as f:
76
+ self.clean()
75
77
  dump(asdict(self), f, indent=True)
78
+
79
+ def clean(self):
80
+ now = time()
81
+ copy = self.cache.copy()
82
+ self.cache = {k: data for k, data in copy.items() if data[0] > now}
83
+ if copy != self.cache:
84
+ self._dirty = True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: koleo-cli
3
- Version: 0.2.137.8
3
+ Version: 0.2.137.10
4
4
  Summary: Koleo CLI
5
5
  Home-page: https://github.com/lzgirlcat/koleo-cli
6
6
  Author: Zoey !
@@ -0,0 +1,13 @@
1
+ koleo/__init__.py,sha256=N_IkOBZCSPCCw31Hu72CFys707PziGFmXpNVl0CXAz8,47
2
+ koleo/__main__.py,sha256=wu5N2wk8mvBgyvr2ghmQf4prezAe0_i-p123VVreyYc,62
3
+ koleo/api.py,sha256=07PSwLFmirdJ_JhPBJ7rO1nv_v90njIcwmOoxT4P_4M,5708
4
+ koleo/cli.py,sha256=CeZBwuS2ibZZ_HQq8bRwcY4HLq59_tEb9ux7daOvgc4,23239
5
+ koleo/storage.py,sha256=U1ydt8AZ3WsiNBOmThD-cxomLzLrpHRG4BZbMg-14Fc,2304
6
+ koleo/types.py,sha256=pjVCIH39rUNeipazeRKOuTRCWoslLdbGivKiQmfd5Pw,5226
7
+ koleo/utils.py,sha256=CsYWNf3IPhHJln445tzXSA7r2z3NpmqVSmw8Rrb7YT0,1822
8
+ koleo_cli-0.2.137.10.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
9
+ koleo_cli-0.2.137.10.dist-info/METADATA,sha256=wwrlHORzN11td36xS_fjWglZpIWA11EryaJ6rpm9kXk,3096
10
+ koleo_cli-0.2.137.10.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
11
+ koleo_cli-0.2.137.10.dist-info/entry_points.txt,sha256=LtCidkVDq8Zd7-fxpRbys1Xa9LTHMZwXVbdcQEscdes,41
12
+ koleo_cli-0.2.137.10.dist-info/top_level.txt,sha256=AlWdXotkRYzHpFfOBYi6xOXl1H0zq4-tqtZ2XivoWB4,6
13
+ koleo_cli-0.2.137.10.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,13 +0,0 @@
1
- koleo/__init__.py,sha256=N_IkOBZCSPCCw31Hu72CFys707PziGFmXpNVl0CXAz8,47
2
- koleo/__main__.py,sha256=wu5N2wk8mvBgyvr2ghmQf4prezAe0_i-p123VVreyYc,62
3
- koleo/api.py,sha256=07PSwLFmirdJ_JhPBJ7rO1nv_v90njIcwmOoxT4P_4M,5708
4
- koleo/cli.py,sha256=WJARHIDzhjQuKxlsjjkNkGbnOprU_I-KfL3ZI383EyI,18533
5
- koleo/storage.py,sha256=_VztM8d3YTnmZOR9JvOsobThrQhb4gEzT1azC8N7baY,2024
6
- koleo/types.py,sha256=pjVCIH39rUNeipazeRKOuTRCWoslLdbGivKiQmfd5Pw,5226
7
- koleo/utils.py,sha256=CsYWNf3IPhHJln445tzXSA7r2z3NpmqVSmw8Rrb7YT0,1822
8
- koleo_cli-0.2.137.8.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
9
- koleo_cli-0.2.137.8.dist-info/METADATA,sha256=2_4tYhSb6u865m96qR6CbwJtWPFep8LJlTioym5Eo60,3095
10
- koleo_cli-0.2.137.8.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
11
- koleo_cli-0.2.137.8.dist-info/entry_points.txt,sha256=LtCidkVDq8Zd7-fxpRbys1Xa9LTHMZwXVbdcQEscdes,41
12
- koleo_cli-0.2.137.8.dist-info/top_level.txt,sha256=AlWdXotkRYzHpFfOBYi6xOXl1H0zq4-tqtZ2XivoWB4,6
13
- koleo_cli-0.2.137.8.dist-info/RECORD,,