geniuslib 5.5.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.
- geniuslib-5.5.0/LICENSE +21 -0
- geniuslib-5.5.0/PKG-INFO +375 -0
- geniuslib-5.5.0/README.md +333 -0
- geniuslib-5.5.0/geniuslib/__init__.py +186 -0
- geniuslib-5.5.0/geniuslib/__main__.py +8 -0
- geniuslib-5.5.0/geniuslib/abc.py +274 -0
- geniuslib-5.5.0/geniuslib/battlelog.py +458 -0
- geniuslib-5.5.0/geniuslib/battlelog_analytics.py +672 -0
- geniuslib-5.5.0/geniuslib/buildings.py +510 -0
- geniuslib-5.5.0/geniuslib/characters.py +144 -0
- geniuslib-5.5.0/geniuslib/clans.py +289 -0
- geniuslib-5.5.0/geniuslib/cli.py +239 -0
- geniuslib-5.5.0/geniuslib/client.py +2924 -0
- geniuslib-5.5.0/geniuslib/comparer.py +122 -0
- geniuslib-5.5.0/geniuslib/constants.py +331 -0
- geniuslib-5.5.0/geniuslib/cosmetics.py +198 -0
- geniuslib-5.5.0/geniuslib/entry_logs.py +260 -0
- geniuslib-5.5.0/geniuslib/enums.py +186 -0
- geniuslib-5.5.0/geniuslib/errors.py +139 -0
- geniuslib-5.5.0/geniuslib/events.py +1153 -0
- geniuslib-5.5.0/geniuslib/events.pyi +232 -0
- geniuslib-5.5.0/geniuslib/exporter.py +248 -0
- geniuslib-5.5.0/geniuslib/ext/discordlinks/__init__.py +279 -0
- geniuslib-5.5.0/geniuslib/ext/triggers/__init__.py +15 -0
- geniuslib-5.5.0/geniuslib/ext/triggers/cron.py +215 -0
- geniuslib-5.5.0/geniuslib/ext/triggers/triggers.py +503 -0
- geniuslib-5.5.0/geniuslib/formatters.py +151 -0
- geniuslib-5.5.0/geniuslib/game_data.py +687 -0
- geniuslib-5.5.0/geniuslib/hero.py +414 -0
- geniuslib-5.5.0/geniuslib/http.py +707 -0
- geniuslib-5.5.0/geniuslib/iterators.py +217 -0
- geniuslib-5.5.0/geniuslib/middleware.py +197 -0
- geniuslib-5.5.0/geniuslib/miscmodels.py +918 -0
- geniuslib-5.5.0/geniuslib/player_clan.py +41 -0
- geniuslib-5.5.0/geniuslib/players.py +758 -0
- geniuslib-5.5.0/geniuslib/raid.py +502 -0
- geniuslib-5.5.0/geniuslib/raid_analytics.py +130 -0
- geniuslib-5.5.0/geniuslib/spell.py +126 -0
- geniuslib-5.5.0/geniuslib/static/__init__.py +0 -0
- geniuslib-5.5.0/geniuslib/static/static_data.json +63983 -0
- geniuslib-5.5.0/geniuslib/static/update_static.py +1481 -0
- geniuslib-5.5.0/geniuslib/troop.py +192 -0
- geniuslib-5.5.0/geniuslib/upgrade_tracker.py +510 -0
- geniuslib-5.5.0/geniuslib/utils.py +856 -0
- geniuslib-5.5.0/geniuslib/war_analytics.py +218 -0
- geniuslib-5.5.0/geniuslib/war_attack.py +105 -0
- geniuslib-5.5.0/geniuslib/war_clans.py +199 -0
- geniuslib-5.5.0/geniuslib/war_members.py +143 -0
- geniuslib-5.5.0/geniuslib/wars.py +538 -0
- geniuslib-5.5.0/geniuslib.egg-info/PKG-INFO +375 -0
- geniuslib-5.5.0/geniuslib.egg-info/SOURCES.txt +60 -0
- geniuslib-5.5.0/geniuslib.egg-info/dependency_links.txt +1 -0
- geniuslib-5.5.0/geniuslib.egg-info/requires.txt +12 -0
- geniuslib-5.5.0/geniuslib.egg-info/top_level.txt +1 -0
- geniuslib-5.5.0/pyproject.toml +86 -0
- geniuslib-5.5.0/setup.cfg +4 -0
- geniuslib-5.5.0/tests/test_battlelog_analytics.py +319 -0
- geniuslib-5.5.0/tests/test_formatters.py +113 -0
- geniuslib-5.5.0/tests/test_middleware.py +222 -0
- geniuslib-5.5.0/tests/test_raid_analytics.py +105 -0
- geniuslib-5.5.0/tests/test_utils.py +156 -0
- geniuslib-5.5.0/tests/test_war_analytics.py +115 -0
geniuslib-5.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AkumaHalls
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
geniuslib-5.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: geniuslib
|
|
3
|
+
Version: 5.5.0
|
|
4
|
+
Summary: Async Python wrapper for the Clash of Clans API — events, war analytics, raid analytics, middleware, CLI, and 3000+ bundled game assets.
|
|
5
|
+
Author-email: AkumaHalls <akumahalls@proton.me>
|
|
6
|
+
Maintainer-email: AkumaHalls <akumahalls@proton.me>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/AkumaHalls/GeniusLib
|
|
9
|
+
Project-URL: Documentation, https://geniuslib.readthedocs.io
|
|
10
|
+
Project-URL: Repository, https://github.com/AkumaHalls/GeniusLib
|
|
11
|
+
Project-URL: Changelog, https://github.com/AkumaHalls/GeniusLib/blob/main/CHANGELOG.md
|
|
12
|
+
Project-URL: Issues, https://github.com/AkumaHalls/GeniusLib/issues
|
|
13
|
+
Keywords: clash-of-clans,coc-api,clash-of-clans-api,discord-bot,async,gaming,supercell,war-analytics,clashgenius
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Topic :: Games/Entertainment
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
24
|
+
Classifier: Operating System :: OS Independent
|
|
25
|
+
Classifier: Framework :: AsyncIO
|
|
26
|
+
Classifier: Natural Language :: English
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.10
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: aiohttp>=3.9
|
|
32
|
+
Requires-Dist: orjson>=3.9
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
36
|
+
Requires-Dist: ruff; extra == "dev"
|
|
37
|
+
Provides-Extra: docs
|
|
38
|
+
Requires-Dist: mkdocs; extra == "docs"
|
|
39
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
40
|
+
Requires-Dist: mkdocstrings[python]; extra == "docs"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
<](https://pypi.org/project/geniuslib/)
|
|
50
|
+
[](https://pypi.org/project/geniuslib/)
|
|
51
|
+
[](https://github.com/AkumaHalls/GeniusLib/blob/main/LICENSE)
|
|
52
|
+
[](https://pypi.org/project/geniuslib/)
|
|
53
|
+
[](https://github.com/AkumaHalls/GeniusLib)
|
|
54
|
+
[](https://geniuslib.readthedocs.io)
|
|
55
|
+
[](https://github.com/astral-sh/ruff)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
GeniusLib is a **fully async** Python wrapper for the official [Clash of Clans API](https://developer.clashofclans.com/).
|
|
60
|
+
Built for Discord bots, war trackers, capital raid analyzers, and anything that needs fast, reliable CoC data.
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
pip install geniuslib
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import geniuslib, asyncio
|
|
68
|
+
|
|
69
|
+
async def main():
|
|
70
|
+
async with geniuslib.Client() as client:
|
|
71
|
+
await client.login("email", "password")
|
|
72
|
+
player = await client.get_player("#TAG")
|
|
73
|
+
print(f"{player.name} — TH{player.town_hall} — {player.trophies} trophies")
|
|
74
|
+
|
|
75
|
+
asyncio.run(main())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Why GeniusLib?
|
|
83
|
+
|
|
84
|
+
| Feature | GeniusLib | coc.py |
|
|
85
|
+
|---------|-----------|--------|
|
|
86
|
+
| **Async/await** | Native async throughout | Partial (sync wrappers) |
|
|
87
|
+
| **API Coverage** | 35/35 endpoints | 30/35 endpoints |
|
|
88
|
+
| **Events System** | Real-time clan/war/player events | Not included |
|
|
89
|
+
| **War Analytics** | new_stars, best_attack, missed, cleanup | Basic only |
|
|
90
|
+
| **Raid Analytics** | Full offensive/defensive breakdown | Not included |
|
|
91
|
+
| **Battle Log Analytics** | Win rate, streaks, league progression | Not included |
|
|
92
|
+
| **Middleware Pipeline** | Request/response interceptors | Not included |
|
|
93
|
+
| **Game Assets** | 3000+ bundled WebP icons | Not included |
|
|
94
|
+
| **CLI** | Built-in (`python -m geniuslib`) | Not included |
|
|
95
|
+
| **Upgrade Tracker** | Cost/time estimation per TH level | Not included |
|
|
96
|
+
| **Cache TTL** | Auto-expiring cache with background sweep | Not included |
|
|
97
|
+
| **Maintenance Polling** | Auto-detects Supercell maintenance | Not included |
|
|
98
|
+
| **Army Link Parser** | Decode in-game army share codes | Not included |
|
|
99
|
+
| **Test Suite** | 110 pytest tests | Minimal |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Quick Start
|
|
104
|
+
|
|
105
|
+
### Installation
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
# From PyPI (recommended)
|
|
109
|
+
pip install geniuslib
|
|
110
|
+
|
|
111
|
+
# From source
|
|
112
|
+
pip install git+https://github.com/AkumaHalls/GeniusLib.git
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Authentication
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
import geniuslib, asyncio
|
|
119
|
+
|
|
120
|
+
async def main():
|
|
121
|
+
client = geniuslib.Client()
|
|
122
|
+
|
|
123
|
+
# Option 1: Email/password (recommended for bots)
|
|
124
|
+
await client.login("email@example.com", "password")
|
|
125
|
+
|
|
126
|
+
# Option 2: Direct API token
|
|
127
|
+
await client.login_with_tokens("your-api-token")
|
|
128
|
+
|
|
129
|
+
# Now use the client...
|
|
130
|
+
clan = await client.get_clan("#2PP")
|
|
131
|
+
print(f"{clan.name} — Level {clan.level}")
|
|
132
|
+
|
|
133
|
+
await client.close()
|
|
134
|
+
|
|
135
|
+
asyncio.run(main())
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Using as context manager
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
async with geniuslib.Client() as client:
|
|
142
|
+
await client.login("email", "password")
|
|
143
|
+
player = await client.get_player("#TAG")
|
|
144
|
+
print(player.name, player.town_hall)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Features
|
|
150
|
+
|
|
151
|
+
### All 35 Official API Endpoints
|
|
152
|
+
|
|
153
|
+
GeniusLib covers every endpoint in the Clash of Clans API:
|
|
154
|
+
|
|
155
|
+
**Clans** — search, info, members, war log, current war, CWL group, capital raids
|
|
156
|
+
**Players** — info, battle log, league history, token verification
|
|
157
|
+
**Leagues** — all leagues, seasons, rankings, tiers
|
|
158
|
+
**Locations** — rankings for clans, players, builder base, capital
|
|
159
|
+
**War Leagues** — search, info, individual wars
|
|
160
|
+
**Capital Leagues** — search, info
|
|
161
|
+
**Builder Base Leagues** — search, info
|
|
162
|
+
**Labels** — clan labels, player labels
|
|
163
|
+
**Gold Pass** — current season info
|
|
164
|
+
|
|
165
|
+
### Real-Time Events
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from geniuslib import EventsClient, ClanEvents, WarEvents, PlayerEvents, ClientEvents
|
|
169
|
+
|
|
170
|
+
events = EventsClient(client, clan_tags=["#TAG1", "#TAG2"])
|
|
171
|
+
|
|
172
|
+
@ClanEvents.member_join()
|
|
173
|
+
async def on_join(member, clan):
|
|
174
|
+
print(f"{member.name} joined {clan.name}")
|
|
175
|
+
|
|
176
|
+
@WarEvents.war_attack()
|
|
177
|
+
async def on_attack(member, attack):
|
|
178
|
+
print(f"{member.name}: {attack.stars} stars!")
|
|
179
|
+
|
|
180
|
+
@ClientEvents.maintenance_start
|
|
181
|
+
async def on_maintenance():
|
|
182
|
+
print("Supercell maintenance started")
|
|
183
|
+
|
|
184
|
+
await events.start()
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### War Analytics
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from geniuslib.war_analytics import *
|
|
191
|
+
|
|
192
|
+
war = await client.get_current_war("#TAG")
|
|
193
|
+
|
|
194
|
+
count_missed_attacks(war, "#TAG") # 2
|
|
195
|
+
best_attack_on(member) # WarAttack object
|
|
196
|
+
get_cleanup_attacks(war, "#TAG") # list of wasted attacks
|
|
197
|
+
get_war_result(war, "#TAG") # 'win', 'lose', 'tie'
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Raid Analytics
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from geniuslib.raid_analytics import *
|
|
204
|
+
|
|
205
|
+
logs = await client.get_raid_log("#TAG", limit=1)
|
|
206
|
+
summary = raid_summary(logs[0])
|
|
207
|
+
|
|
208
|
+
summary["offensive"]["total_loot"] # 45000
|
|
209
|
+
summary["missed_attacks"] # 3
|
|
210
|
+
summary["inactive_members"] # ['Player1', 'Player2']
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Batch Fetching
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
from geniuslib import Client, ClanIterator
|
|
217
|
+
|
|
218
|
+
async with Client() as client:
|
|
219
|
+
await client.login("email", "password")
|
|
220
|
+
|
|
221
|
+
# Fetch multiple clans in parallel
|
|
222
|
+
tags = ["#TAG1", "#TAG2", "#TAG3", "#TAG4", "#TAG5"]
|
|
223
|
+
async for clan in ClanIterator(client, tags):
|
|
224
|
+
print(f"{clan.name}: {clan.level}")
|
|
225
|
+
|
|
226
|
+
# Or use gather for specific fetches
|
|
227
|
+
import asyncio
|
|
228
|
+
players = await asyncio.gather(*[
|
|
229
|
+
client.get_player(tag) for tag in ["#P1", "#P2", "#P3"]
|
|
230
|
+
])
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Middleware Pipeline
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
from geniuslib.middleware import middleware, request_logger
|
|
237
|
+
|
|
238
|
+
# Built-in request logging
|
|
239
|
+
client.http.add_middleware(request_logger)
|
|
240
|
+
|
|
241
|
+
# Custom middleware
|
|
242
|
+
@middleware("response")
|
|
243
|
+
async def cache_buster(resp):
|
|
244
|
+
resp.data["cached"] = False
|
|
245
|
+
return resp
|
|
246
|
+
|
|
247
|
+
client.http.add_middleware(cache_buster)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Game Assets (3000+ icons)
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
player = await client.get_player("#TAG")
|
|
254
|
+
|
|
255
|
+
for troop in player.troops:
|
|
256
|
+
print(f"{troop.name}: {troop.asset_url}")
|
|
257
|
+
# "Barbarian": "/assets/troops/barbarian/icon.webp"
|
|
258
|
+
|
|
259
|
+
for hero in player.heroes:
|
|
260
|
+
print(f"{hero.name}: {hero.asset_url}")
|
|
261
|
+
for eq in hero.equipment:
|
|
262
|
+
print(f" {eq.name}: {eq.asset_url}")
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Serve them with any framework:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
# aiohttp
|
|
269
|
+
from geniuslib.utils import get_assets_dir
|
|
270
|
+
app.router.add_static('/assets/', get_assets_dir())
|
|
271
|
+
|
|
272
|
+
# FastAPI
|
|
273
|
+
from starlette.staticfiles import StaticFiles
|
|
274
|
+
app.mount('/assets/', StaticFiles(directory=get_assets_dir()))
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### CLI
|
|
278
|
+
|
|
279
|
+
```sh
|
|
280
|
+
python -m geniuslib player #TAG
|
|
281
|
+
python -m geniuslib clan #TAG
|
|
282
|
+
python -m geniuslib war #TAG
|
|
283
|
+
python -m geniuslib raid #TAG
|
|
284
|
+
python -m geniuslib search "clan name"
|
|
285
|
+
python -m geniuslib export #TAG --format json
|
|
286
|
+
python -m geniuslib compare player #TAG1 #TAG2
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Utilities
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
from geniuslib.utils import encode_tag, decode_tag, get_season_id
|
|
293
|
+
from geniuslib.formatters import format_th, format_trophies, format_role
|
|
294
|
+
from geniuslib.exporter import to_json, to_csv
|
|
295
|
+
from geniuslib.comparer import compare_players, compare_clans
|
|
296
|
+
from geniuslib.upgrade_tracker import get_th_upgrade_summary
|
|
297
|
+
|
|
298
|
+
# Tag encoding
|
|
299
|
+
encode_tag("#2PP") # 256
|
|
300
|
+
|
|
301
|
+
# Season math
|
|
302
|
+
get_season_id() # "2026-07"
|
|
303
|
+
|
|
304
|
+
# Formatters
|
|
305
|
+
format_th(16) # "🔑 TH16"
|
|
306
|
+
format_trophies(5000) # "🏆 5,000"
|
|
307
|
+
|
|
308
|
+
# Upgrade cost estimation
|
|
309
|
+
summary = get_th_upgrade_summary(16)
|
|
310
|
+
print(f"Total time: {summary.total_time_days} days")
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Examples
|
|
316
|
+
|
|
317
|
+
The [`examples/`](https://github.com/AkumaHalls/GeniusLib/tree/main/examples) folder contains ready-to-run scripts:
|
|
318
|
+
|
|
319
|
+
| Example | Description |
|
|
320
|
+
|---------|-------------|
|
|
321
|
+
| [`discord_bot.py`](examples/discord_bot.py) | Full Discord bot with /player, /clan, /war, /raid commands + real-time events |
|
|
322
|
+
| [`war_analyzer.py`](examples/war_analyzer.py) | Detailed war performance report with top attackers, defense, cleanup |
|
|
323
|
+
| [`raid_reporter.py`](examples/raid_reporter.py) | Capital Raid report with offensive/defensive stats and inactive detection |
|
|
324
|
+
| [`export_data.py`](examples/export_data.py) | Export player/clan data to JSON or CSV |
|
|
325
|
+
| [`batch_fetch.py`](examples/batch_fetch.py) | Fetch multiple clans/players in parallel |
|
|
326
|
+
| [`web_dashboard.py`](examples/web_dashboard.py) | Minimal web dashboard with aiohttp |
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Documentation
|
|
331
|
+
|
|
332
|
+
Full documentation is available at **[geniuslib.readthedocs.io](https://geniuslib.readthedocs.io)**.
|
|
333
|
+
|
|
334
|
+
### Building docs locally
|
|
335
|
+
|
|
336
|
+
```sh
|
|
337
|
+
pip install mkdocs mkdocs-material mkdocstrings[python]
|
|
338
|
+
mkdocs serve
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Testing
|
|
344
|
+
|
|
345
|
+
```sh
|
|
346
|
+
pip install pytest pytest-asyncio
|
|
347
|
+
pytest tests/ -v
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
110 tests covering utils, war analytics, raid analytics, battle log analytics, formatters, middleware, exporters, and comparers.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Contributing
|
|
355
|
+
|
|
356
|
+
Contributions are welcome! Please:
|
|
357
|
+
|
|
358
|
+
1. Fork the repository
|
|
359
|
+
2. Create a feature branch (`git checkout -b feature/my-feature`)
|
|
360
|
+
3. Run tests (`pytest tests/ -v`)
|
|
361
|
+
4. Submit a pull request
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## License
|
|
366
|
+
|
|
367
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Credits
|
|
372
|
+
|
|
373
|
+
Built by [AkumaHalls](https://github.com/AkumaHalls) for the [ClashGenius](https://github.com/AkumaHalls/ClashGenius) project.
|
|
374
|
+
Based on the original [coc.py](https://github.com/mathsman5133/coc.py) by mathsman5133.
|
|
375
|
+
]]>
|