Skip to content

Commit e72a313

Browse files
authored
Merge pull request #238 from mathsman5133/3.5.4
Fixing broken docs & Adding manual ip overwrite
2 parents a477898 + e7a3528 commit e72a313

File tree

13 files changed

+61
-42
lines changed

13 files changed

+61
-42
lines changed

coc/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
SOFTWARE.
2323
"""
2424

25-
__version__ = "3.5.3"
25+
__version__ = "3.6.0"
2626

2727
from .abc import BasePlayer, BaseClan
2828
from .clans import RankedClan, Clan

coc/clans.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ def _from_data(self, data: dict) -> None:
248248

249249
@cached_property("_cs_labels")
250250
def labels(self) -> typing.List[Label]:
251-
"""List[:class:`Label`]: A :class:`List` of :class:`Label`s that the clan has."""
251+
"""List[:class:`Label`]: A :class:`List` of :class:`Label`\s that the clan has."""
252252
return list(self._iter_labels)
253253

254254
@cached_property("_cs_members")

coc/client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ class Client:
145145
base_url: :class:`str`
146146
The base URL to use for API requests. Defaults to "https://api.clashofclans.com/v1"
147147
148+
ip: :class:`str`
149+
The IP address to use for API requests. Defaults to None, which means the IP address will be automatically
150+
detected.
151+
148152
Attributes
149153
----------
150154
loop : :class:`asyncio.AbstractEventLoop`
@@ -153,6 +157,7 @@ class Client:
153157

154158
__slots__ = (
155159
"base_url",
160+
"ip",
156161
"loop",
157162
"correct_key_count",
158163
"key_names",
@@ -197,6 +202,7 @@ def __init__(
197202
realtime=False,
198203
raw_attribute=False,
199204
base_url: str = "https://api.clashofclans.com/v1",
205+
ip: Optional[str] = None,
200206
**kwargs,
201207
):
202208

@@ -222,6 +228,7 @@ def __init__(
222228
self.correct_tags = correct_tags
223229
self.load_game_data = load_game_data
224230
self.base_url = base_url
231+
self.ip = ip
225232
# cache
226233
self._players = {}
227234
self._clans = {}
@@ -247,6 +254,7 @@ def _create_client(self, email, password):
247254
cache_max_size=self.cache_max_size,
248255
stats_max_size=self.stats_max_size,
249256
base_url=self.base_url,
257+
ip=self.ip,
250258
)
251259

252260
def _load_holders(self):

coc/ext/triggers/triggers.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ class IntervalTrigger(BaseTrigger):
214214
error_handler: Optional[:class:`coc.ext.triggers.CoroFunction`]
215215
an optional coroutine function that will be called on each error incurred during the trigger execution.
216216
The handler will receive three arguments:
217+
217218
function_name: :class:`str`
218219
the name of the failing trigger's decorated function
219220
arg: Optional[:class:`Any`]
@@ -320,6 +321,7 @@ class CronTrigger(BaseTrigger):
320321
error_handler: Optional[:class:`coc.ext.triggers.CoroFunction`]
321322
an optional coroutine function that will be called on each error incurred during the trigger execution.
322323
The handler will receive three arguments:
324+
323325
function_name: :class:`str`
324326
the name of the failing trigger's decorated function
325327
arg: Optional[:class:`Any`]
@@ -340,12 +342,13 @@ class CronTrigger(BaseTrigger):
340342
341343
342344
Example
343-
----------
345+
-------
346+
344347
.. code-block:: python3
345348
346349
@CronTrigger(cron_schedule='0 0 * * *', iter_args=['#2PP', '#2PPP'])
347350
async def download_current_war(clan_tag: str):
348-
# use your coc client to fetch war data, store it to a file or database, ...
351+
# use your coc client to fetch war data, store it to a file or database,
349352
pass
350353
351354
"""

