diff --git a/.gitignore b/.gitignore index eb7342a..2794cc8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ exclude .pytest_cache tests/.pytest_cache build +pyclasher.egg-info +testing \ No newline at end of file diff --git a/pyclasher/Exceptions.py b/pyclasher/Exceptions.py index b2ab452..bc08846 100644 --- a/pyclasher/Exceptions.py +++ b/pyclasher/Exceptions.py @@ -18,7 +18,11 @@ def __repr__(self): MISSING = Missing() -class ApiCode(Exception): +class PyClasherException(Exception): + pass + + +class ApiCode(PyClasherException): """ exception class to handle ClashOfClans API client errors """ @@ -41,23 +45,23 @@ def __repr__(self): return f"ApiException(code={self.code})" -class RequestNotDone(Exception): +class RequestNotDone(PyClasherException): def __str__(self): return "The request was not done." -class NoneToken(Exception): +class NoneToken(PyClasherException): def __str__(self): return "The token must be passed to the client. " \ "You can do this in the initialisation process or pass the tokens to the start function." -class InvalidLoginData(Exception): +class InvalidLoginData(PyClasherException): def __str__(self): return "The login data is invalid." -class InvalidType(Exception): +class InvalidType(PyClasherException): def __init__(self, element, allowed_types): super().__init__() self.element = element @@ -68,32 +72,32 @@ def __str__(self): return f"{self.element} is of invalid type\nallowed types are {self.types}." -class LoginNotDone(Exception): +class LoginNotDone(PyClasherException): def __str__(self): return "The login was not done. You need to login first." -class ClientIsRunning(Exception): +class ClientIsRunning(PyClasherException): def __str__(self): return "The client is already running." -class ClientIsNotRunning(Exception): +class ClientIsNotRunning(PyClasherException): def __str__(self): return "The client is not running." -class ClientAlreadyInitialised(Exception): +class ClientAlreadyInitialised(PyClasherException): def __str__(self): return "The PyClasherClient has already been initialised." -class NoClient(Exception): +class NoClient(PyClasherException): def __str__(self): return "No client has been initialised." -class InvalidTimeFormat(Exception): +class InvalidTimeFormat(PyClasherException): def __init__(self, value, time_format): super().__init__() self.value = value @@ -104,16 +108,16 @@ def __str__(self): return f"The time {self.value} does not match the format '{self.time_format}'." -class ClientRunningOverwrite(Exception): +class ClientRunningOverwrite(PyClasherException): def __str__(self): return "You cannot overwrite the parameter of a running client." -class InvalidSeasonFormat(Exception): +class InvalidSeasonFormat(PyClasherException): def __str__(self): return "The season string is not valid. It must be follow the following format: where is the year and is the month." -class RequestTimeout(Exception): +class RequestTimeout(PyClasherException): def __str__(self): return "The request took to much time and was cancelled." diff --git a/pyclasher/Exceptions.pyi b/pyclasher/Exceptions.pyi index 2f73468..9404858 100644 --- a/pyclasher/Exceptions.pyi +++ b/pyclasher/Exceptions.pyi @@ -26,6 +26,10 @@ class Missing: MISSING = Missing() +class PyClasherException(Exception): + pass + + class ApiCode(Exception): """ exception class to handle ClashOfClans API exceptions diff --git a/pyclasher/__init__.py b/pyclasher/__init__.py index 7c2624e..0b6e9e1 100644 --- a/pyclasher/__init__.py +++ b/pyclasher/__init__.py @@ -11,6 +11,6 @@ from .Exceptions import ApiCode, ClientIsRunning, ClientIsNotRunning, ClientAlreadyInitialised, NoClient, \ InvalidType, InvalidLoginData, LoginNotDone, NoneToken, RequestNotDone, InvalidTimeFormat, \ - InvalidSeasonFormat, Missing, MISSING + InvalidSeasonFormat, Missing, MISSING, PyClasherException from .client import RequestMethods, Status, Auth, Developer, Login, Consumer, PyClasherClient from .requests import * diff --git a/pyclasher/bulk_requests/BulkPlayer.pyi b/pyclasher/bulk_requests/BulkPlayer.pyi index a7e1844..8db8c42 100644 --- a/pyclasher/bulk_requests/BulkPlayer.pyi +++ b/pyclasher/bulk_requests/BulkPlayer.pyi @@ -1,4 +1,4 @@ -from typing import Iterable +from typing import Iterable, Coroutine, Any from .BulkRequestModel import BulkRequestModel from ..models import BaseClan, ClanMemberList, ClanWarMemberList, ClanWarLeagueClanMemberList, ClanCapitalRaidSeasonMemberList @@ -41,13 +41,13 @@ class PlayerBulkRequest(BulkRequestModel): ... @classmethod - def from_clan(cls, clan: BaseClan | str) -> PlayerBulkRequest: + def from_clan(cls, clan: BaseClan | str) -> PlayerBulkRequest | Coroutine[Any, Any, PlayerBulkRequest]: """ class method to create an instance using a clan or a clan tag :param cls: PlayerBulkRequest :param clan: clan or clan tag - :rtype: PlayerBulkRequest + :rtype: PlayerBulkRequest | Coroutine[Any, Any, PlayerBulkRequest] """ ... @@ -66,7 +66,7 @@ class PlayerBulkRequest(BulkRequestModel): """ ... - def __getitem__(self, item: int) -> _request_model: + def __getitem__(self, item: int) -> PlayerRequest: """ getter for a player of the bulk request @@ -75,7 +75,7 @@ class PlayerBulkRequest(BulkRequestModel): """ ... - def __next__(self) -> _request_model: + def __next__(self) -> PlayerRequest: """ returns the next player of the bulk request if an iterator is used """ diff --git a/pyclasher/bulk_requests/BulkRequestModel.py b/pyclasher/bulk_requests/BulkRequestModel.py index 5238b59..060d327 100644 --- a/pyclasher/bulk_requests/BulkRequestModel.py +++ b/pyclasher/bulk_requests/BulkRequestModel.py @@ -41,7 +41,7 @@ def __iter__(self): return self def __next__(self): - return self._request_model(next(self._iter)) + return next(self._iter) def __str__(self): return f"{self.__class__.__name__}({self._main_attribute})" diff --git a/pyclasher/client.py b/pyclasher/client.py index af2fbb8..d09b216 100644 --- a/pyclasher/client.py +++ b/pyclasher/client.py @@ -10,6 +10,7 @@ NoneToken, MISSING from .models import ApiCodes from .models.BaseModels import BaseModel +from .utils import ExecutionTimer class RequestMethods(Enum): @@ -210,11 +211,10 @@ async def consume(self): while True: future, url, method, body, status, error = await self.queue.get() - create_task(self._request(future, url, method.value, body, status, error)) + async with ExecutionTimer(self.wait): + create_task(self._request(future, url, method.value, body, status, error)) - self.queue.task_done() - - await sleep(self.wait) + self.queue.task_done() async def close(self): await self.session.close() diff --git a/pyclasher/models/Clan.pyi b/pyclasher/models/Clan.pyi index 18372e9..2499594 100644 --- a/pyclasher/models/Clan.pyi +++ b/pyclasher/models/Clan.pyi @@ -57,10 +57,10 @@ class ClanDistrictDataList(IterBaseModel): _iter_rtype = ClanDistrictData - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> ClanDistrictData: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanDistrictData: ... diff --git a/pyclasher/models/ClanBuilderBaseRankingList.pyi b/pyclasher/models/ClanBuilderBaseRankingList.pyi index ee0b11e..d65cab1 100644 --- a/pyclasher/models/ClanBuilderBaseRankingList.pyi +++ b/pyclasher/models/ClanBuilderBaseRankingList.pyi @@ -34,8 +34,8 @@ class ClanBuilderBaseRankingList(IterBaseModel): _iter_rtype = ClanBuilderBaseRanking - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanBuilderBaseRanking: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanBuilderBaseRanking: ... diff --git a/pyclasher/models/ClanCapitalRaidSeasons.pyi b/pyclasher/models/ClanCapitalRaidSeasons.pyi index 3dc0db6..983b2d3 100644 --- a/pyclasher/models/ClanCapitalRaidSeasons.pyi +++ b/pyclasher/models/ClanCapitalRaidSeasons.pyi @@ -87,10 +87,10 @@ class ClanCapitalRaidSeasonAttackList(IterBaseModel): _iter_rtype = ClanCapitalRaidSeasonAttack - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanCapitalRaidSeasonAttack: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanCapitalRaidSeasonAttack: ... @@ -189,10 +189,10 @@ class ClanCapitalRaidSeasonDistrictList(IterBaseModel): _iter_rtype = ClanCapitalRaidSeasonDistrict - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanCapitalRaidSeasonDistrict: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanCapitalRaidSeasonDistrict: ... @@ -317,10 +317,10 @@ class ClanCapitalRaidSeasonDefenseLogList(IterBaseModel): _iter_rtype = ClanCapitalRaidSeasonDefenseLogEntry - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanCapitalRaidSeasonDefenseLogEntry: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanCapitalRaidSeasonDefenseLogEntry: ... @@ -333,10 +333,10 @@ class ClanCapitalRaidSeasonAttackLogList(IterBaseModel): _iter_rtype = ClanCapitalRaidSeasonAttackLogEntry - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanCapitalRaidSeasonAttackLogEntry: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanCapitalRaidSeasonAttackLogEntry: ... @@ -395,10 +395,10 @@ class ClanCapitalRaidSeasonMemberList(IterBaseModel): _iter_rtype = ClanCapitalRaidSeasonMember - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanCapitalRaidSeasonMember: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanCapitalRaidSeasonMember: ... @@ -528,8 +528,8 @@ class ClanCapitalRaidSeasons(IterBaseModel): _iter_rtype = ClanCapitalRaidSeason - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanCapitalRaidSeason: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanCapitalRaidSeason: ... diff --git a/pyclasher/models/ClanCapitalRankingList.pyi b/pyclasher/models/ClanCapitalRankingList.pyi index 61047b6..86a11ae 100644 --- a/pyclasher/models/ClanCapitalRankingList.pyi +++ b/pyclasher/models/ClanCapitalRankingList.pyi @@ -36,8 +36,8 @@ class ClanCapitalRankingList(IterBaseModel): _iter_rtype = ClanCapitalRanking - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanCapitalRanking: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanCapitalRanking: ... diff --git a/pyclasher/models/ClanList.pyi b/pyclasher/models/ClanList.pyi index 564ab67..7a4420e 100644 --- a/pyclasher/models/ClanList.pyi +++ b/pyclasher/models/ClanList.pyi @@ -11,8 +11,8 @@ class ClanList(IterBaseModel): _iter_rtype = Clan - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> Clan: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> Clan: ... diff --git a/pyclasher/models/ClanMemberList.pyi b/pyclasher/models/ClanMemberList.pyi index 11f19a4..2cd107d 100644 --- a/pyclasher/models/ClanMemberList.pyi +++ b/pyclasher/models/ClanMemberList.pyi @@ -13,8 +13,8 @@ class ClanMemberList(IterBaseModel): _iter_rtype = ClanMember - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> ClanMember: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanMember: ... diff --git a/pyclasher/models/ClanWarLeagueGroup.pyi b/pyclasher/models/ClanWarLeagueGroup.pyi index 54c1849..ed596da 100644 --- a/pyclasher/models/ClanWarLeagueGroup.pyi +++ b/pyclasher/models/ClanWarLeagueGroup.pyi @@ -27,10 +27,10 @@ class ClanWarLeagueRoundList(IterBaseModel): _iter_rtype = ClanWarLeagueRound - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> ClanWarLeagueRound: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanWarLeagueRound: ... @@ -59,10 +59,10 @@ class ClanWarLeagueClanMemberList(IterBaseModel): _iter_rtype = ClanWarLeagueClanMember - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> ClanWarLeagueClanMember: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanWarLeagueClanMember: ... @@ -101,10 +101,10 @@ class ClanWarLeagueClanList(IterBaseModel): _iter_rtype = ClanWarLeagueClan - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> ClanWarLeagueClan: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanWarLeagueClan: ... diff --git a/pyclasher/models/ClanWarLog.pyi b/pyclasher/models/ClanWarLog.pyi index 8f0b263..6e0e47c 100644 --- a/pyclasher/models/ClanWarLog.pyi +++ b/pyclasher/models/ClanWarLog.pyi @@ -78,8 +78,8 @@ class ClanWarLog(IterBaseModel): _iter_rtype = ClanWarLogEntry - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> ClanWarLogEntry: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanWarLogEntry: ... diff --git a/pyclasher/models/Labels.pyi b/pyclasher/models/Labels.pyi index 93f2c89..b6c8043 100644 --- a/pyclasher/models/Labels.pyi +++ b/pyclasher/models/Labels.pyi @@ -44,8 +44,8 @@ class LabelList(IterBaseModel): _iter_rtype = Label - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> Label: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> Label: ... diff --git a/pyclasher/models/Leagues.pyi b/pyclasher/models/Leagues.pyi index 1cd2e72..a85bee4 100644 --- a/pyclasher/models/Leagues.pyi +++ b/pyclasher/models/Leagues.pyi @@ -51,10 +51,10 @@ class LeagueList(IterBaseModel): _iter_rtype = League - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> League: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> League: ... @@ -67,10 +67,10 @@ class BuilderBaseLeagueList(IterBaseModel): _iter_rtype = BuilderBaseLeague - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> BuilderBaseLeague: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> BuilderBaseLeague: ... @@ -83,10 +83,10 @@ class CapitalLeagueList(IterBaseModel): _iter_rtype = CapitalLeague - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> CapitalLeague: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> CapitalLeague: ... @@ -99,10 +99,10 @@ class WarLeagueList(IterBaseModel): _iter_rtype = WarLeague - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> WarLeague: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> WarLeague: ... @@ -131,8 +131,8 @@ class LeagueSeasonList(IterBaseModel): _iter_rtype = LeagueSeason - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> LeagueSeason: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> LeagueSeason: ... diff --git a/pyclasher/models/Location.pyi b/pyclasher/models/Location.pyi index 71ad2b8..e783aba 100644 --- a/pyclasher/models/Location.pyi +++ b/pyclasher/models/Location.pyi @@ -61,8 +61,8 @@ class LocationList(IterBaseModel): _iter_rtype = Location - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> Location: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> Location: ... diff --git a/pyclasher/models/Player.pyi b/pyclasher/models/Player.pyi index 6a7cb85..bfeac2d 100644 --- a/pyclasher/models/Player.pyi +++ b/pyclasher/models/Player.pyi @@ -118,10 +118,10 @@ class PlayerItemLevel(BaseModel): class PlayerItemLevelList(IterBaseModel): _iter_rtype = PlayerItemLevel - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> PlayerItemLevel: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> PlayerItemLevel: ... diff --git a/pyclasher/models/PlayerBuilderBaseRankingList.pyi b/pyclasher/models/PlayerBuilderBaseRankingList.pyi index b12d6bc..b747928 100644 --- a/pyclasher/models/PlayerBuilderBaseRankingList.pyi +++ b/pyclasher/models/PlayerBuilderBaseRankingList.pyi @@ -48,8 +48,8 @@ class PlayerBuilderBaseRanking(BaseModel): class PlayerBuilderBaseRankingList(IterBaseModel): _iter_rtype = PlayerBuilderBaseRanking - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> PlayerBuilderBaseRanking: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> PlayerBuilderBaseRanking: ... diff --git a/pyclasher/models/PlayerHouse.pyi b/pyclasher/models/PlayerHouse.pyi index e098c57..25bccdb 100644 --- a/pyclasher/models/PlayerHouse.pyi +++ b/pyclasher/models/PlayerHouse.pyi @@ -15,10 +15,10 @@ class PlayerHouseElement(BaseModel): class PlayerHouseElementList(IterBaseModel): _iter_rtype = PlayerHouseElement - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> PlayerHouseElement: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> PlayerHouseElement: ... diff --git a/pyclasher/models/PlayerRankingList.pyi b/pyclasher/models/PlayerRankingList.pyi index d832aa9..449738d 100644 --- a/pyclasher/models/PlayerRankingList.pyi +++ b/pyclasher/models/PlayerRankingList.pyi @@ -48,8 +48,8 @@ class PlayerRanking(BaseModel): class PlayerRankingList(IterBaseModel): _iter_rtype = PlayerRanking - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> PlayerRanking: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> PlayerRanking: ... diff --git a/pyclasher/models/WarClan.pyi b/pyclasher/models/WarClan.pyi index e91ac86..865a50b 100644 --- a/pyclasher/models/WarClan.pyi +++ b/pyclasher/models/WarClan.pyi @@ -30,10 +30,10 @@ class ClanWarAttack(BaseModel): class ClanWarAttackList(IterBaseModel): _iter_rtype = ClanWarAttack - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> ClanWarAttack: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanWarAttack: ... @@ -60,10 +60,10 @@ class ClanWarMember(BaseClanMember): class ClanWarMemberList(IterBaseModel): _iter_rtype = ClanWarMember - def __getitem__(self, item: int) -> _iter_rtype: + def __getitem__(self, item: int) -> ClanWarMember: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> ClanWarMember: ... diff --git a/pyclasher/models/misc/WarStatus.pyi b/pyclasher/models/misc/WarStatus.pyi index 80525dd..b786f44 100644 --- a/pyclasher/models/misc/WarStatus.pyi +++ b/pyclasher/models/misc/WarStatus.pyi @@ -65,8 +65,8 @@ class WarStatusList(IterBaseModel): _iter_rtype = WarStatus - def __getitem__(self, item: int | str) -> _iter_rtype: + def __getitem__(self, item: int | str) -> WarStatus: ... - def __next__(self) -> _iter_rtype: + def __next__(self) -> WarStatus: ... diff --git a/pyclasher/utils/ExecTimer.py b/pyclasher/utils/ExecTimer.py new file mode 100644 index 0000000..f67b39c --- /dev/null +++ b/pyclasher/utils/ExecTimer.py @@ -0,0 +1,20 @@ +from time import perf_counter +from asyncio import sleep + + +class ExecutionTimer: + def __init__(self, min_time=0): + self._min_time = min_time + return + + async def __aenter__(self): + self._start = perf_counter() + return self + + async def __aexit__(self, exc_type, exc_val, exc_tb): + end = perf_counter() + if (diff := end - self._start) < self._min_time: + await sleep(diff) + return + + diff --git a/pyclasher/utils/ExecTimer.pyi b/pyclasher/utils/ExecTimer.pyi new file mode 100644 index 0000000..73a642e --- /dev/null +++ b/pyclasher/utils/ExecTimer.pyi @@ -0,0 +1,14 @@ +from asyncio import Task + + +class ExecutionTimer: + def __init__(self, min_time: float = 0) -> None: + self._min_time = min_time + ... + + async def __aenter__(self) -> ExecutionTimer: + self._start: float = ... + ... + + async def __aexit__(self, exc_type, exc_val, exc_tb) -> None: + ... diff --git a/pyclasher/utils/__init__.py b/pyclasher/utils/__init__.py new file mode 100644 index 0000000..90e33c5 --- /dev/null +++ b/pyclasher/utils/__init__.py @@ -0,0 +1 @@ +from .ExecTimer import ExecutionTimer diff --git a/requirements.txt b/requirements.txt index ce23571..3322dfd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -aiohttp \ No newline at end of file +aiohttp>=3.8 \ No newline at end of file