from box import Box, BoxList
from .utils import API
API_ENDPOINTS = API('https://api.royaleapi.com')
__all__ = [
'BaseAttrDict', 'Refreshable', 'PartialTournament',
'PartialClan', 'PartialPlayer', 'PartialPlayerClan',
'Member', 'FullPlayer', 'FullClan', 'rlist'
]
[docs]class BaseAttrDict:
"""This class is the base class for all models, its a
wrapper around the `python-box`_ which allows access to data
via dot notation, in this case, API data will be accessed
using this class. This class shouldnt normally be used by the
user since its a base class for the actual models returned from
the client.
.. _python-box: https://github.com/cdgriffith/Box
Example
-------
Accessing data via dot notation:
.. code-block:: python
sample_data = {
"stats": {
"maxTrophies": 5724,
"favoriteCard": {
"name": "P.E.K.K.A"
}
}
}
model = SomeModel(client, sample_data)
x = sample_data['stats']['maxTrophies']
# Same as
x = model['stats']['max_trophies']
# Same as
x = model.stats.max_trophies
This functionality allows this library to present API
data in a clean dynamic way.
Attributes
----------
raw_data: dict
The raw data in the form of a dictionary being used
cached: bool
Whether or not the data being used is cached data from
the cache database.
last_updated: datetime.datetime
When the data which is currently being used was last updated.
response: requests.Response or aiohttp.ClientResponse or None
Response object containing headers and more information. Returns None if cached
"""
def __init__(self, client, data, response, cached=False, ts=None):
self.client = client
self.response = response
self.from_data(data, cached, ts, response)
def from_data(self, data, cached, ts, response):
self.cached = cached
self.last_updated = ts
self.raw_data = data
self.response = response
if isinstance(data, list):
self._boxed_data = BoxList(
data, camel_killer_box=not self.client.camel_case
)
else:
self._boxed_data = Box(
data, camel_killer_box=not self.client.camel_case
)
return self
def __getattr__(self, attr):
try:
return getattr(self._boxed_data, attr)
except AttributeError:
try:
return super().__getattr__(attr)
except AttributeError:
return None
def __getitem__(self, item):
try:
return getattr(self._boxed_data, item)
except AttributeError:
raise KeyError('No such key: {}'.format(item))
def __repr__(self):
_type = self.__class__.__name__
return "<{}: {}>".format(_type, self.raw_data)
[docs]class Refreshable(BaseAttrDict):
"""Mixin class for re requesting data from
the api for the specific model.
"""
[docs] def refresh(self):
"""(a)sync refresh the data."""
if self.client.is_async:
return self._arefresh()
data, cached, ts, response = self.client.request(self.url, timeout=None, refresh=True)
return self.from_data(data, cached, ts, response)
async def _arefresh(self):
data, cached, ts, response = await self.client.request(self.url, timeout=None, refresh=True)
return self.from_data(data, cached, ts, response)
@property
def url(self):
endpoint = self.__class__.__name__.lower()
return '{}/{}/{}'.format(API_ENDPOINTS.BASE, endpoint, self.tag)
[docs]class PartialTournament(BaseAttrDict):
def get_tournament(self):
return self.client.get_player(self.tag)
[docs]class PartialClan(BaseAttrDict):
[docs] def get_clan(self):
"""(a)sync function to return clan."""
try:
return self.client.get_clan(self.clan.tag)
except AttributeError:
try:
return self.client.get_clan(self.tag)
except AttributeError:
raise ValueError('This player does not have a clan.')
[docs]class PartialPlayer(BaseAttrDict):
[docs] def get_player(self):
"""(a)sync function to return player."""
return self.client.get_player(self.tag)
[docs]class PartialPlayerClan(PartialClan, PartialPlayer):
"""Brief player model,
does not contain full data, non refreshable.
"""
pass
[docs]class Member(PartialPlayer):
"""A clan member model,
keeps a reference to the clan object it came from.
"""
def __init__(self, clan, data, response):
self.clan = clan
super().__init__(clan.client, data, response)
[docs]class FullPlayer(Refreshable, PartialClan):
"""A clash royale player model."""
pass
[docs]class FullClan(Refreshable):
"""A clash royale clan model, full data + refreshable."""
def from_data(self, data, cached, ts, response):
super().from_data(data, cached, ts, response)
self.members = [Member(self, m, self.response) for m in data.get('members', [])]
[docs]class rlist(list, Refreshable):
def __init__(self, client, data, cached, ts, response):
self.client = client
self.from_data(data, cached, ts, response)
def from_data(self, data, cached, ts, response):
self.cached = cached
self.last_updated = ts
self.response = response
super().__init__(data)
return self
@property
def url(self):
return '{}/endpoints'.format(API_ENDPOINTS.BASE)