copsapi-wrapper 1.1.0__tar.gz → 1.1.1__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 (23) hide show
  1. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/CHANGELOG.md +5 -0
  2. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/PKG-INFO +29 -18
  3. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/README.md +28 -17
  4. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/pyproject.toml +1 -1
  5. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/_async_client.py +632 -630
  6. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/_core.py +14 -5
  7. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/_sync_client.py +5 -3
  8. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/cli.py +242 -242
  9. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/helpers.py +175 -175
  10. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/models.py +365 -365
  11. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/.gitignore +0 -0
  12. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/LICENSE +0 -0
  13. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/__init__.py +0 -0
  14. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/__main__.py +0 -0
  15. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/_io_async.py +0 -0
  16. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/_io_sync.py +0 -0
  17. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/cache.py +0 -0
  18. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/catalog.py +0 -0
  19. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/enums.py +0 -0
  20. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/errors.py +0 -0
  21. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/py.typed +0 -0
  22. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/quota.py +0 -0
  23. {copsapi_wrapper-1.1.0 → copsapi_wrapper-1.1.1}/src/copsapi/watcher.py +0 -0
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.1
4
+
5
+ - On Python 3.10, constants such as `GameType.CASUAL` passed to client methods are now sent to the API as their plain values (`2`), not as their names.
6
+ - The README and examples use the named constants throughout.
7
+
3
8
  ## 1.1.0
4
9
 
5
10
  - Named constants for every code the API uses, such as `BanReason.HACKING`, `UserType.MODERATOR`, `MapId.CASTELLO`, `GameModeId.TOURNAMENT_MODE`, `LeaderboardType.KILLS` and `AutohostCommand.KICK`. Number codes are `IntEnum`s and text codes are `str` enums, so both compare equal to the plain values in the models.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: copsapi-wrapper
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: Typed, quota-aware Python client for the Critical Ops Public API v2, sync and async: profiles, leaderboards, match history, weapon stats, server status and Autohost with a live room watcher.
5
5
  Project-URL: Homepage, https://github.com/Matchmaking-Live/copsapi-wrapper-python
6
6
  Project-URL: Repository, https://github.com/Matchmaking-Live/copsapi-wrapper-python
@@ -95,7 +95,7 @@ What a token can do depends on its permissions:
95
95
  | Endpoints | Needs |
96
96
  | --- | --- |
97
97
  | Profiles, servers, match history, weapon stats, leaderboards | Any valid token |
98
- | Autohost (`create`, `poll`, `control`, `host`, the watcher) | A token with the `Autohost` permission |
98
+ | Autohost (`create`, `poll`, `control`, `host`, the watcher) | A token with the `Autohost` permission (Developer Issued) |
99
99
 
100
100
  There are three ways to pass the token:
101
101
 
@@ -129,14 +129,14 @@ If your token lacks `Autohost`, hosting calls raise `PermissionDeniedError` with
129
129
  ## Sync and async
130
130
 
131
131
  ```python
132
- from copsapi import CopsClient, AsyncCopsClient
132
+ from copsapi import CopsClient, AsyncCopsClient, LeaderboardType
133
133
 
134
134
  with CopsClient() as cops:
135
135
  servers = cops.servers.online()
136
136
 
137
137
  async with AsyncCopsClient() as cops:
138
138
  servers = await cops.servers.online()
139
- async for entry in cops.leaderboards.iterate("kills", max_pages=3):
139
+ async for entry in cops.leaderboards.iterate(LeaderboardType.KILLS, max_pages=3):
140
140
  print(entry.position, entry.basic_info.name)
141
141
  ```
142
142
 
@@ -212,9 +212,11 @@ server = cops.servers.pick(region="EU")
212
212
  ## Match history
213
213
 
214
214
  ```python
215
+ from copsapi import GameType
216
+
215
217
  history = cops.matches.history(user_id)
216
218
  match = cops.matches.one(history[0].id)
217
- recent = cops.matches.recent(user_id, limit=5, game_type="ranked")
219
+ recent = cops.matches.recent(user_id, limit=5, game_type=GameType.RANKED)
218
220
  ```
219
221
 
220
222
  - `history` returns the player's recent matches, newest first. The history resets with each game update.
@@ -224,26 +226,31 @@ recent = cops.matches.recent(user_id, limit=5, game_type="ranked")
224
226
  ## Weapon stats
225
227
 
