Skip to content

Commit

Permalink
Merge pull request #28 from 201st-Luka/structure-rework
Browse files Browse the repository at this point in the history
Structure rework
  • Loading branch information
201st-Luka authored Aug 22, 2023
2 parents 34b283e + 00eddc5 commit a84dccc
Show file tree
Hide file tree
Showing 73 changed files with 1,011 additions and 965 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 120
max_line_length = 80
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
Expand Down
5 changes: 0 additions & 5 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8
pip install -r requirements-tests.txt
- name: linting
run: |
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
env:
CLASH_OF_CLANS_LOGIN_EMAIL: ${{ secrets.CLASH_OF_CLANS_LOGIN_EMAIL }}
Expand Down
2 changes: 1 addition & 1 deletion pyclasher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from .utils import *

# client.py
from .client import RequestMethods, Status, Auth, Developer, Login, RequestQueue, Consumer, PyClasherClient
from .client import Client

# exceptions.py
from .exceptions import (Missing, MISSING, PyClasherException, ApiCode, RequestNotDone, NoneToken, InvalidLoginData,
Expand Down
11 changes: 8 additions & 3 deletions pyclasher/api/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""
ClashOfClans API models
"""

# abc
from .abc import BaseModel, IterBaseModel
# base models, miscellaneous models and enums
from .base_models import BaseModel, IterBaseModel, ImageUrl, IconUrl, IconUrls, After, Before, \
from .base_models import ImageUrl, IconUrl, IconUrls, After, Before, \
Cursor, Paging, BadgeUrl, BadgeUrls, Time, BaseClanMember, BaseClan, BaseLeague
# clan models
from .clan import ClanDistrictData, ClanDistrictDataList, ClanCapital, Clan
Expand All @@ -29,18 +30,22 @@
from .gold_pass_season import GoldPassSeason
# labels
from .labels import Label, LabelList
from .language import Language
# league models
from .leagues import League, BuilderBaseLeague, CapitalLeague, WarLeague, LeagueList, \
BuilderBaseLeagueList, CapitalLeagueList, WarLeagueList, LeagueSeason, LeagueSeasonList
# locations
from .location import Location, LocationList
# login
from .login import *
from .misc import *
# player models
from .player import PlayerClan, LegendLeagueTournamentSeasonResult, PlayerLegendStatistics, \
PlayerItemLevel, PlayerItemLevelList, PlayerAchievementProgress, PlayerAchievementProgressList, Player
from .player_builder_base_ranking_list import PlayerBuilderBaseRanking, PlayerBuilderBaseRankingList
from .player_house import PlayerHouseElement, PlayerHouseElementList, PlayerHouse
from .player_ranking_clan import PlayerRankingClan
from .player_ranking_list import PlayerRanking, PlayerRankingList
# misc
from .season import Season
from .war_clan import ClanWarAttack, ClanWarAttackList, ClanWarMember, ClanWarMemberList, WarClan
from .misc import *
101 changes: 101 additions & 0 deletions pyclasher/api/models/abc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from abc import ABC
from typing import Any

from ...exceptions import RequestNotDone, MISSING


class BaseModel(ABC):
def __new__(cls, data=None):
if data is MISSING:
return MISSING
return super().__new__(cls)

def __init__(self, data=None):
if data is not None:
self._data = data
return

def to_dict(self):
return self._data

def _get_properties(self):
if isinstance(self._data, dict):
return {name: prop.__get__(self) for name, prop in vars(type(self)).items() if isinstance(prop, property)}
return self._data

def _get_data(self, item):
if self._data is None:
return None
if self._data is MISSING:
raise RequestNotDone
if item in self._data:
return self._data[item]
else:
return MISSING

def __str__(self):
if self._data is MISSING:
return f"{self.__class__.__name__}(RequestNotDone)"
return f"{self.__class__.__name__}()"

def __repr__(self):
return (f"{self.__class__.__name__}"
f"({', '.join(('='.join((key, str(value))) for key, value in self._get_properties().items()))})")


class IterBaseModel(ABC):
_iter_rtype: Any

def __new__(cls, data):
if data is MISSING:
return MISSING
return super().__new__(cls)

def __init__(self, data):
self._data = data
self._len = len(self._data) if self._data is not None else None
return

def to_dict_list(self):
return self._data

def __len__(self):
if self._len is None and self._data is not None:
self._len = len(self._data)
return self._len

def __getitem__(self, item):
if self._data is MISSING:
raise RequestNotDone
if self._data is None:
return None
if isinstance(item, int):
return self._iter_rtype(self._data[item])
if isinstance(item, slice):
return (self._iter_rtype(self._data[i]) for i in range(*item.indices(len(self._data))))
raise NotImplementedError(f"there is no implementation for type {item.__class__.__name__} in "
f"{self.__class__.__name__}.__getitem__()")

def __iter__(self):
self._iter = iter(self._data)
return self

def __next__(self):
return self._iter_rtype(next(self._iter))

def __contains__(self, item):
if isinstance(item, (self._iter_rtype, str)):
for item_ in self:
if item_ == item:
return True
return False
return NotImplemented

def __str__(self):
return f"{self.__class__.__name__}()"

def __repr__(self):
return f"{self.__class__.__name__}(len={self._len}, type={self._iter_rtype.__name__}, {list(self)})"



131 changes: 131 additions & 0 deletions pyclasher/api/models/abc.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""
abstract base classes for the API models
"""


from typing import Any, Generator, Iterator

from ...exceptions import MISSING, Missing


class BaseModel:
"""
base model
this model is a base for all other ClashOfClans API response models
can be inherited from
"""

def __new__(cls, data: Missing | dict = None) -> BaseModel:
...

def __init__(self, data: Missing | dict = None) -> None:
"""
initialisation of the base model
:param data: the data dictionary, None or MISSING
:return: None
:rtype: None
"""
self._data = data

def to_dict(self) -> None | Missing | dict:
"""
method that returns the response as a dict
:return: response as a dict
:rtype: dict | None | Missing
"""
...

def _get_properties(self) -> None | Missing | dict:
"""
protected method that returns a dict of the properties of a class (also works with inherited classes)
or None or MISSING if the data is not defined
key: name of the property
value: value of the property
:return: dict of properties
:rtype: dict
"""
...

def _get_data(self, item: str) -> None | Missing | dict | list | int | str | float | bool:
"""
getter for the data class attribute that handles errors if the data is not defined
:param item: the key of the dict item
:type item: str
:return: the value of the key or MISSING
:rtype: dict | list | int | str | float | bool | None | MISSING
:raises RequestNotDone: if the data is not defined (MISSING)
"""
...

def __str__(self) -> str:
...

def __repr__(self) -> str:
...


class IterBaseModel:
"""
iterative base model
this model is an iterative base model for the ClashOfClans API response models
can be inherited from
:ivar _len: length of the iterative data
:type _len: int
:ivar _data: a list of dicts containing the data
:type _data: list[dict] | None
"""

_iter_rtype: Any = Any

def __init__(self, data: list[dict] | None) -> None:
"""
initialisation of the iterative base model
:param data: a list of dicts containing the data
:type data: list[dict] | None
:return: None
:rtype: None
"""

self._data = data
if self._data is not None:
self._len = len(self._data)

def to_dict_list(self) -> list[dict] | None | MISSING:
"""
method that returns the response as a list of dicts
:return: response as a list of dicts
:rtype: list[dict] | None | Missing
"""
...

def __len__(self) -> int:
...

def __getitem__(self, item: int | slice) -> MISSING | Generator | _iter_rtype:
...

def __iter__(self) -> Iterator[_iter_rtype]:
self._iter = iter(self._data)
...

def __next__(self):
...

def __contains__(self, item) -> bool:
...

def __str__(self) -> str:
...

def __repr__(self) -> str:
...

Loading

0 comments on commit a84dccc

Please sign in to comment.