koleo-cli 0.2.137.17__tar.gz → 0.2.137.18__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.

Potentially problematic release.


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

Files changed (43) hide show
  1. {koleo_cli-0.2.137.17/koleo_cli.egg-info → koleo_cli-0.2.137.18}/PKG-INFO +32 -13
  2. koleo_cli-0.2.137.18/README.md +70 -0
  3. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/koleo/__init__.py +1 -1
  4. koleo_cli-0.2.137.18/koleo/api/__init__.py +2 -0
  5. koleo_cli-0.2.137.18/koleo/api/base.py +70 -0
  6. koleo_cli-0.2.137.18/koleo/api/client.py +221 -0
  7. koleo_cli-0.2.137.18/koleo/api/errors.py +46 -0
  8. koleo_cli-0.2.137.18/koleo/api/logging.py +56 -0
  9. koleo_cli-0.2.137.18/koleo/api/types.py +488 -0
  10. koleo_cli-0.2.137.18/koleo/args.py +279 -0
  11. koleo_cli-0.2.137.18/koleo/cli/__init__.py +9 -0
  12. koleo_cli-0.2.137.18/koleo/cli/aliases.py +15 -0
  13. koleo_cli-0.2.137.18/koleo/cli/base.py +103 -0
  14. koleo_cli-0.2.137.18/koleo/cli/connections.py +142 -0
  15. koleo_cli-0.2.137.18/koleo/cli/seats.py +103 -0
  16. koleo_cli-0.2.137.18/koleo/cli/station_board.py +72 -0
  17. koleo_cli-0.2.137.18/koleo/cli/stations.py +37 -0
  18. koleo_cli-0.2.137.18/koleo/cli/train_info.py +142 -0
  19. koleo_cli-0.2.137.18/koleo/cli/utils.py +27 -0
  20. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/koleo/storage.py +66 -12
  21. koleo_cli-0.2.137.18/koleo/utils.py +168 -0
  22. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18/koleo_cli.egg-info}/PKG-INFO +32 -13
  23. koleo_cli-0.2.137.18/koleo_cli.egg-info/SOURCES.txt +32 -0
  24. koleo_cli-0.2.137.18/koleo_cli.egg-info/entry_points.txt +2 -0
  25. koleo_cli-0.2.137.18/koleo_cli.egg-info/requires.txt +3 -0
  26. koleo_cli-0.2.137.18/requirements.txt +3 -0
  27. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/setup.py +2 -2
  28. koleo_cli-0.2.137.17/README.md +0 -52
  29. koleo_cli-0.2.137.17/koleo/api.py +0 -161
  30. koleo_cli-0.2.137.17/koleo/cli.py +0 -608
  31. koleo_cli-0.2.137.17/koleo/types.py +0 -237
  32. koleo_cli-0.2.137.17/koleo/utils.py +0 -81
  33. koleo_cli-0.2.137.17/koleo_cli.egg-info/SOURCES.txt +0 -19
  34. koleo_cli-0.2.137.17/koleo_cli.egg-info/entry_points.txt +0 -2
  35. koleo_cli-0.2.137.17/koleo_cli.egg-info/requires.txt +0 -2
  36. koleo_cli-0.2.137.17/requirements.txt +0 -2
  37. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/LICENSE +0 -0
  38. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/MANIFEST.in +0 -0
  39. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/koleo/__main__.py +0 -0
  40. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/koleo_cli.egg-info/dependency_links.txt +0 -0
  41. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/koleo_cli.egg-info/top_level.txt +0 -0
  42. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/pyproject.toml +0 -0
  43. {koleo_cli-0.2.137.17 → koleo_cli-0.2.137.18}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koleo-cli
3
- Version: 0.2.137.17
3
+ Version: 0.2.137.18
4
4
  Summary: Koleo CLI
5
5
  Home-page: https://github.com/lzgirlcat/koleo-cli
6
6
  Author: Zoey !
@@ -14,8 +14,9 @@ Classifier: Operating System :: OS Independent
14
14
  Requires-Python: >=3.12
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: rich~=13.7
18
- Requires-Dist: requests~=2.32
17
+ Requires-Dist: rich~=14.0.0
18
+ Requires-Dist: aiohttp~=3.12.13
19
+ Requires-Dist: orjson~=3.10.18
19
20
  Dynamic: author