226
228
  ```python
227
- weapons = cops.stats.weapons(user_id, "ranked")
228
- best = cops.stats.top_weapons(user_id, by="k", limit=5)
229
+ from copsapi import GameType
230
+
231
+ ranked = cops.stats.weapons(user_id, GameType.RANKED)
232
+ casual = cops.stats.weapons(user_id, GameType.CASUAL)
233
+ best = cops.stats.top_weapons(user_id, game_type=GameType.RANKED, by="k", limit=5)
229
234
  ```
230
235
 
231
- - The game type is `"ranked"` or `"casual"`. Custom games count as casual.
236
+ - The game type is `GameType.RANKED` or `GameType.CASUAL`; the strings `"ranked"` and `"casual"` work too. Custom games count as casual.
232
237
  - `top_weapons` sorts by kills (`k`), assists (`a`) or headshots (`h`). Each `WeaponStats` also has a `.headshot_rate`.
233
238
 
234
239
  ## Leaderboards
235
240
 
236
241
  ```python
237
- page = cops.leaderboards.page("mmr", page=1)
238
- elite = cops.leaderboards.page("mmr", rank=9)
242
+ from copsapi import LeaderboardType
243
+
244
+ page = cops.leaderboards.page(LeaderboardType.MMR, page=1)
245
+ elite = cops.leaderboards.page(LeaderboardType.MMR, rank=9)
239
246
 
240
- for entry in cops.leaderboards.iterate("kills", max_pages=10):
247
+ for entry in cops.leaderboards.iterate(LeaderboardType.KILLS, max_pages=10):
241
248
  print(entry.position, entry.basic_info.name, entry.score)
242
249
 
243
- top50 = cops.leaderboards.top("wins", 50)
250
+ top50 = cops.leaderboards.top(LeaderboardType.WINS, 50)
244
251
  ```
245
252
 
246
- - The types are `mmr`, `kills`, `deaths`, `assists`, `matches`, `wins`, `losses`, `xp` and `mvp`. Pages hold 10 entries.
253
+ - The types are `LeaderboardType.MMR`, `KILLS`, `DEATHS`, `ASSISTS`, `MATCHES`, `WINS`, `LOSSES`, `XP` and `MVP`; the plain strings (`"mmr"`, `"kills"` and so on) work too. Pages hold 10 entries.
247
254
  - `page` returns a `LeaderboardPage(type, page, rank, size, pages, entries)`. `rank` (0 to 9) filters to one rank.
248
255
  - Players move as matches end, so `iterate` skips anyone already yielded on an earlier page.
249
256
 
@@ -254,25 +261,27 @@ This needs a token with the `Autohost` permission. To check before offering host
254
261
  ### One call: host, wait for the code, add owners
255
262
 
256
263
  ```python
264
+ from copsapi import GameModeId, MapId
265
+
257
266
  server = cops.servers.pick(region="EU")
258
267
  room = cops.autohost.host(
259
268
  server_id=server.id,
260
- mode="tournament",
261
- map="Castello",
269
+ mode=GameModeId.TOURNAMENT_MODE,
270
+ map=MapId.CASTELLO,
262
271
  room_name="Scrim #42",
263
272
  owners=[captain_user_id],
264
273
  )
265
274
  print(f"Join with code {room.code}, password {room.password}")
266
275
  ```
267
276
 
268
- - `mode` and `map` accept names (`"Tournament Mode"`, `"castello"`) or ids. Combinations the API doesn't allow raise `BadRequestError` before the request is sent; pass `validate=False` if Critical Force added a map after this release.
277
+ - `mode` and `map` take a `GameModeId` and a `MapId`. Names (`"Tournament Mode"`, `"castello"`) and raw ids work too. Combinations the API doesn't allow raise `BadRequestError` before the request is sent; pass `validate=False` if Critical Force added a map after this release.
269
278
  - A random 6-character password is generated unless you pass `password="..."`. Pass `password=False` for an open room.
