geniuslib 5.5.0__py3-none-any.whl
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/__init__.py +186 -0
- geniuslib/__main__.py +8 -0
- geniuslib/abc.py +274 -0
- geniuslib/battlelog.py +458 -0
- geniuslib/battlelog_analytics.py +672 -0
- geniuslib/buildings.py +510 -0
- geniuslib/characters.py +144 -0
- geniuslib/clans.py +289 -0
- geniuslib/cli.py +239 -0
- geniuslib/client.py +2924 -0
- geniuslib/comparer.py +122 -0
- geniuslib/constants.py +331 -0
- geniuslib/cosmetics.py +198 -0
- geniuslib/entry_logs.py +260 -0
- geniuslib/enums.py +186 -0
- geniuslib/errors.py +139 -0
- geniuslib/events.py +1153 -0
- geniuslib/events.pyi +232 -0
- geniuslib/exporter.py +248 -0
- geniuslib/ext/discordlinks/__init__.py +279 -0
- geniuslib/ext/triggers/__init__.py +15 -0
- geniuslib/ext/triggers/cron.py +215 -0
- geniuslib/ext/triggers/triggers.py +503 -0
- geniuslib/formatters.py +151 -0
- geniuslib/game_data.py +687 -0
- geniuslib/hero.py +414 -0
- geniuslib/http.py +707 -0
- geniuslib/iterators.py +217 -0
- geniuslib/middleware.py +197 -0
- geniuslib/miscmodels.py +918 -0
- geniuslib/player_clan.py +41 -0
- geniuslib/players.py +758 -0
- geniuslib/raid.py +502 -0
- geniuslib/raid_analytics.py +130 -0
- geniuslib/spell.py +126 -0
- geniuslib/static/__init__.py +0 -0
- geniuslib/static/static_data.json +63983 -0
- geniuslib/static/update_static.py +1481 -0
- geniuslib/troop.py +192 -0
- geniuslib/upgrade_tracker.py +510 -0
- geniuslib/utils.py +856 -0
- geniuslib/war_analytics.py +218 -0
- geniuslib/war_attack.py +105 -0
- geniuslib/war_clans.py +199 -0
- geniuslib/war_members.py +143 -0
- geniuslib/wars.py +538 -0
- geniuslib-5.5.0.dist-info/METADATA +375 -0
- geniuslib-5.5.0.dist-info/RECORD +51 -0
- geniuslib-5.5.0.dist-info/WHEEL +5 -0
- geniuslib-5.5.0.dist-info/licenses/LICENSE +21 -0
- geniuslib-5.5.0.dist-info/top_level.txt +1 -0
geniuslib/battlelog.py
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
# GeniusLib - Clash of Clans API wrapper
|
|
2
|
+
# Based on coc.py (MIT License, copyright (c) 2019-2020 mathsman5133)
|
|
3
|
+
# (c) 2026 AkumaHalls / ClashGenius
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import List, Optional, TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from .utils import from_timestamp
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .client import Client
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BattleLogResource:
|
|
17
|
+
"""Represents a resource amount in a player battle log entry.
|
|
18
|
+
|
|
19
|
+
Attributes
|
|
20
|
+
----------
|
|
21
|
+
name:
|
|
22
|
+
:class:`str`: The resource name (e.g. ``gold``, ``elixir``, ``darkElixir``).
|
|
23
|
+
amount:
|
|
24
|
+
:class:`int`: The amount of this resource.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
__slots__ = ("name", "amount")
|
|
28
|
+
|
|
29
|
+
def __init__(self, *, data):
|
|
30
|
+
self._from_data(data)
|
|
31
|
+
|
|
32
|
+
def _from_data(self, data: dict) -> None:
|
|
33
|
+
self.name: str = data.get("name")
|
|
34
|
+
self.amount: int = data.get("amount")
|
|
35
|
+
|
|
36
|
+
def __repr__(self):
|
|
37
|
+
attrs = [("name", self.name), ("amount", self.amount)]
|
|
38
|
+
return "<%s %s>" % (self.__class__.__name__, " ".join("%s=%r" % t for t in attrs),)
|
|
39
|
+
|
|
40
|
+
def __eq__(self, other):
|
|
41
|
+
return isinstance(other, self.__class__) and self.name == other.name and self.amount == other.amount
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class BattleLogEntry:
|
|
45
|
+
"""Represents a single player battle log entry from the ``/players/{tag}/battlelog`` endpoint.
|
|
46
|
+
|
|
47
|
+
Attributes
|
|
48
|
+
----------
|
|
49
|
+
battle_type:
|
|
50
|
+
:class:`str`: The type of battle (e.g. ``legendLeague``).
|
|
51
|
+
attack:
|
|
52
|
+
:class:`bool`: ``True`` if this was an attack, ``False`` if a defense.
|
|
53
|
+
timestamp:
|
|
54
|
+
Optional[:class:`datetime`]: When the battle occurred.
|
|
55
|
+
army_share_code:
|
|
56
|
+
:class:`str`: Code to share the army composition used.
|
|
57
|
+
opponent_player_tag:
|
|
58
|
+
:class:`str`: The tag of the opponent player.
|
|
59
|
+
stars:
|
|
60
|
+
:class:`int`: Stars earned in this battle.
|
|
61
|
+
destruction_percentage:
|
|
62
|
+
:class:`int`: Destruction percentage achieved.
|
|
63
|
+
looted_resources:
|
|
64
|
+
List[:class:`BattleLogResource`]: Resources looted.
|
|
65
|
+
extra_looted_resources:
|
|
66
|
+
List[:class:`BattleLogResource`]: Bonus resources looted.
|
|
67
|
+
available_loot:
|
|
68
|
+
List[:class:`BattleLogResource`]: Resources available to loot before the battle.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
__slots__ = (
|
|
72
|
+
"battle_type",
|
|
73
|
+
"attack",
|
|
74
|
+
"timestamp",
|
|
75
|
+
"army_share_code",
|
|
76
|
+
"opponent_player_tag",
|
|
77
|
+
"stars",
|
|
78
|
+
"destruction_percentage",
|
|
79
|
+
"looted_resources",
|
|
80
|
+
"extra_looted_resources",
|
|
81
|
+
"available_loot",
|
|
82
|
+
"_client",
|
|
83
|
+
"_response_retry",
|
|
84
|
+
"_raw_data",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def __init__(self, *, data, client: Optional[Client] = None, **_):
|
|
88
|
+
self._client = client
|
|
89
|
+
self._response_retry = data.get("_response_retry")
|
|
90
|
+
self._raw_data = data if client and client.raw_attribute else None
|
|
91
|
+
self._from_data(data)
|
|
92
|
+
|
|
93
|
+
def _from_data(self, data: dict) -> None:
|
|
94
|
+
data_get = data.get
|
|
95
|
+
self.battle_type: str = data_get("battleType")
|
|
96
|
+
self.attack: bool = data_get("attack")
|
|
97
|
+
raw_ts = data_get("timestamp")
|
|
98
|
+
self.timestamp: Optional[datetime] = from_timestamp(raw_ts) if raw_ts else None
|
|
99
|
+
self.army_share_code: str = data_get("armyShareCode")
|
|
100
|
+
self.opponent_player_tag: str = data_get("opponentPlayerTag")
|
|
101
|
+
self.stars: int = data_get("stars")
|
|
102
|
+
self.destruction_percentage: int = data_get("destructionPercentage")
|
|
103
|
+
self.looted_resources: List[BattleLogResource] = [
|
|
104
|
+
BattleLogResource(data=item) for item in data_get("lootedResources", [])
|
|
105
|
+
]
|
|
106
|
+
self.extra_looted_resources: List[BattleLogResource] = [
|
|
107
|
+
BattleLogResource(data=item) for item in data_get("extraLootedResources", [])
|
|
108
|
+
]
|
|
109
|
+
self.available_loot: List[BattleLogResource] = [
|
|
110
|
+
BattleLogResource(data=item) for item in data_get("availableLoot", [])
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
def __repr__(self):
|
|
114
|
+
attrs = [
|
|
115
|
+
("battle_type", self.battle_type),
|
|
116
|
+
("attack", self.attack),
|
|
117
|
+
("stars", self.stars),
|
|
118
|
+
("destruction_percentage", self.destruction_percentage),
|
|
119
|
+
("opponent", self.opponent_player_tag),
|
|
120
|
+
]
|
|
121
|
+
return "<%s %s>" % (self.__class__.__name__, " ".join("%s=%r" % t for t in attrs),)
|
|
122
|
+
|
|
123
|
+
def __eq__(self, other):
|
|
124
|
+
if not isinstance(other, self.__class__):
|
|
125
|
+
return False
|
|
126
|
+
return (
|
|
127
|
+
self.opponent_player_tag == other.opponent_player_tag
|
|
128
|
+
and self.timestamp == other.timestamp
|
|
129
|
+
and self.attack == other.attack
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def is_attack(self) -> bool:
|
|
134
|
+
""":class:`bool`: Returns ``True`` if this entry is an attack."""
|
|
135
|
+
return self.attack is True
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def is_defense(self) -> bool:
|
|
139
|
+
""":class:`bool`: Returns ``True`` if this entry is a defense."""
|
|
140
|
+
return self.attack is False
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def total_looted(self) -> int:
|
|
144
|
+
""":class:`int`: Total resources looted across all resource types."""
|
|
145
|
+
return sum(r.amount for r in self.looted_resources)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def total_available(self) -> int:
|
|
149
|
+
""":class:`int`: Total resources available before the battle."""
|
|
150
|
+
return sum(r.amount for r in self.available_loot)
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def loot_efficiency(self) -> float:
|
|
154
|
+
""":class:`float`: Percentage of available loot that was actually looted."""
|
|
155
|
+
available = self.total_available
|
|
156
|
+
if available == 0:
|
|
157
|
+
return 0.0
|
|
158
|
+
return (self.total_looted / available) * 100.0
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class LeagueHistoryEntry:
|
|
162
|
+
"""Represents a player league season history entry from the ``/players/{tag}/leaguehistory`` endpoint.
|
|
163
|
+
|
|
164
|
+
Attributes
|
|
165
|
+
----------
|
|
166
|
+
league_season_id:
|
|
167
|
+
:class:`int`: The league season identifier.
|
|
168
|
+
league_trophies:
|
|
169
|
+
:class:`int`: Trophies earned in this season.
|
|
170
|
+
league_tier_id:
|
|
171
|
+
:class:`int`: The league tier ID.
|
|
172
|
+
placement:
|
|
173
|
+
:class:`int`: Global or local ranking placement.
|
|
174
|
+
attack_wins:
|
|
175
|
+
:class:`int`: Number of attack wins.
|
|
176
|
+
attack_losses:
|
|
177
|
+
:class:`int`: Number of attack losses.
|
|
178
|
+
attack_stars:
|
|
179
|
+
:class:`int`: Total stars earned from attacks.
|
|
180
|
+
defense_wins:
|
|
181
|
+
:class:`int`: Number of defense wins.
|
|
182
|
+
defense_losses:
|
|
183
|
+
:class:`int`: Number of defense losses.
|
|
184
|
+
defense_stars:
|
|
185
|
+
:class:`int`: Total stars conceded from defenses.
|
|
186
|
+
max_battles:
|
|
187
|
+
:class:`int`: Maximum battles available this season.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
__slots__ = (
|
|
191
|
+
"league_season_id",
|
|
192
|
+
"league_trophies",
|
|
193
|
+
"league_tier_id",
|
|
194
|
+
"placement",
|
|
195
|
+
"attack_wins",
|
|
196
|
+
"attack_losses",
|
|
197
|
+
"attack_stars",
|
|
198
|
+
"defense_wins",
|
|
199
|
+
"defense_losses",
|
|
200
|
+
"defense_stars",
|
|
201
|
+
"max_battles",
|
|
202
|
+
"_client",
|
|
203
|
+
"_response_retry",
|
|
204
|
+
"_raw_data",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def __init__(self, *, data, client: Optional[Client] = None, **_):
|
|
208
|
+
self._client = client
|
|
209
|
+
self._response_retry = data.get("_response_retry")
|
|
210
|
+
self._raw_data = data if client and client.raw_attribute else None
|
|
211
|
+
self._from_data(data)
|
|
212
|
+
|
|
213
|
+
def _from_data(self, data: dict) -> None:
|
|
214
|
+
data_get = data.get
|
|
215
|
+
self.league_season_id: int = data_get("leagueSeasonId")
|
|
216
|
+
self.league_trophies: int = data_get("leagueTrophies")
|
|
217
|
+
self.league_tier_id: int = data_get("leagueTierId")
|
|
218
|
+
self.placement: int = data_get("placement")
|
|
219
|
+
self.attack_wins: int = data_get("attackWins")
|
|
220
|
+
self.attack_losses: int = data_get("attackLosses")
|
|
221
|
+
self.attack_stars: int = data_get("attackStars")
|
|
222
|
+
self.defense_wins: int = data_get("defenseWins")
|
|
223
|
+
self.defense_losses: int = data_get("defenseLosses")
|
|
224
|
+
self.defense_stars: int = data_get("defenseStars")
|
|
225
|
+
self.max_battles: int = data_get("maxBattles")
|
|
226
|
+
|
|
227
|
+
def __repr__(self):
|
|
228
|
+
attrs = [
|
|
229
|
+
("season", self.league_season_id),
|
|
230
|
+
("trophies", self.league_trophies),
|
|
231
|
+
("tier", self.league_tier_id),
|
|
232
|
+
("placement", self.placement),
|
|
233
|
+
]
|
|
234
|
+
return "<%s %s>" % (self.__class__.__name__, " ".join("%s=%r" % t for t in attrs),)
|
|
235
|
+
|
|
236
|
+
def __eq__(self, other):
|
|
237
|
+
return isinstance(other, self.__class__) and self.league_season_id == other.league_season_id
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def total_attacks(self) -> int:
|
|
241
|
+
""":class:`int`: Total attacks performed (wins + losses)."""
|
|
242
|
+
return self.attack_wins + self.attack_losses
|
|
243
|
+
|
|
244
|
+
@property
|
|
245
|
+
def total_defenses(self) -> int:
|
|
246
|
+
""":class:`int`: Total defenses received (wins + losses)."""
|
|
247
|
+
return self.defense_wins + self.defense_losses
|
|
248
|
+
|
|
249
|
+
@property
|
|
250
|
+
def attack_win_rate(self) -> float:
|
|
251
|
+
""":class:`float`: Attack win rate as a percentage (0-100)."""
|
|
252
|
+
total = self.total_attacks
|
|
253
|
+
if total == 0:
|
|
254
|
+
return 0.0
|
|
255
|
+
return (self.attack_wins / total) * 100.0
|
|
256
|
+
|
|
257
|
+
@property
|
|
258
|
+
def defense_win_rate(self) -> float:
|
|
259
|
+
""":class:`float`: Defense win rate as a percentage (0-100)."""
|
|
260
|
+
total = self.total_defenses
|
|
261
|
+
if total == 0:
|
|
262
|
+
return 0.0
|
|
263
|
+
return (self.defense_wins / total) * 100.0
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class LeagueTierGroupBattleLogEntry:
|
|
267
|
+
"""Represents an attack or defense log entry inside a league tier group.
|
|
268
|
+
|
|
269
|
+
Attributes
|
|
270
|
+
----------
|
|
271
|
+
opponent_player_tag:
|
|
272
|
+
:class:`str`: The tag of the opponent.
|
|
273
|
+
opponent_name:
|
|
274
|
+
:class:`str`: The name of the opponent.
|
|
275
|
+
stars:
|
|
276
|
+
:class:`int`: Stars earned or conceded.
|
|
277
|
+
destruction_percentage:
|
|
278
|
+
:class:`int`: Destruction percentage.
|
|
279
|
+
trophies:
|
|
280
|
+
:class:`int`: Trophies gained or lost.
|
|
281
|
+
creation_time:
|
|
282
|
+
Optional[:class:`datetime`]: When the battle occurred.
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
__slots__ = (
|
|
286
|
+
"opponent_player_tag",
|
|
287
|
+
"opponent_name",
|
|
288
|
+
"stars",
|
|
289
|
+
"destruction_percentage",
|
|
290
|
+
"trophies",
|
|
291
|
+
"creation_time",
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
def __init__(self, *, data):
|
|
295
|
+
self._from_data(data)
|
|
296
|
+
|
|
297
|
+
def _from_data(self, data: dict) -> None:
|
|
298
|
+
data_get = data.get
|
|
299
|
+
self.opponent_player_tag: str = data_get("opponentPlayerTag")
|
|
300
|
+
self.opponent_name: str = data_get("opponentName")
|
|
301
|
+
self.stars: int = data_get("stars")
|
|
302
|
+
self.destruction_percentage: int = data_get("destructionPercentage")
|
|
303
|
+
self.trophies: int = data_get("trophies")
|
|
304
|
+
raw_time = data_get("creationTime")
|
|
305
|
+
self.creation_time: Optional[datetime] = from_timestamp(raw_time) if raw_time else None
|
|
306
|
+
|
|
307
|
+
def __repr__(self):
|
|
308
|
+
attrs = [
|
|
309
|
+
("opponent", self.opponent_name),
|
|
310
|
+
("stars", self.stars),
|
|
311
|
+
("trophies", self.trophies),
|
|
312
|
+
]
|
|
313
|
+
return "<%s %s>" % (self.__class__.__name__, " ".join("%s=%r" % t for t in attrs),)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
class LeagueTierGroupMember:
|
|
317
|
+
"""Represents a member inside a league tier group.
|
|
318
|
+
|
|
319
|
+
Attributes
|
|
320
|
+
----------
|
|
321
|
+
player_tag:
|
|
322
|
+
:class:`str`: The player's tag.
|
|
323
|
+
player_name:
|
|
324
|
+
:class:`str`: The player's name.
|
|
325
|
+
clan_tag:
|
|
326
|
+
:class:`str`: The player's clan tag.
|
|
327
|
+
clan_name:
|
|
328
|
+
:class:`str`: The player's clan name.
|
|
329
|
+
league_trophies:
|
|
330
|
+
:class:`int`: Current league trophies.
|
|
331
|
+
attack_win_count:
|
|
332
|
+
:class:`int`: Number of attack wins in this group.
|
|
333
|
+
attack_lose_count:
|
|
334
|
+
:class:`int`: Number of attack losses in this group.
|
|
335
|
+
defense_win_count:
|
|
336
|
+
:class:`int`: Number of defense wins in this group.
|
|
337
|
+
defense_lose_count:
|
|
338
|
+
:class:`int`: Number of defense losses in this group.
|
|
339
|
+
"""
|
|
340
|
+
|
|
341
|
+
__slots__ = (
|
|
342
|
+
"player_tag",
|
|
343
|
+
"player_name",
|
|
344
|
+
"clan_tag",
|
|
345
|
+
"clan_name",
|
|
346
|
+
"league_trophies",
|
|
347
|
+
"attack_win_count",
|
|
348
|
+
"attack_lose_count",
|
|
349
|
+
"defense_win_count",
|
|
350
|
+
"defense_lose_count",
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
def __init__(self, *, data):
|
|
354
|
+
self._from_data(data)
|
|
355
|
+
|
|
356
|
+
def _from_data(self, data: dict) -> None:
|
|
357
|
+
data_get = data.get
|
|
358
|
+
self.player_tag: str = data_get("playerTag")
|
|
359
|
+
self.player_name: str = data_get("playerName")
|
|
360
|
+
self.clan_tag: str = data_get("clanTag")
|
|
361
|
+
self.clan_name: str = data_get("clanName")
|
|
362
|
+
self.league_trophies: int = data_get("leagueTrophies")
|
|
363
|
+
self.attack_win_count: int = data_get("attackWinCount")
|
|
364
|
+
self.attack_lose_count: int = data_get("attackLoseCount")
|
|
365
|
+
self.defense_win_count: int = data_get("defenseWinCount")
|
|
366
|
+
self.defense_lose_count: int = data_get("defenseLoseCount")
|
|
367
|
+
|
|
368
|
+
def __repr__(self):
|
|
369
|
+
attrs = [
|
|
370
|
+
("name", self.player_name),
|
|
371
|
+
("clan", self.clan_name),
|
|
372
|
+
("trophies", self.league_trophies),
|
|
373
|
+
]
|
|
374
|
+
return "<%s %s>" % (self.__class__.__name__, " ".join("%s=%r" % t for t in attrs),)
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def total_attacks(self) -> int:
|
|
378
|
+
""":class:`int`: Total attacks (wins + losses)."""
|
|
379
|
+
return self.attack_win_count + self.attack_lose_count
|
|
380
|
+
|
|
381
|
+
@property
|
|
382
|
+
def total_defenses(self) -> int:
|
|
383
|
+
""":class:`int`: Total defenses (wins + losses)."""
|
|
384
|
+
return self.defense_win_count + self.defense_lose_count
|
|
385
|
+
|
|
386
|
+
@property
|
|
387
|
+
def attack_win_rate(self) -> float:
|
|
388
|
+
""":class:`float`: Attack win rate as a percentage (0-100)."""
|
|
389
|
+
total = self.total_attacks
|
|
390
|
+
if total == 0:
|
|
391
|
+
return 0.0
|
|
392
|
+
return (self.attack_win_count / total) * 100.0
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
class LeagueTierGroup:
|
|
396
|
+
"""Represents a league tier group for a league season from the ``/leaguegroup/{tag}/{seasonId}`` endpoint.
|
|
397
|
+
|
|
398
|
+
Attributes
|
|
399
|
+
----------
|
|
400
|
+
members:
|
|
401
|
+
List[:class:`LeagueTierGroupMember`]: All members in the group.
|
|
402
|
+
attack_logs:
|
|
403
|
+
List[:class:`LeagueTierGroupBattleLogEntry`]: Detailed attack history.
|
|
404
|
+
defense_logs:
|
|
405
|
+
List[:class:`LeagueTierGroupBattleLogEntry`]: Detailed defense history.
|
|
406
|
+
"""
|
|
407
|
+
|
|
408
|
+
__slots__ = (
|
|
409
|
+
"members",
|
|
410
|
+
"attack_logs",
|
|
411
|
+
"defense_logs",
|
|
412
|
+
"_client",
|
|
413
|
+
"_response_retry",
|
|
414
|
+
"_raw_data",
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
def __init__(self, *, data, client: Optional[Client] = None, **_):
|
|
418
|
+
self._client = client
|
|
419
|
+
self._response_retry = data.get("_response_retry")
|
|
420
|
+
self._raw_data = data if client and client.raw_attribute else None
|
|
421
|
+
self._from_data(data)
|
|
422
|
+
|
|
423
|
+
def _from_data(self, data: dict) -> None:
|
|
424
|
+
self.members: List[LeagueTierGroupMember] = [
|
|
425
|
+
LeagueTierGroupMember(data=item) for item in data.get("members", [])
|
|
426
|
+
]
|
|
427
|
+
self.attack_logs: List[LeagueTierGroupBattleLogEntry] = [
|
|
428
|
+
LeagueTierGroupBattleLogEntry(data=item) for item in data.get("attackLogs", [])
|
|
429
|
+
]
|
|
430
|
+
self.defense_logs: List[LeagueTierGroupBattleLogEntry] = [
|
|
431
|
+
LeagueTierGroupBattleLogEntry(data=item) for item in data.get("defenseLogs", [])
|
|
432
|
+
]
|
|
433
|
+
|
|
434
|
+
def __repr__(self):
|
|
435
|
+
attrs = [
|
|
436
|
+
("members", len(self.members)),
|
|
437
|
+
("attacks", len(self.attack_logs)),
|
|
438
|
+
("defenses", len(self.defense_logs)),
|
|
439
|
+
]
|
|
440
|
+
return "<%s %s>" % (self.__class__.__name__, " ".join("%s=%r" % t for t in attrs),)
|
|
441
|
+
|
|
442
|
+
def get_member(self, tag: str) -> Optional[LeagueTierGroupMember]:
|
|
443
|
+
"""Find a member by their player tag.
|
|
444
|
+
|
|
445
|
+
Parameters
|
|
446
|
+
----------
|
|
447
|
+
tag:
|
|
448
|
+
:class:`str`: The player tag to search for.
|
|
449
|
+
|
|
450
|
+
Returns
|
|
451
|
+
-------
|
|
452
|
+
Optional[:class:`LeagueTierGroupMember`]
|
|
453
|
+
The member, or ``None`` if not found.
|
|
454
|
+
"""
|
|
455
|
+
for member in self.members:
|
|
456
|
+
if member.player_tag == tag:
|
|
457
|
+
return member
|
|
458
|
+
return None
|