From 59aa12136d09d0469630d9e7b3affaa61a70f713 Mon Sep 17 00:00:00 2001 From: 201st-Luka Date: Sat, 26 Aug 2023 15:48:48 +0200 Subject: [PATCH 1/7] fix: explicit setting of `requests_per_second` and `request_timeout` --- pyclasher/client.py | 4 ++-- tests/requests/conftest.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pyclasher/client.py b/pyclasher/client.py index deaaf20..4568b5b 100644 --- a/pyclasher/client.py +++ b/pyclasher/client.py @@ -103,8 +103,8 @@ async def from_login(cls, email, password, requests_per_second=5, logger.info("initialising client via login") self = cls([login.temporary_api_token for login in logins], - requests_per_second, - request_timeout, + requests_per_second=requests_per_second, + request_timeout=request_timeout, swagger_url=logins[0].swagger_url) self.logger = logger self.__temporary_session = True diff --git a/tests/requests/conftest.py b/tests/requests/conftest.py index 920a17f..8e4d1d3 100644 --- a/tests/requests/conftest.py +++ b/tests/requests/conftest.py @@ -24,7 +24,9 @@ async def pyclasher_client(event_loop): print("Setting PyClasherClient ...") client = await Client.from_login(CLASH_OF_CLANS_LOGIN_EMAIL, - CLASH_OF_CLANS_LOGIN_PASSWORD) + CLASH_OF_CLANS_LOGIN_PASSWORD, + requests_per_second=5, + request_timeout=30) client.client_id = "test_client" await client.start() From d9f3a183487a63d467b8b6be68a46415afbda21b Mon Sep 17 00:00:00 2001 From: 201st-Luka Date: Sat, 26 Aug 2023 15:55:44 +0200 Subject: [PATCH 2/7] refactor: updated README.md --- README.md | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index fc5f792..c20ef71 100644 --- a/README.md +++ b/README.md @@ -10,33 +10,35 @@ requested data. --- -I am planning to release the package on pypi.org after my exams. This is probably in the first week of september. +I am planning to release the package on pypi.org after my exams. This is +probably in the first week of september. The package is still in development and will be finished as short as -possible for me. When the package covers the -whole ClashOfClans API, the repository will be transformed into -a python package and will be available for everyone. +possible for me. When the package covers the whole ClashOfClans API, the +repository will be transformed into a python package and will be available for +everyone. -If you have any questions, feel free to join my discord server -to ask you question. +If you have any questions, feel free to join my discord server to ask your +question. ## Installation -It is possible to install the package from GitHib releases. You can use the following command to add PyClasher to your library: +It is possible to install the package from GitHib releases. You can use the +following command to add PyClasher to your library: ```bash -pip install git+https://github.com/201st-Luka/PyClasher.git@v0.0.1-alpha3 +pip install git+https://github.com/201st-Luka/PyClasher.git@v1.0.0-alpha1 ``` --- ## Features - Asynchronous and parallel requesting - - Possibility to use multiple tokens and to login via email address -and password of the ClashOfClans developer portal - - Control over the number of requests per second and the number of -used tokens + - Possibility to use multiple tokens and to login via email address and +password of the ClashOfClans developer portal + - Control over the number of requests per second and the number of used tokens - Open source - - Documented and type hinted + - Type hinted + - Sopports Python 3.8 -> 3.11 --- @@ -44,15 +46,14 @@ used tokens Feel free to contribute to the repository. -You can fork the repository and commit your changes in a pull request. Please consider to check out the -[Discord server][discord_url] if so. +You can fork the repository and commit your changes in a pull request. Please +consider to check out the [Discord server][discord_url] if so. --- ## Future -I'm planning to keep the API wrapper up to date and improve it as -good as I can. +I'm planning to keep the API wrapper up to date and improve it as good as I can. ### Planned features @@ -67,23 +68,25 @@ good as I can. ### Planned code implementations (ToDo-list) -- `total_wars` attribute for `ClanWarLogEntry` -- war log filtering for `ClanWarLogRequest` (for example filter the number of attacks per member) +- war log filtering for `ClanWarLogRequest` (for example filter the number of +attacks per member) - some "average" attributes for `Clan`-classes, `WarLog`-classes, ... -- attributes `king`, `queen`, `warden`, `royal_champion` for the `Player.heroes` attribute -- autosort for the `ClanCurrentWarRequest` members of the `member_list` attribute (sorted by the map position) +- attributes `king`, `queen`, `warden`, `royal_champion` for the +`Player.heroes` attribute +- autosort for the `ClanCurrentWarRequest` members of the `member_list` +attribute (sorted by the map position) - events and an `EventClient` --- -If you find a bug, an error or want custom functionality, please tell -me via Discord or open an issue or start a discussion on the -GitHub-repository. +If you find a bug, an error or want custom functionality, please tell me via +Discord or open an issue or start a discussion on the GitHub-repository. --- ##### Disclaimer -This material is unofficial and is not endorsed by Supercell. For more information see Supercell's Fan Content Policy: +This material is unofficial and is not endorsed by Supercell. For more +information see Supercell's Fan Content Policy: www.supercell.com/fan-content-policy. From 74f7d05c758f2438cca4a98541554cfb4500baf4 Mon Sep 17 00:00:00 2001 From: 201st-Luka Date: Sat, 26 Aug 2023 17:36:41 +0200 Subject: [PATCH 3/7] feat: implemented war log sorting --- README.md | 2 -- pyclasher/api/models/clan_war_log.py | 36 +++++++++++++++++++++++ pyclasher/api/models/clan_war_log.pyi | 13 ++++++++- pyclasher/api/requests/clan_war_log.py | 39 +++++++++++++++++++++++++ pyclasher/api/requests/clan_war_log.pyi | 14 ++++++++- pyclasher/utils/__init__.py | 1 + pyclasher/utils/functions.py | 5 ++++ pyclasher/utils/functions.pyi | 2 ++ tests/requests/test_clan.py | 11 +++++++ 9 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 pyclasher/utils/functions.py create mode 100644 pyclasher/utils/functions.pyi diff --git a/README.md b/README.md index c20ef71..d11d4ec 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,6 @@ I'm planning to keep the API wrapper up to date and improve it as good as I can. ### Planned code implementations (ToDo-list) -- war log filtering for `ClanWarLogRequest` (for example filter the number of -attacks per member) - some "average" attributes for `Clan`-classes, `WarLog`-classes, ... - attributes `king`, `queen`, `warden`, `royal_champion` for the `Player.heroes` attribute diff --git a/pyclasher/api/models/clan_war_log.py b/pyclasher/api/models/clan_war_log.py index 6231975..48fe099 100644 --- a/pyclasher/api/models/clan_war_log.py +++ b/pyclasher/api/models/clan_war_log.py @@ -1,7 +1,11 @@ +from typing import Literal + +from ...utils.functions import snake_to_camel from .abc import IterBaseModel, BaseModel from .base_models import Time from .enums import ClanWarResult from .war_clan import WarClan +from ...exceptions import PyClasherException class ClanWarLogEntry(BaseModel): @@ -32,3 +36,35 @@ def result(self): class ClanWarLog(IterBaseModel): _iter_rtype = ClanWarLogEntry + __Criteria = Literal["team_size", "attacks_per_member", "result"] + + @staticmethod + def __sort_key(item, key): + if key == "result": + if item[snake_to_camel(key)] == ClanWarResult.WIN.value: + return 3 + if item[snake_to_camel(key)] == ClanWarResult.LOSE.value: + return 1 + if item[snake_to_camel(key)] == ClanWarResult.TIE.value: + return 2 + if item[snake_to_camel(key)] == ClanWarResult.NONE.value: + return 0 + else: + return item[snake_to_camel(key)] + + def sort(self, criteria, descending=True): + if not isinstance(self.to_dict_list(), list): + raise PyClasherException("no value for `self._data`") + self._data = sorted(self._data, + key=lambda war: self.__sort_key(war, criteria), + reverse=descending) + return + + def filter(self, criteria, value): + if isinstance(value, ClanWarResult): + value = value.value + + self._data = [war + for war in self.to_dict_list() + if war[snake_to_camel(criteria)] == value] + return diff --git a/pyclasher/api/models/clan_war_log.pyi b/pyclasher/api/models/clan_war_log.pyi index b6910c9..c17d599 100644 --- a/pyclasher/api/models/clan_war_log.pyi +++ b/pyclasher/api/models/clan_war_log.pyi @@ -1,4 +1,4 @@ -from typing import Iterator +from typing import Iterator, Literal from .abc import IterBaseModel, BaseModel from .base_models import Time @@ -80,6 +80,17 @@ class ClanWarLog(IterBaseModel): """ _iter_rtype = ClanWarLogEntry + __Criteria = Literal["team_size", "attacks_per_member", "result"] + + @staticmethod + def __sort_key(item: dict, key: str) -> int: + ... + + def sort(self, criteria: __Criteria, descending=True) -> None: + ... + + def filter(self, criteria: __Criteria, value: int | ClanWarResult) -> None: + ... def __getitem__(self, item: int) -> ClanWarLogEntry: ... diff --git a/pyclasher/api/requests/clan_war_log.py b/pyclasher/api/requests/clan_war_log.py index 85b9a81..9f5e1ea 100644 --- a/pyclasher/api/requests/clan_war_log.py +++ b/pyclasher/api/requests/clan_war_log.py @@ -1,5 +1,10 @@ +from typing import Literal + +from ...utils import snake_to_camel +from ...exceptions import PyClasherException, RequestNotDone from .abc import IterRequestModel from ..models import ClanWarLog, ClanWarLogEntry +from ..models.enums import ClanWarResult class ClanWarLogRequest(IterRequestModel): @@ -9,6 +14,7 @@ class ClanWarLogRequest(IterRequestModel): clan_tag: str = None _iter_rtype = ClanWarLogEntry _list_rtype = ClanWarLog + __Criteria = Literal["team_size", "attacks_per_member", "result"] def __init__(self, clan_tag, limit=None, after=None, before=None): """ @@ -36,3 +42,36 @@ def __init__(self, clan_tag, limit=None, after=None, before=None): }) self._main_attribute = self.clan_tag return + + @staticmethod + def __sort_key(item, key): + if key == "result": + if item[snake_to_camel(key)] == ClanWarResult.WIN.value: + return 3 + if item[snake_to_camel(key)] == ClanWarResult.LOSE.value: + return 1 + if item[snake_to_camel(key)] == ClanWarResult.TIE.value: + return 2 + if item[snake_to_camel(key)] == ClanWarResult.NONE.value: + return 0 + else: + return item[snake_to_camel(key)] + + def sort(self, criteria, descending=True): + if not isinstance(self._data, dict): + raise RequestNotDone + self._data['items'] = sorted( + self._data['items'], + key=lambda war: self.__sort_key(war, criteria), + reverse=descending + ) + return + + def filter(self, criteria, value): + if isinstance(value, ClanWarResult): + value = value.value + + self._data['items'] = [war + for war in self._data['items'] + if war[snake_to_camel(criteria)] == value] + return diff --git a/pyclasher/api/requests/clan_war_log.pyi b/pyclasher/api/requests/clan_war_log.pyi index f0e41ac..e8a896a 100644 --- a/pyclasher/api/requests/clan_war_log.pyi +++ b/pyclasher/api/requests/clan_war_log.pyi @@ -1,18 +1,30 @@ -from typing import Iterator +from typing import Iterator, Literal from .abc import IterRequestModel from ..models import ClanWarLog, ClanWarLogEntry +from ..models.enums import ClanWarResult class ClanWarLogRequest(IterRequestModel): clan_tag: str = None _iter_rtype = ClanWarLogEntry _list_rtype = ClanWarLog + __Criteria = Literal["team_size", "attacks_per_member", "result"] def __init__(self, clan_tag: str, limit: int = None, after: str = None, before: str = None) -> None: self.clan_tag = clan_tag ... + @staticmethod + def __sort_key(item: dict, key: str) -> int: + ... + + def sort(self, criteria: __Criteria, descending=True) -> None: + ... + + def filter(self, criteria: __Criteria, value: int | ClanWarResult) -> None: + ... + @property def items(self) -> _list_rtype: ... diff --git a/pyclasher/utils/__init__.py b/pyclasher/utils/__init__.py index 98ee5d7..17443fc 100644 --- a/pyclasher/utils/__init__.py +++ b/pyclasher/utils/__init__.py @@ -1,3 +1,4 @@ from .exectimer import ExecutionTimer from .login import Login from .request_methods import RequestMethods +from .functions import snake_to_camel diff --git a/pyclasher/utils/functions.py b/pyclasher/utils/functions.py new file mode 100644 index 0000000..c32a304 --- /dev/null +++ b/pyclasher/utils/functions.py @@ -0,0 +1,5 @@ +def snake_to_camel(snake_str: str) -> str: + components = snake_str.split('_') + camel_str = components[0] + ''.join( + x.title() for x in components[1:]) + return camel_str diff --git a/pyclasher/utils/functions.pyi b/pyclasher/utils/functions.pyi new file mode 100644 index 0000000..656dc05 --- /dev/null +++ b/pyclasher/utils/functions.pyi @@ -0,0 +1,2 @@ +def snake_to_camel(snake_str: str) -> str: + ... diff --git a/tests/requests/test_clan.py b/tests/requests/test_clan.py index cf0e41e..628f424 100644 --- a/tests/requests/test_clan.py +++ b/tests/requests/test_clan.py @@ -132,6 +132,17 @@ async def test_clan_war_log(event_loop, pyclasher_client): assert 5 <= war.team_size <= 50 assert isinstance(war.result, ClanWarResult) + war_log.sort("team_size", descending=False) + previous = 0 + + for war in war_log: + assert war.team_size >= previous + previous = war.team_size + + war_log.filter("attacks_per_member", 1) + for war in war_log: + assert war.attacks_per_member == 1 + @pytest.mark.asyncio async def test_clan_search(event_loop, pyclasher_client): From 1d92cab302788c15e941b03ef3a1308ea277939f Mon Sep 17 00:00:00 2001 From: 201st-Luka Date: Sat, 26 Aug 2023 21:14:40 +0200 Subject: [PATCH 4/7] feat: implemented `average_...` properties --- README.md | 1 - pyclasher/api/models/clan.py | 21 +++++++ pyclasher/api/models/clan.pyi | 20 +++++++ .../api/models/clan_capital_raid_seasons.py | 56 +++++++++++++++++-- .../api/models/clan_capital_raid_seasons.pyi | 45 +++++++++++++++ pyclasher/api/models/clan_member_list.py | 21 +++++++ pyclasher/api/models/clan_member_list.pyi | 20 +++++++ pyclasher/api/models/clan_war_log.py | 40 +++++++++++++ pyclasher/api/models/clan_war_log.pyi | 20 +++++++ pyclasher/api/models/player.py | 8 +++ pyclasher/api/models/player.pyi | 4 ++ pyclasher/api/requests/abc.py | 11 ++-- pyclasher/api/requests/abc.pyi | 4 +- .../api/requests/clan_capital_raid_seasons.py | 24 ++++++++ .../requests/clan_capital_raid_seasons.pyi | 24 ++++++++ pyclasher/api/requests/clan_members.py | 20 +++++++ pyclasher/api/requests/clan_members.pyi | 20 +++++++ pyclasher/api/requests/clan_war_log.py | 20 +++++++ pyclasher/api/requests/clan_war_log.pyi | 20 +++++++ 19 files changed, 383 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d11d4ec..7144a4c 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,6 @@ I'm planning to keep the API wrapper up to date and improve it as good as I can. ### Planned code implementations (ToDo-list) -- some "average" attributes for `Clan`-classes, `WarLog`-classes, ... - attributes `king`, `queen`, `warden`, `royal_champion` for the `Player.heroes` attribute - autosort for the `ClanCurrentWarRequest` members of the `member_list` diff --git a/pyclasher/api/models/clan.py b/pyclasher/api/models/clan.py index 9c78528..469e186 100644 --- a/pyclasher/api/models/clan.py +++ b/pyclasher/api/models/clan.py @@ -146,3 +146,24 @@ def description(self): @property def clan_capital(self): return ClanCapital(self._get_data('clanCapital')) + + @property + def average_exp_level_per_member(self): + return self.member_list.average_exp_level + + @property + def average_trophies_per_member(self): + return self.member_list.average_trophies + + @property + def average_builder_base_trophies_per_member(self): + return self.member_list.average_builder_base_trophies + + @property + def average_donations_per_member(self): + return self.member_list.average_donations + + @property + def average_donations_received_per_member(self): + return self.member_list.average_donations_received + diff --git a/pyclasher/api/models/clan.pyi b/pyclasher/api/models/clan.pyi index bad0932..e87bc6d 100644 --- a/pyclasher/api/models/clan.pyi +++ b/pyclasher/api/models/clan.pyi @@ -343,3 +343,23 @@ class Clan(BaseClan): :rtype: ClanCapital """ ... + + @property + def average_exp_level_per_member(self) -> float: + ... + + @property + def average_trophies_per_member(self) -> float: + ... + + @property + def average_builder_base_trophies_per_member(self) -> float: + ... + + @property + def average_donations_per_member(self) -> float: + ... + + @property + def average_donations_received_per_member(self) -> float: + ... diff --git a/pyclasher/api/models/clan_capital_raid_seasons.py b/pyclasher/api/models/clan_capital_raid_seasons.py index 9579215..3919745 100644 --- a/pyclasher/api/models/clan_capital_raid_seasons.py +++ b/pyclasher/api/models/clan_capital_raid_seasons.py @@ -157,12 +157,6 @@ class ClanCapitalRaidSeasonDefenseLogList(IterBaseModel): class ClanCapitalRaidSeasonAttackLogList(IterBaseModel): _iter_rtype = ClanCapitalRaidSeasonAttackLogEntry - def __getitem__(self, item): - return super().__getitem__(item) - - def __next__(self) -> _iter_rtype: - return super().__next__() - class ClanCapitalRaidSeasonMember(BaseClanMember): @property @@ -185,6 +179,15 @@ def capital_resources_looted(self): class ClanCapitalRaidSeasonMemberList(IterBaseModel): _iter_rtype = ClanCapitalRaidSeasonMember + @property + def average_attacks(self): + return sum((member.attacks for member in self)) / len(self) + + @property + def average_resources_looted(self): + return (sum((member.capital_resources_looted for member in self)) / + len(self)) + class ClanCapitalRaidSeason(BaseModel): def __init__(self, data): @@ -232,10 +235,51 @@ def enemy_districts_destroyed(self): def defensive_reward(self): return self._get_data('defensiveReward') + @property + def offensive_reward(self): + return self._get_data('offensiveReward') + @property def members(self): return ClanCapitalRaidSeasonMemberList(self._get_data('members')) + @property + def average_attacks_per_member(self): + return (sum((member.attacks for member in self.members)) / + len(self.members)) + + @property + def average_resources_looted_per_member(self): + return ( + sum((member.capital_resources_looted for member in self.members)) / + len(self.members) + ) + class ClanCapitalRaidSeasons(IterBaseModel): _iter_rtype = ClanCapitalRaidSeason + + @property + def average_capital_total_loot(self): + return sum((season.capital_total_loot for season in self)) / len(self) + + @property + def average_raids_completed(self): + return sum((season.raids_completed for season in self)) / len(self) + + @property + def average_total_attacks(self): + return sum((season.total_attacks for season in self)) / len(self) + + @property + def average_enemy_districts_destroyed(self): + return (sum((season.enemy_districts_destroyed for season in self)) / + len(self)) + + @property + def average_defensive_reward(self): + return sum((season.defensive_reward for season in self)) / len(self) + + @property + def average_offensive_reward(self): + return sum((season.offensive_reward for season in self)) / len(self) diff --git a/pyclasher/api/models/clan_capital_raid_seasons.pyi b/pyclasher/api/models/clan_capital_raid_seasons.pyi index 42662ef..b175771 100644 --- a/pyclasher/api/models/clan_capital_raid_seasons.pyi +++ b/pyclasher/api/models/clan_capital_raid_seasons.pyi @@ -411,6 +411,14 @@ class ClanCapitalRaidSeasonMemberList(IterBaseModel): _iter_rtype = ClanCapitalRaidSeasonMember + @property + def average_attacks(self) -> float: + ... + + @property + def average_resources_looted(self) -> float: + ... + def __getitem__(self, item: int | str) -> ClanCapitalRaidSeasonMember: ... @@ -527,6 +535,10 @@ class ClanCapitalRaidSeason(BaseModel): """ ... + @property + def offensive_reward(self) -> int: + ... + @property def members(self) -> Missing | ClanCapitalRaidSeasonMemberList: """ @@ -537,6 +549,15 @@ class ClanCapitalRaidSeason(BaseModel): """ ... + @property + def average_attacks_per_member(self) -> float: + ... + + @property + def average_resources_looted_per_member(self) -> float: + ... + + class ClanCapitalRaidSeasons(IterBaseModel): """ @@ -547,6 +568,30 @@ class ClanCapitalRaidSeasons(IterBaseModel): _iter_rtype = ClanCapitalRaidSeason + @property + def average_capital_total_loot(self) -> float: + ... + + @property + def average_raids_completed(self) -> float: + ... + + @property + def average_total_attacks(self) -> float: + ... + + @property + def average_enemy_districts_destroyed(self) -> float: + ... + + @property + def average_defensive_reward(self) -> float: + ... + + @property + def average_offensive_reward(self) -> float: + ... + def __getitem__(self, item: int | str) -> ClanCapitalRaidSeason: ... diff --git a/pyclasher/api/models/clan_member_list.py b/pyclasher/api/models/clan_member_list.py index e5ea1cc..3da7836 100644 --- a/pyclasher/api/models/clan_member_list.py +++ b/pyclasher/api/models/clan_member_list.py @@ -5,6 +5,27 @@ class ClanMemberList(IterBaseModel): _iter_rtype = ClanMember + @property + def average_exp_level(self): + return sum((member.exp_level for member in self)) / len(self) + + @property + def average_trophies(self): + return sum((member.trophies for member in self)) / len(self) + + @property + def average_builder_base_trophies(self): + return (sum((member.builder_base_trophies for member in self)) / + len(self)) + + @property + def average_donations(self): + return sum((member.donations for member in self)) / len(self) + + @property + def average_donations_received(self): + return sum((member.donations_received for member in self)) / len(self) + def __getitem__(self, item): return super().__getitem__(item) diff --git a/pyclasher/api/models/clan_member_list.pyi b/pyclasher/api/models/clan_member_list.pyi index ad036d9..67189bf 100644 --- a/pyclasher/api/models/clan_member_list.pyi +++ b/pyclasher/api/models/clan_member_list.pyi @@ -15,6 +15,26 @@ class ClanMemberList(IterBaseModel): _iter_rtype = ClanMember + @property + def average_exp_level(self) -> float: + ... + + @property + def average_trophies(self) -> float: + ... + + @property + def average_builder_base_trophies(self) -> float: + ... + + @property + def average_donations(self) -> float: + ... + + @property + def average_donations_received(self) -> float: + ... + def __getitem__(self, item: int | str) -> ClanMember: ... diff --git a/pyclasher/api/models/clan_war_log.py b/pyclasher/api/models/clan_war_log.py index 48fe099..d6b2d7c 100644 --- a/pyclasher/api/models/clan_war_log.py +++ b/pyclasher/api/models/clan_war_log.py @@ -38,6 +38,46 @@ class ClanWarLog(IterBaseModel): _iter_rtype = ClanWarLogEntry __Criteria = Literal["team_size", "attacks_per_member", "result"] + @property + def average_team_size(self): + try: + return sum((war.team_size for war in self + if war.attacks_per_member == 2)) / len(self) + except ZeroDivisionError: + return None + + @property + def average_destruction_percentage(self): + try: + return sum((war.clan.destruction_percentage for war in self + if war.attacks_per_member == 2)) / len(self) + except ZeroDivisionError: + return None + + @property + def average_attacks(self): + try: + return sum((war.clan.attacks for war in self + if war.attacks_per_member == 2)) / len(self) + except ZeroDivisionError: + return None + + @property + def average_stars(self): + try: + return sum((war.clan.stars for war in self + if war.attacks_per_member == 2)) / len(self) + except ZeroDivisionError: + return None + + @property + def average_exp_earned(self): + try: + return sum((war.clan.exp_earned for war in self + if war.attacks_per_member == 2)) / len(self) + except ZeroDivisionError: + return None + @staticmethod def __sort_key(item, key): if key == "result": diff --git a/pyclasher/api/models/clan_war_log.pyi b/pyclasher/api/models/clan_war_log.pyi index c17d599..07f914c 100644 --- a/pyclasher/api/models/clan_war_log.pyi +++ b/pyclasher/api/models/clan_war_log.pyi @@ -82,6 +82,26 @@ class ClanWarLog(IterBaseModel): _iter_rtype = ClanWarLogEntry __Criteria = Literal["team_size", "attacks_per_member", "result"] + @property + def average_team_size(self) -> None | float: + ... + + @property + def average_destruction_percentage(self) -> None | float: + ... + + @property + def average_attacks(self) -> None | float: + ... + + @property + def average_stars(self) -> None | float: + ... + + @property + def average_exp_earned(self) -> None | float: + ... + @staticmethod def __sort_key(item: dict, key: str) -> int: ... diff --git a/pyclasher/api/models/player.py b/pyclasher/api/models/player.py index c4b9669..994f208 100644 --- a/pyclasher/api/models/player.py +++ b/pyclasher/api/models/player.py @@ -191,6 +191,14 @@ def troops(self): def heroes(self): return PlayerItemLevelList(self._get_data('heroes')) + @property + def average_hero_level(self): + return (sum((hero + for hero in self.heroes + if hero.village == Village.HOME_VILLAGE)) / + sum((hero.village == Village.HOME_VILLAGE + for hero in self.heroes))) + @property def spells(self): return PlayerItemLevelList(self._get_data('spells')) diff --git a/pyclasher/api/models/player.pyi b/pyclasher/api/models/player.pyi index 5ea9ef1..474968d 100644 --- a/pyclasher/api/models/player.pyi +++ b/pyclasher/api/models/player.pyi @@ -228,6 +228,10 @@ class Player(BaseModel): def heroes(self) -> PlayerItemLevelList: ... + @property + def average_hero_level(self) -> float: + ... + @property def spells(self) -> PlayerItemLevelList: ... diff --git a/pyclasher/api/requests/abc.py b/pyclasher/api/requests/abc.py index 31463fc..f84bf9e 100644 --- a/pyclasher/api/requests/abc.py +++ b/pyclasher/api/requests/abc.py @@ -158,14 +158,8 @@ def __init__(self, kwargs=kwargs, request_method=request_method, **url_kwargs) - self._len = None return - async def request(self, client_id=None): - await super().request(client_id) - self._len = len(self._get_data('items')) - return self - @property def items(self): return self._list_rtype(self._get_data('items')) @@ -196,4 +190,7 @@ def __contains__(self, item): raise NotImplementedError def __len__(self): - return self._len + try: + return len(self._get_data('items')) + except RequestNotDone: + return None diff --git a/pyclasher/api/requests/abc.pyi b/pyclasher/api/requests/abc.pyi index 6e7d8c9..dc6288e 100644 --- a/pyclasher/api/requests/abc.pyi +++ b/pyclasher/api/requests/abc.pyi @@ -69,7 +69,7 @@ class IterRequestModel(RequestModel, ABC): request_method: RequestMethods = RequestMethods.REQUEST, **url_kwargs ) -> None: - self._len: None | int = ... + ... @property def items(self) -> _list_rtype: @@ -92,5 +92,5 @@ class IterRequestModel(RequestModel, ABC): def __contains__(self, item: _iter_rtype) -> bool: ... - def __len__(self) -> int: + def __len__(self) -> None | int: ... diff --git a/pyclasher/api/requests/clan_capital_raid_seasons.py b/pyclasher/api/requests/clan_capital_raid_seasons.py index 32d7b59..801c7f8 100644 --- a/pyclasher/api/requests/clan_capital_raid_seasons.py +++ b/pyclasher/api/requests/clan_capital_raid_seasons.py @@ -36,3 +36,27 @@ def __init__(self, clan_tag, limit=None, after=None, before=None): }) self._main_attribute = self.clan_tag return + + @property + def average_capital_total_loot_per_season(self): + return self.items.average_capital_total_loot + + @property + def average_raids_completed_per_season(self): + return self.items.average_raids_completed + + @property + def average_total_attacks_per_season(self): + return self.items.average_total_attacks + + @property + def average_enemy_districts_destroyed_per_season(self): + return self.items.average_enemy_districts_destroyed + + @property + def average_defensive_reward_per_season(self): + return self.items.average_defensive_reward + + @property + def average_offensive_reward_per_season(self): + return self.items.average_offensive_reward diff --git a/pyclasher/api/requests/clan_capital_raid_seasons.pyi b/pyclasher/api/requests/clan_capital_raid_seasons.pyi index 3c21800..52dedd8 100644 --- a/pyclasher/api/requests/clan_capital_raid_seasons.pyi +++ b/pyclasher/api/requests/clan_capital_raid_seasons.pyi @@ -24,3 +24,27 @@ class ClanCapitalRaidSeasonsRequest(IterRequestModel): def __next__(self) -> _iter_rtype: ... + + @property + def average_capital_total_loot_per_season(self) -> float: + ... + + @property + def average_raids_completed_per_season(self) -> float: + ... + + @property + def average_total_attacks_per_season(self) -> float: + ... + + @property + def average_enemy_districts_destroyed_per_season(self) -> float: + ... + + @property + def average_defensive_reward_per_season(self) -> float: + ... + + @property + def average_offensive_reward_per_season(self) -> float: + ... diff --git a/pyclasher/api/requests/clan_members.py b/pyclasher/api/requests/clan_members.py index 4babaca..f4b3e99 100644 --- a/pyclasher/api/requests/clan_members.py +++ b/pyclasher/api/requests/clan_members.py @@ -36,3 +36,23 @@ def __init__(self, clan_tag, limit=None, after=None, before=None): }) self._main_attribute = self.clan_tag return + + @property + def average_exp_level_per_member(self): + return self.items.average_exp_level + + @property + def average_trophies_per_member(self): + return self.items.average_trophies + + @property + def average_builder_base_trophies_per_member(self): + return self.items.average_builder_base_trophies + + @property + def average_donations_per_member(self): + return self.items.average_donations + + @property + def average_donations_received_per_member(self): + return self.items.average_donations_received diff --git a/pyclasher/api/requests/clan_members.pyi b/pyclasher/api/requests/clan_members.pyi index 2a69a6d..820e485 100644 --- a/pyclasher/api/requests/clan_members.pyi +++ b/pyclasher/api/requests/clan_members.pyi @@ -12,6 +12,26 @@ class ClanMembersRequest(IterRequestModel): self.clan_tag = clan_tag ... + @property + def average_exp_level_per_member(self) -> float: + ... + + @property + def average_trophies_per_member(self) -> float: + ... + + @property + def average_builder_base_trophies_per_member(self) -> float: + ... + + @property + def average_donations_per_member(self) -> float: + ... + + @property + def average_donations_received_per_member(self) -> float: + ... + @property def items(self) -> _list_rtype: ... diff --git a/pyclasher/api/requests/clan_war_log.py b/pyclasher/api/requests/clan_war_log.py index 9f5e1ea..1914ff7 100644 --- a/pyclasher/api/requests/clan_war_log.py +++ b/pyclasher/api/requests/clan_war_log.py @@ -75,3 +75,23 @@ def filter(self, criteria, value): for war in self._data['items'] if war[snake_to_camel(criteria)] == value] return + + @property + def average_team_size(self): + return self.items.average_team_size + + @property + def average_destruction_percentage(self): + return self.items.average_destruction_percentage + + @property + def average_attacks(self): + return self.items.average_attacks + + @property + def average_stars(self): + return self.items.average_stars + + @property + def average_exp_earned(self): + return self.items.average_exp_earned diff --git a/pyclasher/api/requests/clan_war_log.pyi b/pyclasher/api/requests/clan_war_log.pyi index e8a896a..6cf1eb2 100644 --- a/pyclasher/api/requests/clan_war_log.pyi +++ b/pyclasher/api/requests/clan_war_log.pyi @@ -25,6 +25,26 @@ class ClanWarLogRequest(IterRequestModel): def filter(self, criteria: __Criteria, value: int | ClanWarResult) -> None: ... + @property + def average_team_size(self) -> float: + ... + + @property + def average_destruction_percentage(self) -> float: + ... + + @property + def average_attacks(self) -> float: + ... + + @property + def average_stars(self) -> float: + ... + + @property + def average_exp_earned(self) -> float: + ... + @property def items(self) -> _list_rtype: ... From 7b867d14d6b209358cc44d1aa7854a2e4db91834 Mon Sep 17 00:00:00 2001 From: 201st-Luka Date: Sat, 26 Aug 2023 21:22:39 +0200 Subject: [PATCH 5/7] feat: player sorting in `ClanCurrentWarRequest` implemented automatic player sorting (by map position) for the clan and opponent members of the `ClanCurrentWarRequest` --- README.md | 2 -- pyclasher/api/requests/clan_current_war.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7144a4c..1492a70 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,6 @@ I'm planning to keep the API wrapper up to date and improve it as good as I can. - attributes `king`, `queen`, `warden`, `royal_champion` for the `Player.heroes` attribute -- autosort for the `ClanCurrentWarRequest` members of the `member_list` -attribute (sorted by the map position) - events and an `EventClient` --- diff --git a/pyclasher/api/requests/clan_current_war.py b/pyclasher/api/requests/clan_current_war.py index ae73b7e..dcfa3b4 100644 --- a/pyclasher/api/requests/clan_current_war.py +++ b/pyclasher/api/requests/clan_current_war.py @@ -35,3 +35,14 @@ async def from_base_clan(cls, base_clan): self = await cls(base_clan.tag).request() return self + async def request(self, client_id=None): + await super().request(client_id) + + self._data['clan']['members'] = sorted( + self._data['clan']['members'], + key=lambda member: member['mapPosition'] + ) + self._data['opponent']['members'] = sorted( + self._data['opponent']['members'], + key=lambda member: member['mapPosition'] + ) From 80d0a2228232762f731ff4a731a89b0e4cd5e8a7 Mon Sep 17 00:00:00 2001 From: 201st-Luka Date: Sat, 26 Aug 2023 22:02:14 +0200 Subject: [PATCH 6/7] refactor: optimized imports --- pyclasher/__init__.py | 83 ++++++++++++++++--- pyclasher/api/__init__.py | 34 ++++++++ pyclasher/api/bulk_requests/__init__.py | 5 ++ pyclasher/api/bulk_requests/b_player.pyi | 3 +- pyclasher/api/models/__init__.py | 29 ++++++- pyclasher/api/models/clan_war_log.py | 2 +- pyclasher/api/requests/__init__.py | 55 ++++++++---- pyclasher/api/requests/abc.py | 2 +- pyclasher/api/requests/abc.pyi | 2 +- .../requests/clan_builder_base_rankings.pyi | 3 +- pyclasher/api/requests/clan_war_log.py | 4 +- pyclasher/api/requests/player.py | 4 +- .../requests/player_builder_base_rankings.pyi | 3 +- pyclasher/client.py | 7 +- pyclasher/client.pyi | 1 - pyclasher/request_queue/__init__.py | 2 +- pyclasher/request_queue/request_consumer.py | 4 +- pyclasher/request_queue/request_consumer.pyi | 1 + pyclasher/utils/__init__.py | 2 +- 19 files changed, 198 insertions(+), 48 deletions(-) diff --git a/pyclasher/__init__.py b/pyclasher/__init__.py index 25728f8..71c6f7a 100644 --- a/pyclasher/__init__.py +++ b/pyclasher/__init__.py @@ -1,7 +1,7 @@ """ pyclasher ClashOfClans API wrapper client -This wrapper client has been created by 201st-Luka. +This wrapper client has been created and developed by 201st-Luka. `GitHub `_ `Wiki `_ @@ -11,20 +11,77 @@ __version__ = '1.0.0-alpha1' -# api from .api import * +from .client import Client +from .exceptions import ( + PyClasherException, ApiException, ApiExceptions, UnknownApiException, + MISSING, Missing, RequestNotDone, RequestTimeout, BadRequest, NotFound, + Throttled, Maintenance, AccessDenied, NoClient, InvalidClientId, + ClientIsRunning, ClientIsNotRunning, ClientRunningOverwrite, + ClientAlreadyInitialised, LoginNotDone, InvalidLoginData, InvalidType, + InvalidTimeFormat, InvalidSeasonFormat, NoneToken +) -# utils -from .utils import * +__all__ = ( + "PlayerBulkRequest", -# client.py -from .client import Client + "BuilderBaseLeagueRequest", + "BuilderBaseLeaguesRequest", + "CapitalLeagueRequest", + "CapitalLeaguesRequest", + "CapitalRankingsRequest", + "ClanRequest", + "ClanBuilderBaseRankingsRequest", + "ClanCapitalRaidSeasonsRequest", + "ClanCurrentWarRequest", + "ClanCurrentwarLeaguegroupRequest", + "ClanLabelsRequest", + "ClanMembersRequest", + "ClanRankingsRequest", + "ClanSearchRequest", + "ClanWarLogRequest", + "ClanWarleaguesWarsRequest", + "GoldPassRequest", + "LeagueRequest", + "LeagueSeasonRequest", + "LeagueSeasonsRequest", + "LeaguesRequest", + "LocationRequest", + "LocationsRequest", + "PlayerRequest", + "PlayerBuilderBaseRankingsRequest", + "PlayerLabelsRequest", + "PlayerRankingsRequest", + "WarLeagueRequest", + "WarLeaguesRequest", -# exceptions.py -from .exceptions import ( - Missing, MISSING, PyClasherException, RequestNotDone, NoneToken, - InvalidLoginData, InvalidType, LoginNotDone, ClientIsRunning, - ClientIsNotRunning, ClientAlreadyInitialised, NoClient, - InvalidTimeFormat, ClientRunningOverwrite, InvalidSeasonFormat, - RequestTimeout + "__version__", + + "Client", + + "PyClasherException", + "ApiException", + "ApiExceptions", + "UnknownApiException", + "MISSING", + "Missing", + "RequestNotDone", + "RequestTimeout", + "BadRequest", + "NotFound", + "Throttled", + "Maintenance", + "AccessDenied", + "NoClient", + "InvalidClientId", + "ClientIsRunning", + "ClientIsNotRunning", + "ClientRunningOverwrite", + "ClientAlreadyInitialised", + "LoginNotDone", + "InvalidLoginData", + "InvalidType", + "InvalidTimeFormat", + "InvalidSeasonFormat", + "NoneToken" ) diff --git a/pyclasher/api/__init__.py b/pyclasher/api/__init__.py index ce0dd00..c39edf6 100644 --- a/pyclasher/api/__init__.py +++ b/pyclasher/api/__init__.py @@ -1,3 +1,37 @@ from .bulk_requests import * from .models import * from .requests import * + +__all__ = ( + "PlayerBulkRequest", + + "BuilderBaseLeagueRequest", + "BuilderBaseLeaguesRequest", + "CapitalLeagueRequest", + "CapitalLeaguesRequest", + "CapitalRankingsRequest", + "ClanRequest", + "ClanBuilderBaseRankingsRequest", + "ClanCapitalRaidSeasonsRequest", + "ClanCurrentWarRequest", + "ClanCurrentwarLeaguegroupRequest", + "ClanLabelsRequest", + "ClanMembersRequest", + "ClanRankingsRequest", + "ClanSearchRequest", + "ClanWarLogRequest", + "ClanWarleaguesWarsRequest", + "GoldPassRequest", + "LeagueRequest", + "LeagueSeasonRequest", + "LeagueSeasonsRequest", + "LeaguesRequest", + "LocationRequest", + "LocationsRequest", + "PlayerRequest", + "PlayerBuilderBaseRankingsRequest", + "PlayerLabelsRequest", + "PlayerRankingsRequest", + "WarLeagueRequest", + "WarLeaguesRequest" +) diff --git a/pyclasher/api/bulk_requests/__init__.py b/pyclasher/api/bulk_requests/__init__.py index af95121..832923a 100644 --- a/pyclasher/api/bulk_requests/__init__.py +++ b/pyclasher/api/bulk_requests/__init__.py @@ -1 +1,6 @@ from .b_player import PlayerBulkRequest +from .b_request_model import BulkRequestModel + +__all__ = ( + "PlayerBulkRequest", +) diff --git a/pyclasher/api/bulk_requests/b_player.pyi b/pyclasher/api/bulk_requests/b_player.pyi index 6bcf63a..d7a80a9 100644 --- a/pyclasher/api/bulk_requests/b_player.pyi +++ b/pyclasher/api/bulk_requests/b_player.pyi @@ -1,7 +1,8 @@ from typing import Iterable, Coroutine, Any, Iterator from .b_request_model import BulkRequestModel -from ..models import BaseClan, ClanMemberList, ClanWarMemberList, ClanWarLeagueClanMemberList, \ +from ..models import BaseClan, ClanMemberList, ClanWarMemberList, \ + ClanWarLeagueClanMemberList, \ ClanCapitalRaidSeasonMemberList from ..requests import PlayerRequest, ClanMembersRequest diff --git a/pyclasher/api/models/__init__.py b/pyclasher/api/models/__init__.py index a3a74e8..be3dd99 100644 --- a/pyclasher/api/models/__init__.py +++ b/pyclasher/api/models/__init__.py @@ -10,6 +10,7 @@ BaseClanMember, BaseClan, BaseLeague ) + # clan models from .clan import ClanDistrictData, ClanDistrictDataList, ClanCapital, Clan from .clan_builder_base_ranking_list import ( @@ -60,6 +61,7 @@ from .location import Location, LocationList # login from .login import * +# misc from .misc import * # player models from .player import ( @@ -75,8 +77,33 @@ ) from .player_ranking_clan import PlayerRankingClan from .player_ranking_list import PlayerRanking, PlayerRankingList -# misc +# miscellaneous from .season import Season from .war_clan import ( ClanWarAttack, ClanWarAttackList, ClanWarMember, ClanWarMemberList, WarClan ) + +__all__ = ( + "ClanCapital", + "Clan", + "ClanBuilderBaseRanking", + "ClanCapitalRaidSeason", + "ClanCapitalRaidSeasons", + "ClanCapitalRanking", + "ClanMember", + "ClanRanking", + "ClanWar", + "ClanWarLeagueGroup", + "ClanWarLog", + "Label", + "Language", + "League", + "BuilderBaseLeague", + "CapitalLeague", + "WarLeague", + "Location", + "LoginModel", + "Player", + "PlayerBuilderBaseRanking", + "WarClan" +) diff --git a/pyclasher/api/models/clan_war_log.py b/pyclasher/api/models/clan_war_log.py index d6b2d7c..743d693 100644 --- a/pyclasher/api/models/clan_war_log.py +++ b/pyclasher/api/models/clan_war_log.py @@ -1,11 +1,11 @@ from typing import Literal -from ...utils.functions import snake_to_camel from .abc import IterBaseModel, BaseModel from .base_models import Time from .enums import ClanWarResult from .war_clan import WarClan from ...exceptions import PyClasherException +from ...utils.functions import snake_to_camel class ClanWarLogEntry(BaseModel): diff --git a/pyclasher/api/requests/__init__.py b/pyclasher/api/requests/__init__.py index c0b520f..ef7c33a 100644 --- a/pyclasher/api/requests/__init__.py +++ b/pyclasher/api/requests/__init__.py @@ -2,41 +2,66 @@ requests that can be used """ +from .abc import RequestModel, IterRequestModel, request_id from .builder_base_league import BuilderBaseLeagueRequest from .builder_base_leagues import BuilderBaseLeaguesRequest from .capital_league import CapitalLeagueRequest from .capital_league_seasons import CapitalLeaguesRequest -# clan +from .capital_rankings import CapitalRankingsRequest from .clan import ClanRequest +from .clan_builder_base_rankings import ClanBuilderBaseRankingsRequest from .clan_capital_raid_seasons import ClanCapitalRaidSeasonsRequest from .clan_current_war import ClanCurrentWarRequest +from .clan_currentwar_leaguegroup import ClanCurrentwarLeaguegroupRequest from .clan_labels import ClanLabelsRequest from .clan_members import ClanMembersRequest +from .clan_rankings import ClanRankingsRequest from .clan_search import ClanSearchRequest from .clan_war_log import ClanWarLogRequest -from .clan_currentwar_leaguegroup import ClanCurrentwarLeaguegroupRequest from .clan_warleagues_wars import ClanWarleaguesWarsRequest -# goldpass from .gold_pass import GoldPassRequest from .league import LeagueRequest -# leagues from .league_season import LeagueSeasonRequest -from .leagues import LeaguesRequest from .league_seasons import LeagueSeasonsRequest -# locations +from .leagues import LeaguesRequest from .location import LocationRequest from .locations import LocationsRequest -# player from .player import PlayerRequest -# labels +from .player_builder_base_rankings import PlayerBuilderBaseRankingsRequest from .player_labels import PlayerLabelsRequest -from .abc import RequestModel, IterRequestModel, request_id +from .player_rankings import PlayerRankingsRequest from .war_league import WarLeagueRequest from .war_leagues import WarLeaguesRequest -# rankings -from .clan_builder_base_rankings import ClanBuilderBaseRankingsRequest -from .clan_rankings import ClanRankingsRequest -from .player_builder_base_rankings import PlayerBuilderBaseRankingsRequest -from .player_rankings import PlayerRankingsRequest -from .capital_rankings import CapitalRankingsRequest + +__all__ = ( + "BuilderBaseLeagueRequest", + "BuilderBaseLeaguesRequest", + "CapitalLeagueRequest", + "CapitalLeaguesRequest", + "CapitalRankingsRequest", + "ClanRequest", + "ClanBuilderBaseRankingsRequest", + "ClanCapitalRaidSeasonsRequest", + "ClanCurrentWarRequest", + "ClanCurrentwarLeaguegroupRequest", + "ClanLabelsRequest", + "ClanMembersRequest", + "ClanRankingsRequest", + "ClanSearchRequest", + "ClanWarLogRequest", + "ClanWarleaguesWarsRequest", + "GoldPassRequest", + "LeagueRequest", + "LeagueSeasonRequest", + "LeagueSeasonsRequest", + "LeaguesRequest", + "LocationRequest", + "LocationsRequest", + "PlayerRequest", + "PlayerBuilderBaseRankingsRequest", + "PlayerLabelsRequest", + "PlayerRankingsRequest", + "WarLeagueRequest", + "WarLeaguesRequest" +) diff --git a/pyclasher/api/requests/abc.py b/pyclasher/api/requests/abc.py index f84bf9e..5d34aeb 100644 --- a/pyclasher/api/requests/abc.py +++ b/pyclasher/api/requests/abc.py @@ -4,9 +4,9 @@ from ..models import Paging from ...client import Client -from ...utils.request_methods import RequestMethods from ...exceptions import (NoClient, ClientIsNotRunning, RequestNotDone, MISSING, InvalidClientId) +from ...utils.request_methods import RequestMethods request_id = 0 diff --git a/pyclasher/api/requests/abc.pyi b/pyclasher/api/requests/abc.pyi index dc6288e..6e31d90 100644 --- a/pyclasher/api/requests/abc.pyi +++ b/pyclasher/api/requests/abc.pyi @@ -3,8 +3,8 @@ from typing import Any, Iterator, Generator from ..models import Paging from ...client import Client -from ...utils import RequestMethods from ...exceptions import MISSING, Missing +from ...utils import RequestMethods request_id: int = 0 diff --git a/pyclasher/api/requests/clan_builder_base_rankings.pyi b/pyclasher/api/requests/clan_builder_base_rankings.pyi index 4cb4ba2..af1372c 100644 --- a/pyclasher/api/requests/clan_builder_base_rankings.pyi +++ b/pyclasher/api/requests/clan_builder_base_rankings.pyi @@ -1,7 +1,8 @@ from typing import Iterator from .abc import IterRequestModel -from ..models import ClanBuilderBaseRanking, ClanBuilderBaseRankingList, Location +from ..models import ClanBuilderBaseRanking, ClanBuilderBaseRankingList, \ + Location class ClanBuilderBaseRankingsRequest(IterRequestModel): diff --git a/pyclasher/api/requests/clan_war_log.py b/pyclasher/api/requests/clan_war_log.py index 1914ff7..bce99fa 100644 --- a/pyclasher/api/requests/clan_war_log.py +++ b/pyclasher/api/requests/clan_war_log.py @@ -1,10 +1,10 @@ from typing import Literal -from ...utils import snake_to_camel -from ...exceptions import PyClasherException, RequestNotDone from .abc import IterRequestModel from ..models import ClanWarLog, ClanWarLogEntry from ..models.enums import ClanWarResult +from ...exceptions import RequestNotDone +from ...utils import snake_to_camel class ClanWarLogRequest(IterRequestModel): diff --git a/pyclasher/api/requests/player.py b/pyclasher/api/requests/player.py index 38e471b..5cdf19e 100644 --- a/pyclasher/api/requests/player.py +++ b/pyclasher/api/requests/player.py @@ -1,11 +1,11 @@ from asyncio import Future from urllib.parse import quote -from ...client import Client from .abc import RequestModel from ..models import Player, VerifyTokenRequest, VerifyTokenResponse -from ...utils.request_methods import RequestMethods +from ...client import Client from ...exceptions import ClientIsNotRunning +from ...utils.request_methods import RequestMethods class PlayerRequest(RequestModel, Player): diff --git a/pyclasher/api/requests/player_builder_base_rankings.pyi b/pyclasher/api/requests/player_builder_base_rankings.pyi index 06907d9..cf8f685 100644 --- a/pyclasher/api/requests/player_builder_base_rankings.pyi +++ b/pyclasher/api/requests/player_builder_base_rankings.pyi @@ -1,7 +1,8 @@ from typing import Iterator from .abc import IterRequestModel -from ..models import PlayerBuilderBaseRanking, PlayerBuilderBaseRankingList, Location +from ..models import PlayerBuilderBaseRanking, PlayerBuilderBaseRankingList, \ + Location class PlayerBuilderBaseRankingsRequest(IterRequestModel): diff --git a/pyclasher/client.py b/pyclasher/client.py index 4568b5b..8d72630 100644 --- a/pyclasher/client.py +++ b/pyclasher/client.py @@ -1,14 +1,13 @@ -from sys import stderr from asyncio import create_task, run +from sys import stderr from typing import Iterable from urllib.parse import urlparse -from .request_queue import PConsumer, PQueue -from .utils.login import Login from .exceptions import (InvalidType, ClientIsRunning, ClientIsNotRunning, NoneToken, MISSING, ClientAlreadyInitialised, PyClasherException) - +from .request_queue import PConsumer, PQueue +from .utils.login import Login global_client_id = 0 diff --git a/pyclasher/client.pyi b/pyclasher/client.pyi index a079680..e6a377e 100644 --- a/pyclasher/client.pyi +++ b/pyclasher/client.pyi @@ -4,7 +4,6 @@ from typing import Iterable from .exceptions import MISSING from .request_queue import PQueue - global_client_id: int = ... diff --git a/pyclasher/request_queue/__init__.py b/pyclasher/request_queue/__init__.py index 8713b0a..edebc14 100644 --- a/pyclasher/request_queue/__init__.py +++ b/pyclasher/request_queue/__init__.py @@ -1,2 +1,2 @@ -from .request_queue import PQueue from .request_consumer import PConsumer +from .request_queue import PQueue diff --git a/pyclasher/request_queue/request_consumer.py b/pyclasher/request_queue/request_consumer.py index 8953f61..91228c0 100644 --- a/pyclasher/request_queue/request_consumer.py +++ b/pyclasher/request_queue/request_consumer.py @@ -3,9 +3,9 @@ from aiohttp import ClientSession, ClientTimeout -from ..utils import ExecutionTimer -from ..exceptions import ApiExceptions, MISSING, RequestTimeout from ..api.models import ClientError +from ..exceptions import ApiExceptions, MISSING, RequestTimeout +from ..utils import ExecutionTimer class PConsumer: diff --git a/pyclasher/request_queue/request_consumer.pyi b/pyclasher/request_queue/request_consumer.pyi index 7468242..a5b8aed 100644 --- a/pyclasher/request_queue/request_consumer.pyi +++ b/pyclasher/request_queue/request_consumer.pyi @@ -1,4 +1,5 @@ from asyncio import Future + from aiohttp import ClientSession from .request_queue import PQueue diff --git a/pyclasher/utils/__init__.py b/pyclasher/utils/__init__.py index 17443fc..d8e0abd 100644 --- a/pyclasher/utils/__init__.py +++ b/pyclasher/utils/__init__.py @@ -1,4 +1,4 @@ from .exectimer import ExecutionTimer +from .functions import snake_to_camel from .login import Login from .request_methods import RequestMethods -from .functions import snake_to_camel From da329bb6009bf1c6cfc25b52ea84c29a5626610c Mon Sep 17 00:00:00 2001 From: 201st-Luka Date: Sun, 27 Aug 2023 13:05:39 +0200 Subject: [PATCH 7/7] feat: implemented `average_...` properties for `PlayerBulkRequest` --- pyclasher/api/bulk_requests/b_player.py | 52 ++++++++++++++++++++++++ pyclasher/api/bulk_requests/b_player.pyi | 52 ++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/pyclasher/api/bulk_requests/b_player.py b/pyclasher/api/bulk_requests/b_player.py index 8954157..6976fb0 100644 --- a/pyclasher/api/bulk_requests/b_player.py +++ b/pyclasher/api/bulk_requests/b_player.py @@ -42,3 +42,55 @@ def from_clan(cls, clan): @classmethod def from_member_list(cls, member_list): return cls((member.tag for member in member_list)) + + @property + def average_attack_wins(self): + return sum((p.attack_wins for p in self)) / len(self) + + @property + def average_defense_wins(self): + return sum((p.defense_wins for p in self)) / len(self) + + @property + def average_town_hall_level(self): + return sum((p.town_hall_level for p in self)) / len(self) + + @property + def average_versus_battle_wins(self): + return sum((p.versus_battle_wins for p in self)) / len(self) + + @property + def average_exp_level(self): + return sum((p.exp_level for p in self)) / len(self) + + @property + def average_trophies(self): + return sum((p.trophies for p in self)) / len(self) + + @property + def average_donations(self): + return sum((p.donations for p in self)) / len(self) + + @property + def average_donations_received(self): + return sum((p.donations_received for p in self)) / len(self) + + @property + def average_builder_hall_level(self): + return sum((p.builder_hall_level for p in self)) / len(self) + + @property + def average_builder_base_trophies(self): + return sum((p.builder_base_trophies for p in self)) / len(self) + + @property + def average_best_builder_base_trophies(self): + return sum((p.best_builder_base_trophies for p in self)) / len(self) + + @property + def average_war_stars(self): + return sum((p.war_stars for p in self)) / len(self) + + @property + def average_clan_capital_contributions(self): + return sum((p.clan_capital_contributions for p in self)) / len(self) diff --git a/pyclasher/api/bulk_requests/b_player.pyi b/pyclasher/api/bulk_requests/b_player.pyi index d7a80a9..60fc3d7 100644 --- a/pyclasher/api/bulk_requests/b_player.pyi +++ b/pyclasher/api/bulk_requests/b_player.pyi @@ -68,6 +68,58 @@ class PlayerBulkRequest(BulkRequestModel): """ ... + @property + def average_attack_wins(self) -> float: + ... + + @property + def average_defense_wins(self) -> float: + ... + + @property + def average_town_hall_level(self) -> float: + ... + + @property + def average_versus_battle_wins(self) -> float: + ... + + @property + def average_exp_level(self) -> float: + ... + + @property + def average_trophies(self) -> float: + ... + + @property + def average_donations(self) -> float: + ... + + @property + def average_donations_received(self) -> float: + ... + + @property + def average_builder_hall_level(self) -> float: + ... + + @property + def average_builder_base_trophies(self) -> float: + ... + + @property + def average_best_builder_base_trophies(self) -> float: + ... + + @property + def average_war_stars(self) -> float: + ... + + @property + def average_clan_capital_contributions(self) -> float: + ... + def __getitem__(self, item: int) -> PlayerRequest: """ getter for a player of the bulk request