cocapi 4.0.0__tar.gz → 4.0.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.
- cocapi-4.0.1/.github/workflows/docs.yml +33 -0
- cocapi-4.0.1/PKG-INFO +256 -0
- cocapi-4.0.1/README.md +217 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/__init__.py +1 -1
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/events/_state.py +10 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/events/_stream.py +10 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/events/_watchers.py +56 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/schemas.py +90 -0
- cocapi-4.0.1/docs/changelog.md +46 -0
- cocapi-4.0.1/docs/examples.md +123 -0
- cocapi-4.0.1/docs/getting-started/authentication.md +82 -0
- cocapi-4.0.1/docs/getting-started/installation.md +53 -0
- cocapi-4.0.1/docs/getting-started/quickstart.md +76 -0
- cocapi-4.0.1/docs/guides/async.md +112 -0
- cocapi-4.0.1/docs/guides/caching.md +57 -0
- cocapi-4.0.1/docs/guides/cli.md +94 -0
- cocapi-4.0.1/docs/guides/configuration.md +88 -0
- cocapi-4.0.1/docs/guides/error-handling.md +86 -0
- cocapi-4.0.1/docs/guides/events.md +152 -0
- cocapi-4.0.1/docs/guides/metrics.md +54 -0
- cocapi-4.0.1/docs/guides/middleware.md +83 -0
- cocapi-4.0.1/docs/guides/pagination-batch.md +88 -0
- cocapi-4.0.1/docs/guides/pydantic-models.md +70 -0
- cocapi-4.0.1/docs/index.md +62 -0
- cocapi-4.0.1/mkdocs.yml +135 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/pyproject.toml +16 -1
- {cocapi-4.0.0 → cocapi-4.0.1}/uv.lock +639 -2
- cocapi-4.0.0/PKG-INFO +0 -955
- cocapi-4.0.0/README.md +0 -924
- cocapi-4.0.0/_config.yml +0 -1
- {cocapi-4.0.0 → cocapi-4.0.1}/.github/FUNDING.yml +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/.github/workflows/ci.yml +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/.github/workflows/release.yml +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/.gitignore +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/.pre-commit-config.yaml +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/CODE_OF_CONDUCT.md +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/LICENSE +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/SECURITY.md +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/api_methods.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/async_client.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/cache.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/cli.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/client.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/cocapi.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/config.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/events/__init__.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/events/_diff.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/events/_types.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/events/_war_fsm.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/key_manager.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/metrics.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/middleware.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/model_registry.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/models.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/py.typed +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/cocapi/utils.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/mypy.ini +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/setup.py +0 -0
- {cocapi-4.0.0 → cocapi-4.0.1}/sonar-project.properties +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Deploy Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: deploy-docs
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
deploy:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
|
|
26
|
+
- name: Install uv
|
|
27
|
+
uses: astral-sh/setup-uv@v3
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: uv sync --dev --extra pydantic --extra docs
|
|
31
|
+
|
|
32
|
+
- name: Build and deploy docs
|
|
33
|
+
run: uv run mkdocs gh-deploy --force
|
cocapi-4.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cocapi
|
|
3
|
+
Version: 4.0.1
|
|
4
|
+
Summary: Async & sync Python wrapper for the Clash of Clans API with auto key management
|
|
5
|
+
Project-URL: Homepage, https://github.com/tonybenoy/cocapi
|
|
6
|
+
Project-URL: Documentation, https://tonybenoy.github.io/cocapi/
|
|
7
|
+
Project-URL: Repository, https://github.com/tonybenoy/cocapi
|
|
8
|
+
Project-URL: Issues, https://github.com/tonybenoy/cocapi/issues
|
|
9
|
+
Author-email: Tony Benoy <me@tonybenoy.com>
|
|
10
|
+
License: GPL-3.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api-wrapper,async,clans,clash,clash-of-clans,coc,coc-api,game-api,supercell
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Framework :: AsyncIO
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Games/Entertainment :: Real Time Strategy
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: httpx>=0.23.0
|
|
27
|
+
Provides-Extra: cli
|
|
28
|
+
Requires-Dist: typer>=0.9.0; extra == 'cli'
|
|
29
|
+
Provides-Extra: docs
|
|
30
|
+
Requires-Dist: mkdocs-gen-files>=0.5.0; extra == 'docs'
|
|
31
|
+
Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == 'docs'
|
|
32
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
33
|
+
Requires-Dist: mkdocs-section-index>=0.3.9; extra == 'docs'
|
|
34
|
+
Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
|
|
35
|
+
Requires-Dist: mkdocstrings[python]>=0.27.0; extra == 'docs'
|
|
36
|
+
Provides-Extra: pydantic
|
|
37
|
+
Requires-Dist: pydantic>=2.0.0; extra == 'pydantic'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
<p>
|
|
41
|
+
<a href="https://github.com/tonybenoy/cocapi/actions">
|
|
42
|
+
<img src="https://github.com/tonybenoy/cocapi/workflows/CI/badge.svg" alt="CI Status" height="20">
|
|
43
|
+
</a>
|
|
44
|
+
<a href="https://pypi.org/project/cocapi/"><img src="https://img.shields.io/pypi/v/cocapi" alt="Pypi version" height="21"></a>
|
|
45
|
+
<a href="https://pypi.org/project/cocapi/"><img src="https://img.shields.io/pypi/dm/cocapi" alt="PyPI Downloads" height="21"></a>
|
|
46
|
+
<a href="https://tonybenoy.github.io/cocapi/"><img src="https://img.shields.io/badge/docs-mkdocs-blue.svg" alt="Documentation" height="21"></a>
|
|
47
|
+
</p>
|
|
48
|
+
<p>
|
|
49
|
+
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="Python version" height="17"></a>
|
|
50
|
+
<a href="https://github.com/tonybenoy/cocapi/blob/main/LICENSE"><img src="https://img.shields.io/github/license/tonybenoy/cocapi" alt="License" height="17"></a>
|
|
51
|
+
<a href="https://github.com/astral-sh/ruff">
|
|
52
|
+
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff" height="17">
|
|
53
|
+
</a>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
# cocapi
|
|
57
|
+
|
|
58
|
+
A Python wrapper for the official [Clash of Clans API](https://developer.clashofclans.com/) with full async support, automatic key management, caching, retries, and optional Pydantic models.
|
|
59
|
+
|
|
60
|
+
**[Full Documentation](https://tonybenoy.github.io/cocapi/)**
|
|
61
|
+
|
|
62
|
+
## Features
|
|
63
|
+
|
|
64
|
+
- **Sync & async** — same methods, same names, both modes
|
|
65
|
+
- **Automatic key management** — login with email/password, keys are created, reused, and rotated automatically
|
|
66
|
+
- **Caching** — TTL-based response caching with stats
|
|
67
|
+
- **Retries** — exponential backoff for rate limits and server errors
|
|
68
|
+
- **Pagination & batch** — `paginate()` auto-follows cursors, `batch()` fetches many resources at once
|
|
69
|
+
- **Event polling** — real-time monitoring of clans, wars, and players with `async for` or callbacks
|
|
70
|
+
- **Pydantic models** — optional typed response objects with IDE autocompletion
|
|
71
|
+
- **Middleware** — plug in custom request/response processing
|
|
72
|
+
- **CLI** — `cocapi clan "#2PP"` from the terminal
|
|
73
|
+
- **Maintenance detection** — automatic detection of API maintenance windows
|
|
74
|
+
|
|
75
|
+
## Install
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install cocapi
|
|
79
|
+
|
|
80
|
+
# With Pydantic model support
|
|
81
|
+
pip install 'cocapi[pydantic]'
|
|
82
|
+
|
|
83
|
+
# With CLI
|
|
84
|
+
pip install 'cocapi[cli]'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Requires Python 3.10+.
|
|
88
|
+
|
|
89
|
+
## Quick Start
|
|
90
|
+
|
|
91
|
+
### With an API Token
|
|
92
|
+
|
|
93
|
+
Get a token from [developer.clashofclans.com](https://developer.clashofclans.com/):
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from cocapi import CocApi
|
|
97
|
+
|
|
98
|
+
api = CocApi("your_api_token")
|
|
99
|
+
|
|
100
|
+
clan = api.clan_tag("#2PP")
|
|
101
|
+
print(clan["name"])
|
|
102
|
+
|
|
103
|
+
player = api.players("#900PUCPV")
|
|
104
|
+
print(player["trophies"])
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### With Email/Password (Automatic Key Management)
|
|
108
|
+
|
|
109
|
+
Skip manual key creation entirely. cocapi logs into the developer portal, detects your IP, and manages keys for you:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from cocapi import CocApi
|
|
113
|
+
|
|
114
|
+
api = CocApi.from_credentials("you@example.com", "your_password")
|
|
115
|
+
clan = api.clan_tag("#2PP")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Keys are created automatically, reused when valid, and rotated when your IP changes. See the [Authentication guide](https://tonybenoy.github.io/cocapi/getting-started/authentication/) for details.
|
|
119
|
+
|
|
120
|
+
### Async
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
import asyncio
|
|
124
|
+
from cocapi import CocApi
|
|
125
|
+
|
|
126
|
+
async def main():
|
|
127
|
+
async with CocApi("your_token") as api:
|
|
128
|
+
clan = await api.clan_tag("#2PP")
|
|
129
|
+
player = await api.players("#900PUCPV")
|
|
130
|
+
print(clan["name"], player["trophies"])
|
|
131
|
+
|
|
132
|
+
asyncio.run(main())
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
See the [Async guide](https://tonybenoy.github.io/cocapi/guides/async/) for more patterns.
|
|
136
|
+
|
|
137
|
+
## Configuration
|
|
138
|
+
|
|
139
|
+
All options are set through `ApiConfig`:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from cocapi import CocApi, ApiConfig
|
|
143
|
+
|
|
144
|
+
config = ApiConfig(
|
|
145
|
+
timeout=30,
|
|
146
|
+
max_retries=3,
|
|
147
|
+
enable_caching=True,
|
|
148
|
+
cache_ttl=600,
|
|
149
|
+
enable_rate_limiting=True, # async only
|
|
150
|
+
requests_per_second=10.0,
|
|
151
|
+
enable_metrics=True,
|
|
152
|
+
use_pydantic_models=True, # requires cocapi[pydantic]
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
api = CocApi("your_token", config=config)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
See the [Configuration guide](https://tonybenoy.github.io/cocapi/guides/configuration/) for all options.
|
|
159
|
+
|
|
160
|
+
## Pagination & Batch
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# Auto-paginate through all clan members
|
|
164
|
+
for member in api.paginate(api.clan_members, "#CLAN_TAG"):
|
|
165
|
+
print(member["name"])
|
|
166
|
+
|
|
167
|
+
# Fetch multiple players at once
|
|
168
|
+
results = api.batch(api.players, ["#TAG1", "#TAG2", "#TAG3"])
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Both work in sync and async. See the [Pagination & Batch guide](https://tonybenoy.github.io/cocapi/guides/pagination-batch/).
|
|
172
|
+
|
|
173
|
+
## Event Polling
|
|
174
|
+
|
|
175
|
+
Monitor clans, wars, and players in real time. Async only.
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from cocapi.events import EventStream, EventType
|
|
179
|
+
|
|
180
|
+
async with CocApi("token") as api:
|
|
181
|
+
stream = EventStream(api)
|
|
182
|
+
stream.watch_clans(["#2PP"], interval=60)
|
|
183
|
+
stream.watch_wars(["#2PP"], interval=30)
|
|
184
|
+
stream.watch_players(["#900PUCPV"], interval=120)
|
|
185
|
+
|
|
186
|
+
async with stream:
|
|
187
|
+
async for event in stream:
|
|
188
|
+
print(event.event_type, event.tag)
|
|
189
|
+
for change in event.changes:
|
|
190
|
+
print(f" {change.field}: {change.old_value} -> {change.new_value}")
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Supports 20+ event types including member join/leave, war state transitions, troop/hero upgrades, maintenance detection, and more. See the [Event Polling guide](https://tonybenoy.github.io/cocapi/guides/events/).
|
|
194
|
+
|
|
195
|
+
## CLI
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install 'cocapi[cli]'
|
|
199
|
+
|
|
200
|
+
# Login once (key is persisted)
|
|
201
|
+
cocapi login --email you@example.com --password yourpass
|
|
202
|
+
|
|
203
|
+
# Use without --token
|
|
204
|
+
cocapi clan "#2PP"
|
|
205
|
+
cocapi player "#900PUCPV"
|
|
206
|
+
cocapi war "#2PP"
|
|
207
|
+
cocapi search "clash" --limit 5
|
|
208
|
+
cocapi goldpass
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
See the [CLI guide](https://tonybenoy.github.io/cocapi/guides/cli/) for all commands.
|
|
212
|
+
|
|
213
|
+
## Error Handling
|
|
214
|
+
|
|
215
|
+
All endpoints return a dict (or Pydantic model). Errors never raise exceptions:
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
result = api.clan_tag("#INVALID")
|
|
219
|
+
if result.get("result") == "error":
|
|
220
|
+
print(result["message"]) # Human-readable message
|
|
221
|
+
print(result["error_type"]) # "timeout", "connection", "http", "json", etc.
|
|
222
|
+
print(result.get("status_code"))
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
See the [Error Handling guide](https://tonybenoy.github.io/cocapi/guides/error-handling/).
|
|
226
|
+
|
|
227
|
+
## Examples
|
|
228
|
+
|
|
229
|
+
Runnable scripts in the [`examples/`](examples/) folder:
|
|
230
|
+
|
|
231
|
+
| Script | What it covers |
|
|
232
|
+
|---|---|
|
|
233
|
+
| [`basic_usage.py`](examples/basic_usage.py) | Sync: clan info, player info, search, error handling |
|
|
234
|
+
| [`async_usage.py`](examples/async_usage.py) | Async with context manager, concurrent requests |
|
|
235
|
+
| [`credential_auth.py`](examples/credential_auth.py) | Email/password login, key persistence, auto-refresh |
|
|
236
|
+
| [`pagination_batch.py`](examples/pagination_batch.py) | `paginate()` and `batch()` in sync and async |
|
|
237
|
+
| [`event_polling.py`](examples/event_polling.py) | `EventStream` with `async for` — real-time monitoring |
|
|
238
|
+
| [`event_callbacks.py`](examples/event_callbacks.py) | `@stream.on()` decorators and `stream.run()` |
|
|
239
|
+
| [`configuration.py`](examples/configuration.py) | ApiConfig, caching, metrics, middleware |
|
|
240
|
+
|
|
241
|
+
## API Reference
|
|
242
|
+
|
|
243
|
+
Full API reference with all endpoints, parameters, and response schemas is available in the [documentation](https://tonybenoy.github.io/cocapi/reference/).
|
|
244
|
+
|
|
245
|
+
Key classes:
|
|
246
|
+
- [`CocApi`](https://tonybenoy.github.io/cocapi/reference/client/) — main entry point (sync/async)
|
|
247
|
+
- [`ApiConfig`](https://tonybenoy.github.io/cocapi/reference/config/) — configuration options
|
|
248
|
+
- [`EventStream`](https://tonybenoy.github.io/cocapi/reference/events/) — real-time event polling
|
|
249
|
+
- [Pydantic Schemas](https://tonybenoy.github.io/cocapi/reference/schemas/) — typed response models
|
|
250
|
+
- [All Endpoints](https://tonybenoy.github.io/cocapi/reference/api_methods/) — every API method
|
|
251
|
+
|
|
252
|
+
## Credits
|
|
253
|
+
|
|
254
|
+
- [All Contributors](../../contributors)
|
|
255
|
+
|
|
256
|
+
*cocapi is not affiliated with SuperCell.*
|
cocapi-4.0.1/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
<p>
|
|
2
|
+
<a href="https://github.com/tonybenoy/cocapi/actions">
|
|
3
|
+
<img src="https://github.com/tonybenoy/cocapi/workflows/CI/badge.svg" alt="CI Status" height="20">
|
|
4
|
+
</a>
|
|
5
|
+
<a href="https://pypi.org/project/cocapi/"><img src="https://img.shields.io/pypi/v/cocapi" alt="Pypi version" height="21"></a>
|
|
6
|
+
<a href="https://pypi.org/project/cocapi/"><img src="https://img.shields.io/pypi/dm/cocapi" alt="PyPI Downloads" height="21"></a>
|
|
7
|
+
<a href="https://tonybenoy.github.io/cocapi/"><img src="https://img.shields.io/badge/docs-mkdocs-blue.svg" alt="Documentation" height="21"></a>
|
|
8
|
+
</p>
|
|
9
|
+
<p>
|
|
10
|
+
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="Python version" height="17"></a>
|
|
11
|
+
<a href="https://github.com/tonybenoy/cocapi/blob/main/LICENSE"><img src="https://img.shields.io/github/license/tonybenoy/cocapi" alt="License" height="17"></a>
|
|
12
|
+
<a href="https://github.com/astral-sh/ruff">
|
|
13
|
+
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff" height="17">
|
|
14
|
+
</a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
# cocapi
|
|
18
|
+
|
|
19
|
+
A Python wrapper for the official [Clash of Clans API](https://developer.clashofclans.com/) with full async support, automatic key management, caching, retries, and optional Pydantic models.
|
|
20
|
+
|
|
21
|
+
**[Full Documentation](https://tonybenoy.github.io/cocapi/)**
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **Sync & async** — same methods, same names, both modes
|
|
26
|
+
- **Automatic key management** — login with email/password, keys are created, reused, and rotated automatically
|
|
27
|
+
- **Caching** — TTL-based response caching with stats
|
|
28
|
+
- **Retries** — exponential backoff for rate limits and server errors
|
|
29
|
+
- **Pagination & batch** — `paginate()` auto-follows cursors, `batch()` fetches many resources at once
|
|
30
|
+
- **Event polling** — real-time monitoring of clans, wars, and players with `async for` or callbacks
|
|
31
|
+
- **Pydantic models** — optional typed response objects with IDE autocompletion
|
|
32
|
+
- **Middleware** — plug in custom request/response processing
|
|
33
|
+
- **CLI** — `cocapi clan "#2PP"` from the terminal
|
|
34
|
+
- **Maintenance detection** — automatic detection of API maintenance windows
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install cocapi
|
|
40
|
+
|
|
41
|
+
# With Pydantic model support
|
|
42
|
+
pip install 'cocapi[pydantic]'
|
|
43
|
+
|
|
44
|
+
# With CLI
|
|
45
|
+
pip install 'cocapi[cli]'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Requires Python 3.10+.
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
### With an API Token
|
|
53
|
+
|
|
54
|
+
Get a token from [developer.clashofclans.com](https://developer.clashofclans.com/):
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from cocapi import CocApi
|
|
58
|
+
|
|
59
|
+
api = CocApi("your_api_token")
|
|
60
|
+
|
|
61
|
+
clan = api.clan_tag("#2PP")
|
|
62
|
+
print(clan["name"])
|
|
63
|
+
|
|
64
|
+
player = api.players("#900PUCPV")
|
|
65
|
+
print(player["trophies"])
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### With Email/Password (Automatic Key Management)
|
|
69
|
+
|
|
70
|
+
Skip manual key creation entirely. cocapi logs into the developer portal, detects your IP, and manages keys for you:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from cocapi import CocApi
|
|
74
|
+
|
|
75
|
+
api = CocApi.from_credentials("you@example.com", "your_password")
|
|
76
|
+
clan = api.clan_tag("#2PP")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Keys are created automatically, reused when valid, and rotated when your IP changes. See the [Authentication guide](https://tonybenoy.github.io/cocapi/getting-started/authentication/) for details.
|
|
80
|
+
|
|
81
|
+
### Async
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
import asyncio
|
|
85
|
+
from cocapi import CocApi
|
|
86
|
+
|
|
87
|
+
async def main():
|
|
88
|
+
async with CocApi("your_token") as api:
|
|
89
|
+
clan = await api.clan_tag("#2PP")
|
|
90
|
+
player = await api.players("#900PUCPV")
|
|
91
|
+
print(clan["name"], player["trophies"])
|
|
92
|
+
|
|
93
|
+
asyncio.run(main())
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
See the [Async guide](https://tonybenoy.github.io/cocapi/guides/async/) for more patterns.
|
|
97
|
+
|
|
98
|
+
## Configuration
|
|
99
|
+
|
|
100
|
+
All options are set through `ApiConfig`:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from cocapi import CocApi, ApiConfig
|
|
104
|
+
|
|
105
|
+
config = ApiConfig(
|
|
106
|
+
timeout=30,
|
|
107
|
+
max_retries=3,
|
|
108
|
+
enable_caching=True,
|
|
109
|
+
cache_ttl=600,
|
|
110
|
+
enable_rate_limiting=True, # async only
|
|
111
|
+
requests_per_second=10.0,
|
|
112
|
+
enable_metrics=True,
|
|
113
|
+
use_pydantic_models=True, # requires cocapi[pydantic]
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
api = CocApi("your_token", config=config)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
See the [Configuration guide](https://tonybenoy.github.io/cocapi/guides/configuration/) for all options.
|
|
120
|
+
|
|
121
|
+
## Pagination & Batch
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
# Auto-paginate through all clan members
|
|
125
|
+
for member in api.paginate(api.clan_members, "#CLAN_TAG"):
|
|
126
|
+
print(member["name"])
|
|
127
|
+
|
|
128
|
+
# Fetch multiple players at once
|
|
129
|
+
results = api.batch(api.players, ["#TAG1", "#TAG2", "#TAG3"])
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Both work in sync and async. See the [Pagination & Batch guide](https://tonybenoy.github.io/cocapi/guides/pagination-batch/).
|
|
133
|
+
|
|
134
|
+
## Event Polling
|
|
135
|
+
|
|
136
|
+
Monitor clans, wars, and players in real time. Async only.
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from cocapi.events import EventStream, EventType
|
|
140
|
+
|
|
141
|
+
async with CocApi("token") as api:
|
|
142
|
+
stream = EventStream(api)
|
|
143
|
+
stream.watch_clans(["#2PP"], interval=60)
|
|
144
|
+
stream.watch_wars(["#2PP"], interval=30)
|
|
145
|
+
stream.watch_players(["#900PUCPV"], interval=120)
|
|
146
|
+
|
|
147
|
+
async with stream:
|
|
148
|
+
async for event in stream:
|
|
149
|
+
print(event.event_type, event.tag)
|
|
150
|
+
for change in event.changes:
|
|
151
|
+
print(f" {change.field}: {change.old_value} -> {change.new_value}")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Supports 20+ event types including member join/leave, war state transitions, troop/hero upgrades, maintenance detection, and more. See the [Event Polling guide](https://tonybenoy.github.io/cocapi/guides/events/).
|
|
155
|
+
|
|
156
|
+
## CLI
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
pip install 'cocapi[cli]'
|
|
160
|
+
|
|
161
|
+
# Login once (key is persisted)
|
|
162
|
+
cocapi login --email you@example.com --password yourpass
|
|
163
|
+
|
|
164
|
+
# Use without --token
|
|
165
|
+
cocapi clan "#2PP"
|
|
166
|
+
cocapi player "#900PUCPV"
|
|
167
|
+
cocapi war "#2PP"
|
|
168
|
+
cocapi search "clash" --limit 5
|
|
169
|
+
cocapi goldpass
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
See the [CLI guide](https://tonybenoy.github.io/cocapi/guides/cli/) for all commands.
|
|
173
|
+
|
|
174
|
+
## Error Handling
|
|
175
|
+
|
|
176
|
+
All endpoints return a dict (or Pydantic model). Errors never raise exceptions:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
result = api.clan_tag("#INVALID")
|
|
180
|
+
if result.get("result") == "error":
|
|
181
|
+
print(result["message"]) # Human-readable message
|
|
182
|
+
print(result["error_type"]) # "timeout", "connection", "http", "json", etc.
|
|
183
|
+
print(result.get("status_code"))
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
See the [Error Handling guide](https://tonybenoy.github.io/cocapi/guides/error-handling/).
|
|
187
|
+
|
|
188
|
+
## Examples
|
|
189
|
+
|
|
190
|
+
Runnable scripts in the [`examples/`](examples/) folder:
|
|
191
|
+
|
|
192
|
+
| Script | What it covers |
|
|
193
|
+
|---|---|
|
|
194
|
+
| [`basic_usage.py`](examples/basic_usage.py) | Sync: clan info, player info, search, error handling |
|
|
195
|
+
| [`async_usage.py`](examples/async_usage.py) | Async with context manager, concurrent requests |
|
|
196
|
+
| [`credential_auth.py`](examples/credential_auth.py) | Email/password login, key persistence, auto-refresh |
|
|
197
|
+
| [`pagination_batch.py`](examples/pagination_batch.py) | `paginate()` and `batch()` in sync and async |
|
|
198
|
+
| [`event_polling.py`](examples/event_polling.py) | `EventStream` with `async for` — real-time monitoring |
|
|
199
|
+
| [`event_callbacks.py`](examples/event_callbacks.py) | `@stream.on()` decorators and `stream.run()` |
|
|
200
|
+
| [`configuration.py`](examples/configuration.py) | ApiConfig, caching, metrics, middleware |
|
|
201
|
+
|
|
202
|
+
## API Reference
|
|
203
|
+
|
|
204
|
+
Full API reference with all endpoints, parameters, and response schemas is available in the [documentation](https://tonybenoy.github.io/cocapi/reference/).
|
|
205
|
+
|
|
206
|
+
Key classes:
|
|
207
|
+
- [`CocApi`](https://tonybenoy.github.io/cocapi/reference/client/) — main entry point (sync/async)
|
|
208
|
+
- [`ApiConfig`](https://tonybenoy.github.io/cocapi/reference/config/) — configuration options
|
|
209
|
+
- [`EventStream`](https://tonybenoy.github.io/cocapi/reference/events/) — real-time event polling
|
|
210
|
+
- [Pydantic Schemas](https://tonybenoy.github.io/cocapi/reference/schemas/) — typed response models
|
|
211
|
+
- [All Endpoints](https://tonybenoy.github.io/cocapi/reference/api_methods/) — every API method
|
|
212
|
+
|
|
213
|
+
## Credits
|
|
214
|
+
|
|
215
|
+
- [All Contributors](../../contributors)
|
|
216
|
+
|
|
217
|
+
*cocapi is not affiliated with SuperCell.*
|
|
@@ -36,28 +36,35 @@ class PollingState:
|
|
|
36
36
|
# --- Clan ---
|
|
37
37
|
|
|
38
38
|
def get_clan(self, tag: str) -> dict[str, Any] | None:
|
|
39
|
+
"""Return the last-polled clan snapshot, or None if not yet polled."""
|
|
39
40
|
return self._clan_snapshots.get(tag)
|
|
40
41
|
|
|
41
42
|
def set_clan(self, tag: str, data: dict[str, Any]) -> None:
|
|
43
|
+
"""Store the latest clan snapshot for diffing on the next poll."""
|
|
42
44
|
self._clan_snapshots[tag] = data
|
|
43
45
|
|
|
44
46
|
# --- Members ---
|
|
45
47
|
|
|
46
48
|
def get_members(self, tag: str) -> list[dict[str, Any]] | None:
|
|
49
|
+
"""Return the last-polled member list for a clan, or None."""
|
|
47
50
|
return self._member_snapshots.get(tag)
|
|
48
51
|
|
|
49
52
|
def set_members(self, tag: str, members: list[dict[str, Any]]) -> None:
|
|
53
|
+
"""Store the latest member list snapshot for a clan."""
|
|
50
54
|
self._member_snapshots[tag] = members
|
|
51
55
|
|
|
52
56
|
# --- War ---
|
|
53
57
|
|
|
54
58
|
def get_war(self, tag: str) -> dict[str, Any] | None:
|
|
59
|
+
"""Return the last-polled war snapshot, or None if not yet polled."""
|
|
55
60
|
return self._war_snapshots.get(tag)
|
|
56
61
|
|
|
57
62
|
def set_war(self, tag: str, data: dict[str, Any]) -> None:
|
|
63
|
+
"""Store the latest war snapshot for diffing on the next poll."""
|
|
58
64
|
self._war_snapshots[tag] = data
|
|
59
65
|
|
|
60
66
|
def get_war_fsm(self, tag: str) -> WarStateMachine:
|
|
67
|
+
"""Return the war state machine for a clan, creating one if needed."""
|
|
61
68
|
if tag not in self._war_fsms:
|
|
62
69
|
self._war_fsms[tag] = WarStateMachine()
|
|
63
70
|
return self._war_fsms[tag]
|
|
@@ -65,9 +72,11 @@ class PollingState:
|
|
|
65
72
|
# --- Player ---
|
|
66
73
|
|
|
67
74
|
def get_player(self, tag: str) -> dict[str, Any] | None:
|
|
75
|
+
"""Return the last-polled player snapshot, or None if not yet polled."""
|
|
68
76
|
return self._player_snapshots.get(tag)
|
|
69
77
|
|
|
70
78
|
def set_player(self, tag: str, data: dict[str, Any]) -> None:
|
|
79
|
+
"""Store the latest player snapshot for diffing on the next poll."""
|
|
71
80
|
self._player_snapshots[tag] = data
|
|
72
81
|
|
|
73
82
|
# --- Poll timing ---
|
|
@@ -78,6 +87,7 @@ class PollingState:
|
|
|
78
87
|
return (time.time() - last) >= interval
|
|
79
88
|
|
|
80
89
|
def mark_polled(self, resource_key: str) -> None:
|
|
90
|
+
"""Record the current time as the last poll time for a resource."""
|
|
81
91
|
self._last_poll_times[resource_key] = time.time()
|
|
82
92
|
|
|
83
93
|
# --- Persistence ---
|
|
@@ -53,6 +53,16 @@ class EventStream:
|
|
|
53
53
|
queue_size: int = 1000,
|
|
54
54
|
persist_path: Path | str | None = None,
|
|
55
55
|
) -> None:
|
|
56
|
+
"""Initialize the event stream.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
api: A CocApi instance in async mode (inside ``async with``).
|
|
60
|
+
queue_size: Max events buffered before backpressure (0 = unlimited).
|
|
61
|
+
persist_path: Optional path for state persistence across restarts.
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
RuntimeError: If the CocApi instance is not in async mode.
|
|
65
|
+
"""
|
|
56
66
|
if not api.async_mode:
|
|
57
67
|
raise RuntimeError(
|
|
58
68
|
"EventStream requires CocApi in async mode. "
|