coc/http.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ def __init__(
200200
cache_max_size=10000,
201201
stats_max_size=1000,
202202
base_url="https://api.clashofclans.com/v1",
203+
ip=None,
203204
):
204205
self.client = client
205206
self.loop = loop
@@ -222,6 +223,7 @@ def __init__(
222223
self.base_url = base_url
223224
else:
224225
raise ValueError("base_url must be a string and not empty.")
226+
self.ip = ip
225227
if issubclass(throttler, BasicThrottler):
226228
self.__throttle = throttler(1 / per_second)
227229
elif issubclass(throttler, BatchThrottler):
@@ -507,8 +509,10 @@ async def initialise_keys(self):
507509
LOG.info("Successfully logged into the developer site.")
508510

509511
resp_payload = await resp.json()
510-
ip = json_loads(base64_b64decode(resp_payload["temporaryAPIToken"].split(".")[1] + "====").decode("utf-8"))["limits"][1]["cidrs"][0].split("/")[0]
511-
512+
if not self.ip:
513+
ip = json_loads(base64_b64decode(resp_payload["temporaryAPIToken"].split(".")[1] + "====").decode("utf-8"))["limits"][1]["cidrs"][0].split("/")[0]
514+
else:
515+
ip = self.ip
512516
LOG.info("Found IP address to be %s", ip)
513517

514518
resp = await session.post("https://developer.clashofclans.com/api/apikey/list")

coc/miscmodels.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ class Badge:
390390
:class:`str` - URL for a large sized badge (512x512).
391391
"""
392392

393-
__slots__ = ("small", "medium", "large", "url", "_client")
393+
__slots__ = ("small", "medium", "large", "_client")
394394

395395
def __repr__(self):
396396
attrs = [
@@ -459,7 +459,7 @@ class Icon:
459459
:class:`str`: URL for a medium sized icon (288x288).
460460
"""
461461

462-
__slots__ = ("small", "medium", "tiny", "url", "_client")
462+
__slots__ = ("small", "medium", "tiny", "_client")
463463

464464
def __repr__(self):
465465
attrs = [

coc/players.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,13 @@ async def get_detailed_clan(self) -> Optional["Clan"]:
172172

173173
@cached_property("_cs_player_house_elements")
174174
def player_house_elements(self) -> List[PlayerHouseElement]:
175-
"""List[:class:`PlayerHouseElement`]: A :class:`List` of :class:`PlayerHouseElement`s that the player has."""
175+
"""List[:class:`PlayerHouseElement`]: A :class:`List` of :class:`PlayerHouseElement`\s that the player has."""
176176
return list(self._iter_player_house_elements)
177177

178178

179179
class RankedPlayer(ClanMember):
180-
"""Represents a leaderboard-ranked player.
180+
"""
181+
Represents a leaderboard-ranked player.
181182
182183
Attributes
183184
----------
@@ -209,7 +210,8 @@ def _from_data(self, data: dict) -> None:
209210

210211

211212
class Player(ClanMember):
212-
"""Represents a Clash of Clans Player.
213+
"""
214+
Represents a Clash of Clans Player.
213215
214216
Attributes
215217
----------
@@ -247,8 +249,6 @@ class Player(ClanMember):
247249
war_opted_in: Optional[:class:`bool`]
248250
Whether the player has selected that they are opted "in" (True) for wars, or opted "out" (False).
249251
This will be ``None`` if the player is not in a clan.
250-
equipment: List[:class:`Equipment`]
251-
The player's unlocked hero equipment
252252
"""
253253

254254
__slots__ = (
@@ -362,7 +362,7 @@ def _from_data(self, data: dict) -> None:
362362
label_cls = self.label_cls
363363
achievement_cls = self.achievement_cls
364364
troop_loader = self._client._troop_holder.load if self._client else None
365-
hero_loader = self._client._hero_holder.load if self._client else None
365+
hero_loader = self._client._hero_holder.load if self._client else None
366366
spell_loader = self._client._spell_holder.load if self._client else None
367367
pet_loader = self._client._pet_holder.load if self._client else None
368368
equipment_loader = self._client._equipment_holder.load if self._client else None
@@ -462,7 +462,7 @@ def load_game_data(self):
462462

463463
@cached_property("_cs_labels")
464464
def labels(self) -> List[Label]:
465-
"""List[:class:`Label`]: A :class:`List` of :class:`Label`s that the player has."""
465+
"""List[:class:`Label`]: A :class:`List` of :class:`Label`\s that the player has."""
466466
return list(self._iter_labels)
467467

468468
@cached_property("_cs_achievements")
@@ -547,7 +547,7 @@ def troops(self) -> List[Troop]:
547547
def home_troops(self) -> List[Troop]:
548548
"""List[:class:`Troop`]: A :class:`List` of the player's home-base :class:`Troop`.
549549
550-
This will return troops in the order found in both barracks and labatory in-game.
550+
This will return troops in the order found in both barracks and laboratory in-game.
551551
552552
This includes:
553553
- Elixir Troops (Barbarian, Balloon, etc.)
@@ -566,7 +566,7 @@ def home_troops(self) -> List[Troop]:
566566
def builder_troops(self) -> List[Troop]:
567567
"""List[:class:`Troop`]: A :class:`List` of the player's builder-base :class:`Troop`.
568568
569-
This will return troops in the order found in both barracks and labatory in-game.
569+
This will return troops in the order found in both barracks and laboratory in-game.
570570
571571
This includes:
572572
- Builder troops
@@ -582,7 +582,7 @@ def builder_troops(self) -> List[Troop]:
582582
def siege_machines(self) -> List[Troop]:
583583
"""List[:class:`Troop`]: A :class:`List` of the player's siege-machine :class:`Troop`.
584584
585-
This will return siege machines in the order found in both barracks and labatory in-game.
585+
This will return siege machines in the order found in both barracks and laboratory in-game.
586586
587587
This includes:
588588
- Siege machines only.
@@ -699,7 +699,7 @@ def get_troop(self, name: str, is_home_troop=None, default_value=None) -> Option
699699
Returns
700700
--------
701701
Optional[:class:`Troop`]
702-
The returned troop or the ``default_value`` if not found, which defaults to ``None``..
702+
The returned troop or the ``default_value`` if not found, which defaults to ``None``.
703703
"""
704704
_ = self.troops
705705

@@ -721,7 +721,7 @@ def get_troop(self, name: str, is_home_troop=None, default_value=None) -> Option
721721
def heroes(self) -> List[Hero]:
722722
"""List[:class:`Hero`]: A :class:`List` of the player's :class:`Hero`.
723723
724-
This will return heroes in the order found in the store and labatory in-game.
724+
This will return heroes in the order found in the store and laboratory in-game.
725725
"""
726726
heroes_dict = {h.name: h for h in self._iter_heroes}
727727
sorted_heroes = {}
@@ -763,15 +763,15 @@ def get_hero(self, name: str, default_value=None) -> Optional[Hero]:
763763
def spells(self) -> List[Spell]:
764764
"""List[:class:`Spell`]: A :class:`List` of the player's :class:`Spell` ordered as they appear in-game.
765765
766-
This will return spells in the order found in both spell factory and labatory in-game.
766+
This will return spells in the order found in both spell factory and laboratory in-game.
767767
"""
768768
self._spells = {s.name: s for s in self._iter_spells}
769769
dict_spells = self._spells
770770
order = {k: v for v, k in enumerate(SPELL_ORDER)}
771771

772772
return list(sorted(
773-
dict_spells.values(),
774-
key=lambda s: order.get(s.name, 0)))
773+
dict_spells.values(),
774+
key=lambda s: order.get(s.name, 0)))
775775

776776
def get_spell(self, name: str, default_value=None) -> Optional[Spell]:
777777
"""Gets the spell with the given name.
@@ -786,7 +786,7 @@ def get_spell(self, name: str, default_value=None) -> Optional[Spell]:
786786
Returns
787787
--------
788788
Optional[:class:`Spell`]
789-
The returned spell or the ``default_value`` if not found, which defaults to ``None``..
789+
The returned spell or the ``default_value`` if not found, which defaults to ``None``.
790790
"""
791791
if not self._spells:
792792
_ = self.spells

docs/client/logging_in.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ Logging In
44
==========
55
A coc.py client instance can be created directly by :class:`Client`. The instance can then be logged in with the methods
66

7-
.. autofunction:: coc.Client.login
7+
.. automethod:: coc.Client.login
8+
:noindex:
89

9-
.. autofunction:: coc.Client.login_with_tokens
10+
.. automethod:: coc.Client.login_with_tokens
11+
:noindex:
1012

1113

1214
Example

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
project = 'coc'
1616
copyright = '2022, mathsman5133'
1717
author = 'mathsman5133'
18-
release = '3.5.3'
18+
release = '3.6.0'
1919

2020
# -- General configuration ---------------------------------------------------
2121
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

docs/miscellaneous/changelog.rst

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,24 @@ Changelog
77
This page keeps a fairly detailed, human readable version
88
of what has changed, and whats new for each version of the lib.
99

10-
v3.5.3
10+
v3.6.0
1111
------
1212

1313
Bugs Fixed:
14+
~~~~~~~~~~~
15+
- Issues causing the documentation to not build properly have been fixed.
16+
- Fixed a few spelling errors in the documentation.
17+
18+
Additions:
1419
~~~~~~~~~~
20+
- Added :attr:`coc.Client.ip` to manually overwrite the IP address used for generating API keys. This is especially useful
21+
for using the API with a proxy.
22+
23+
v3.5.3
24+
------
25+
26+
Bugs Fixed:
27+
~~~~~~~~~~~
1528
- :attr:`coc.Badge.url` and :attr:`coc.Icon.url` now use differently sized fallbacks if the default URL is not
1629
available. The same is true if :func:`coc.Badge.save` or :func:`coc.Icon.save` are called without the optional
1730
size parameter
@@ -158,7 +171,7 @@ Additions:
158171
- Added optional cls parameters to all the :func:`coc.Client.get_location_...` methods
159172
in order to allow the usage of custom classes
160173

161-
- Added the :ref:`triggers`
174+
- Added the :ref:`triggers_extension` as an extension
162175

163176
- Added some cached properties to raid classes: :func:`coc.RaidClan.looted`,
164177
:func:`coc.RaidLogEntry.total_defensive_loot`, :func:`coc.RaidLogEntry.defense_attack_count`

0 commit comments

Comments
 (0)