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

Commit

Permalink
Release of 2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
iann838 committed Jul 30, 2020
1 parent a5bc3d8 commit 8875d1c
Show file tree
Hide file tree
Showing 82 changed files with 11,126 additions and 772 deletions.
14 changes: 13 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
pids
logs
node_modules
npm-debug.log
coverage/
run
.DS_Store
.nyc_output
.basement
config.local.js
basement_dist

__pycache__/
*.py[cod]

Expand All @@ -9,7 +21,7 @@ __pycache__/
env/
build/
develop-eggs/
dist/
/dist/
downloads/
eggs/
.eggs/
Expand Down
16 changes: 16 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
language: node_js
node_js:
- lts/*
install:
- yarn install # npm ci
script:
- yarn build # npm run docs:build
deploy:
provider: pages
skip_cleanup: true
local_dir: docs/.vuepress/dist
github_token: $TRAVIS_CI_TOKEN
keep_history: true
committer_from_gh: true
on:
branch: master
105 changes: 45 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
[![MIT Licensed](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/paaksing/django-cassiopeia/blob/master/LICENSE.txt)
[![Documentation Status](https://readthedocs.org/projects/django-cassiopeia/badge/?version=latest)](https://django-cassiopeia.readthedocs.io/en/latest/?badge=latest)
[![GitHub issues](https://img.shields.io/github/issues/Naereen/StrapDown.js.svg)](https://github.com/paaksing/django-cassiopeia/issues)


# Django Cassiopeia

An Integration of [Cassiopeia](https://github.com/meraki-analytics/cassiopeia) to the Django Framework (Compatible with DRF) including more new features.
Django Cassiopeia has finished beta test, Django Cassiopeia 2 has **_backward incompatible changes_**, please check them out [here](https://paaksing.github.io/django-cassiopeia/documentation/migrating1to2.html).

An Integration of [Cassiopeia](https://github.com/meraki-analytics/cassiopeia) to the Django Framework (Compatible with DRF) with enhanced new features.

Cassiopeia itself is a Python adaptation of the Riot Games League of Legends API (https://developer.riotgames.com/). For instance it is also the sister library to [Orianna](https://github.com/robrua/Orianna) (Java). It's been designed with usability in mind - making sure all the bookkeeping is done right so you can focus on getting the data you need and building your application.
Cassiopeia is a Python adaptation of the Riot Games League of Legends API (https://developer.riotgames.com/). For instance it is also the sister library to [Orianna](https://github.com/robrua/Orianna) (Java). It's been designed with usability in mind - making sure all the bookkeeping is done right so you can focus on getting the data you need and building your application.

## 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/).
A changelog of the last 10 releases is at the bottom of this page.
Django Cassiopeia has detailed [documentation](https://paaksing.github.io/django-cassiopeia/).
For functions and methods of Cassiopeia is found in this [documentation](http://cassiopeia.readthedocs.org/en/latest/).

## Installation and Requirements
```python
Expand All @@ -22,72 +20,59 @@ Python>=3.6
pip install django-cassiopeia
```

## Quick Start and/or Setup for your Django Project

* Please check out the things that you should NOT do when using django-cassiopeia in this [page](https://django-cassiopeia.readthedocs.io/en/latest/cautions/)
* For setup in your Django environment, follow the setup instructions in django-cassiopeia's [documentation](https://django-cassiopeia.readthedocs.io/en/latest/django-setup/)
* A Quick Start is also provided on django-cassiopeia's [documentation](https://django-cassiopeia.readthedocs.io/en/latest/examples/)
* Taking in mind the instruction above, for all the methods and function of cassiopeia is found in this [documentation](http://cassiopeia.readthedocs.org/en/latest/)

## Why use Cassiopeia (quoting from Cassiopeia repository)?

* An excellent user interface that makes working with data from the Riot API easy and fun.

* "Perfect" rate limiting.

* Guaranteed optimal usage of your API key.

* Built in caching and (coming) the ability to easily hook into a database for offline storage of data.

* Extendability to non-Riot data. Because Cass is a framework and not just an API wrapper, you can integrate your own data sources into your project. Cass already supports Data Dragon and the ``champion.gg`` API in addition to the Riot API.

* Dynamic settings so you can configure Cass for your specific use case.

## Features Integration and Fixed Issues

* **_Issue:_** Cassiopeia current caching system does not automatically (or regularly) expire objects on expirations which might cause severe memory issues when working with web frameworks if it goes out of your control. **_Solution:_** This integration will give you the ability to use Django's cache framework for your caching, which is full production tested.

* **_Issue:_** The variety of cache backends that Cass provides may not fit your needs when paired with Django. **_Solution:_** Now you can use ANY cache backends of your like that the Django's cache framework supports: Django-Redis, python-Memcached, pylibmc, Filebased, MySQL, Postgre, SQLite, ... (Check out [Django's cache framework official docs](https://docs.djangoproject.com/en/dev/topics/cache/) for more). Also ! You can configure it to have more than 1 cache, the ability to separate multiple objects to different caching system.

* **_Issue:_** When not imported Cassiopeia correctly within the Django environment, each time you call a function that uses cass will create a new instance of it and killing all existing Ghost modules (for information of Cassiopeia's Ghost(Lazy) loading check out its [documentations](http://cassiopeia.readthedocs.org/en/latest/)), creating conflicts that might crash your server. **_Solution:_** Django Cassiopeia is an app, which you add it through the `INSTALLED_APPS` settings which automatically loads the adapted version of Cassiopeia.
## Quick Start

* **_Issue:_** Cassiopeia's settings code block is too large compared to others Django settings. **_Solution:_** The Settings interface is adapted to a syntax that is compatible (visually) with Django Settings (see Setup for Django environment in documentations).

* **_Issue:_** When cassiopeia is paired with a web framework (e.g. Django, Flask), the "Perfect" rate limiting is not totally "Perfect" **_(it STILL WORKS, just not as atomic as in a single process environment, AKA normal python scripts without Multi-threading/processing modules)_**, since a Web Framework can behave in a variety of process flow: multi-process, async, conj. (see Existing Problems below).

## Existing and Future Plans.
In your `settings.py`:
```python
INSTALLED_APPS = [
# ...
'django_cassiopeia',
]

CASSIOPEIA_RIOT_API_KEY = os.environ["RIOT_API_KEY"] # api key in env var
CASSIOPEIA_DEFAULT_REGION = "NA" # default region
CASSIOPEIA_PIPELINE = { # small pipeine to get started
"Omnistone": {},
"DDragon": {},
"RiotAPI": {},
}
```
In your `views.py` that you wish to use cassiopeia functions:
```python
from django_cassiopeia import cassiopeia as cass
from django.http import JsonResponse
from django.views import View

class SummonerView(View): # Django CBV with json response
def get(self, request):
summoner = cass.Summoner(name="Kalturi")
return JsonResponse({"name": summoner.name, "level": summoner.level})
```
Reminder: it can be used anywhere as long as you do the correct import:
```python
from django_cassiopeia import cassiopeia
# You can add "as cass" for shorter module name ^.
```

* The current rate limiter is the SAME used in `cassiopeia`, so is rather a "Do not black list me" rate limiter **_(it holds calls for the time returned in retry-after header when an unexpected 429 is returned, which is what the Riot Team recommends)_**, but we (both cass and django-cass devs) prefer to not get a single 429 (or only in extreme cases), a rate limiter that fits (or may fits) to Django is under going research. _See the **Project** tab if you want to contribute for this, if compatible, we will consider porting it over to the main cassiopeia._
## Integrated Features

* Django's Cache cannot cache `Champion.gg` data yet .. in a very very short time will be updated the support. _I currently don't feel the need, the support is good to go by just adding some 50 lines of codes, fire me an issue if you need it._
* **_Bypass the limitation of cassiopeia caching:_** No more worries about memory issues! Now you have the ability to use Django's cache framework for your caching, compatible with any cache backends that Django supports (Filebased, Database, Redis, MemCached, LocalMem, more).

* **_If you want any new feature for Django Cassiopeia_**, fire me a Feature Request and I will try to give you a response, I have some thoughts about replacing ddragon's champion json files with meraki's json files, or have an additional object for that.
* **_Same performance (New in 2.0):_** You still get the same fast performance as cassiopeia's `Cache`, here you have its fine tuned version called `Omnistone` and safe to use (I am looking at you memory hunter).

## Trade-offs
* **_Prevent infinite instances:_** Weird things will happen if you don't import correctly cassiopeia in your Django project (happens to Flask too), now you add to `INSTALLED_APPS` and import it from there, no more infinite intances crashing around.

* There is a minor caveat when using Django's cache over the Standard cache that Cassiopeia provides: It cannot cache `cassiopeia.core` objects due to the fact of its `key` not being of type `string` or a `picklable` object, so it rather caches `cassiopeia.dto` objects which then automatically be transform to `cassiopeia.core`. The time consumption difference is super minimal `cassiopeia.dto` needs some 20ms more than `cassiopeia.core`, **_but this is considered this is a good trade-off because `cassiopeia.core` takes a lot more memory (at least 5 times more if you use compressors on your Django's cache) compared to `cassiopeia.dto`._**
* **_Adapted settings syntax:_** Keep all settings in one place, the standard place -> `settings.py`, with adapted syntax that fits into the Django trend.

## Questions/Contributions/Bugs
* For Django Cassiopeia: Feel free to send pull requests or to contact us via this github or our general [discord](https://discord.gg/uYW7qhP). More information can be found in our [documentation](https://django-cassiopeia.readthedocs.io/en/latest/).
* For Django Cassiopeia: Feel free to send pull requests or to contact us via this github or our general [discord](https://discord.gg/uYW7qhP). More information can be found in our [documentation](https://paaksing.github.io/django-cassiopeia/).
* For Cassiopeia: feel free to send pull requests or to contact cassiopeia devs via [cassiopeia's github](https://github.com/meraki-analytics/cassiopeia) or the same discord server. More information about main cassiopeia is found in this [documentation](http://cassiopeia.readthedocs.org/en/latest/).

## Citing Cassiopeia (Quoting from cassiopeia repository)
If you used Cassiopeia for your research, please [cite the project](https://doi.org/10.5281/zenodo.1170906).

## Supporting Cassiopeia and Django Cassiopeia
* If you've loved using Cassiopeia, consider supporting the former developers of the main framework through [PayPal](https://www.paypal.me/merakianalytics) or [Patreon](https://www.patreon.com/merakianalytics).
* If you want to support this specific project (`django-cassiopeia`), consider supporting me through [Patreon](https://www.patreon.com/paaksing) too.
* If you've loved using Cassiopeia, consider supporting the former developers of the main framework through [PayPal](https://www.paypal.me/merakianalytics) or [Patreon](https://www.patreon.com/merakianalytics).

## Disclaimer
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
18 changes: 8 additions & 10 deletions _cassiopeia/_configuration/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def create_pipeline(service_configs: Dict, verbose: int = 0) -> DataPipeline:
service_transformers = getattr(module, "__transformers__", [])
transformers.extend(service_transformers)

from ..datastores import Cache, MerakiAnalyticsCDN, LolWikia
from ..datastores import Cache, Omnistone, MerakiAnalyticsCDN, LolWikia

# Automatically insert the ghost store if it isn't there
from ..datastores import UnloadedGhostStore
Expand All @@ -47,15 +47,13 @@ def create_pipeline(service_configs: Dict, verbose: int = 0) -> DataPipeline:
found = True
break
if not found:
if any(isinstance(service, Cache) for service in services):
# Find the cache and insert the ghost store directly after it
for i, datastore in enumerate(services):
if isinstance(datastore, Cache):
services.insert(i+1, UnloadedGhostStore())
break
else:
# Insert the ghost store at the beginning of the pipeline
services.insert(0, UnloadedGhostStore())
# Find the cache and insert the ghost store directly after it
# OR Insert the ghost store at the beginning of the pipeline
j = 0
for i, datastore in enumerate(services):
if isinstance(datastore, Cache) or isinstance(datastore, Omnistone):
j = i+1 if i+1 > j else j
services.insert(j, UnloadedGhostStore())

services.append(MerakiAnalyticsCDN())
services.append(LolWikia())
Expand Down
4 changes: 2 additions & 2 deletions _cassiopeia/cassiopeia.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ def get_version(date: datetime.date = None, region: Union[Region, str] = None) -
return None


def get_verification_string(summoner: Summoner) -> VerificationString:
return VerificationString(summoner=summoner)
def get_verification_string(summoner: Summoner, region: Union[Region, str] = None) -> VerificationString:
return VerificationString(summoner=summoner, region=region)


def get_champion_rotations(region: Union[Region, str] = None) -> ChampionRotation:
Expand Down
3 changes: 2 additions & 1 deletion _cassiopeia/datastores/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
from .ghost import UnloadedGhostStore
from .merakianalyticscdn import MerakiAnalyticsCDN
from .lolwikia import LolWikia
from .django_cache import DjangoCache
from .django_cache import DjangoCache
from .omnistone import Omnistone
6 changes: 3 additions & 3 deletions _cassiopeia/datastores/django_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@


class DjangoCache(DataSource, DataSink):
def __init__(self, expirations: Mapping[type, float] = None, alias: str = None, logs_enabled: bool = True) -> None:
def __init__(self, expirations: Mapping[type, float] = None, alias: str = None, logs_enabled: bool = False, safe_check: bool = True) -> None:
self._alias = alias
self._cache = DjangoCacheBackend(alias, logs_enabled)
self._expirations = dict(expirations) if expirations is not None else default_expirations
Expand All @@ -72,8 +72,8 @@ def __init__(self, expirations: Mapping[type, float] = None, alias: str = None,
key = new_key
if value != -1 and isinstance(value, datetime.timedelta):
self._expirations[key] = value.total_seconds()
elif value == -1:
LOGGER.warn(f"[Traceback: django_cassiopeia > {self._alias}] WARNING: {key.__name__} has set with 'forever' caching, and a cache is meant to expire at some point.")
elif value == -1 and safe_check:
raise RuntimeError(f"Secure check is enabled: You are trying to set {key.__name__} expiration to 'forever'")

@DataSource.dispatch
def get(self, type: Type[T], query: Mapping[str, Any], context: PipelineContext = None) -> T:
Expand Down
Loading

0 comments on commit 8875d1c

Please sign in to comment.