infinitode.py 1.2.0__tar.gz → 1.3.0__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 (36) hide show
  1. {infinitode_py-1.2.0/infinitode.py.egg-info → infinitode_py-1.3.0}/PKG-INFO +46 -1
  2. infinitode_py-1.2.0/PKG-INFO → infinitode_py-1.3.0/README.md +289 -265
  3. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/__init__.py +41 -39
  4. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/core.py +668 -634
  5. infinitode_py-1.3.0/infinitode/daily_quest.py +27 -0
  6. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/errors.py +39 -39
  7. infinitode_py-1.3.0/infinitode/stats/__init__.py +9 -0
  8. infinitode_py-1.3.0/infinitode/stats/_parsers/__init__.py +1 -0
  9. infinitode_py-1.3.0/infinitode/stats/_parsers/common.py +303 -0
  10. infinitode_py-1.3.0/infinitode/stats/_parsers/index.py +56 -0
  11. infinitode_py-1.3.0/infinitode/stats/_parsers/replay.py +49 -0
  12. infinitode_py-1.3.0/infinitode/stats/_parsers/statistics.py +119 -0
  13. infinitode_py-1.3.0/infinitode/stats/_parsers/summary.py +30 -0
  14. infinitode_py-1.3.0/infinitode/stats/_parsers/timelines.py +146 -0
  15. infinitode_py-1.3.0/infinitode/stats/client.py +93 -0
  16. infinitode_py-1.3.0/infinitode/stats/keys.py +101 -0
  17. infinitode_py-1.3.0/infinitode/stats/models/__init__.py +53 -0
  18. infinitode_py-1.3.0/infinitode/stats/models/common.py +104 -0
  19. infinitode_py-1.3.0/infinitode/stats/models/reports.py +163 -0
  20. infinitode_py-1.3.0/infinitode/stats/query.py +50 -0
  21. infinitode_py-1.3.0/infinitode/stats/views.py +232 -0
  22. infinitode_py-1.2.0/README.md → infinitode_py-1.3.0/infinitode.py.egg-info/PKG-INFO +64 -0
  23. infinitode_py-1.3.0/infinitode.py.egg-info/SOURCES.txt +32 -0
  24. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/setup.py +27 -26
  25. infinitode_py-1.2.0/infinitode.py.egg-info/SOURCES.txt +0 -17
  26. infinitode_py-1.2.0/tests/test_core.py +0 -235
  27. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/badge.py +0 -0
  28. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/leaderboard.py +0 -0
  29. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/player.py +0 -0
  30. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/py.typed +0 -0
  31. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/score.py +0 -0
  32. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode/utils.py +0 -0
  33. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode.py.egg-info/dependency_links.txt +0 -0
  34. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode.py.egg-info/requires.txt +0 -0
  35. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/infinitode.py.egg-info/top_level.txt +0 -0
  36. {infinitode_py-1.2.0 → infinitode_py-1.3.0}/setup.cfg +0 -0
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: infinitode.py
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: A python wrapper for the Infinitode 2 API.
5
5
  Home-page: https://github.com/Sprylos/infinitode.py
6
6
  Author: Sprylos
7
7
  License: MIT
8
+ Requires-Python: >=3.10
8
9
  Description-Content-Type: text/markdown
9
10
  Requires-Dist: aiohttp
10
11
  Requires-Dist: lxml
@@ -15,6 +16,7 @@ Dynamic: description-content-type
15
16
  Dynamic: home-page
16
17
  Dynamic: license
17
18
  Dynamic: requires-dist
19
+ Dynamic: requires-python
18
20
  Dynamic: summary
19
21
 
20
22
  # Infinitode.py
@@ -126,6 +128,15 @@ Retrieve the top 200 players of today's daily quest or a specified date.
126
128
  dq_leaderboard = await API.daily_quest_leaderboards("2024-12-05")