20
21
  Dynamic: classifier
21
22
  Dynamic: description
@@ -46,39 +47,57 @@ Dynamic: summary
46
47
  - find a station or list all known stations
47
48
  - find a connection from station a to b, with filtering by operators
48
49
  - save a station as your favourite to quickly check it's departures
50
+ - add station aliases to query them more easily
51
+ - check seat allocation statistics
49
52
 
53
+ ### coming soon™️:
54
+ - TUI ticket purchase interface
55
+ - ticket display
56
+ - your previous tickets + stats
57
+ - find empty compartments
50
58
  additionally you can also use the KoleoAPI wrapper directly in your own projects, all returns are fully typed using `typing.TypedDict`
51
59
 
52
60
  ## MY(possibly controversial) design choices:
53
61
  - platforms and track numbers are shown using arabic numerals instead of roman
54
- - you can change it by adding `use_roman_numerals: true` to your config.json file
62
+ - you can change it by adding `use_roman_numerals: true` to your `koleo-cli.json` config file
55
63
  - most api queries are cached for 24h
56
- - you can change it by adding `disable_cache: true` to your config.json file
57
- - the cli.py code is really dirty but printing formatted data is hard :<
58
-
64
+ - you can change it by adding `disable_cache: true` to your `koleo-cli.json` config file
65
+ - stations/ls uses emojis by default
66
+ - you can disable them by adding `use_country_flags_emoji: false` and `use_country_flags_emoji: false` to your `koleo-cli.json` config file
59
67
  pull requests are welcome!!
60
68
 
61
69
  ```
62
- usage: koleo [-h] [-c CONFIG] [--nocolor] {departures,d,dep,odjazdy,o,arrivals,a,arr,przyjazdy,p,trainroute,r,tr,t,poc,pociąg,stations,s,find,f,stacje,ls,connections,do,z,szukaj,path} ...
70
+ usage: koleo [-h] [-c CONFIG] [--nocolor]
71
+ {departures,d,dep,odjazdy,o,arrivals,a,arr,przyjazdy,p,all,w,wszystkie,all_trains,pociagi,trainroute,r,tr,t,poc,pociąg,traincalendar,kursowanie,tc,k,traindetail,td,tid,id,idpoc,stations,s,find,f,stacje,ls,q,connections,do,z,szukaj,path,trainstats,ts,tp,miejsca,frekwencja,trainconnectionstats,tcs,aliases} ...
63
72
 
64
73
  Koleo CLI
65
74
 
66
75
  options:
67
76
  -h, --help show this help message and exit
68
- -c CONFIG, --config CONFIG
69
- Custom config path.
77
+ -c, --config CONFIG Custom config path.
70
78
  --nocolor Disable color output and formatting
71
79
 
72
80
  actions:
73
- {departures,d,dep,odjazdy,o,arrivals,a,arr,przyjazdy,p,trainroute,r,tr,t,poc,pociąg,stations,s,find,f,stacje,ls,connections,do,z,szukaj,path}
81
+ {departures,d,dep,odjazdy,o,arrivals,a,arr,przyjazdy,p,all,w,wszystkie,all_trains,pociagi,trainroute,r,tr,t,poc,pociąg,traincalendar,kursowanie,tc,k,traindetail,td,tid,id,idpoc,stations,s,find,f,stacje,ls,q,connections,do,z,szukaj,path,trainstats,ts,tp,miejsca,frekwencja,trainconnectionstats,tcs,aliases}
74
82
  departures (d, dep, odjazdy, o)
75
83
  Allows you to list station departures
76
84
  arrivals (a, arr, przyjazdy, p)
77
85
  Allows you to list station departures
86
+ all (w, wszystkie, all_trains, pociagi)
87
+ Allows you to list all station trains
78
88
  trainroute (r, tr, t, poc, pociąg)
79
- Allows you to show the train's route
80
- stations (s, find, f, stacje, ls)
89
+ Allows you to check the train's route
90
+ traincalendar (kursowanie, tc, k)
91
+ Allows you to check what days the train runs on
92
+ traindetail (td, tid, id, idpoc)
93
+ Allows you to show the train's route given it's koleo ID
94
+ stations (s, find, f, stacje, ls, q)
81
95
  Allows you to find stations by their name
82
96
  connections (do, z, szukaj, path)
83
97
  Allows you to search for connections from a to b
98
+ trainstats (ts, tp, miejsca, frekwencja)
99
+ Allows you to check seat allocation info for a train.
100
+ trainconnectionstats (tcs)
101
+ Allows you to check the seat allocations on the train connection given it's koleo ID
102
+ aliases Save quick aliases for station names!
84
103
  ```
