koleo-cli 0.2.137.19__py3-none-any.whl → 0.2.137.21__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/args.py CHANGED
@@ -14,6 +14,8 @@ def main():
14
14
 
15
15
  parser = ArgumentParser("koleo", description="Koleo CLI")
16
16
  parser.add_argument("-c", "--config", help="Custom config path.", default=DEFAULT_CONFIG_PATH)
17
+ parser.add_argument("--ignore_cache", action="store_true", default=False)
18
+
17
19
  parser.add_argument("--nocolor", help="Disable color output and formatting", action="store_true", default=False)
18
20
  subparsers = parser.add_subparsers(title="actions", required=False) # type: ignore
19
21
 
@@ -169,20 +171,20 @@ def main():
169
171
  connections.add_argument(
170
172
  "-n",
171
173
  "--direct",
172
- help="whether or not the result should only include direct trains",
174
+ help="whether the result should only include direct trains",
173
175
  action="store_true",
174
176
  default=False,
175
177
  )
176
178
  connections.add_argument(
177
179
  "-p",
178
180
  "--include_prices",
179
- help="whether or not the result should include the price",
181
+ help="whether the result should include the price",
180
182
  action="store_true",
181
183
  default=False,
182
184
  )
183
185
  connections.add_argument(
184
186
  "--only_purchasable",
185
- help="whether or not the result should include only purchasable connections",
187
+ help="whether the result should include only purchasable connections",
186
188
  action="store_true",
187
189
  default=False,
188
190
  )
@@ -218,8 +220,14 @@ def main():
218
220
  train_passenger_stats.add_argument(
219
221
  "-t", "--type", help="limit the result to seats of a given type", type=str, required=False
220
222
  )
223
+ train_passenger_stats.add_argument(
224
+ "--detailed",
225
+ help="whether to display occupancy status for each seat",
226
+ action="store_true",
227
+ default=False,
228
+ )
221
229
  train_passenger_stats.set_defaults(
222
- func=cli.train_passenger_stats_view, pass_=["brand", "name", "date", "stations", "type"]
230
+ func=cli.train_passenger_stats_view, pass_=["brand", "name", "date", "stations", "type", "detailed"]
223
231
  )
224
232
 
225
233
  train_connection_stats = subparsers.add_parser(
@@ -230,8 +238,14 @@ def main():
230
238
  train_connection_stats.add_argument(
231
239
  "-t", "--type", help="limit the result to seats of a given type", type=str, required=False
232
240
  )
241
+ train_connection_stats.add_argument(
242
+ "--detailed",
243
+ help="whether to display occupancy status for each seat",
244
+ action="store_true",
245
+ default=False,
246
+ )
233
247
  train_connection_stats.add_argument("connection_id", help="The koleo ID", type=int)
234
- train_connection_stats.set_defaults(func=cli.train_connection_stats_view, pass_=["connection_id", "type"])
248
+ train_connection_stats.set_defaults(func=cli.train_connection_stats_view, pass_=["connection_id", "type", "detailed"])
235
249
 
236
250
  aliases = subparsers.add_parser("aliases", help="Save quick aliases for station names!")
237
251
  aliases.set_defaults(func=cli.alias_list_view)
@@ -250,9 +264,15 @@ def main():
250
264
  aliases_remove.add_argument("alias", help="The alias")
251
265
  aliases_remove.set_defaults(func=cli.alias_remove_view, pass_=["alias"])
252
266
 
267
+ clear_cache = subparsers.add_parser(
268
+ "clear_cache",
269
+ help="Allows you to clear koleo-cli cache",
270
+ )
271
+ clear_cache.set_defaults(func="clear_cache")
272
+
253
273
  args = parser.parse_args()
254
274
 
255
- storage = Storage.load(path=args.config)
275
+ storage = Storage.load(path=args.config, ignore_cache=args.ignore_cache)
256
276
  client = KoleoAPI()
257
277
 
258
278
  async def run_view(func, *args, **kwargs):
@@ -274,6 +294,9 @@ def main():
274
294
  else:
275
295
  parser.print_help()
276
296
  else:
277
- run(run_view(args.func, **{k: v for k, v in args.__dict__.items() if k in getattr(args, "pass_", [])}))
297
+ if args.func == "clear_cache":
298
+ storage.clear_cache()
299
+ else:
300
+ run(run_view(args.func, **{k: v for k, v in args.__dict__.items() if k in getattr(args, "pass_", [])}))
278
301
  if storage.dirty:
279
302
  storage.save()
koleo/cli/base.py CHANGED
@@ -80,7 +80,10 @@ class BaseCli:
80
80
  def format_position(self, platform: str, track: str | None = None):
81
81
  res = str(convert_platform_number(platform) or "" if not self.storage.use_roman_numerals else platform)
82
82
  if track is not None and track != "":
83
- res += f"/{track}"
83
+ if self.storage.platform_first:
84
+ res += f"/{track}"
85
+ else:
86
+ res = f"{track}/{res}"
84
87
  return res
85
88
 
86
89
  async def get_station(self, station: str) -> ExtendedStationInfo:
@@ -101,3 +104,17 @@ class BaseCli:
101
104
  async def get_station_by_id(self, id: int):
102
105
  key = f"st-{id}"
103
106
  return self.storage.get_cache(key) or self.storage.set_cache(key, await self.client.get_station_by_id(id))
107
+
108
+ async def get_brand_by_shortcut(self, s: str, *, name: str | None = None):
109
+ brands = await self.get_brands()
110
+ s = s.upper()
111
+ if name and "SŁONECZNY" in name and s == "KM":
112
+ return "SLONECZNY" # OH MY FUCKING GOD
113
+ if s == "AR":
114
+ return "ARRIVARP"
115
+ if s not in [i["name"] for i in brands]:
116
+ res = {i["logo_text"]: i["name"] for i in brands}.get(s)
117
+ if not res:
118
+ await self.error_and_exit(f"Invalid brand name not found: [underline]{s},[/underline]")
119
+ return res
120
+ return s
koleo/cli/seats.py CHANGED
@@ -16,6 +16,7 @@ class Seats(TrainInfo):
16
16
  date: datetime,
17
17
  stations: tuple[str, str] | None = None,
18
18
  type: str | None = None,
19
+ detailed: bool = False,
19
20
  ):