127
129
  ```
128
130
 
131
+ Retrieve metadata for the currently active Daily Quest. The reset timestamp is
132
+ also available as `reset_timestamp`, and `mapname` is derived from `quest_id`.
133
+
134
+ ```python
135
+ dq = await API.daily_quest_info()
136
+ print(dq.date, dq.quest_id, dq.mapname)
137
+ print(dq.end_timestamp, dq.reset_timestamp, dq.data_hash)
138
+ ```
139
+
129
140
  ---
130
141
 
131
142
  ### Working with Leaderboards
@@ -227,6 +238,40 @@ updated.
227
238
 
228
239
  ---
229
240
 
241
+ ### Replay statistics
242
+
243
+ `infinitode.stats` provides an independent async client for the public stats
244
+ website. Python 3.10 or later is required.
245
+
246
+ ```python
247
+ from infinitode.stats import StatsClient, ReplayQuery
248
+
249
+ async def inspect_stats():
250
+ async with StatsClient() as stats:
251
+ query = ReplayQuery(report_count=10, game_modes=("BASIC_LEVELS",))
252
+ browser = await stats.replays(query)
253
+ print(browser.available_filters.maps)
254
+
255
+ aggregate = await stats.summary(query)
256
+ print(aggregate.statistics.general.towers_built)
257
+
258
+ replay = await stats.replay("R-RLX6-YSQL-LGNNCV")
259
+ print(replay.info.mapname, replay.overview.duration)
260
+ print(replay.statistics.towers.tower("GAUSS").damage)
261
+ print(replay.statistics.resources.resource("SCALAR").gained)
262
+
263
+ score = replay.statistics.score_sources
264
+ if score is not None:
265
+ for entry in score.entries:
266
+ print(entry.entity.key, entry.value, entry.share)
267
+ for timeline in score.timelines or ():
268
+ for point in timeline.points:
269
+ print(timeline.entity.key, point.elapsed, point.value)
270
+
271
+ for issue in replay.metadata.issues:
272
+ print(issue.code, issue.section, issue.entity_key, issue.sample_index)
273
+ ```
274
+
230
275
  ### Beta Scores
231
276
 
232
277
  Almost all API calls support an additional `beta` boolean parameter. This will make a request to the beta servers instead. No guarantees for it working.
@@ -1,265 +1,289 @@
1
- Metadata-Version: 2.4
2
- Name: infinitode.py
3
- Version: 1.2.0
4
- Summary: A python wrapper for the Infinitode 2 API.
5
- Home-page: https://github.com/Sprylos/infinitode.py
6
- Author: Sprylos
7
- License: MIT
8
- Description-Content-Type: text/markdown
9
- Requires-Dist: aiohttp
10
- Requires-Dist: lxml
11
- Requires-Dist: bs4
12
- Dynamic: author
13
- Dynamic: description
14
- Dynamic: description-content-type
15
- Dynamic: home-page
16
- Dynamic: license
17
- Dynamic: requires-dist
18
- Dynamic: summary
19
-
20
- # Infinitode.py
21
-
22
- An asynchronous Python wrapper for the Infinitode-2 API using `async`-`await` syntax.
23
-
24
- ---
25
-
26
- ## Installation
27
-
28
- Install the library via pip:
29
-
30
- ```bash
31
- pip install infinitode.py
32
- ```
33
-
34
- ---
35
-
36
- ## Showcase
37
-
38
- ### Setting Up a Session
39
-
40
- Create a session to communicate with Rainy's API. Use the `with` statement to ensure the session closes properly.
41
- Alternatively you can can simply call `Session.close()` once you don't need it anymore.
42
-
43
- ```python
44
- import asyncio
45
- import infinitode
46
-
47
- async def main():
48
- async with infinitode.Session() as API:
49
- # Your API calls go here
50
- pass
51
-
52
- asyncio.run(main())
53
- ```
54
-
55
- ---
56
-
57
- ### Fetching Leaderboard Data
58
-
59
- Parameters:
60
- - `mapname`: The map identifier (e.g., "5.1" or "4.b1" or "zecred").
61
- - `playerid` (sometimes optional): The player's unique identifier.
62
- - `mode` (optional): One of `'score'`, `'waves'`. Defaults to `'score'`.
63
- - `difficulty` (optional): One of `'EASY'`, `'NORMAL'`, `'ENDLESS_I'`. Defaults to `'NORMAL'`.
64
-
65
- The immutable `infinitode.SUPPORTED_MAPS`, `infinitode.SUPPORTED_MODES`, and
66
- `infinitode.SUPPORTED_DIFFICULTIES` tuples contain the values accepted by the
67
- current library. `infinitode.GAME_API_VERSION` exposes the game API version used
68
- for JSON API calls.
69
-
70
- #### Player Score on a Specific Map
71
-
72
- Retrieve the score of a specific player on a particular map.
73
-
74
- ```python
75
- score_5_1 = await API.leaderboards_rank(
76
- mapname="5.1",
77
- playerid="U-E9BP-FSN9-H6ENMQ",
78
- mode="score",
79
- difficulty="NORMAL"
80
- )
81
- ```
82
-
83
- #### Top 200 Leaderboard on a Specific Map
84
-
85
- Retrieve the leaderboard of the top 200 wave scores on 5.1.
86
-
87
- ```python
88
- leaderboard_5_1 = await API.leaderboards(
89
- mapname=5.1,
90
- mode="waves"
91
- )
92
- ```
93
-
94
- #### Runtime Leaderboard
95
-
96
- Fetch the leaderboard displayed during gameplay. This provides additional percentile information.
97
-
98
- ```python
99
- runtime_5_1 = await API.runtime_leaderboards(
100
- mapname=5.1,
101
- playerid="U-E9BP-FSN9-H6ENMQ",
102
- difficulty="ENDLESS_I"
103
- )
104
- ```
105
-
106
- ---
107
-
108
- #### Skill Point Leaderboard
109
-
110
- Get the top 3 skill point owners. Optionally specify a `playerid`.
111
-
112
- ```python
113
- sp_leaderboard = await API.skill_point_leaderboard(
114
- playerid="U-E9BP-FSN9-H6ENMQ"
115
- )
116
- ```
117
-
118
-
119
- #### Daily Quest Leaderboard
120
-
121
- Retrieve the top 200 players of today's daily quest or a specified date.
122
-
123
- - `date`: `YYYY-MM-DD` (string) or `datetime.datetime`.
124
-
125
- ```python
126
- dq_leaderboard = await API.daily_quest_leaderboards("2024-12-05")
127
- ```
128
-
129
- ---
130
-
131
- ### Working with Leaderboards
132
-
133
- A leaderboard is a sequence of scores with additional utility functions.
134
-
135
- #### Access Score and Leaderboard Attributes
136
-
137
- Leaderboards always have these attributes:
138
- - `mapname`, `mode`, `difficulty`, `total`
139
-
140
- And optionally these:
141
- - `date`, `season`, `player` (will return a score object)
142
-
143
- Scores always have these attributes:
144
- - `playerid`, `rank`, `score`, `mapname`, `mode`, `difficulty`
145
-
146
- And optionally these:
147
- - `has_pfp`, `level`, `nickname`, `pinned_badge`, `position`, `top`, `total`, `player` (will return a Player object if fetched beforehand)
148
-
149
- #### Example for printing attributes, scores, and leaderboards
150
-
151
- ```python
152
- for score in leaderboard_5_1:
153
- print(score.nickname)
154
- score.print_score() # Helper method
155
-
156
- leaderboard_5_1.print_scores()
157
- ```
158
-
159
- #### Slice a Leaderboard
160
-
161
- Retrieve a subset of the leaderboard:
162
-
163
- ```python
164
- top_1 = leaderboard_5_1[0]
165
- top_10 = leaderboard_5_1[0:10]
166
- print(len(top_10))
167
- ```
168
-
169
- ---
170
-
171
- ### Player Information
172
-
173
- #### Fetch Player Data
174
-
175
- Retrieve detailed player information.
176
-
177
- ```python
178
- player = await API.player(playerid="U-E9BP-FSN9-H6ENMQ")
179
- # Or look up a case-insensitive, exact nickname:
180
- player = await API.player(nickname="EuphoRowan")
181
- ```
182
-
183
- Attributes include:
184
- - `playerid`, `nickname`, `level`, `xp`, `season_level`, `total_score`, and many more.
185
-
186
- #### Get Player Scores
187
-
188
- Use the `score` method to access specific map scores.
189
-
190
- ```python
191
- player.score(5.1).print_score()
192
- ```
193
-
194
- #### Fetch Daily Quest and Skill Point Scores
195
-
196
- Use additional API calls to retrieve daily quest and skill point scores:
197
-
198
- ```python
199
- await player.fetch_daily_quest(API)
200
- await player.fetch_skill_point(API)
201
-
202
- print(player.daily_quest.rank, player.skill_point.score)
203
- ```
204
-
205
- An invalid argument raises `infinitode.errors.BadArgument`, and an exact lookup
206
- with no matching player raises its `PlayerNotFound` subclass. HTTP and JSON API
207
- failures raise `APIError`; unexpected changes to parsed HTML raise `ParseError`.
208
-
209
- ---
210
-
211
- ### Experimental features
212
-
213
- `Session.search_players()` performs an unauthenticated, case-insensitive
214
- substring search of player nicknames:
215
-
216
- ```python
217
- players = await API.search_players("eupho", limit=20)
218
- for result in players:
219
- print(result.playerid, result.nickname, result.level, result.has_avatar)
220
- ```
221
-
222
- Each `PlayerSummary` contains only the verified `playerid`, `nickname`, `level`,
223
- and `has_avatar` fields. The upstream page returns at most 100 results and does
224
- not offer pagination. This feature parses an HTML page rather than a stable JSON
225
- API, so upstream markup changes may cause `ParseError` until the parser is
226
- updated.
227
-
228
- ---
229
-
230
- ### Beta Scores
231
-
232
- Almost all API calls support an additional `beta` boolean parameter. This will make a request to the beta servers instead. No guarantees for it working.
233
-
234
- ```python
235
- leaderboard_5_1 = await API.leaderboards(mapname=5.1, mode='waves', beta=True)
236
- ```
237
-
238
-
239
- ### Logging
240
-
241
- Set up logging to monitor requests and responses.
242
-
243
- - `INFO`: Logs every request.
244
- - `DEBUG`: Logs server responses.
245
-
246
- ```python
247
- import infinitode
248
- import asyncio
249
- import logging
250
-
251
- logging.basicConfig(level=logging.INFO)
252
-
253
- async def main():
254
- async with infinitode.Session() as API:
255
- await API.leaderboards("6.3")
256
-
257
- asyncio.run(main())
258
- ```
259
-
260
- ---
261
-
262
- ### Notes
263
-
264
- - Some data (e.g., seasonal leaderboard, players) require additional parsing and will take longer to process.
265
- - Do not abuse this API wrapper for any kind of malicious action.
1
+ # Infinitode.py
2
+
3
+ An asynchronous Python wrapper for the Infinitode-2 API using `async`-`await` syntax.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ Install the library via pip:
10
+
11
+ ```bash
12
+ pip install infinitode.py
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Showcase
18
+
19
+ ### Setting Up a Session
20
+
21
+ Create a session to communicate with Rainy's API. Use the `with` statement to ensure the session closes properly.
22
+ Alternatively you can can simply call `Session.close()` once you don't need it anymore.
23
+
24
+ ```python
25
+ import asyncio
26
+ import infinitode
27
+
28
+ async def main():
29
+ async with infinitode.Session() as API:
30
+ # Your API calls go here
31
+ pass
32
+
33
+ asyncio.run(main())
34
+ ```
35
+
36
+ ---
37
+
38
+ ### Fetching Leaderboard Data
39
+
40
+ Parameters:
41
+ - `mapname`: The map identifier (e.g., "5.1" or "4.b1" or "zecred").
42
+ - `playerid` (sometimes optional): The player's unique identifier.
43
+ - `mode` (optional): One of `'score'`, `'waves'`. Defaults to `'score'`.
44
+ - `difficulty` (optional): One of `'EASY'`, `'NORMAL'`, `'ENDLESS_I'`. Defaults to `'NORMAL'`.
45
+
46
+ The immutable `infinitode.SUPPORTED_MAPS`, `infinitode.SUPPORTED_MODES`, and
47
+ `infinitode.SUPPORTED_DIFFICULTIES` tuples contain the values accepted by the
48
+ current library. `infinitode.GAME_API_VERSION` exposes the game API version used
49
+ for JSON API calls.
50
+
51
+ #### Player Score on a Specific Map
52
+
53
+ Retrieve the score of a specific player on a particular map.
54
+
55
+ ```python
56
+ score_5_1 = await API.leaderboards_rank(
57
+ mapname="5.1",
58
+ playerid="U-E9BP-FSN9-H6ENMQ",
59
+ mode="score",
60
+ difficulty="NORMAL"
61
+ )
62
+ ```
63
+
64
+ #### Top 200 Leaderboard on a Specific Map
65
+
66
+ Retrieve the leaderboard of the top 200 wave scores on 5.1.
67
+
68
+ ```python
69
+ leaderboard_5_1 = await API.leaderboards(
70
+ mapname=5.1,
71
+ mode="waves"
72
+ )
73
+ ```
74
+
75
+ #### Runtime Leaderboard
76
+
77
+ Fetch the leaderboard displayed during gameplay. This provides additional percentile information.
78
+
79
+ ```python
80
+ runtime_5_1 = await API.runtime_leaderboards(
81
+ mapname=5.1,
82
+ playerid="U-E9BP-FSN9-H6ENMQ",
83
+ difficulty="ENDLESS_I"
84
+ )
85
+ ```
86
+
87
+ ---
88
+
89
+ #### Skill Point Leaderboard
90
+
91
+ Get the top 3 skill point owners. Optionally specify a `playerid`.
92
+
93
+ ```python
94
+ sp_leaderboard = await API.skill_point_leaderboard(
95
+ playerid="U-E9BP-FSN9-H6ENMQ"
96
+ )
97
+ ```
98
+
99
+
100
+ #### Daily Quest Leaderboard
101
+
102
+ Retrieve the top 200 players of today's daily quest or a specified date.
103
+
104
+ - `date`: `YYYY-MM-DD` (string) or `datetime.datetime`.
105
+
106
+ ```python
107
+ dq_leaderboard = await API.daily_quest_leaderboards("2024-12-05")
108
+ ```
109
+
110
+ Retrieve metadata for the currently active Daily Quest. The reset timestamp is
111
+ also available as `reset_timestamp`, and `mapname` is derived from `quest_id`.
112
+
113
+ ```python
114
+ dq = await API.daily_quest_info()
115
+ print(dq.date, dq.quest_id, dq.mapname)
116
+ print(dq.end_timestamp, dq.reset_timestamp, dq.data_hash)
117
+ ```
118
+
119
+ ---
120
+
121
+ ### Working with Leaderboards
122
+
123
+ A leaderboard is a sequence of scores with additional utility functions.
124
+
125
+ #### Access Score and Leaderboard Attributes
126
+
127
+ Leaderboards always have these attributes:
128
+ - `mapname`, `mode`, `difficulty`, `total`
129
+
130
+ And optionally these:
131
+ - `date`, `season`, `player` (will return a score object)
132
+
133
+ Scores always have these attributes:
134
+ - `playerid`, `rank`, `score`, `mapname`, `mode`, `difficulty`
135
+
136
+ And optionally these:
137
+ - `has_pfp`, `level`, `nickname`, `pinned_badge`, `position`, `top`, `total`, `player` (will return a Player object if fetched beforehand)
138
+
139
+ #### Example for printing attributes, scores, and leaderboards
140
+
141
+ ```python
142
+ for score in leaderboard_5_1:
143
+ print(score.nickname)
144
+ score.print_score() # Helper method
145
+
146
+ leaderboard_5_1.print_scores()
147
+ ```
148
+
149
+ #### Slice a Leaderboard
150
+
151
+ Retrieve a subset of the leaderboard:
152
+
153
+ ```python
154
+ top_1 = leaderboard_5_1[0]
155
+ top_10 = leaderboard_5_1[0:10]
156
+ print(len(top_10))
157
+ ```
158
+
159
+ ---
160
+
161
+ ### Player Information
162
+
163
+ #### Fetch Player Data
164
+
165
+ Retrieve detailed player information.
166
+
167
+ ```python
168
+ player = await API.player(playerid="U-E9BP-FSN9-H6ENMQ")
169
+ # Or look up a case-insensitive, exact nickname:
170
+ player = await API.player(nickname="EuphoRowan")
171
+ ```
172
+
173
+ Attributes include:
174
+ - `playerid`, `nickname`, `level`, `xp`, `season_level`, `total_score`, and many more.
175
+
176
+ #### Get Player Scores
177
+
178
+ Use the `score` method to access specific map scores.
179
+
180
+ ```python
181
+ player.score(5.1).print_score()
182
+ ```
183
+
184
+ #### Fetch Daily Quest and Skill Point Scores
185
+
186
+ Use additional API calls to retrieve daily quest and skill point scores:
187
+
188
+ ```python
189
+ await player.fetch_daily_quest(API)
190
+ await player.fetch_skill_point(API)
191
+
192
+ print(player.daily_quest.rank, player.skill_point.score)
193
+ ```
194
+
195
+ An invalid argument raises `infinitode.errors.BadArgument`, and an exact lookup
196
+ with no matching player raises its `PlayerNotFound` subclass. HTTP and JSON API
197
+ failures raise `APIError`; unexpected changes to parsed HTML raise `ParseError`.
198
+
199
+ ---
200
+
201
+ ### Experimental features
202
+
203
+ `Session.search_players()` performs an unauthenticated, case-insensitive
204
+ substring search of player nicknames:
205
+
206
+ ```python
207
+ players = await API.search_players("eupho", limit=20)
208
+ for result in players:
209
+ print(result.playerid, result.nickname, result.level, result.has_avatar)
210
+ ```
211
+
212
+ Each `PlayerSummary` contains only the verified `playerid`, `nickname`, `level`,
213
+ and `has_avatar` fields. The upstream page returns at most 100 results and does
214
+ not offer pagination. This feature parses an HTML page rather than a stable JSON
215
+ API, so upstream markup changes may cause `ParseError` until the parser is
216
+ updated.
217
+
218
+ ---
219
+
220
+ ### Replay statistics
221
+
222
+ `infinitode.stats` provides an independent async client for the public stats
223
+ website. Python 3.10 or later is required.
224
+
225
+ ```python
226
+ from infinitode.stats import StatsClient, ReplayQuery
227
+
228
+ async def inspect_stats():
229
+ async with StatsClient() as stats:
230
+ query = ReplayQuery(report_count=10, game_modes=("BASIC_LEVELS",))
231
+ browser = await stats.replays(query)
232
+ print(browser.available_filters.maps)
233
+
234
+ aggregate = await stats.summary(query)
235
+ print(aggregate.statistics.general.towers_built)
236
+
237
+ replay = await stats.replay("R-RLX6-YSQL-LGNNCV")
238
+ print(replay.info.mapname, replay.overview.duration)
239
+ print(replay.statistics.towers.tower("GAUSS").damage)
240
+ print(replay.statistics.resources.resource("SCALAR").gained)
241
+
242
+ score = replay.statistics.score_sources
243
+ if score is not None:
244
+ for entry in score.entries:
245
+ print(entry.entity.key, entry.value, entry.share)
246
+ for timeline in score.timelines or ():
247
+ for point in timeline.points:
248
+ print(timeline.entity.key, point.elapsed, point.value)
249
+
250
+ for issue in replay.metadata.issues:
251
+ print(issue.code, issue.section, issue.entity_key, issue.sample_index)
252
+ ```
253
+
254
+ ### Beta Scores
255
+
256
+ Almost all API calls support an additional `beta` boolean parameter. This will make a request to the beta servers instead. No guarantees for it working.
257
+
258
+ ```python
259
+ leaderboard_5_1 = await API.leaderboards(mapname=5.1, mode='waves', beta=True)
260
+ ```
261
+
262
+
263
+ ### Logging
264
+
265
+ Set up logging to monitor requests and responses.
266
+
267
+ - `INFO`: Logs every request.
268
+ - `DEBUG`: Logs server responses.
269
+
270
+ ```python
271
+ import infinitode
272
+ import asyncio
273
+ import logging
274
+
275
+ logging.basicConfig(level=logging.INFO)
276
+
277
+ async def main():
278
+ async with infinitode.Session() as API:
279
+ await API.leaderboards("6.3")
280
+
281
+ asyncio.run(main())
282
+ ```
283
+
284
+ ---
285
+
286
+ ### Notes
287
+
288
+ - Some data (e.g., seasonal leaderboard, players) require additional parsing and will take longer to process.
289
+ - Do not abuse this API wrapper for any kind of malicious action.