Skip to content

Commit

Permalink
Merge pull request #35 from 201st-Luka/new-features
Browse files Browse the repository at this point in the history
New features
  • Loading branch information
201st-Luka authored Aug 26, 2023
2 parents 3a4aa11 + d978b9e commit d1c33cc
Show file tree
Hide file tree
Showing 31 changed files with 709 additions and 187 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.11"]
python-version: ["3.11", "3.10", "3.9", "3.8"]

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.11"]
python-version: ["3.11", "3.10", "3.9", "3.8"]

steps:
- uses: actions/checkout@v3
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ good as I can.
### Planned features

- more bulk requests
- pytests for every request
- pytests for the models
- possibility to download files (images, etc) from `api-assets.clashofclans.com`
- events

### Planned utils

Expand All @@ -74,6 +73,7 @@ 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`

---

If you find a bug, an error or want custom functionality, please tell
Expand Down
2 changes: 1 addition & 1 deletion pyclasher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

# exceptions.py
from .exceptions import (
Missing, MISSING, PyClasherException, ApiCode, RequestNotDone, NoneToken,
Missing, MISSING, PyClasherException, RequestNotDone, NoneToken,
InvalidLoginData, InvalidType, LoginNotDone, ClientIsRunning,
ClientIsNotRunning, ClientAlreadyInitialised, NoClient,
InvalidTimeFormat, ClientRunningOverwrite, InvalidSeasonFormat,
Expand Down
2 changes: 1 addition & 1 deletion pyclasher/api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
)
from .clan_war_log import ClanWarLogEntry, ClanWarLog
from .enums import (
ApiCodes, ClanType, WarFrequency, Locations, Leagues, CapitalLeagues,
ClanType, WarFrequency, Locations, Leagues, CapitalLeagues,
BuilderBaseLeagues, WarLeagues, Labels, Languages, ClanWarState,
ClanWarLeagueGroupState, ClanWarResult, WarPreference,
PlayerHouseElementType, Village, TokenStatus, ClanRole
Expand Down
19 changes: 14 additions & 5 deletions pyclasher/api/models/base_models.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
from datetime import datetime

from aiohttp import ClientSession

from .abc import BaseModel
from ...exceptions import InvalidTimeFormat
from ...exceptions import InvalidTimeFormat, MISSING


class ImageUrl:
__url = None

def __init__(self, url):
self.__url = url
return

async def get_image(self):
raise NotImplementedError
async def get_image(self, logger=MISSING) -> bytes:
async with ClientSession() as session:
async with session.get(self.url) as request:
if request.status == 200:
logger.info(f"Successfully downloaded {self.url}")
return await request.read()

async def save_image(self, filename, logger=MISSING):
image = await self.get_image(logger)
with open(filename, "wb") as file:
file.write(image)

@property
def url(self):
Expand Down
10 changes: 6 additions & 4 deletions pyclasher/api/models/base_models.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
base models for this API wrapper client
"""
from logging import Logger

from .abc import BaseModel
from ...exceptions import MISSING, Missing
Expand All @@ -10,19 +11,20 @@ class ImageUrl:
"""
image URL model
:cvar __url: URL of the image
:ivar __url: URL of the image
:type __url: str
"""

__url: str = None

def __init__(self, url: str) -> None:
"""
initialisation of the image url model
"""
self.__url = url

async def get_image(self):
async def get_image(self, logger: Logger = MISSING) -> bytes:
...

async def save_image(self, logger: Logger):
"""
NOT IMPLEMENTED YET
Expand Down
4 changes: 4 additions & 0 deletions pyclasher/api/models/clan.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ def war_ties(self):
def war_losses(self):
return self._get_data('warLosses')

@property
def total_wars(self):
return self.war_wins + self.war_losses + self.war_ties

@property
def clan_points(self):
return self._get_data('clanPoints')
Expand Down
4 changes: 4 additions & 0 deletions pyclasher/api/models/clan.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ class Clan(BaseClan):
"""
...

@property
def total_wars(self) -> int:
...

@property
def clan_points(self) -> int:
"""
Expand Down
2 changes: 1 addition & 1 deletion pyclasher/api/models/clan_member_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class ClanMemberList(IterBaseModel):
_iter_rtype = ClanMember

def __getitem__(self, item: int | str):
def __getitem__(self, item):
return super().__getitem__(item)

def __next__(self):
Expand Down
25 changes: 0 additions & 25 deletions pyclasher/api/models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,6 @@
from .labels import Label
from .leagues import League, CapitalLeague, BuilderBaseLeague, WarLeague
from .location import Location
from ...exceptions import ApiCode


class ApiCodes(Enum):
SUCCESS = ApiCode(200, "Successful response")
BAD_REQUEST = ApiCode(400, "Client provided incorrect parameters for the request.")
ACCESS_DENIED = ApiCode(403,
"Access denied, either because of missing/incorrect credentials or used API token does not grant access to the requested resource.")
NOT_FOUND = ApiCode(404, "Resource was not found.")
THROTTLED = ApiCode(429, "Request was throttled, because amount of requests was above the threshold defined for the used API token.")
UNKNOWN = ApiCode(500, "Unknown error happened when handling the request.")
MAINTENANCE = ApiCode(503, "Service is temporarily unavailable because of maintenance.")

@classmethod
def from_code(cls, code):
for exception in cls:
if exception.value.code == code:
return exception
raise ValueError

@classmethod
def from_exception(cls, code, response_json):
self = cls.from_code(code)
self.value.response_json = response_json
return self


class ClanType(Enum):
Expand Down
41 changes: 0 additions & 41 deletions pyclasher/api/models/enums.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,6 @@ from enum import Enum
from .labels import Label
from .leagues import League, CapitalLeague, BuilderBaseLeague, WarLeague
from .location import Location
from ...exceptions import ApiCode


class ApiCodes(Enum):
SUCCESS = ApiCode(..., ...)
BAD_REQUEST = ApiCode(..., ...)
ACCESS_DENIED = ApiCode(..., ...,
"Access denied, either because of missing/incorrect credentials or used API token does not grant access to the requested resource.")
NOT_FOUND = ApiCode(..., ...)
THROTTLED = ApiCode(..., ...)
UNKNOWN = ApiCode(..., ...)
MAINTENANCE = ApiCode(..., ...)

@classmethod
def from_code(cls, code: int) -> ApiCodes:
"""
class method that allows to initialise ApiCodes with the error code
:param code: error or success code
:type code: int
:return: the corresponding ApiCode
:rtype: ApiCodes
"""
...

@classmethod
def from_exception(cls,
code: int,
response_json: dict
) -> ApiCodes:
"""
class method that allows to initialise ApiCodes with a failed request response
:param code: error code
:type code: int
:param response_json: failed request response json
:type response_json: dict
:return: the corresponding ApiCode
:rtype: ApiCodes
"""
...


class ClanType(Enum):
Expand Down
2 changes: 1 addition & 1 deletion pyclasher/api/models/location.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Location(BaseModel):
...

@property
def country_code(self) -> Missing | int:
def country_code(self) -> Missing | str:
"""
location country code
Expand Down
10 changes: 10 additions & 0 deletions pyclasher/api/models/season.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@ def from_str(cls, season):
year = int(season[0])
month = int(season[1])
return cls(year, month)

def to_str(self):
return f"{self.year}-{self.month}"

def __eq__(self, other):
if isinstance(other, Season):
return self.year == other.year and self.month == other.month
if isinstance(other, str):
return self == Season.from_str(other)
raise NotImplementedError
3 changes: 3 additions & 0 deletions pyclasher/api/models/season.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ class Season:
@classmethod
def from_str(cls, season: str):
...

def to_str(self) -> str:
...
14 changes: 9 additions & 5 deletions pyclasher/api/requests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
from .capital_league_seasons import CapitalLeaguesRequest
# clan
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_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
Expand All @@ -24,15 +22,21 @@
# leagues
from .league_season import LeagueSeasonRequest
from .leagues import LeaguesRequest
from .location import LocationRequest
from .league_seasons import LeagueSeasonsRequest
# locations
from .location import LocationRequest
from .locations import LocationsRequest
# player
from .player import PlayerRequest
from .player_builder_base_rankings import PlayerBuilderBaseRankingsRequest
# labels
from .player_labels import PlayerLabelsRequest
from .player_rankings import PlayerRankingsRequest
from .abc import RequestModel, IterRequestModel, request_id
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

2 changes: 1 addition & 1 deletion pyclasher/api/requests/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ async def request(self, client_id=None):
await error)

if req_status != 200:
raise req_error.value
raise req_error

self.client.logger.debug(f"request {self._request_id} done")

Expand Down
20 changes: 20 additions & 0 deletions pyclasher/api/requests/capital_rankings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from .abc import IterRequestModel
from ..models import ClanCapitalRanking, ClanCapitalRankingList, Location


class CapitalRankingsRequest(IterRequestModel):
_iter_rtype = ClanCapitalRanking
_list_rtype = ClanCapitalRankingList

def __init__(self, location_id, limit=None, after=None, before=None):
self.location_id = (location_id.id if isinstance(location_id, Location)
else location_id)
super().__init__("locations/{location_id}/rankings/capitals",
location_id=self.location_id,
kwargs={
'limit': limit,
'after': after,
'before': before
})
return

27 changes: 27 additions & 0 deletions pyclasher/api/requests/capital_rankings.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import Iterator

from .abc import IterRequestModel
from ..models import ClanCapitalRanking, ClanCapitalRankingList, Location


class CapitalRankingsRequest(IterRequestModel):
_iter_rtype = ClanCapitalRanking
_list_rtype = ClanCapitalRankingList

def __init__(self, location_id: int | Location,
limit: int = None, after: str = None, before: str = None):
self.location_id: int = ...
...

@property
def items(self) -> _list_rtype:
...

def __getitem__(self, item: int) -> _iter_rtype:
...

def __iter__(self) -> Iterator[_iter_rtype]:
...

def __next__(self) -> _iter_rtype:
...
1 change: 1 addition & 0 deletions pyclasher/api/requests/league_season.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class LeagueSeasonRequest(IterRequestModel):
async def _async_request(self) -> LeagueSeasonRequest:
...

@property
def items(self) -> _list_rtype:
...

Expand Down
12 changes: 12 additions & 0 deletions pyclasher/api/requests/league_seasons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from .abc import IterRequestModel
from ..models import LeagueSeason, LeagueSeasonList


class LeagueSeasonsRequest(IterRequestModel):
_iter_rtype = LeagueSeason
_list_rtype = LeagueSeasonList

def __init__(self, league_id):
super().__init__("leagues/{league_id}/seasons",
league_id=league_id)
return
Loading

0 comments on commit d1c33cc

Please sign in to comment.