20
21
  train_calendars = await self.get_train_calendars(brand, name)
21
22
  if not (train_id := train_calendars[0]["date_train_map"].get(date.strftime("%Y-%m-%d"))):
@@ -48,28 +49,37 @@ class Seats(TrainInfo):
48
49
  direct=True,
49
50
  date=koleo_time_to_dt(train_stops_by_slug[first_station]["departure"], base_date=date),
50
51
  )
51
- connection = next(iter(i for i in connections if i["trains"][0]["train_id"] == train_details["train"]["id"]))
52
+ connection = next(iter(i for i in connections if i["trains"][0]["train_id"] == train_details["train"]["id"]), None)
53
+ if connection is None:
54
+ await self.error_and_exit("Train not found:<")
52
55
  connection_train = connection["trains"][0]
53
56
  if connection_train["brand_id"] not in BRAND_SEAT_TYPE_MAPPING:
54
57
  await self.error_and_exit(f"Brand [underline]{connection_train["brand_id"]}[/underline] is not supported.")
55
58
  await self.show_train_header(
56
59
  train_details, train_stops_by_slug[first_station], train_stops_by_slug[last_station]
57
60
  )
58
- await self.train_seat_info(connection["id"], type, connection_train["brand_id"], connection_train["train_nr"])
61
+ await self.train_seat_info(connection["id"], type, connection_train["brand_id"], connection_train["train_nr"], detailed=detailed)
59
62
 
60
- async def train_connection_stats_view(self, connection_id: int, type: str | None):
63
+ async def train_connection_stats_view(self, connection_id: int, type: str | None, detailed: bool = False):
61
64
  connection = await self.client.get_connection(connection_id)
62
65
  train = connection["trains"][0]
63
66
  if train["brand_id"] not in BRAND_SEAT_TYPE_MAPPING:
64
67
  await self.error_and_exit(f'Brand [underline]{train["brand_id"]}[/underline] is not supported.')
65
- print(connection)
66
68
  train_details = await self.client.get_train(train["train_id"])
67
69
  first_stop = next(iter(i for i in train_details["stops"] if i["station_id"] == connection["start_station_id"]))
68
70
  last_stop = next(iter(i for i in train_details["stops"] if i["station_id"] == connection["end_station_id"]))
69
71
  await self.show_train_header(train_details, first_stop, last_stop)
70
- await self.train_seat_info(connection_id, type, train["brand_id"], train["train_nr"])
72
+ await self.train_seat_info(connection_id, type, train["brand_id"], train["train_nr"], detailed=detailed)
71
73
 