@@ -0,0 +1,70 @@
1
+ # Koleo CLI
2
+ [![PyPI - Version](https://img.shields.io/pypi/v/koleo-cli.svg)](https://pypi.org/project/koleo-cli)
3
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/koleo-cli.svg)](https://pypi.org/project/koleo-cli)
4
+
5
+ ## Installation
6
+ **install via pip by running** `pip install koleo-cli`
7
+
8
+
9
+ ![gif showcasing the functionality](https://github.com/lzgirlcat/koleo-cli/blob/main/koleo-cli.gif?raw=true)
10
+
11
+ ## it currently allows you to:
12
+ - get departures/arrival list for a station
13
+ - get train info given its number and name(pull requests are welcome if you know how to get a train object by just the number)
14
+ - find a station or list all known stations
15
+ - find a connection from station a to b, with filtering by operators
16
+ - save a station as your favourite to quickly check it's departures
17
+ - add station aliases to query them more easily
18
+ - check seat allocation statistics
19
+
20
+ ### coming soon™️:
21
+ - TUI ticket purchase interface
22
+ - ticket display
23
+ - your previous tickets + stats
24
+ - find empty compartments
25
+ additionally you can also use the KoleoAPI wrapper directly in your own projects, all returns are fully typed using `typing.TypedDict`
26
+
27
+ ## MY(possibly controversial) design choices:
28
+ - platforms and track numbers are shown using arabic numerals instead of roman
29
+ - you can change it by adding `use_roman_numerals: true` to your `koleo-cli.json` config file
30
+ - most api queries are cached for 24h
31
+ - you can change it by adding `disable_cache: true` to your `koleo-cli.json` config file
32
+ - stations/ls uses emojis by default
33
+ - you can disable them by adding `use_country_flags_emoji: false` and `use_country_flags_emoji: false` to your `koleo-cli.json` config file
34
+ pull requests are welcome!!
35
+
36
+ ```
37
+ usage: koleo [-h] [-c CONFIG] [--nocolor]
38
+ {departures,d,dep,odjazdy,o,arrivals,a,arr,przyjazdy,p,all,w,wszystkie,all_trains,pociagi,trainroute,r,tr,t,poc,pociąg,traincalendar,kursowanie,tc,k,traindetail,td,tid,id,idpoc,stations,s,find,f,stacje,ls,q,connections,do,z,szukaj,path,trainstats,ts,tp,miejsca,frekwencja,trainconnectionstats,tcs,aliases} ...
39
+
40
+ Koleo CLI
41
+
42
+ options:
43
+ -h, --help show this help message and exit
44
+ -c, --config CONFIG Custom config path.
45
+ --nocolor Disable color output and formatting
46
+
47
+ actions:
48
+ {departures,d,dep,odjazdy,o,arrivals,a,arr,przyjazdy,p,all,w,wszystkie,all_trains,pociagi,trainroute,r,tr,t,poc,pociąg,traincalendar,kursowanie,tc,k,traindetail,td,tid,id,idpoc,stations,s,find,f,stacje,ls,q,connections,do,z,szukaj,path,trainstats,ts,tp,miejsca,frekwencja,trainconnectionstats,tcs,aliases}
49
+ departures (d, dep, odjazdy, o)
50
+ Allows you to list station departures
51
+ arrivals (a, arr, przyjazdy, p)
52
+ Allows you to list station departures
53
+ all (w, wszystkie, all_trains, pociagi)
54
+ Allows you to list all station trains
55
+ trainroute (r, tr, t, poc, pociąg)
56
+ Allows you to check the train's route
57
+ traincalendar (kursowanie, tc, k)
58
+ Allows you to check what days the train runs on
59
+ traindetail (td, tid, id, idpoc)
60
+ Allows you to show the train's route given it's koleo ID
61
+ stations (s, find, f, stacje, ls, q)
62
+ Allows you to find stations by their name
63
+ connections (do, z, szukaj, path)
64
+ Allows you to search for connections from a to b
65
+ trainstats (ts, tp, miejsca, frekwencja)
66
+ Allows you to check seat allocation info for a train.
67
+ trainconnectionstats (tcs)
68
+ Allows you to check the seat allocations on the train connection given it's koleo ID
69
+ aliases Save quick aliases for station names!
70
+ ```
@@ -1,2 +1,2 @@
1
1
  from .api import KoleoAPI
2
- from .types import *
2
+ from .api.types import *
@@ -0,0 +1,2 @@
1
+ from .client import KoleoAPI
2
+ from .types import *
@@ -0,0 +1,70 @@
1
+ from asyncio import sleep as asleep
2
+
3
+ from aiohttp import (
4
+ ClientConnectorError,
5
+ ClientOSError,
6
+ ClientResponse,
7
+ ClientResponseError,
8
+ ClientSession,
9
+ )
10
+ from orjson import loads
11
+
12
+ from .logging import LoggingMixin
13
+
14
+
15
+ class JsonableData(bytes):
16
+ response: ClientResponse
17
+
18
+ def __new__(cls, *args, response: ClientResponse, **kwargs):
19
+ obj = super().__new__(cls, *args, **kwargs)
20
+ obj.response = response
21
+ return obj
22
+
23
+ def json(self):
24
+ if "_json" not in self.__dict__:
25
+ self._json = loads(bytes(self))
26
+ return self._json
27
+
28
+
29
+ class BaseAPIClient(LoggingMixin):
30
+ _session: ClientSession
31
+
32
+ exc = ClientResponseError
33
+
34
+ @property
35
+ def session(self) -> "ClientSession":
36
+ if not hasattr(self, "_session"):
37
+ self._session = ClientSession()
38
+ return self._session
39
+
40
+ async def close(self):
41
+ return await self.session.close()
42
+
43
+ async def exc_getter(self, r: ClientResponse) -> Exception | None:
44
+ return
45
+
46
+ async def request(self, method, url: str, *args, retries: int = 4, fail_wait: float = 8, **kwargs) -> JsonableData:
47
+ try:
48
+ async with self.session.request(method, url, *args, **kwargs) as r:
49
+ if not r.ok:
50
+ self.dl(r.headers)
51
+ try:
52
+ self.dl(await r.text())
53
+ except UnicodeDecodeError:
54
+ self.dl("Response is not text!")
55
+ if exc := (await self.exc_getter(r)):
56
+ raise exc
57
+ r.raise_for_status()
58
+ return JsonableData(await r.read(), response=r)
59
+ except (ClientConnectorError, ClientOSError) as e:
60
+ if retries > 0:
61
+ await asleep(fail_wait)
62
+ return await self.request(
63
+ method,
64
+ url,
65
+ *args,
66
+ retries=retries - 1,
67
+ fail_wait=fail_wait,
68
+ **kwargs,
69
+ )
70
+ raise e
@@ -0,0 +1,221 @@
1
+ import typing as t
2
+ from datetime import datetime
3
+
4
+ from aiohttp import ClientResponse
5
+
6
+ from koleo.api.types import *
7
+
8
+ from .base import BaseAPIClient
9
+ from .errors import errors
10
+
11
+
12
+ class KoleoAPI(BaseAPIClient):
13
+ errors = errors
14
+
15
+ def __init__(self, auth: dict[str, str] | None = None) -> None:
16
+ self.base_url = "https://koleo.pl"
17
+ self.version = 2
18
+ self.base_headers = {
19
+ "x-koleo-version": str(self.version),
20
+ "User-Agent": "Koleo-CLI(https://pypi.org/project/koleo-cli)",
21
+ }
22
+ self._auth: dict[str, str] | None = auth
23
+ self._auth_valid: bool | None = None
24
+
25
+ async def get(self, path, use_auth: bool = False, *args, **kwargs):
26
+ headers = {**self.base_headers, **kwargs.pop("headers", {})}
27
+ if self._auth and use_auth:
28
+ headers["cookie"] = "; ".join([f"{k}={v}" for k, v in self._auth.items()])
29
+ r = await self.request("GET", self.base_url + path, headers=headers, *args, **kwargs)
30
+ if len(r) == 0:
31
+ raise self.errors.KoleoNotFound(r.response)
32
+ return r
33
+
34
+ async def post(self, path, use_auth: bool = False, *args, **kwargs):
35
+ headers = {**self.base_headers, **kwargs.pop("headers", {})}
36
+ if self._auth and use_auth:
37
+ headers["cookie"] = ("; ".join([f"{k}={v}" for k, v in self._auth.items()]),)
38
+ r = await self.request("POST", self.base_url + path, headers=headers, *args, **kwargs)
39
+ if len(r) == 0:
40
+ raise self.errors.KoleoNotFound(r.response)
41
+ return r
42
+
43
+ async def exc_getter(self, r: ClientResponse) -> Exception | None:
44
+ return await self.errors.from_response(r)
45
+
46
+ async def _require_auth(self) -> t.Literal[True]:
47
+ if self._auth is None:
48
+ raise errors.AuthRequired()
49
+ if self._auth_valid is None:
50
+ await self.get_current_session()
51
+ self._auth_valid = True
52
+ return True
53
+
54
+ async def get_stations(self) -> list[ExtendedStationInfo]:
55
+ return (await self.get("/api/v2/main/stations")).json()
56
+
57
+ async def find_station(self, query: str, language: str = "pl") -> list[SearchStationInfo]:
58
+ # https://koleo.pl/ls?q=tere&language=pl
59
+ return (await self.get("/ls", params={"q": query, "language": language})).json()["stations"]
60
+
61
+ async def get_station_by_id(self, id: int) -> ExtendedStationInfo:
62
+ # https://koleo.pl/api/v2/main/stations/by_id/24000
63
+ return (
64
+ await self.get(
65
+ f"/api/v2/main/stations/by_id/{id}",
66
+ )
67
+ ).json()
68
+
69
+ async def get_station_by_slug(self, slug: str) -> ExtendedStationInfo:
70
+ # https://koleo.pl/api/v2/main/stations/by_slug/inowroclaw
71
+ return (
72
+ await self.get(
73
+ f"/api/v2/main/stations/by_slug/{slug}",
74
+ )
75
+ ).json()
76
+
77
+ async def get_station_info_by_slug(self, slug: str) -> StationDetails:
78
+ # https://koleo.pl/api/v2/main/station_info/inowroclaw
79
+ return (
80
+ await self.get(
81
+ f"/api/v2/main/station_info/{slug}",
82
+ )
83
+ ).json()
84
+
85
+ async def get_departures(self, station_id: int, date: datetime) -> list[TrainOnStationInfo]:
86
+ # https://koleo.pl/api/v2/main/timetables/18705/2024-03-25/departures
87
+ return (
88
+ await self.get(
89
+ f"/api/v2/main/timetables/{station_id}/{date.strftime("%Y-%m-%d")}/departures",
90
+ )
91
+ ).json()
92
+
93
+ async def get_arrivals(self, station_id: int, date: datetime) -> list[TrainOnStationInfo]:
94
+ # https://koleo.pl/api/v2/main/timetables/18705/2024-03-25/arrivals
95
+ return (
96
+ await self.get(
97
+ f"/api/v2/main/timetables/{station_id}/{date.strftime("%Y-%m-%d")}/arrivals",
98
+ )
99
+ ).json()
100
+
101
+ async def get_train_calendars(self, brand_name: str, number: int, name: str | None = None) -> TrainCalendarResponse:
102
+ # https://koleo.pl/pl/train_calendars?brand=REG&nr=10417
103
+ # https://koleo.pl/pl/train_calendars?brand=IC&nr=1106&name=ESPERANTO ; WHY!!!! WHY!!!!!!1
104
+ params = {"brand": brand_name, "nr": number}
105
+ if name:
106
+ params["name"] = name.upper() # WHY!!!!!!!!!
107
+ return (await self.get("/pl/train_calendars", params=params)).json()
108
+
109
+ async def get_train(self, id: int) -> TrainDetailResponse:
110
+ # https://koleo.pl/pl/trains/142821312
111
+ return (await self.get(f"/pl/trains/{id}")).json()
112
+
113
+ async def get_connections(
114
+ self,
115
+ start: str,
116
+ end: str,
117
+ brand_ids: list[int],
118
+ date: datetime,
119
+ direct: bool = False,
120
+ purchasable: bool = False,
121
+ ) -> list[ConnectionDetail]:
122
+ params = {
123
+ "query[date]": date.strftime("%d-%m-%Y %H:%M:%S"),
124
+ "query[start_station]": start,
125
+ "query[end_station]": end,
126
+ "query[only_purchasable]": str(purchasable).lower(),
127
+ "query[only_direct]": str(direct).lower(),
128
+ "query[brand_ids][]": brand_ids,
129
+ }
130
+ return (await self.get("/api/v2/main/connections", params=params)).json()["connections"]
131
+
132
+ async def get_connection(self, id: int) -> ConnectionDetail:
133
+ return (
134
+ await self.get(
135
+ f"/api/v2/main/connections/{id}",
136
+ )
137
+ ).json()
138
+
139
+ async def get_brands(self) -> list[ApiBrand]:
140
+ # https://koleo.pl/api/v2/main/brands
141
+ return (
142
+ await self.get(
143
+ "/api/v2/main/brands",
144
+ )
145
+ ).json()
146
+
147
+ async def get_carriers(self) -> list[Carrier]:
148
+ # https://koleo.pl/api/v2/main/carriers
149
+ return (
150
+ await self.get(
151
+ "/api/v2/main/carriers",
152
+ )
153
+ ).json()
154
+
155
+ async def get_discounts(self) -> list[DiscountInfo]:
156
+ # https://koleo.pl/api/v2/main/discounts
157
+ return (
158
+ await self.get(
159
+ "/api/v2/main/discounts",
160
+ )
161
+ ).json()
162
+
163
+ async def get_nested_train_place_types(self, connection_id: int) -> SeatsAvailabilityResponse:
164
+ # https://koleo.pl/api/v2/main/seats_availability/connection_id/train_nr/place_type
165
+ await self._require_auth()
166
+ if self._auth and "_koleo_token" not in self._auth:
167
+ res = await self.post(f"/prices/{connection_id}/passengers")
168
+ self._auth["_koleo_token"] = koleo_token = res.response.cookies["_koleo_token"].value
169
+ return (
170
+ await self.get(
171
+ f"/api/v2/main/nested_train_place_types/{connection_id}",
172
+ headers={"Authorization": f"Bearer {koleo_token}"},
173
+ use_auth=True,
174
+ )
175
+ ).json()
176
+
177
+ async def get_seats_availability(
178
+ self, connection_id: int, train_nr: int, place_type: int
179
+ ) -> SeatsAvailabilityResponse:
180
+ # https://koleo.pl/api/v2/main/seats_availability/connection_id/train_nr/place_type
181
+ return (
182
+ await self.get(
183
+ f"/api/v2/main/seats_availability/{connection_id}/{train_nr}/{place_type}",
184
+ )
185
+ ).json()
186
+
187
+ async def get_train_composition(
188
+ self, connection_id: int, train_nr: int, place_type: int
189
+ ) -> SeatsAvailabilityResponse:
190
+ # https://koleo.pl/api/v2/main/train_composition/connection_id/train_nr/place_type
191
+ return (
192
+ await self.get(
193
+ f"/api/v2/main/train_composition/{connection_id}/{train_nr}/{place_type}",
194
+ )
195
+ ).json()
196
+
197
+ async def get_carriage_type(self, id: int) -> CarriageType:
198
+ # https://koleo.pl/api/v2/main/carriage_types/id
199
+ return (
200
+ await self.get(
201
+ f"/api/v2/main/carriage_types/{id}",
202
+ )
203
+ ).json()
204
+
205
+ async def get_carriage_types(self) -> list[CarriageType]:
206
+ return (await self.get("/api/v2/main/carriage_types")).json()
207
+
208
+ async def get_station_keywoards(self) -> list[StationKeyword]:
209
+ return (await self.get("/api/v2/main/station_keywords")).json()
210
+
211
+ async def get_price(self, connection_id: int) -> Price | None:
212
+ res = await self.get(
213
+ f"/pl/prices/{connection_id}",
214
+ )
215
+ return res.json().get("price")
216
+
217
+ async def get_current_session(self) -> CurrentSession:
218
+ return (await self.get(f"/sessions/current", use_auth=True)).json()
219
+
220
+ async def get_current_user(self) -> CurrentUser:
221
+ return (await self.get(f"/users/current", use_auth=True)).json()
@@ -0,0 +1,46 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+
4
+ if TYPE_CHECKING:
5
+ from aiohttp import ClientResponse, RequestInfo
6
+
7
+
8
+ class errors:
9
+ class KoleoAPIException(Exception):
10
+ status: int
11
+ request: "RequestInfo"
12
+ response: "ClientResponse"
13
+
14
+ def __init__(self, response: "ClientResponse", *args: object) -> None:
15
+ super().__init__(*args)
16
+ self.status = response.status
17
+ self.request = response.request_info
18
+ self.response = response
19
+
20
+ @staticmethod
21
+ async def from_response(response: "ClientResponse") -> "KoleoAPIException":
22
+ if response.status == 404:
23
+ return errors.KoleoNotFound(response)
24
+ elif response.status == 401:
25
+ return errors.KoleoUnauthorized(response)
26
+ elif response.status == 403:
27
+ return errors.KoleoForbidden(response)
28
+ elif response.status == 429:
29
+ return errors.KoleoRatelimited(response)
30
+ else:
31
+ return errors.KoleoAPIException(response, await response.text())
32
+
33
+ class KoleoNotFound(KoleoAPIException):
34
+ pass
35
+
36
+ class KoleoForbidden(KoleoAPIException):
37
+ pass
38
+
39
+ class KoleoUnauthorized(KoleoAPIException):
40
+ pass
41
+
42
+ class KoleoRatelimited(KoleoAPIException):
43
+ pass
44
+
45
+ class AuthRequired(Exception):
46
+ pass
@@ -0,0 +1,56 @@
1
+ import logging
2
+
3
+
4
+ class LoggingMixin:
5
+ _l: logging.Logger
6
+ _l_name: str | None = None
7
+
8
+ def __init__(self, name: str | None = None) -> None:
9
+ if name:
10
+ self._l_name = name
11
+
12
+ @property
13
+ def logger(self) -> logging.Logger:
14
+ if not getattr(self, "_l", None):
15
+ self._l = logging.getLogger(self.logger_name)
16
+ return self._l
17
+
18
+ @property
19
+ def logger_name(self) -> str:
20
+ return getattr(self, "_l_name", None) or self.__class__.__name__.lower()
21
+
22
+ def dl(self, msg, *args, **kwargs):
23
+ self.logger.debug(msg, *args, **kwargs)
24
+
25
+ def error(self, msg, *args, **kwargs):
26
+ self.logger.error(msg, *args, **kwargs)
27
+
28
+ def warn(self, msg, *args, **kwargs):
29
+ self.logger.warning(msg, *args, **kwargs)
30
+
31
+ def info(self, msg, *args, **kwargs):
32
+ self.logger.info(msg, *args, **kwargs)
33
+
34
+ def create_logging_context(self, prefix: str) -> "ContextLogger":
35
+ return ContextLogger(self.logger, prefix)
36
+
37
+
38
+ class ContextLogger:
39
+ def __init__(self, logger: logging.Logger, prefix: str) -> None:
40
+ self.logger = logger
41
+ self.prefix = prefix
42
+
43
+ def _make_msg(self, msg: str):
44
+ return f"{self.prefix}: {msg}"
45
+
46
+ def dl(self, msg, *args, **kwargs):
47
+ self.logger.debug(self._make_msg(msg), *args, **kwargs)
48
+
49
+ def info(self, msg, *args, **kwargs):
50
+ self.logger.info(self._make_msg(msg), *args, **kwargs)
51
+
52
+ def error(self, msg, *args, **kwargs):
53
+ self.logger.error(self._make_msg(msg), *args, **kwargs)
54
+
55
+ def warn(self, msg, *args, **kwargs):
56
+ self.logger.warning(self._make_msg(msg), *args, **kwargs)