270
279
  - `host` raises `GameRejectedError` if the game server refuses the game (it's full or in maintenance, or the token already hosts 10 games there). It raises `GameGoneError`, or `ConnectionFailedError` with code `timeout`, if the room never appears.
271
280
 
272
281
  ### Step by step
273
282
 
274
283
  ```python
275
- game = cops.autohost.create(server_id=6, mode=15847, map=15391, room_name="Final", password="abc")
284
+ game = cops.autohost.create(server_id=6, mode=GameModeId.DEFUSE, map=MapId.RAID, room_name="Final", password="abc")
276
285
  ready = cops.autohost.wait_for_room(game.id)
277
286
  games = cops.autohost.poll([game.id, other_id])
278
287
  one = cops.autohost.get(game.id)
@@ -285,12 +294,14 @@ one = cops.autohost.get(game.id)
285
294
  ### Room commands
286
295
 
287
296
  ```python
297
+ from copsapi import AutohostCommand
298
+
288
299
  cops.autohost.kick(game_id, user_id)
289
300
  cops.autohost.add_owner(game_id, user_id)
290
301
  cops.autohost.remove_owner(game_id, user_id)
291
302
  cops.autohost.restart(game_id)
292
303
  cops.autohost.close(game_id)
293
- cops.autohost.control(game_id, "kick", user_id)
304
+ cops.autohost.control(game_id, AutohostCommand.KICK, user_id)
294
305
  ```
295
306
 
296
307
  - `kick` removes the player and keeps them out for an hour.
@@ -60,7 +60,7 @@ What a token can do depends on its permissions:
60
60
  | Endpoints | Needs |
61
61
  | --- | --- |
62
62
  | Profiles, servers, match history, weapon stats, leaderboards | Any valid token |
63
- | Autohost (`create`, `poll`, `control`, `host`, the watcher) | A token with the `Autohost` permission |
63
+ | Autohost (`create`, `poll`, `control`, `host`, the watcher) | A token with the `Autohost` permission (Developer Issued) |
64
64
 
65
65
  There are three ways to pass the token:
66
66
 
@@ -94,14 +94,14 @@ If your token lacks `Autohost`, hosting calls raise `PermissionDeniedError` with
94
94
  ## Sync and async
95
95
 
96
96
  ```python
97
- from copsapi import CopsClient, AsyncCopsClient
97
+ from copsapi import CopsClient, AsyncCopsClient, LeaderboardType
98
98
 
99
99
  with CopsClient() as cops:
100
100
  servers = cops.servers.online()
101
101
 
102
102
  async with AsyncCopsClient() as cops:
103
103
  servers = await cops.servers.online()
104
- async for entry in cops.leaderboards.iterate("kills", max_pages=3):
104
+ async for entry in cops.leaderboards.iterate(LeaderboardType.KILLS, max_pages=3):
105
105
  print(entry.position, entry.basic_info.name)
106
106
  ```
107
107
 
@@ -177,9 +177,11 @@ server = cops.servers.pick(region="EU")
177
177
  ## Match history
178
178
 
179
179
  ```python
180
+ from copsapi import GameType
181
+
180
182
  history = cops.matches.history(user_id)
181
183
  match = cops.matches.one(history[0].id)
182
- recent = cops.matches.recent(user_id, limit=5, game_type="ranked")
184
+ recent = cops.matches.recent(user_id, limit=5, game_type=GameType.RANKED)
183
185
  ```
184
186
 
185
187
  - `history` returns the player's recent matches, newest first. The history resets with each game update.
@@ -189,26 +191,31 @@ recent = cops.matches.recent(user_id, limit=5, game_type="ranked")
189
191
  ## Weapon stats
190
192
 
191
193
  ```python
192
- weapons = cops.stats.weapons(user_id, "ranked")
193
- best = cops.stats.top_weapons(user_id, by="k", limit=5)
194
+ from copsapi import GameType
195
+
196
+ ranked = cops.stats.weapons(user_id, GameType.RANKED)
197
+ casual = cops.stats.weapons(user_id, GameType.CASUAL)
198
+ best = cops.stats.top_weapons(user_id, game_type=GameType.RANKED, by="k", limit=5)
194
199
  ```
195
200
 
196
- - The game type is `"ranked"` or `"casual"`. Custom games count as casual.
201
+ - The game type is `GameType.RANKED` or `GameType.CASUAL`; the strings `"ranked"` and `"casual"` work too. Custom games count as casual.
197
202
  - `top_weapons` sorts by kills (`k`), assists (`a`) or headshots (`h`). Each `WeaponStats` also has a `.headshot_rate`.
198
203
 
199
204
  ## Leaderboards
200
205
 
201
206
  ```python
202
- page = cops.leaderboards.page("mmr", page=1)
203
- elite = cops.leaderboards.page("mmr", rank=9)
207
+ from copsapi import LeaderboardType
208
+
209
+ page = cops.leaderboards.page(LeaderboardType.MMR, page=1)
210
+ elite = cops.leaderboards.page(LeaderboardType.MMR, rank=9)
204
211
 
205
- for entry in cops.leaderboards.iterate("kills", max_pages=10):
212
+ for entry in cops.leaderboards.iterate(LeaderboardType.KILLS, max_pages=10):
206
213
  print(entry.position, entry.basic_info.name, entry.score)
207
214
 
208
- top50 = cops.leaderboards.top("wins", 50)
215
+ top50 = cops.leaderboards.top(LeaderboardType.WINS, 50)
209
216
  ```
210
217
 
211
- - The types are `mmr`, `kills`, `deaths`, `assists`, `matches`, `wins`, `losses`, `xp` and `mvp`. Pages hold 10 entries.
218
+ - The types are `LeaderboardType.MMR`, `KILLS`, `DEATHS`, `ASSISTS`, `MATCHES`, `WINS`, `LOSSES`, `XP` and `MVP`; the plain strings (`"mmr"`, `"kills"` and so on) work too. Pages hold 10 entries.
212
219
  - `page` returns a `LeaderboardPage(type, page, rank, size, pages, entries)`. `rank` (0 to 9) filters to one rank.
213
220
  - Players move as matches end, so `iterate` skips anyone already yielded on an earlier page.
214
221
 
@@ -219,25 +226,27 @@ This needs a token with the `Autohost` permission. To check before offering host
219
226
  ### One call: host, wait for the code, add owners
220
227
 
221
228
  ```python
229
+ from copsapi import GameModeId, MapId
230
+
222
231
  server = cops.servers.pick(region="EU")
223
232
  room = cops.autohost.host(
224
233
  server_id=server.id,
225
- mode="tournament",
226
- map="Castello",
234
+ mode=GameModeId.TOURNAMENT_MODE,
235
+ map=MapId.CASTELLO,
227
236
  room_name="Scrim #42",
228
237
  owners=[captain_user_id],
229
238
  )
230
239
  print(f"Join with code {room.code}, password {room.password}")
231
240
  ```
232
241
 
233
- - `mode` and `map` accept names (`"Tournament Mode"`, `"castello"`) or ids. Combinations the API doesn't allow raise `BadRequestError` before the request is sent; pass `validate=False` if Critical Force added a map after this release.
242
+ - `mode` and `map` take a `GameModeId` and a `MapId`. Names (`"Tournament Mode"`, `"castello"`) and raw ids work too. Combinations the API doesn't allow raise `BadRequestError` before the request is sent; pass `validate=False` if Critical Force added a map after this release.
234
243
  - A random 6-character password is generated unless you pass `password="..."`. Pass `password=False` for an open room.
235
244
  - `host` raises `GameRejectedError` if the game server refuses the game (it's full or in maintenance, or the token already hosts 10 games there). It raises `GameGoneError`, or `ConnectionFailedError` with code `timeout`, if the room never appears.
236
245
 
237
246
  ### Step by step
238
247
 
239
248
  ```python
240
- game = cops.autohost.create(server_id=6, mode=15847, map=15391, room_name="Final", password="abc")
249
+ game = cops.autohost.create(server_id=6, mode=GameModeId.DEFUSE, map=MapId.RAID, room_name="Final", password="abc")
241
250
  ready = cops.autohost.wait_for_room(game.id)
242
251
  games = cops.autohost.poll([game.id, other_id])
243
252
  one = cops.autohost.get(game.id)
@@ -250,12 +259,14 @@ one = cops.autohost.get(game.id)
250
259
  ### Room commands
251
260
 
252
261
  ```python
262
+ from copsapi import AutohostCommand
263
+
253
264
  cops.autohost.kick(game_id, user_id)
254
265
  cops.autohost.add_owner(game_id, user_id)
255
266
  cops.autohost.remove_owner(game_id, user_id)
256
267
  cops.autohost.restart(game_id)
257
268
  cops.autohost.close(game_id)
258
- cops.autohost.control(game_id, "kick", user_id)
269
+ cops.autohost.control(game_id, AutohostCommand.KICK, user_id)
259
270
  ```
260
271
 
261
272
  - `kick` removes the player and keeps them out for an hour.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "copsapi-wrapper"
7
- version = "1.1.0"
7
+ version = "1.1.1"
8
8
  description = "Typed, quota-aware Python client for the Critical Ops Public API v2, sync and async: profiles, leaderboards, match history, weapon stats, server status and Autohost with a live room watcher."
9
9
  readme = "README.md"
10
10
  license = "MIT"