72
- async def train_seat_info(self, connection_id: int, type: str | None, brand_id: int, train_nr: int):
74
+ async def train_seat_info(
75
+ self,
76
+ connection_id: int,
77
+ type: str | None,
78
+ brand_id: int,
79
+ train_nr: int,
80
+ *,
81
+ detailed: bool = False
82
+ ):
73
83
  seat_name_map = BRAND_SEAT_TYPE_MAPPING[brand_id]
74
84
  if type is not None:
75
85
  if type.isnumeric() and int(type) in seat_name_map:
@@ -83,7 +93,6 @@ class Seats(TrainInfo):
83
93
  res: dict[int, SeatsAvailabilityResponse] = {}
84
94
  for seat_type in types:
85
95
  res[seat_type] = await self.client.get_seats_availability(connection_id, train_nr, seat_type)
86
- total_seats = sum(len(i["seats"]) for i in res.values())
87
96
  for seat_type, result in res.items():
88
97
  counters: dict[SeatState, int] = {"FREE": 0, "RESERVED": 0, "BLOCKED": 0}
89
98
  for seat in result["seats"]:
@@ -91,7 +100,6 @@ class Seats(TrainInfo):
91
100
  color = CLASS_COLOR_MAP.get(seat_name_map[seat_type], "")
92
101
  self.print(f"[bold {color}]{seat_name_map[seat_type]}: [/bold {color}]")
93
102
  total = sum(i for i in counters.values())
94
- not_available = counters["BLOCKED"] + counters["RESERVED"]
95
103
  self.print(
96
104
  f" Free: [{color}]{counters["FREE"]}/{total}, ~{counters["FREE"]/total*100:.1f}%[/{color}]"
97
105
  )
@@ -101,3 +109,15 @@ class Seats(TrainInfo):
101
109
  self.print(
102
110
  f" Blocked: [underline {color}]{counters["BLOCKED"]}[/underline {color}]"
103
111
  )
112
+ taken = counters["BLOCKED"] + counters["RESERVED"]
113
+ self.print(
114
+ f" Total: [underline {color}]{taken}/{total}, ~{taken/total*100:.1f}%[/underline {color}]"
115
+ )
116
+
117
+ if detailed: # super temporary!!!!!!
118
+ for seat_type, result in res.items():
119
+ type_color = CLASS_COLOR_MAP.get(seat_name_map[seat_type], "")
120
+ self.print(f"[bold {type_color}]{seat_name_map[seat_type]}: [/bold {type_color}]")
121
+ for seat in result["seats"]:
122
+ color = "green" if seat["state"] == "FREE" else "red"
123
+ self.print(f" [{type_color}]{seat["carriage_nr"]}[/{type_color}] {seat['seat_nr']}: [{color}]{seat["state"]}[/{color}]")
koleo/cli/train_info.py CHANGED
@@ -8,7 +8,7 @@ from koleo.utils import koleo_time_to_dt
8
8
 
9
9
  class TrainInfo(BaseCli):
10
10
  async def get_train_calendars(self, brand: str, name: str) -> list[TrainCalendar]:
11
- brand = brand.upper().strip()
11
+ brand = await self.get_brand_by_shortcut(brand, name=name)
12
12
  name_parts = name.split(" ")
13
13
  if len(name_parts) == 1 and name_parts[0].isnumeric():
14
14
  number = int(name_parts[0])
@@ -18,12 +18,7 @@ class TrainInfo(BaseCli):
18
18
  train_name = " ".join(name_parts)
19
19
  else:
20
20
  raise ValueError("Invalid train name!")
21
- brands = await self.get_brands()
22
- if brand not in [i["name"] for i in brands]:
23
- res = {i["logo_text"]: i["name"] for i in brands}.get(brand)
24
- if not res:
25
- raise ValueError("Invalid brand name!")
26
- brand = res
21
+
27
22
  cache_id = f"tc-{brand}-{number}-{name}"
28
23
  try:
29
24
  train_calendars = self.storage.get_cache(cache_id) or self.storage.set_cache(
@@ -38,7 +33,7 @@ class TrainInfo(BaseCli):
38
33
  brands = await self.get_brands()
39
34
  for calendar in train_calendars:
40
35
  brand_obj = next(iter(i for i in brands if i["id"] == calendar["trainBrand"]), {})
41
- link = f"https://koleo.pl/pociag/{brand_obj["name"]}/{name.replace(" ", "-")}"
36
+ link = f"https://koleo.pl/pociag/{brand_obj["name"]}/{name.replace(" ", "-", count=1).replace(" ", "%20")}"
42
37
  brand = brand_obj.get("logo_text", "")
43
38
  self.print(
44
39
  f"[red][link={link}]{brand}[/red] [bold blue]{calendar['train_nr']}{" "+ v if (v:=calendar.get("train_name")) else ""}[/bold blue]:[/link]"
@@ -98,9 +93,10 @@ class TrainInfo(BaseCli):
98
93
  brands = await self.get_brands()
99
94
  brand_obj = next(iter(i for i in brands if i["id"] == train_details["train"]["brand_id"]), {})
100
95
  brand = brand_obj.get("logo_text", "")
96
+ url_brand = await self.get_brand_by_shortcut(brand, name=train_details["train"]["train_full_name"])
101
97
 
102
98
  link = (
103
- f"https://koleo.pl/pociag/{brand_obj["name"]}/{train_details["train"]["train_full_name"].replace(" ", "-")}"
99
+ f"https://koleo.pl/pociag/{url_brand}/{train_details["train"]["train_full_name"].replace(" ", "-", count=1).replace(" ", "%20")}"
104
100
  )
105
101
  if date:
106
102
  link += f"/{date}"
koleo/storage.py CHANGED
@@ -74,18 +74,20 @@ class Storage:
74
74
  show_connection_id: bool = False
75
75
  use_country_flags_emoji: bool = True
76
76
  use_station_type_emoji: bool = True
77
+ platform_first: bool = False
77
78
  auth: Auth | None = None
78
79
 
79
80
  def __post_init__(self):
80
81
  self._path: str
81
82
  self._dirty = False
83
+ self._ignore_cache = False
82
84
 
83
85
  @property
84
86
  def dirty(self) -> bool:
85
87
  return self._dirty
86
88
 
87
89
  @classmethod
88
- def load(cls, *, path: str = DEFAULT_CONFIG_PATH) -> t.Self:
90
+ def load(cls, *, path: str = DEFAULT_CONFIG_PATH, ignore_cache: bool = False) -> t.Self:
89
91
  expanded = ospath.expanduser(path)
90
92
  if ospath.exists(expanded):
91
93
  with open(expanded) as f:
@@ -94,10 +96,11 @@ class Storage:
94
96
  data = {}
95
97
  storage = cls(**data)
96
98
  storage._path = expanded
99
+ storage._ignore_cache = ignore_cache
97
100
  return storage
98
101
 
99
102
  def get_cache(self, id: str) -> t.Any | None:
100
- if self.disable_cache:
103
+ if self.disable_cache or self._ignore_cache:
101
104
  return None
102
105
  cache_result = self.cache.get(id)
103
106
  if not cache_result:
@@ -123,6 +126,10 @@ class Storage:
123
126
  if copy != self.cache:
124
127
  self._dirty = True
125
128
 
129
+ def clear_cache(self):
130
+ self.cache = {}
131
+ self._dirty = True
132
+
126
133
  def save(self):
127
134
  dir = ospath.dirname(self._path)
128
135
  if dir:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koleo-cli
3
- Version: 0.2.137.19
3
+ Version: 0.2.137.21
4
4
  Summary: Koleo CLI
5
5
  Home-page: https://github.com/lzgirlcat/koleo-cli
6
6
  Author: Zoey !
@@ -1,7 +1,7 @@
1
1
  koleo/__init__.py,sha256=dp6PfGcuWP50QBWhjnT-zS03l3KzzYnMJnUeYMKBayc,51
2
2
  koleo/__main__.py,sha256=zRwdn7wRjqzWyDIoQ8PDDd_K2GizFIto35uO-mGFwsQ,63
3
- koleo/args.py,sha256=gncN8HA8a67U1Wpt3lc32bvPBydn0uCkSmiCZNVQRGk,10275
4
- koleo/storage.py,sha256=pffcqpTakYp8o6dbVMkD5oF13R6L2eQR3ambU8qTRuM,4345
3
+ koleo/args.py,sha256=glXMFflV4TMHA1JYEFf54MCry2bSLEOa7ap8bPiJZA0,11025
4
+ koleo/storage.py,sha256=_-vpcO6MwbTsnCNWhaHe9xRKm9jpO0Xl0OOyXSmZJzs,4587
5
5
  koleo/utils.py,sha256=OAjm90SN1BqpgNF8OTAaR9atyLNYIGy5owZ2pLP5OAM,4631
6
6
  koleo/api/__init__.py,sha256=3TfO8eBJcDCDXvIFobgyvN3Sfa1kQ2U0lm7gxEAsaWQ,50
7
7
  koleo/api/base.py,sha256=8wAasDQ1DBDI1PsPESmS3iUE5csIgaGT4DOX_A-hPwI,2070
@@ -11,16 +11,16 @@ koleo/api/logging.py,sha256=VhOFY6N_mofFfg9ZJ5ZnDVCzNuRilqLqrzZU9b-hpZY,1644
11
11
  koleo/api/types.py,sha256=udCQeDjRvUqrUkuE_-Jidzsq_FOCjNyGd_bQWm3f9iA,10594
12
12
  koleo/cli/__init__.py,sha256=50B_lMtZS27_FVrkIa2TOWMX7SozG1CPPMxbY1W9tqk,266
13
13
  koleo/cli/aliases.py,sha256=is3NX5g0-ujJTmyjlFLoNnK_pwoYUVIojWNkgwXRBKk,581
14
- koleo/cli/base.py,sha256=Rdv8FwenM0ymSHNrW9faGYI6mr65EL-n24bN5YXfLkg,4261
14
+ koleo/cli/base.py,sha256=4vnQ4HS5GD6WXReWiJs1E7Bt8cDU4anlZCDb8xXqXS0,4954
15
15
  koleo/cli/connections.py,sha256=LJzoq3ADVUmBeqF4-h_me3pZbBHYg1sG3MaDYprwuLU,6873
16
- koleo/cli/seats.py,sha256=hIALtopQPD-BcBGI_XpPo3ht6f_D5e16VpI7mFgN0Ao,5477
16
+ koleo/cli/seats.py,sha256=h7pRWdeQ8frHD1ZuiGZO6UGQRboty9PtiVHg49lkw4Q,6337
17
17
  koleo/cli/station_board.py,sha256=lRGIeEKEOvUcctM6cwmqVE7Yk9m9R12gfFZahlWLQFc,3669
18
18
  koleo/cli/stations.py,sha256=6L3PBWc6xssyR9eeLacuvGBJmaY7Ny3DalKy2Xq7zsA,1633
19
- koleo/cli/train_info.py,sha256=XS_G4dsevHBPuGSpsbNTh_adSLyedame7WVe71oIe5M,7259
19
+ koleo/cli/train_info.py,sha256=bwM1pGH4-nqhw8V8hiQqs_LlRmpYf09GbKwNiYBjndc,7176
20
20
  koleo/cli/utils.py,sha256=FzPGcJdwRwcz10mYiW63Y4zpjM9j6DzNH91UNR3MS8s,666
21
- koleo_cli-0.2.137.19.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
22
- koleo_cli-0.2.137.19.dist-info/METADATA,sha256=Ewvfre33HQFcAPNrlK_KmD8teeBHXJf_-ZxT4DLX5iA,4731
23
- koleo_cli-0.2.137.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- koleo_cli-0.2.137.19.dist-info/entry_points.txt,sha256=ouWbMR_XWpEwV7zfkFKeiFLe_IMP-47kTvVahgy4PRg,42
25
- koleo_cli-0.2.137.19.dist-info/top_level.txt,sha256=AlWdXotkRYzHpFfOBYi6xOXl1H0zq4-tqtZ2XivoWB4,6
26
- koleo_cli-0.2.137.19.dist-info/RECORD,,
21
+ koleo_cli-0.2.137.21.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
22
+ koleo_cli-0.2.137.21.dist-info/METADATA,sha256=IF1UExJ-_VDEyTKdegvJOu9qYllZdfsS4ipTW1OGBr4,4731
23
+ koleo_cli-0.2.137.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
+ koleo_cli-0.2.137.21.dist-info/entry_points.txt,sha256=ouWbMR_XWpEwV7zfkFKeiFLe_IMP-47kTvVahgy4PRg,42
25
+ koleo_cli-0.2.137.21.dist-info/top_level.txt,sha256=AlWdXotkRYzHpFfOBYi6xOXl1H0zq4-tqtZ2XivoWB4,6
26
+ koleo_cli-0.2.137.21.dist-info/RECORD,,