From 93bd973cfff625dab7432f9180d22d964ba1c7fe Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 06:54:38 -0600 Subject: [PATCH 1/9] fix: duplicated **kwarg values --- coc/client.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/coc/client.py b/coc/client.py index 56af5408..a001092c 100644 --- a/coc/client.py +++ b/coc/client.py @@ -26,6 +26,7 @@ from enum import Enum from itertools import cycle +from functools import wraps from pathlib import Path from typing import AsyncIterator, Iterable, List, Optional, Type, Union, TYPE_CHECKING @@ -76,6 +77,14 @@ class ClashAccountScopes(Enum): USER = "clash" REAL = "clash:*:verifytoken,realtime" +def with_defaults(): + def decorator(func): + @wraps(func) + async def wrapper(self, *args, **kwargs): + merged_kwargs = {**self._defaults, **kwargs} + return await func(self, *args, **merged_kwargs) + return wrapper + return decorator class Client: """This is the client connection used to interact with the Clash of Clans API. @@ -198,6 +207,7 @@ class Client: "load_game_data", "lookup_cache", "update_cache", + "_defaults", "ignore_cached_errors", "_players", "_clans", @@ -253,6 +263,11 @@ def __init__( self.lookup_cache = lookup_cache self.update_cache = update_cache self.ignore_cached_errors = ignore_cached_errors + self._defaults = { + "lookup_cache": self.lookup_cache, + "update_cache": self.update_cache, + "ignore_cached_errors": self.ignore_cached_errors, + } self.http: Optional[HTTPClient] = None # set in method login() self.realtime = realtime @@ -320,7 +335,6 @@ class must be a subclass of the corresponding default class type. raise TypeError(f"The cls {cls} must be a subclass of {default_cls[name]}") self.objects_cls[name] = cls - def _create_client(self, email, password): return HTTPClient( client=self, @@ -465,6 +479,7 @@ def dispatch(self, event_name: str, *args, **kwargs) -> None: else: fctn(*args, **kwargs) + @with_defaults() async def search_clans( self, *, @@ -556,6 +571,7 @@ async def search_clans( return [cls(data=n, client=self, **kwargs) for n in data.get("items", [])] + @with_defaults() async def get_clan(self, tag: str, cls: Type[Clan] = None, **kwargs) -> Clan: """Get information about a single clan by clan tag. @@ -603,6 +619,7 @@ async def get_clan(self, tag: str, cls: Type[Clan] = None, **kwargs) -> Clan: ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors),) return cls(data=data, client=self, **kwargs) + @with_defaults() def get_clans(self, tags: Iterable[str], cls: Type[Clan] = None, **kwargs) -> AsyncIterator[Clan]: """Get information about multiple clans by clan tag. Refer to `Client.get_clan` for more information. @@ -647,6 +664,7 @@ def get_clans(self, tags: Iterable[str], cls: Type[Clan] = None, **kwargs) -> As update_cache=kwargs.get("update_cache", self.update_cache), ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs) + @with_defaults() async def get_members(self, clan_tag: str, *, limit: int = 0, after: str = "", before: str = "", cls: Type[ClanMember] = None, **kwargs) -> List[ClanMember]: """List clan members. @@ -711,6 +729,7 @@ async def get_members(self, clan_tag: str, *, limit: int = 0, after: str = "", b data = await self.http.get_clan_members(clan_tag, **args) return [cls(data=mdata, client=self, **kwargs) for mdata in data.get("memberList", [])] + @with_defaults() async def get_war_log( self, clan_tag: str, @@ -818,6 +837,7 @@ async def get_war_log( raise PrivateWarLog(exception.response, exception.reason) from exception + @with_defaults() async def get_raid_log( self, clan_tag: str, @@ -918,6 +938,7 @@ async def get_raid_log( raise PrivateWarLog(exception.response, exception.reason) from exception + @with_defaults() async def get_clan_war(self, clan_tag: str, cls: Type[ClanWar] = None, **kwargs) -> ClanWar: """ Retrieve information about clan's current clan war @@ -974,6 +995,7 @@ async def get_clan_war(self, clan_tag: str, cls: Type[ClanWar] = None, **kwargs) return cls(data=data, client=self, clan_tag=clan_tag, **kwargs) + @with_defaults() def get_clan_wars(self, clan_tags: Iterable[str], cls: Type[ClanWar] = None, **kwargs) -> AsyncIterator[ClanWar]: """ Retrieve information multiple clan's current clan wars @@ -1040,6 +1062,7 @@ def get_clan_wars(self, clan_tags: Iterable[str], cls: Type[ClanWar] = None, **k ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs) + @with_defaults() async def get_league_group( self, clan_tag: str, @@ -1110,6 +1133,7 @@ async def get_league_group( return cls(data=data, client=self, **kwargs) + @with_defaults() async def get_league_war(self, war_tag: str, cls: Type[ClanWar] = None, **kwargs) -> ClanWar: """ Retrieve information about a clan war league war. @@ -1169,6 +1193,7 @@ async def get_league_war(self, war_tag: str, cls: Type[ClanWar] = None, **kwargs data["tag"] = war_tag # API doesn't return this, even though it is in docs. return cls(data=data, client=self, **kwargs) + @with_defaults() def get_league_wars( self, war_tags: Iterable[str], @@ -1219,6 +1244,7 @@ def get_league_wars( ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs) + @with_defaults() async def get_current_war( self, clan_tag: str, @@ -1370,6 +1396,7 @@ async def get_current_war( war.opponent = tmp return war + @with_defaults() def get_current_wars( self, clan_tags: Iterable[str], @@ -1432,7 +1459,7 @@ def get_current_wars( ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs) - # locations + @with_defaults() async def search_locations(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[Location] = None, **kwargs) -> List[Location]: """List all available locations @@ -1474,6 +1501,7 @@ async def search_locations(self, *, limit: int = None, before: str = None, after return [cls(data=n) for n in data["items"]] + @with_defaults() async def get_location(self, location_id: int, cls: Type[Location] = None, **kwargs) -> Location: """Get information about specific location @@ -1511,6 +1539,7 @@ async def get_location(self, location_id: int, cls: Type[Location] = None, **kwa **kwargs) return cls(data=data) + @with_defaults() async def get_location_named(self, location_name: str, cls: Type[Location] = None, **kwargs) -> Optional[Location]: """Get a location by name. @@ -1547,6 +1576,7 @@ async def get_location_named(self, location_name: str, cls: Type[Location] = Non return get(locations, name=location_name) + @with_defaults() async def get_location_clans( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedClan] = None, @@ -1595,6 +1625,7 @@ async def get_location_clans( **kwargs) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_location_clans_capital( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedClan] = None, @@ -1645,6 +1676,7 @@ async def get_location_clans_capital( ) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_location_players( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedPlayer] = None, @@ -1694,6 +1726,7 @@ async def get_location_players( ) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_location_clans_builder_base( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedClan] = None, **kwargs @@ -1743,6 +1776,7 @@ async def get_location_clans_builder_base( ) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_location_players_builder_base( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedPlayer] = None, **kwargs @@ -1793,7 +1827,7 @@ async def get_location_players_builder_base( return [cls(data=n, client=self) for n in data["items"]] # leagues - + @with_defaults() async def search_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[League] = None, **kwargs) -> List[League]: """Get list of leagues. @@ -1834,6 +1868,7 @@ async def search_leagues(self, *, limit: int = None, before: str = None, after: ) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_league(self, league_id: int, cls: Type[League] = None, **kwargs) -> League: """ Get league information @@ -1870,6 +1905,7 @@ async def get_league(self, league_id: int, cls: Type[League] = None, **kwargs) - **kwargs) return cls(data=data, client=self) + @with_defaults() async def get_league_named(self, league_name: str, cls: Type[League] = None, **kwargs) -> Optional[League]: """Get a league by name. @@ -1910,6 +1946,7 @@ async def get_league_named(self, league_name: str, cls: Type[League] = None, **k ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs), name=league_name) + @with_defaults() async def search_builder_base_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[BaseLeague] = None, **kwargs)-> List[BaseLeague]: """Get list of builder base leagues. @@ -1952,6 +1989,7 @@ async def search_builder_base_leagues(self, *, limit: int = None, before: str = **kwargs) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_builder_base_league(self, league_id: int, cls: Type[BaseLeague] = None, **kwargs) -> BaseLeague: """ Get builder base league information @@ -1992,6 +2030,7 @@ async def get_builder_base_league(self, league_id: int, cls: Type[BaseLeague] = **kwargs) return cls(data=data, client=self) + @with_defaults() async def get_builder_base_league_named(self, league_name: str, cls: Type[BaseLeague] = None, **kwargs) -> Optional[BaseLeague]: """Get a builder base league by name. @@ -2031,6 +2070,7 @@ async def get_builder_base_league_named(self, league_name: str, cls: Type[BaseLe **kwargs), name=league_name) + @with_defaults() async def search_war_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[BaseLeague] = None, **kwargs) -> List[BaseLeague]: """Get list of war leagues. @@ -2072,6 +2112,7 @@ async def search_war_leagues(self, *, limit: int = None, before: str = None, aft **kwargs) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_war_league(self, league_id: int, cls: Type[BaseLeague] = None, **kwargs) -> BaseLeague: """ Get war league information @@ -2111,6 +2152,7 @@ async def get_war_league(self, league_id: int, cls: Type[BaseLeague] = None, **k **kwargs) return cls(data=data, client=self) + @with_defaults() async def get_war_league_named(self, league_name: str, cls: Type[BaseLeague] = None, **kwargs) -> Optional[BaseLeague]: """Get a war league by name. @@ -2153,6 +2195,7 @@ async def get_war_league_named(self, league_name: str, cls: Type[BaseLeague] = N **kwargs), name=league_name) + @with_defaults() async def search_capital_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[BaseLeague] = None, **kwargs) -> List[BaseLeague]: """Get list of capital leagues. @@ -2193,6 +2236,7 @@ async def search_capital_leagues(self, *, limit: int = None, before: str = None, **kwargs) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_capital_league(self, league_id: int, cls: Type[BaseLeague] = None, **kwargs) -> BaseLeague: """ Get capital league information @@ -2231,6 +2275,7 @@ async def get_capital_league(self, league_id: int, cls: Type[BaseLeague] = None, **kwargs) return cls(data=data, client=self) + @with_defaults() async def get_capital_league_named(self, league_name: str, cls: Type[BaseLeague] = None, **kwargs) -> Optional[BaseLeague]: """Get a capital league by name. @@ -2271,6 +2316,7 @@ async def get_capital_league_named(self, league_name: str, cls: Type[BaseLeague] ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs), name=league_name) + @with_defaults() async def get_seasons(self, league_id: int = 29000022, **kwargs) -> List[str]: """Get league seasons. @@ -2308,6 +2354,7 @@ async def get_seasons(self, league_id: int = 29000022, **kwargs) -> List[str]: **kwargs) return [entry["id"] for entry in data["items"]] + @with_defaults() async def get_season_rankings(self, league_id: int, season_id: str, cls: Type[RankedPlayer] = None, **kwargs) -> List[RankedPlayer]: """Get league season rankings. @@ -2352,6 +2399,7 @@ async def get_season_rankings(self, league_id: int, season_id: str, cls: Type[Ra **kwargs) return [cls(data=n, client=self) for n in data.get("items", [])] + @with_defaults() async def get_clan_labels(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[Label] = None, **kwargs ) -> List[Label]: """Fetch all possible clan labels. @@ -2392,6 +2440,7 @@ async def get_clan_labels(self, *, limit: int = None, before: str = None, after: **kwargs) return [cls(data=n, client=self) for n in data["items"]] + @with_defaults() async def get_player_labels(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[Label] = None, **kwargs ) -> List[Label]: """Fetch all possible player labels. @@ -2433,7 +2482,7 @@ async def get_player_labels(self, *, limit: int = None, before: str = None, afte return [cls(data=n, client=self) for n in data["items"]] # players - + @with_defaults() async def get_player(self, player_tag: str, cls: Type[Player] = Player, load_game_data: bool = None, **kwargs) -> Player: """Get information about a single player by player tag. @@ -2484,6 +2533,7 @@ async def get_player(self, player_tag: str, cls: Type[Player] = Player, ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs) + @with_defaults() def get_players(self, player_tags: Iterable[str], cls: Type[Player] = None, load_game_data: bool = None, **kwargs) -> AsyncIterator[ Player]: """Get information about a multiple players by player tag. @@ -2531,6 +2581,7 @@ def get_players(self, player_tags: Iterable[str], cls: Type[Player] = None, load ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs) + @with_defaults() async def verify_player_token(self, player_tag: str, token: str, **kwargs) -> bool: """Verify player API token that can be found from the game settings. @@ -2568,6 +2619,7 @@ async def verify_player_token(self, player_tag: str, token: str, **kwargs) -> bo ignore_cached_errors=kwargs.get('ignore_cached_errors', self.ignore_cached_errors)) return data and data["status"] == "ok" or False + @with_defaults() async def get_current_goldpass_season(self, cls: Type[GoldPassSeason] = None, **kwargs) -> GoldPassSeason: """Get the current gold pass season @@ -2599,6 +2651,7 @@ async def get_current_goldpass_season(self, cls: Type[GoldPassSeason] = None, ** **kwargs) return cls(data=data) + @with_defaults() def parse_army_link(self, link: str): """Transform an army link from in-game into a list of troops and spells. @@ -2651,6 +2704,7 @@ def parse_army_link(self, link: str): return [(lookup_troops.get(t_id, self._troop_holder.get('Barbarian')), qty) for t_id, qty in troops], \ [(lookup_spells.get(s_id, s_id), qty) for s_id, qty in spells] + @with_defaults() def create_army_link(self, **kwargs): r"""Transform troops and spells into an in-game army share link. @@ -2725,6 +2779,7 @@ def create_army_link(self, **kwargs): return base + @with_defaults() def get_troop( self, name: str, is_home_village: bool = True, level: int = None, townhall: int = None ) -> Optional[Union[Type["Troop"], "Troop"]]: @@ -2799,6 +2854,7 @@ def get_troop( else: return troop + @with_defaults() def get_spell(self, name: str, level: int = None, townhall: int = None) -> Optional[Union[Type["Spell"], "Spell"]]: """Get an uninitiated Spell object with the given name. @@ -2870,6 +2926,7 @@ def get_spell(self, name: str, level: int = None, townhall: int = None) -> Optio else: return spell + @with_defaults() def get_hero(self, name: str, level: int = None, townhall: int = None) -> Optional[Union[Type["Hero"], "Hero"]]: """Get an uninitiated Hero object with the given name. @@ -2941,6 +2998,7 @@ def get_hero(self, name: str, level: int = None, townhall: int = None) -> Option else: return hero + @with_defaults() def get_pet(self, name: str, level: int = None, townhall: int = None) -> Optional[Union[Type["Pet"], "Pet"]]: """Get an uninitiated Pet object with the given name. @@ -3011,7 +3069,7 @@ def get_pet(self, name: str, level: int = None, townhall: int = None) -> Optiona else: return pet - + @with_defaults() def get_equipment(self, name: str, level: int = None, townhall: int = None) -> Optional[Union[Type["Equipment"], "Equipment"]]: """Get an uninitiated Equipment object with the given name. From de7d6826b4fe41d2cb973075a90f36e0bebfbd23 Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 06:58:51 -0600 Subject: [PATCH 2/9] chore: update versioning --- coc/__init__.py | 2 +- docs/conf.py | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coc/__init__.py b/coc/__init__.py index 92d2bce5..bc95a4a8 100644 --- a/coc/__init__.py +++ b/coc/__init__.py @@ -22,7 +22,7 @@ SOFTWARE. """ -__version__ = "3.8.0" +__version__ = "3.8.1" from .abc import BasePlayer, BaseClan from .clans import RankedClan, Clan diff --git a/docs/conf.py b/docs/conf.py index 7a5811a4..94bf074f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,7 @@ project = 'coc' copyright = '2022, mathsman5133' author = 'mathsman5133' -release = '3.7.2' +release = '3.8.1' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/pyproject.toml b/pyproject.toml index bb4b03b6..584f2310 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "coc.py" authors = [{ name = "mathsman5133" }] maintainers = [{ name = "majordoobie" }, { name = "MagicTheDev" }, { name = "Kuchenmampfer" }, { name = "lukasthaler"}, { name = "doluk"}] -version = "3.8.0" +version = "3.8.1" description = "A python wrapper for the Clash of Clans API" requires-python = ">=3.7.3" readme = "README.rst" From c32ad28cb6ab6e1f8d40ddaf2d0b06073f8b1067 Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 07:01:49 -0600 Subject: [PATCH 3/9] docs: update changelog --- docs/miscellaneous/changelog.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/miscellaneous/changelog.rst b/docs/miscellaneous/changelog.rst index e4b77d63..14c1ca82 100644 --- a/docs/miscellaneous/changelog.rst +++ b/docs/miscellaneous/changelog.rst @@ -7,6 +7,13 @@ Changelog This page keeps a fairly detailed, human readable version of what has changed, and whats new for each version of the lib. +v3.8.1 +------ + +Bugs Fixed: +~~~~~~~~~~~ +- Fixed a bug with **kwargs in :class:`coc.Client` functions that caused duplicated values + v3.8.0 ------ From 2c44682ae993a3ad07735dba5d7f1fe16dc9ed41 Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 07:12:10 -0600 Subject: [PATCH 4/9] fix: decorator must handle both async & sync functions --- coc/client.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/coc/client.py b/coc/client.py index a001092c..4db20714 100644 --- a/coc/client.py +++ b/coc/client.py @@ -25,6 +25,7 @@ import logging from enum import Enum +from inspect import iscoroutinefunction from itertools import cycle from functools import wraps from pathlib import Path @@ -79,11 +80,20 @@ class ClashAccountScopes(Enum): def with_defaults(): def decorator(func): - @wraps(func) - async def wrapper(self, *args, **kwargs): - merged_kwargs = {**self._defaults, **kwargs} - return await func(self, *args, **merged_kwargs) - return wrapper + # we have to check if the function is async or not, because we have both + if iscoroutinefunction(func): + @wraps(func) + async def async_wrapper(self, *args, **kwargs): + merged_kwargs = {**self._defaults, **kwargs} + return await func(self, *args, **merged_kwargs) + return async_wrapper + else: + @wraps(func) + def sync_wrapper(self, *args, **kwargs): + defaults = self._defaults if hasattr(self, "_defaults") else {} + merged_kwargs = {**self._defaults, **kwargs} + return func(self, *args, **merged_kwargs) + return sync_wrapper return decorator class Client: From 4a2a1ed7f68b587a36dc7328cbac7e56c3a67ce0 Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 07:32:29 -0600 Subject: [PATCH 5/9] chore: cleanup decorator usage & remove manual cache setting assignments --- coc/client.py | 248 +++++++++----------------------------------------- 1 file changed, 41 insertions(+), 207 deletions(-) diff --git a/coc/client.py b/coc/client.py index 4db20714..3eeee9bc 100644 --- a/coc/client.py +++ b/coc/client.py @@ -573,15 +573,12 @@ async def search_clans( if isinstance(x, (Label, int,))]), limit=limit, before=before, - after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), + after=after ) return [cls(data=n, client=self, **kwargs) for n in data.get("items", [])] - @with_defaults() + async def get_clan(self, tag: str, cls: Type[Clan] = None, **kwargs) -> Clan: """Get information about a single clan by clan tag. @@ -626,7 +623,7 @@ async def get_clan(self, tag: str, cls: Type[Clan] = None, **kwargs) -> Clan: data = await self.http.get_clan(tag, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors),) + ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors)) return cls(data=data, client=self, **kwargs) @with_defaults() @@ -669,12 +666,9 @@ def get_clans(self, tags: Iterable[str], cls: Type[Clan] = None, **kwargs) -> As if not issubclass(cls, Clan): raise TypeError("cls must be a subclass of Clan.") - return ClanIterator(self, tags, cls, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs) + return ClanIterator(self, tags, cls, **kwargs) + - @with_defaults() async def get_members(self, clan_tag: str, *, limit: int = 0, after: str = "", before: str = "", cls: Type[ClanMember] = None, **kwargs) -> List[ClanMember]: """List clan members. @@ -839,9 +833,6 @@ async def get_war_log( model=cls, after=after, before=before, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs) except Forbidden as exception: raise PrivateWarLog(exception.response, @@ -939,16 +930,12 @@ async def get_raid_log( model=cls, after=after, before=before, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), **kwargs ) except Forbidden as exception: raise PrivateWarLog(exception.response, exception.reason) from exception - @with_defaults() async def get_clan_war(self, clan_tag: str, cls: Type[ClanWar] = None, **kwargs) -> ClanWar: """ Retrieve information about clan's current clan war @@ -1067,10 +1054,7 @@ def get_clan_wars(self, clan_tags: Iterable[str], cls: Type[ClanWar] = None, **k if not issubclass(cls, ClanWar): raise TypeError("cls must be a subclass of ClanWar.") - return ClanWarIterator(self, clan_tags, cls=cls, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + return ClanWarIterator(self, clan_tags, cls=cls, **kwargs) @with_defaults() async def get_league_group( @@ -1126,13 +1110,7 @@ async def get_league_group( realtime = None try: - data = await self.http.get_clan_war_league_group(clan_tag, realtime=realtime, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", - self.ignore_cached_errors), - **kwargs - ) + data = await self.http.get_clan_war_league_group(clan_tag, realtime=realtime, **kwargs) except Forbidden as exception: raise PrivateWarLog(exception.response, exception.reason) from exception except asyncio.TimeoutError: @@ -1191,12 +1169,7 @@ async def get_league_war(self, war_tag: str, cls: Type[ClanWar] = None, **kwargs realtime = None try: - data = await self.http.get_cwl_wars(war_tag, realtime=realtime, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs - ) + data = await self.http.get_cwl_wars(war_tag, realtime=realtime, **kwargs) except Forbidden as exception: raise PrivateWarLog(exception.response, exception.reason) from exception @@ -1249,10 +1222,7 @@ def get_league_wars( if not issubclass(cls, ClanWar): raise TypeError("cls must be a subclass of ClanWar.") - return LeagueWarIterator(self, war_tags, clan_tag, cls, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + return LeagueWarIterator(self, war_tags, clan_tag, cls, **kwargs) @with_defaults() async def get_current_war( @@ -1330,10 +1300,7 @@ async def get_current_war( clan_tag = correct_tag(clan_tag) try: - get_war = await self.get_clan_war(clan_tag, cls=cls, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + get_war = await self.get_clan_war(clan_tag, cls=cls, **kwargs) except PrivateWarLog: get_war = None @@ -1341,10 +1308,7 @@ async def get_current_war( return get_war try: - league_group = await self.get_league_group(clan_tag, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + league_group = await self.get_league_group(clan_tag, **kwargs) except (NotFound, GatewayError) as exception: # either they're not in cwl (NotFound) # or it's an API bug where league group endpoint will timeout when the clan is searching (GatewayError) @@ -1358,11 +1322,7 @@ async def get_current_war( if last_round_active and league_group.state != "ended": # there are the supposed number of rounds, but without any call we are unable to know if the last round is # currently in preparation or already in war - async for war in self.get_league_wars(league_group.rounds[-1], cls=cls, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs): + async for war in self.get_league_wars(league_group.rounds[-1], cls=cls, **kwargs): if war.state == 'inWar': # last round is already in war last_round_active = True @@ -1394,10 +1354,7 @@ async def get_current_war( kwargs["league_group"] = league_group kwargs["clan_tag"] = clan_tag - async for war in self.get_league_wars(round_tags, cls=cls, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs): + async for war in self.get_league_wars(round_tags, cls=cls, **kwargs): if war.clan_tag == clan_tag: return war elif war.opponent.tag == clan_tag: @@ -1464,10 +1421,7 @@ def get_current_wars( if not issubclass(cls, ClanWar): raise TypeError("cls must be a subclass of ClanWar.") - return CurrentWarIterator(client=self, tags=clan_tags, cls=cls, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + return CurrentWarIterator(client=self, tags=clan_tags, cls=cls, **kwargs) @with_defaults() async def search_locations(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[Location] = None, @@ -1503,11 +1457,7 @@ async def search_locations(self, *, limit: int = None, before: str = None, after cls = self.objects_cls['Location'] if not issubclass(cls, Location): raise TypeError("cls must be a subclass of Location.") - data = await self.http.search_locations(limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.search_locations(limit=limit, before=before, after=after, **kwargs) return [cls(data=n) for n in data["items"]] @@ -1543,10 +1493,7 @@ async def get_location(self, location_id: int, cls: Type[Location] = None, **kwa cls = self.objects_cls['Location'] if not issubclass(cls, Location): raise TypeError("cls must be a subclass of Location.") - data = await self.http.get_location(location_id, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_location(location_id, **kwargs) return cls(data=data) @with_defaults() @@ -1577,11 +1524,7 @@ async def get_location_named(self, location_name: str, cls: Type[Location] = Non cls = self.objects_cls['Location'] if not issubclass(cls, Location): raise TypeError("cls must be a subclass of Location.") - data = await self.http.search_locations(limit=None, before=None, after=None, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.search_locations(limit=None, before=None, after=None, **kwargs) locations = [cls(data=n) for n in data["items"]] return get(locations, name=location_name) @@ -1628,11 +1571,7 @@ async def get_location_clans( cls = self.objects_cls['RankedClan'] if not issubclass(cls, RankedClan): raise TypeError("cls must be a subclass of RankedClan.") - data = await self.http.get_location_clans(location_id, limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_location_clans(location_id, limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -1677,13 +1616,7 @@ async def get_location_clans_capital( cls = self.objects_cls['RankedClan'] if not issubclass(cls, RankedClan): raise TypeError("cls must be a subclass of RankedClan.") - data = await self.http.get_location_clans_capital(location_id, limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", - self.ignore_cached_errors), - **kwargs - ) + data = await self.http.get_location_clans_capital(location_id, limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -1728,12 +1661,7 @@ async def get_location_players( cls = self.objects_cls['RankedPlayer'] if not issubclass(cls, RankedPlayer): raise TypeError("cls must be a subclass of RankedPlayer.") - data = await self.http.get_location_players(location_id, limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs - ) + data = await self.http.get_location_players(location_id, limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -1778,12 +1706,7 @@ async def get_location_clans_builder_base( if not issubclass(cls, RankedClan): raise TypeError("cls must be a subclass of RankedClan.") data = await self.http.get_location_clans_builder_base(location_id, limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", - self.ignore_cached_errors), - **kwargs - ) + **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -1828,12 +1751,7 @@ async def get_location_players_builder_base( if not issubclass(cls, RankedPlayer): raise TypeError("cls must be a subclass of RankedPlayer.") data = await self.http.get_location_players_builder_base(location_id, limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", - self.ignore_cached_errors), - **kwargs - ) + **kwargs) return [cls(data=n, client=self) for n in data["items"]] # leagues @@ -1870,12 +1788,7 @@ async def search_leagues(self, *, limit: int = None, before: str = None, after: cls = self.objects_cls['League'] if not issubclass(cls, League): raise TypeError("cls must be a subclass of League.") - data = await self.http.search_leagues(limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs - ) + data = await self.http.search_leagues(limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -1909,10 +1822,7 @@ async def get_league(self, league_id: int, cls: Type[League] = None, **kwargs) - cls = self.objects_cls['League'] if not issubclass(cls, League): raise TypeError("cls must be a subclass of League.") - data = await self.http.get_league(league_id, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_league(league_id, **kwargs) return cls(data=data, client=self) @with_defaults() @@ -1951,10 +1861,7 @@ async def get_league_named(self, league_name: str, cls: Type[League] = None, **k cls = self.objects_cls['League'] if not issubclass(cls, League): raise TypeError("cls must be a subclass of League.") - return get(await self.search_leagues(cls=cls, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs), name=league_name) + return get(await self.search_leagues(cls=cls, **kwargs), name=league_name) @with_defaults() async def search_builder_base_leagues(self, *, limit: int = None, before: str = None, after: str = None, @@ -1991,12 +1898,7 @@ async def search_builder_base_leagues(self, *, limit: int = None, before: str = cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.search_builder_base_leagues(limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", - self.ignore_cached_errors), - **kwargs) + data = await self.http.search_builder_base_leagues(limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -2032,12 +1934,7 @@ async def get_builder_base_league(self, league_id: int, cls: Type[BaseLeague] = cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.get_builder_base_league(league_id, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", - self.ignore_cached_errors), - **kwargs) + data = await self.http.get_builder_base_league(league_id, **kwargs) return cls(data=data, client=self) @with_defaults() @@ -2072,13 +1969,7 @@ async def get_builder_base_league_named(self, league_name: str, cls: Type[BaseLe :class:`BaseLeague` The first league matching the league name. Could be ``None`` if not found. """ - return get(await self.search_builder_base_leagues(cls=cls, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", - self.ignore_cached_errors), - **kwargs), - name=league_name) + return get(await self.search_builder_base_leagues(cls=cls, **kwargs), name=league_name) @with_defaults() async def search_war_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[BaseLeague] = None, @@ -2115,11 +2006,7 @@ async def search_war_leagues(self, *, limit: int = None, before: str = None, aft cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.search_war_leagues(limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.search_war_leagues(limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -2155,11 +2042,7 @@ async def get_war_league(self, league_id: int, cls: Type[BaseLeague] = None, **k cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.get_war_league(league_id, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_war_league(league_id, **kwargs) return cls(data=data, client=self) @with_defaults() @@ -2198,12 +2081,7 @@ async def get_war_league_named(self, league_name: str, cls: Type[BaseLeague] = N cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - return get(await self.search_war_leagues(cls=cls, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs), - name=league_name) + return get(await self.search_war_leagues(cls=cls, **kwargs), name=league_name) @with_defaults() async def search_capital_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[BaseLeague] = None, @@ -2239,11 +2117,7 @@ async def search_capital_leagues(self, *, limit: int = None, before: str = None, cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.search_capital_leagues(limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.search_capital_leagues(limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -2279,10 +2153,7 @@ async def get_capital_league(self, league_id: int, cls: Type[BaseLeague] = None, cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.get_capital_league(league_id, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_capital_league(league_id, **kwargs) return cls(data=data, client=self) @with_defaults() @@ -2321,10 +2192,7 @@ async def get_capital_league_named(self, league_name: str, cls: Type[BaseLeague] cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - return get(await self.search_capital_leagues(cls=cls, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs), name=league_name) + return get(await self.search_capital_leagues(cls=cls, **kwargs), name=league_name) @with_defaults() async def get_seasons(self, league_id: int = 29000022, **kwargs) -> List[str]: @@ -2358,10 +2226,7 @@ async def get_seasons(self, league_id: int = 29000022, **kwargs) -> List[str]: List[str] The legend season IDs, in the form ``YYYY-MM``, ie. ``2020-04``. """ - data = await self.http.get_league_seasons(league_id, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_league_seasons(league_id, **kwargs) return [entry["id"] for entry in data["items"]] @with_defaults() @@ -2403,10 +2268,7 @@ async def get_season_rankings(self, league_id: int, season_id: str, cls: Type[Ra cls = self.objects_cls['RankedPlayer'] if not issubclass(cls, RankedPlayer): raise TypeError("cls must be a subclass of RankedPlayer.") - data = await self.http.get_league_season_info(league_id, season_id, lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_league_season_info(league_id, season_id, **kwargs) return [cls(data=n, client=self) for n in data.get("items", [])] @with_defaults() @@ -2443,11 +2305,7 @@ async def get_clan_labels(self, *, limit: int = None, before: str = None, after: cls = self.objects_cls['Label'] if not issubclass(cls, Label): raise TypeError("cls must be a subclass of Label.") - data = await self.http.get_clan_labels(limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_clan_labels(limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] @with_defaults() @@ -2484,11 +2342,7 @@ async def get_player_labels(self, *, limit: int = None, before: str = None, afte cls = self.objects_cls['Label'] if not issubclass(cls, Label): raise TypeError("cls must be a subclass of Label.") - data = await self.http.get_player_labels(limit=limit, before=before, after=after, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + data = await self.http.get_player_labels(limit=limit, before=before, after=after, **kwargs) return [cls(data=n, client=self) for n in data["items"]] # players @@ -2537,11 +2391,7 @@ async def get_player(self, player_tag: str, cls: Type[Player] = Player, player_tag = correct_tag(player_tag) data = await self.http.get_player(player_tag) - return cls(data=data, client=self, load_game_data=load_game_data, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + return cls(data=data, client=self, load_game_data=load_game_data, **kwargs) @with_defaults() def get_players(self, player_tags: Iterable[str], cls: Type[Player] = None, load_game_data: bool = None, **kwargs) -> AsyncIterator[ @@ -2585,13 +2435,8 @@ def get_players(self, player_tags: Iterable[str], cls: Type[Player] = None, load if load_game_data and not isinstance(load_game_data, bool): raise TypeError("load_game_data must be either True or False.") - return PlayerIterator(self, player_tags, cls=cls, load_game_data=load_game_data, - lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors), - **kwargs) + return PlayerIterator(self, player_tags, cls=cls, load_game_data=load_game_data, **kwargs) - @with_defaults() async def verify_player_token(self, player_tag: str, token: str, **kwargs) -> bool: """Verify player API token that can be found from the game settings. @@ -2654,14 +2499,9 @@ async def get_current_goldpass_season(self, cls: Type[GoldPassSeason] = None, ** cls = self.objects_cls['GoldPassSeason'] if not issubclass(cls, GoldPassSeason): raise TypeError("cls must be a subclass of GoldPassSeason.") - data = await self.http.get_current_goldpass_season(lookup_cache=kwargs.get("lookup_cache", self.lookup_cache), - update_cache=kwargs.get("update_cache", self.update_cache), - ignore_cached_errors=kwargs.get("ignore_cached_errors", - self.ignore_cached_errors), - **kwargs) + data = await self.http.get_current_goldpass_season(**kwargs) return cls(data=data) - @with_defaults() def parse_army_link(self, link: str): """Transform an army link from in-game into a list of troops and spells. @@ -2714,7 +2554,6 @@ def parse_army_link(self, link: str): return [(lookup_troops.get(t_id, self._troop_holder.get('Barbarian')), qty) for t_id, qty in troops], \ [(lookup_spells.get(s_id, s_id), qty) for s_id, qty in spells] - @with_defaults() def create_army_link(self, **kwargs): r"""Transform troops and spells into an in-game army share link. @@ -2789,7 +2628,6 @@ def create_army_link(self, **kwargs): return base - @with_defaults() def get_troop( self, name: str, is_home_village: bool = True, level: int = None, townhall: int = None ) -> Optional[Union[Type["Troop"], "Troop"]]: @@ -2864,7 +2702,6 @@ def get_troop( else: return troop - @with_defaults() def get_spell(self, name: str, level: int = None, townhall: int = None) -> Optional[Union[Type["Spell"], "Spell"]]: """Get an uninitiated Spell object with the given name. @@ -2936,7 +2773,6 @@ def get_spell(self, name: str, level: int = None, townhall: int = None) -> Optio else: return spell - @with_defaults() def get_hero(self, name: str, level: int = None, townhall: int = None) -> Optional[Union[Type["Hero"], "Hero"]]: """Get an uninitiated Hero object with the given name. @@ -3008,7 +2844,6 @@ def get_hero(self, name: str, level: int = None, townhall: int = None) -> Option else: return hero - @with_defaults() def get_pet(self, name: str, level: int = None, townhall: int = None) -> Optional[Union[Type["Pet"], "Pet"]]: """Get an uninitiated Pet object with the given name. @@ -3079,7 +2914,6 @@ def get_pet(self, name: str, level: int = None, townhall: int = None) -> Optiona else: return pet - @with_defaults() def get_equipment(self, name: str, level: int = None, townhall: int = None) -> Optional[Union[Type["Equipment"], "Equipment"]]: """Get an uninitiated Equipment object with the given name. From 96aab48224c72a5547871af3b7b70ad6c3c7c284 Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 08:17:22 -0600 Subject: [PATCH 6/9] refactor: use dictionary union instead of decorator to update kwargs --- coc/client.py | 134 ++++++++++++++++---------------------------------- 1 file changed, 42 insertions(+), 92 deletions(-) diff --git a/coc/client.py b/coc/client.py index 3eeee9bc..1a1834c5 100644 --- a/coc/client.py +++ b/coc/client.py @@ -25,9 +25,7 @@ import logging from enum import Enum -from inspect import iscoroutinefunction from itertools import cycle -from functools import wraps from pathlib import Path from typing import AsyncIterator, Iterable, List, Optional, Type, Union, TYPE_CHECKING @@ -78,23 +76,6 @@ class ClashAccountScopes(Enum): USER = "clash" REAL = "clash:*:verifytoken,realtime" -def with_defaults(): - def decorator(func): - # we have to check if the function is async or not, because we have both - if iscoroutinefunction(func): - @wraps(func) - async def async_wrapper(self, *args, **kwargs): - merged_kwargs = {**self._defaults, **kwargs} - return await func(self, *args, **merged_kwargs) - return async_wrapper - else: - @wraps(func) - def sync_wrapper(self, *args, **kwargs): - defaults = self._defaults if hasattr(self, "_defaults") else {} - merged_kwargs = {**self._defaults, **kwargs} - return func(self, *args, **merged_kwargs) - return sync_wrapper - return decorator class Client: """This is the client connection used to interact with the Clash of Clans API. @@ -489,7 +470,6 @@ def dispatch(self, event_name: str, *args, **kwargs) -> None: else: fctn(*args, **kwargs) - @with_defaults() async def search_clans( self, *, @@ -575,7 +555,7 @@ async def search_clans( before=before, after=after ) - + kwargs = {**self._defaults, **kwargs} return [cls(data=n, client=self, **kwargs) for n in data.get("items", [])] @@ -626,7 +606,6 @@ async def get_clan(self, tag: str, cls: Type[Clan] = None, **kwargs) -> Clan: ignore_cached_errors=kwargs.get("ignore_cached_errors", self.ignore_cached_errors)) return cls(data=data, client=self, **kwargs) - @with_defaults() def get_clans(self, tags: Iterable[str], cls: Type[Clan] = None, **kwargs) -> AsyncIterator[Clan]: """Get information about multiple clans by clan tag. Refer to `Client.get_clan` for more information. @@ -666,7 +645,7 @@ def get_clans(self, tags: Iterable[str], cls: Type[Clan] = None, **kwargs) -> As if not issubclass(cls, Clan): raise TypeError("cls must be a subclass of Clan.") - return ClanIterator(self, tags, cls, **kwargs) + return ClanIterator(self, tags, cls, **{**self._defaults, **kwargs}) async def get_members(self, clan_tag: str, *, limit: int = 0, after: str = "", before: str = "", @@ -733,7 +712,6 @@ async def get_members(self, clan_tag: str, *, limit: int = 0, after: str = "", b data = await self.http.get_clan_members(clan_tag, **args) return [cls(data=mdata, client=self, **kwargs) for mdata in data.get("memberList", [])] - @with_defaults() async def get_war_log( self, clan_tag: str, @@ -833,12 +811,11 @@ async def get_war_log( model=cls, after=after, before=before, - **kwargs) + **{**self._defaults, **kwargs}) except Forbidden as exception: raise PrivateWarLog(exception.response, exception.reason) from exception - @with_defaults() async def get_raid_log( self, clan_tag: str, @@ -930,7 +907,7 @@ async def get_raid_log( model=cls, after=after, before=before, - **kwargs + **{**self._defaults, **kwargs} ) except Forbidden as exception: raise PrivateWarLog(exception.response, @@ -992,7 +969,6 @@ async def get_clan_war(self, clan_tag: str, cls: Type[ClanWar] = None, **kwargs) return cls(data=data, client=self, clan_tag=clan_tag, **kwargs) - @with_defaults() def get_clan_wars(self, clan_tags: Iterable[str], cls: Type[ClanWar] = None, **kwargs) -> AsyncIterator[ClanWar]: """ Retrieve information multiple clan's current clan wars @@ -1054,9 +1030,8 @@ def get_clan_wars(self, clan_tags: Iterable[str], cls: Type[ClanWar] = None, **k if not issubclass(cls, ClanWar): raise TypeError("cls must be a subclass of ClanWar.") - return ClanWarIterator(self, clan_tags, cls=cls, **kwargs) + return ClanWarIterator(self, clan_tags, cls=cls, **{**self._defaults, **kwargs}) - @with_defaults() async def get_league_group( self, clan_tag: str, @@ -1110,7 +1085,7 @@ async def get_league_group( realtime = None try: - data = await self.http.get_clan_war_league_group(clan_tag, realtime=realtime, **kwargs) + data = await self.http.get_clan_war_league_group(clan_tag, realtime=realtime, **{**self._defaults, **kwargs}) except Forbidden as exception: raise PrivateWarLog(exception.response, exception.reason) from exception except asyncio.TimeoutError: @@ -1121,7 +1096,6 @@ async def get_league_group( return cls(data=data, client=self, **kwargs) - @with_defaults() async def get_league_war(self, war_tag: str, cls: Type[ClanWar] = None, **kwargs) -> ClanWar: """ Retrieve information about a clan war league war. @@ -1169,14 +1143,13 @@ async def get_league_war(self, war_tag: str, cls: Type[ClanWar] = None, **kwargs realtime = None try: - data = await self.http.get_cwl_wars(war_tag, realtime=realtime, **kwargs) + data = await self.http.get_cwl_wars(war_tag, realtime=realtime, **{**self._defaults, **kwargs}) except Forbidden as exception: raise PrivateWarLog(exception.response, exception.reason) from exception data["tag"] = war_tag # API doesn't return this, even though it is in docs. return cls(data=data, client=self, **kwargs) - @with_defaults() def get_league_wars( self, war_tags: Iterable[str], @@ -1222,9 +1195,8 @@ def get_league_wars( if not issubclass(cls, ClanWar): raise TypeError("cls must be a subclass of ClanWar.") - return LeagueWarIterator(self, war_tags, clan_tag, cls, **kwargs) + return LeagueWarIterator(self, war_tags, clan_tag, cls, **{**self._defaults, **kwargs}) - @with_defaults() async def get_current_war( self, clan_tag: str, @@ -1290,6 +1262,7 @@ async def get_current_war( If you pass in a :class:`WarRound` and that round doesn't exist (yet), this will return ``None``. """ + kwargs = {**self._defaults, **kwargs} if cls is None: cls = self.objects_cls['ClanWar'] # pylint: disable=protected-access @@ -1363,7 +1336,6 @@ async def get_current_war( war.opponent = tmp return war - @with_defaults() def get_current_wars( self, clan_tags: Iterable[str], @@ -1421,9 +1393,8 @@ def get_current_wars( if not issubclass(cls, ClanWar): raise TypeError("cls must be a subclass of ClanWar.") - return CurrentWarIterator(client=self, tags=clan_tags, cls=cls, **kwargs) + return CurrentWarIterator(client=self, tags=clan_tags, cls=cls, **{**self._defaults, **kwargs}) - @with_defaults() async def search_locations(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[Location] = None, **kwargs) -> List[Location]: """List all available locations @@ -1457,11 +1428,10 @@ async def search_locations(self, *, limit: int = None, before: str = None, after cls = self.objects_cls['Location'] if not issubclass(cls, Location): raise TypeError("cls must be a subclass of Location.") - data = await self.http.search_locations(limit=limit, before=before, after=after, **kwargs) + data = await self.http.search_locations(limit=limit, before=before, after=after, **{**self._defaults, **kwargs}) return [cls(data=n) for n in data["items"]] - @with_defaults() async def get_location(self, location_id: int, cls: Type[Location] = None, **kwargs) -> Location: """Get information about specific location @@ -1493,10 +1463,9 @@ async def get_location(self, location_id: int, cls: Type[Location] = None, **kwa cls = self.objects_cls['Location'] if not issubclass(cls, Location): raise TypeError("cls must be a subclass of Location.") - data = await self.http.get_location(location_id, **kwargs) + data = await self.http.get_location(location_id, **{**self._defaults, **kwargs}) return cls(data=data) - @with_defaults() async def get_location_named(self, location_name: str, cls: Type[Location] = None, **kwargs) -> Optional[Location]: """Get a location by name. @@ -1524,12 +1493,11 @@ async def get_location_named(self, location_name: str, cls: Type[Location] = Non cls = self.objects_cls['Location'] if not issubclass(cls, Location): raise TypeError("cls must be a subclass of Location.") - data = await self.http.search_locations(limit=None, before=None, after=None, **kwargs) + data = await self.http.search_locations(limit=None, before=None, after=None, **{**self._defaults, **kwargs}) locations = [cls(data=n) for n in data["items"]] return get(locations, name=location_name) - @with_defaults() async def get_location_clans( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedClan] = None, @@ -1571,10 +1539,10 @@ async def get_location_clans( cls = self.objects_cls['RankedClan'] if not issubclass(cls, RankedClan): raise TypeError("cls must be a subclass of RankedClan.") - data = await self.http.get_location_clans(location_id, limit=limit, before=before, after=after, **kwargs) + data = await self.http.get_location_clans(location_id, limit=limit, before=before, after=after, + **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_location_clans_capital( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedClan] = None, @@ -1616,10 +1584,10 @@ async def get_location_clans_capital( cls = self.objects_cls['RankedClan'] if not issubclass(cls, RankedClan): raise TypeError("cls must be a subclass of RankedClan.") - data = await self.http.get_location_clans_capital(location_id, limit=limit, before=before, after=after, **kwargs) + data = await self.http.get_location_clans_capital(location_id, limit=limit, before=before, after=after, + **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_location_players( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedPlayer] = None, @@ -1661,10 +1629,10 @@ async def get_location_players( cls = self.objects_cls['RankedPlayer'] if not issubclass(cls, RankedPlayer): raise TypeError("cls must be a subclass of RankedPlayer.") - data = await self.http.get_location_players(location_id, limit=limit, before=before, after=after, **kwargs) + data = await self.http.get_location_players(location_id, limit=limit, before=before, after=after, + **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_location_clans_builder_base( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedClan] = None, **kwargs @@ -1706,10 +1674,9 @@ async def get_location_clans_builder_base( if not issubclass(cls, RankedClan): raise TypeError("cls must be a subclass of RankedClan.") data = await self.http.get_location_clans_builder_base(location_id, limit=limit, before=before, after=after, - **kwargs) + **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_location_players_builder_base( self, location_id: int = "global", *, limit: int = None, before: str = None, after: str = None, cls: Type[RankedPlayer] = None, **kwargs @@ -1751,11 +1718,10 @@ async def get_location_players_builder_base( if not issubclass(cls, RankedPlayer): raise TypeError("cls must be a subclass of RankedPlayer.") data = await self.http.get_location_players_builder_base(location_id, limit=limit, before=before, after=after, - **kwargs) + **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] # leagues - @with_defaults() async def search_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[League] = None, **kwargs) -> List[League]: """Get list of leagues. @@ -1788,10 +1754,9 @@ async def search_leagues(self, *, limit: int = None, before: str = None, after: cls = self.objects_cls['League'] if not issubclass(cls, League): raise TypeError("cls must be a subclass of League.") - data = await self.http.search_leagues(limit=limit, before=before, after=after, **kwargs) + data = await self.http.search_leagues(limit=limit, before=before, after=after, **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_league(self, league_id: int, cls: Type[League] = None, **kwargs) -> League: """ Get league information @@ -1822,10 +1787,9 @@ async def get_league(self, league_id: int, cls: Type[League] = None, **kwargs) - cls = self.objects_cls['League'] if not issubclass(cls, League): raise TypeError("cls must be a subclass of League.") - data = await self.http.get_league(league_id, **kwargs) + data = await self.http.get_league(league_id, **{**self._defaults, **kwargs}) return cls(data=data, client=self) - @with_defaults() async def get_league_named(self, league_name: str, cls: Type[League] = None, **kwargs) -> Optional[League]: """Get a league by name. @@ -1861,9 +1825,8 @@ async def get_league_named(self, league_name: str, cls: Type[League] = None, **k cls = self.objects_cls['League'] if not issubclass(cls, League): raise TypeError("cls must be a subclass of League.") - return get(await self.search_leagues(cls=cls, **kwargs), name=league_name) + return get(await self.search_leagues(cls=cls, **{**self._defaults, **kwargs}), name=league_name) - @with_defaults() async def search_builder_base_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[BaseLeague] = None, **kwargs)-> List[BaseLeague]: """Get list of builder base leagues. @@ -1898,10 +1861,10 @@ async def search_builder_base_leagues(self, *, limit: int = None, before: str = cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.search_builder_base_leagues(limit=limit, before=before, after=after, **kwargs) + data = await self.http.search_builder_base_leagues(limit=limit, before=before, after=after, + **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_builder_base_league(self, league_id: int, cls: Type[BaseLeague] = None, **kwargs) -> BaseLeague: """ Get builder base league information @@ -1934,10 +1897,9 @@ async def get_builder_base_league(self, league_id: int, cls: Type[BaseLeague] = cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.get_builder_base_league(league_id, **kwargs) + data = await self.http.get_builder_base_league(league_id, **{**self._defaults, **kwargs}) return cls(data=data, client=self) - @with_defaults() async def get_builder_base_league_named(self, league_name: str, cls: Type[BaseLeague] = None, **kwargs) -> Optional[BaseLeague]: """Get a builder base league by name. @@ -1969,9 +1931,8 @@ async def get_builder_base_league_named(self, league_name: str, cls: Type[BaseLe :class:`BaseLeague` The first league matching the league name. Could be ``None`` if not found. """ - return get(await self.search_builder_base_leagues(cls=cls, **kwargs), name=league_name) + return get(await self.search_builder_base_leagues(cls=cls, **{**self._defaults, **kwargs}), name=league_name) - @with_defaults() async def search_war_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[BaseLeague] = None, **kwargs) -> List[BaseLeague]: """Get list of war leagues. @@ -2006,10 +1967,9 @@ async def search_war_leagues(self, *, limit: int = None, before: str = None, aft cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.search_war_leagues(limit=limit, before=before, after=after, **kwargs) + data = await self.http.search_war_leagues(limit=limit, before=before, after=after, **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_war_league(self, league_id: int, cls: Type[BaseLeague] = None, **kwargs) -> BaseLeague: """ Get war league information @@ -2042,10 +2002,9 @@ async def get_war_league(self, league_id: int, cls: Type[BaseLeague] = None, **k cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.get_war_league(league_id, **kwargs) + data = await self.http.get_war_league(league_id, **{**self._defaults, **kwargs}) return cls(data=data, client=self) - @with_defaults() async def get_war_league_named(self, league_name: str, cls: Type[BaseLeague] = None, **kwargs) -> Optional[BaseLeague]: """Get a war league by name. @@ -2081,9 +2040,8 @@ async def get_war_league_named(self, league_name: str, cls: Type[BaseLeague] = N cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - return get(await self.search_war_leagues(cls=cls, **kwargs), name=league_name) + return get(await self.search_war_leagues(cls=cls, **{**self._defaults, **kwargs}), name=league_name) - @with_defaults() async def search_capital_leagues(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[BaseLeague] = None, **kwargs) -> List[BaseLeague]: """Get list of capital leagues. @@ -2117,10 +2075,10 @@ async def search_capital_leagues(self, *, limit: int = None, before: str = None, cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.search_capital_leagues(limit=limit, before=before, after=after, **kwargs) + data = await self.http.search_capital_leagues(limit=limit, before=before, after=after, + **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_capital_league(self, league_id: int, cls: Type[BaseLeague] = None, **kwargs) -> BaseLeague: """ Get capital league information @@ -2153,10 +2111,9 @@ async def get_capital_league(self, league_id: int, cls: Type[BaseLeague] = None, cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - data = await self.http.get_capital_league(league_id, **kwargs) + data = await self.http.get_capital_league(league_id, **{**self._defaults, **kwargs}) return cls(data=data, client=self) - @with_defaults() async def get_capital_league_named(self, league_name: str, cls: Type[BaseLeague] = None, **kwargs) -> Optional[BaseLeague]: """Get a capital league by name. @@ -2192,9 +2149,8 @@ async def get_capital_league_named(self, league_name: str, cls: Type[BaseLeague] cls = self.objects_cls['BaseLeague'] if not issubclass(cls, BaseLeague): raise TypeError("cls must be a subclass of BaseLeague.") - return get(await self.search_capital_leagues(cls=cls, **kwargs), name=league_name) + return get(await self.search_capital_leagues(cls=cls, **{**self._defaults, **kwargs}), name=league_name) - @with_defaults() async def get_seasons(self, league_id: int = 29000022, **kwargs) -> List[str]: """Get league seasons. @@ -2226,10 +2182,9 @@ async def get_seasons(self, league_id: int = 29000022, **kwargs) -> List[str]: List[str] The legend season IDs, in the form ``YYYY-MM``, ie. ``2020-04``. """ - data = await self.http.get_league_seasons(league_id, **kwargs) + data = await self.http.get_league_seasons(league_id, **{**self._defaults, **kwargs}) return [entry["id"] for entry in data["items"]] - @with_defaults() async def get_season_rankings(self, league_id: int, season_id: str, cls: Type[RankedPlayer] = None, **kwargs) -> List[RankedPlayer]: """Get league season rankings. @@ -2268,10 +2223,9 @@ async def get_season_rankings(self, league_id: int, season_id: str, cls: Type[Ra cls = self.objects_cls['RankedPlayer'] if not issubclass(cls, RankedPlayer): raise TypeError("cls must be a subclass of RankedPlayer.") - data = await self.http.get_league_season_info(league_id, season_id, **kwargs) + data = await self.http.get_league_season_info(league_id, season_id, **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data.get("items", [])] - @with_defaults() async def get_clan_labels(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[Label] = None, **kwargs ) -> List[Label]: """Fetch all possible clan labels. @@ -2305,10 +2259,9 @@ async def get_clan_labels(self, *, limit: int = None, before: str = None, after: cls = self.objects_cls['Label'] if not issubclass(cls, Label): raise TypeError("cls must be a subclass of Label.") - data = await self.http.get_clan_labels(limit=limit, before=before, after=after, **kwargs) + data = await self.http.get_clan_labels(limit=limit, before=before, after=after, **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] - @with_defaults() async def get_player_labels(self, *, limit: int = None, before: str = None, after: str = None, cls: Type[Label] = None, **kwargs ) -> List[Label]: """Fetch all possible player labels. @@ -2342,11 +2295,10 @@ async def get_player_labels(self, *, limit: int = None, before: str = None, afte cls = self.objects_cls['Label'] if not issubclass(cls, Label): raise TypeError("cls must be a subclass of Label.") - data = await self.http.get_player_labels(limit=limit, before=before, after=after, **kwargs) + data = await self.http.get_player_labels(limit=limit, before=before, after=after, **{**self._defaults, **kwargs}) return [cls(data=n, client=self) for n in data["items"]] # players - @with_defaults() async def get_player(self, player_tag: str, cls: Type[Player] = Player, load_game_data: bool = None, **kwargs) -> Player: """Get information about a single player by player tag. @@ -2391,9 +2343,8 @@ async def get_player(self, player_tag: str, cls: Type[Player] = Player, player_tag = correct_tag(player_tag) data = await self.http.get_player(player_tag) - return cls(data=data, client=self, load_game_data=load_game_data, **kwargs) + return cls(data=data, client=self, load_game_data=load_game_data, **{**self._defaults, **kwargs}) - @with_defaults() def get_players(self, player_tags: Iterable[str], cls: Type[Player] = None, load_game_data: bool = None, **kwargs) -> AsyncIterator[ Player]: """Get information about a multiple players by player tag. @@ -2435,7 +2386,7 @@ def get_players(self, player_tags: Iterable[str], cls: Type[Player] = None, load if load_game_data and not isinstance(load_game_data, bool): raise TypeError("load_game_data must be either True or False.") - return PlayerIterator(self, player_tags, cls=cls, load_game_data=load_game_data, **kwargs) + return PlayerIterator(self, player_tags, cls=cls, load_game_data=load_game_data, **{**self._defaults, **kwargs} ) async def verify_player_token(self, player_tag: str, token: str, **kwargs) -> bool: """Verify player API token that can be found from the game settings. @@ -2474,7 +2425,6 @@ async def verify_player_token(self, player_tag: str, token: str, **kwargs) -> bo ignore_cached_errors=kwargs.get('ignore_cached_errors', self.ignore_cached_errors)) return data and data["status"] == "ok" or False - @with_defaults() async def get_current_goldpass_season(self, cls: Type[GoldPassSeason] = None, **kwargs) -> GoldPassSeason: """Get the current gold pass season @@ -2499,7 +2449,7 @@ async def get_current_goldpass_season(self, cls: Type[GoldPassSeason] = None, ** cls = self.objects_cls['GoldPassSeason'] if not issubclass(cls, GoldPassSeason): raise TypeError("cls must be a subclass of GoldPassSeason.") - data = await self.http.get_current_goldpass_season(**kwargs) + data = await self.http.get_current_goldpass_season(**{**self._defaults, **kwargs}) return cls(data=data) def parse_army_link(self, link: str): From 823aa2b15e1ed58d26541988eda5c091aa966bd1 Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 08:57:43 -0600 Subject: [PATCH 7/9] fix: set _defaults as property to allow it to use any updated values after init --- coc/client.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/coc/client.py b/coc/client.py index 1a1834c5..7f111459 100644 --- a/coc/client.py +++ b/coc/client.py @@ -254,11 +254,6 @@ def __init__( self.lookup_cache = lookup_cache self.update_cache = update_cache self.ignore_cached_errors = ignore_cached_errors - self._defaults = { - "lookup_cache": self.lookup_cache, - "update_cache": self.update_cache, - "ignore_cached_errors": self.ignore_cached_errors, - } self.http: Optional[HTTPClient] = None # set in method login() self.realtime = realtime @@ -280,6 +275,14 @@ def __init__( self._clans = {} self._wars = {} + @property + def _defaults(self): + return { + "lookup_cache": self.lookup_cache, + "update_cache": self.update_cache, + "ignore_cached_errors": self.ignore_cached_errors, + } + async def __aenter__(self): return self From 2015666d9778e1a2be7571062cf2b7b6ed3520c9 Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 08:58:58 -0600 Subject: [PATCH 8/9] fix: remove _defaults from slots --- coc/client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/coc/client.py b/coc/client.py index 7f111459..d5e7dfa0 100644 --- a/coc/client.py +++ b/coc/client.py @@ -198,7 +198,6 @@ class Client: "load_game_data", "lookup_cache", "update_cache", - "_defaults", "ignore_cached_errors", "_players", "_clans", From 7c1a0a9559fe474afd75e6c3ea20a86045abbcd2 Mon Sep 17 00:00:00 2001 From: MagicTheDev Date: Sat, 4 Jan 2025 10:11:56 -0600 Subject: [PATCH 9/9] fix: move kwargs to correct spot --- coc/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coc/client.py b/coc/client.py index d5e7dfa0..ed2e39a4 100644 --- a/coc/client.py +++ b/coc/client.py @@ -555,9 +555,9 @@ async def search_clans( if isinstance(x, (Label, int,))]), limit=limit, before=before, - after=after + after=after, + **{**self._defaults, **kwargs} ) - kwargs = {**self._defaults, **kwargs} return [cls(data=n, client=self, **kwargs) for n in data.get("items", [])]