Skip to content
This repository has been archived by the owner on Oct 27, 2023. It is now read-only.

Commit

Permalink
Release 1.1.0, see changelog at end of README
Browse files Browse the repository at this point in the history
  • Loading branch information
iann838 committed Jul 10, 2020
1 parent 2becd40 commit a5bc3d8
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 248 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ Cassiopeia itself is a Python adaptation of the Riot Games League of Legends API

## Documentation
Django Cassiopeia has detailed [documentation](https://django-cassiopeia.readthedocs.io/en/latest/).
For functions and methods of Cassiopeia is found is this [documentation](http://cassiopeia.readthedocs.org/en/latest/)
For functions and methods of Cassiopeia is found is this [documentation](http://cassiopeia.readthedocs.org/en/latest/).
A changelog of the last 10 releases is at the bottom of this page.

## Installation and Requirements
```python
Expand Down Expand Up @@ -81,3 +82,12 @@ If you used Cassiopeia for your research, please [cite the project](https://doi.
Django Cassiopeia existence is acknowleged by cassiopeia's former developers. Both package/framework/library is updated in parallel with some exceptions due to the fact of different use cases.

Cassiopeia/Django-Cassiopeia isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot Games or anyone officially involved in producing or managing League of Legends. League of Legends and Riot Games are trademarks or registered trademarks of Riot Games, Inc. League of Legends © Riot Games, Inc.

## Change Log

### 1.1.0
* Shorten the Django settings for handling Riot API request errors (in a 1:3 ratio), check out the [documentation](https://django-cassiopeia.readthedocs.io/en/latest/django-setup/) for its new syntax (Ctrl F5 to clean reload in case your brower loads the cached page).
* Moved out the entire setting mapping logic to a separate file for better maintainance, mainly `_cassiopeia.settings.py -> django_cassiopeia.utils.py`.

### 1.0.0
* First Release of Django Cassiopeia
96 changes: 0 additions & 96 deletions _cassiopeia/_configuration/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,98 +12,6 @@

logging.basicConfig(format='%(asctime)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=logging.WARNING)

expire_index = {
"cr":"ChampionRotationData",
"rl":"Realms",
"v":"Versions",
"c":"Champion",
"c+":"Champions",
"r":"Rune",
"r+":"Runes",
"i":"Item",
"i+":"Items",
"ss":"SummonerSpell",
"ss+":"SummonerSpells",
"mp":"Map",
"mp+":"Maps",
"pi":"ProfileIcon",
"pi+":"ProfileIcons",
"ls":"Locales",
"ls+":"LanguageStrings",
"cm":"ChampionMastery",
"cm+":"ChampionMasteries",
"lse":"LeagueSummonerEntries",
"l":"League",
"cl":"ChallengerLeague",
"gl":"GrandmasterLeague",
"ml":"MasterLeague",
"m":"Match",
"t":"Timeline",
"s":"Summoner",
"shs":"ShardStatus",
"cg":"CurrentMatch",
"fg":"FeaturedMatches",
"rl-":"RealmDto",
"v-":"VersionListDto",
"c-":"ChampionDto",
"c+-":"ChampionListDto",
"r-":"RuneDto",
"r+-":"RuneListDto",
"i-":"ItemDto",
"i+-":"ItemListDto",
"ss-":"SummonerSpellDto",
"ss+-":"SummonerSpellListDto",
"mp-":"MapDto",
"mp+-":"MapListDto",
"pi-":"ProfileIconDetailsDto",
"pi+-":"ProfileIconDataDto",
"ls-":"LanguagesDto",
"ls+-":"LanguageStringsDto",
"cr-":"ChampionRotationDto",
"cm-":"ChampionMasteryDto",
"cm+-":"ChampionMasteryListDto",
"cl-":"ChallengerLeagueListDto",
"gl-":"GrandmasterLeagueListDto",
"ml-":"MasterLeagueListDto",
"m-":"MatchDto",
"t-":"TimelineDto",
"s-":"SummonerDto",
"shs-":"ShardStatusDto",
"cg-":"CurrentGameInfoDto",
"fg-":"FeaturedGamesDto",
"p-":"PatchListDto",
"*-": "*-",
"*+": "*+",
"**": "**"
}

def create_expiration(mape) -> Mapping[type, dict]:
expirations = {}
last = False
for time, types in mape.items():
if last:
raise AttributeError("key of type '*' is assigned but not last of object 'expirations_map'")
for typ in types:
if typ[0] == "*" and typ[-1] in ["*","-","+"] and len(typ) == 2:
for mapkey, mapobj in expire_index.items():
key_to_add = None
if typ == "*-" and mapobj not in expirations.keys() and mapobj.endswith('Dto'):
key_to_add = mapobj
elif typ == "*+" and mapobj not in expirations.keys() and not mapobj.endswith('Dto'):
key_to_add = mapobj
elif typ == "**":
key_to_add = mapobj
if key_to_add is not None and key_to_add not in ["**","*-","*+"]:
expirations[mapobj] = time
last = True
elif expire_index[typ] not in expirations.keys():
expirations[expire_index[typ]] = time
else:
if typ[0] == "*":
raise KeyError("'"+typ+"' in object 'expirations_map'")
raise AttributeError("Attempted duplicate key '"+typ+"' in object 'expirations_map'")
return expirations

def create_pipeline(service_configs: Dict, verbose: int = 0) -> DataPipeline:
transformers = []

Expand All @@ -122,12 +30,8 @@ def create_pipeline(service_configs: Dict, verbose: int = 0) -> DataPipeline:
store_cls = getattr(module, store_name)
if store_name.lower() == "djangocache":
for cache_config in config:
if "expirations_map" in cache_config.keys():
cache_config["expirations"] = create_expiration(cache_config.pop("expirations_map"))
services.append(store_cls(**cache_config))
else:
if "expirations_map" in config.keys():
config["expirations"] = create_expiration(config.pop("expirations_map"))
store = store_cls(**config)
services.append(store)
service_transformers = getattr(module, "__transformers__", [])
Expand Down
2 changes: 1 addition & 1 deletion _cassiopeia/core/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def __call__(self, **kwargs):
##############


class MatchHistory(CassiopeiaLazyList): # type: List[Match]
class MatchHistory(CassiopeiaLazyList):
"""The match history for a summoner. By default, this will return the entire match history."""
_data_types = {MatchListData}

Expand Down
32 changes: 1 addition & 31 deletions django_cassiopeia/__init__.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,4 @@
from django.conf import settings
import copy
import sys
import _cassiopeia as cassiopeia
from logging import getLogger
LOGGER = getLogger(__name__)

def get_cass_settings():
cass = {
"global" : getattr(settings, "CASSIOPEIA_GLOBAL", None),
"pipeline" : getattr(settings, "CASSIOPEIA_PIPELINE", None),
"logging" : getattr(settings, "CASSIOPEIA_LOGGING", None),
"plugins": getattr(settings, "CASSIOPEIA_PLUGINS", None)
}
for key, config in copy.deepcopy(cass).items():
if key == "pipeline" and config is None:
raise AttributeError("'pipeline' settings in django-cassiopeia is obligatory")
elif config is None:
LOGGER.warning(f"[Traceback: django-cassiopeia > settings] WARNING: '{key}' is not set, using default settings")
del cass[key]
for store_name, config in copy.deepcopy(cass["pipeline"]).items():
if store_name == "DjangoCache":
cass["pipeline"][store_name] = settings.CASSIOPEIA_DJANGO_CACHES
elif store_name == "RiotAPI":
cass["pipeline"][store_name]["api_key"] = settings.RIOT_API_KEY
cass["pipeline"][store_name]["limiting_share"] = settings.CASSIOPEIA_LIMITING_SHARE
try:
cass["pipeline"][store_name]["request_error_handling"] = settings.CASSIOPEIA_RIOT_API_ERROR_HANDLING
except AttributeError:
LOGGER.warning(f"[Traceback: django-cassiopeia > settings] Warning: 'riotapi_request_error_handling' is not set, using default settings")
return cass
from .utils import get_cass_settings

cassiopeia.apply_settings(get_cass_settings())

177 changes: 177 additions & 0 deletions django_cassiopeia/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
from typing import TypeVar, Type, Dict, Union, List, Mapping
from django.conf import settings
import copy
from logging import getLogger
LOGGER = getLogger(__name__)

expire_index = {
"cr":"ChampionRotationData",
"rl":"Realms",
"v":"Versions",
"c":"Champion",
"c+":"Champions",
"r":"Rune",
"r+":"Runes",
"i":"Item",
"i+":"Items",
"ss":"SummonerSpell",
"ss+":"SummonerSpells",
"mp":"Map",
"mp+":"Maps",
"pi":"ProfileIcon",
"pi+":"ProfileIcons",
"ls":"Locales",
"ls+":"LanguageStrings",
"cm":"ChampionMastery",
"cm+":"ChampionMasteries",
"lse":"LeagueSummonerEntries",
"l":"League",
"cl":"ChallengerLeague",
"gl":"GrandmasterLeague",
"ml":"MasterLeague",
"m":"Match",
"t":"Timeline",
"s":"Summoner",
"shs":"ShardStatus",
"cg":"CurrentMatch",
"fg":"FeaturedMatches",
"rl-":"RealmDto",
"v-":"VersionListDto",
"c-":"ChampionDto",
"c+-":"ChampionListDto",
"r-":"RuneDto",
"r+-":"RuneListDto",
"i-":"ItemDto",
"i+-":"ItemListDto",
"ss-":"SummonerSpellDto",
"ss+-":"SummonerSpellListDto",
"mp-":"MapDto",
"mp+-":"MapListDto",
"pi-":"ProfileIconDetailsDto",
"pi+-":"ProfileIconDataDto",
"ls-":"LanguagesDto",
"ls+-":"LanguageStringsDto",
"cr-":"ChampionRotationDto",
"cm-":"ChampionMasteryDto",
"cm+-":"ChampionMasteryListDto",
"cl-":"ChallengerLeagueListDto",
"gl-":"GrandmasterLeagueListDto",
"ml-":"MasterLeagueListDto",
"m-":"MatchDto",
"t-":"TimelineDto",
"s-":"SummonerDto",
"shs-":"ShardStatusDto",
"cg-":"CurrentGameInfoDto",
"fg-":"FeaturedGamesDto",
"p-":"PatchListDto",
"*-": "*-",
"*+": "*+",
"**": "**"
}

error_handler_map = {
"t": {
"strategy": "throw"
},
"^e": {
"strategy": "exponential_backoff",
1 : "initial_backoff",
2 : "backoff_factor",
3 : "max_attempts",
},
"r": {
"strategy": "retry_from_headers",
1 : "max_attempts",
}
}


def create_expiration(mape) -> Mapping[type, dict]:
expirations = {}
last = False
for time, types in mape.items():
if last:
raise AttributeError("key of type '*' is assigned but not last of object 'expirations_map'")
for typ in types:
if typ[0] == "*" and typ[-1] in ["*","-","+"] and len(typ) == 2:
for mapkey, mapobj in expire_index.items():
key_to_add = None
if typ == "*-" and mapobj not in expirations.keys() and mapobj.endswith('Dto'):
key_to_add = mapobj
elif typ == "*+" and mapobj not in expirations.keys() and not mapobj.endswith('Dto'):
key_to_add = mapobj
elif typ == "**":
key_to_add = mapobj
if key_to_add is not None and key_to_add not in ["**","*-","*+"]:
expirations[mapobj] = time
last = True
elif expire_index[typ] not in expirations.keys():
expirations[expire_index[typ]] = time
else:
if typ[0] == "*":
raise KeyError("'"+typ+"' in object 'expirations_map'")
raise AttributeError("Attempted duplicate key '"+typ+"' in object 'expirations_map'")
return expirations


def create_handler(mape) -> Mapping[type, type]:
handler = {}
for code, values in mape.items():
if code not in handler.keys():
handler[code]= {}
else:
raise KeyError("Attempted duplicate key '"+code+"' in object 'riotapi_request_error_handling'")
if code == "429":
for limit_type, inner_values in values.items():
strategy = error_handler_map[inner_values[0]]
handler[code][limit_type] = {}
for ind in range(len(inner_values)):
if ind == 0:
handler[code][limit_type]["strategy"] = strategy["strategy"]
else:
handler[code][limit_type][strategy[ind]] = inner_values[ind]
else:
for ind in range(len(values)):
strategy = error_handler_map[values[0]]
if ind == 0:
handler[code]["strategy"] = strategy["strategy"]
else:
handler[code][strategy[ind]] = values[ind]
return handler


def get_cass_settings():
cass = {
"global" : getattr(settings, "CASSIOPEIA_GLOBAL", None),
"pipeline" : getattr(settings, "CASSIOPEIA_PIPELINE", None),
"logging" : getattr(settings, "CASSIOPEIA_LOGGING", None),
"plugins": getattr(settings, "CASSIOPEIA_PLUGINS", None)
}
for key, config in copy.deepcopy(cass).items():
if key == "pipeline" and config is None:
raise AttributeError("'pipeline' settings in django-cassiopeia is obligatory")
elif config is None:
LOGGER.warning(f"[Traceback: django-cassiopeia > settings] WARNING: '{key}' is not set, using default settings")
del cass[key]
for store_name, config in copy.deepcopy(cass["pipeline"]).items():
if store_name == "DjangoCache":
cass["pipeline"][store_name] = settings.CASSIOPEIA_DJANGO_CACHES
elif store_name == "RiotAPI":
cass["pipeline"][store_name]["api_key"] = settings.RIOT_API_KEY
cass["pipeline"][store_name]["limiting_share"] = settings.CASSIOPEIA_LIMITING_SHARE
try:
handler = settings.CASSIOPEIA_API_ERROR_HANDLING
cass["pipeline"][store_name]["request_error_handling"] = create_handler(handler)
except AttributeError:
LOGGER.warning("[Traceback: django-cassiopeia > settings] Warning: 'riotapi_request_error_handling' is not set, using default settings")
LOGGER.warning("[Traceback: django-cassiopeia > settings] Warning: 'riotapi_request_error_handling' has changed its syntax since version 1.1.0."+
"No longer accepts 'CASSIOPEIA_RIOT_API_ERROR_HANDLING', a shorter version is replaced on 'CASSIOPEIA_API_ERROR_HANDLING', see documentation.")
for store_name, config in copy.deepcopy(cass["pipeline"]).items():
if store_name.lower() == "djangocache":
for ind in range(len(config)):
if "expirations_map" in config[ind].keys():
cass["pipeline"][store_name][ind]["expirations"] = create_expiration(cass["pipeline"][store_name][ind].pop("expirations_map"))
else:
if "expirations_map" in config.keys():
cass["pipeline"][store_name]["expirations"] = create_expiration(cass["pipeline"][store_name].pop("expirations_map"))
return cass
Loading

0 comments on commit a5bc3d8

Please sign in to comment.