Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
fixes #34, #36, #37, #39,
  • Loading branch information
Kyria committed May 21, 2018
2 parents bc0fc89 + 346d0ef commit a131251
Show file tree
Hide file tree
Showing 16 changed files with 1,743 additions and 289 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@ ENV/

# Rope project settings
.ropeproject

env3/
2 changes: 1 addition & 1 deletion esipy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
# Not installed or in install (not yet installed) so ignore
pass

__version__ = '0.3.4'
__version__ = '0.4.0'
86 changes: 70 additions & 16 deletions esipy/app.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
# -*- encoding: utf-8 -*-
""" App entry point. Uses Esi Meta Endpoint to work """
import time

import requests

from pyswagger import App

from .utils import check_cache
from .utils import get_cache_time_left


class EsiApp(object):
Expand All @@ -12,41 +17,90 @@ class EsiApp(object):
def __init__(self, **kwargs):
""" Constructor.
:param: cache if specified, use that cache, else use DictCache
:param: cache_time is the minimum cache time for versions
endpoints. If set to 0, never expires". Default 86400sec (1day)
:param: cache_prefix the prefix used to all cache key for esiapp
:param cache: if specified, use that cache, else use DictCache
:param cache_time: is the minimum cache time for versions
endpoints. If set to 0, never expires". None uses header expires
Default 86400 (1d)
:param cache_prefix: the prefix used to all cache key for esiapp
:param meta_url: the meta url you want to use. Default is meta esi URL
https://esi.evetech.net/swagger.json
:param datasource: the EVE datasource to be used. Default: tranquility
"""
self.meta_url = kwargs.pop(
'meta_url',
'https://esi.evetech.net/swagger.json'
)
cache_time = kwargs.pop('cache_time', 86400)
if cache_time == 0 or cache_time is None:
self.expire = None
else:
self.expire = cache_time if cache_time > 0 else 86400
self.expire = kwargs.pop('cache_time', 86400)
if self.expire is not None and self.expire < 0:
self.expire = 86400

self.cache_prefix = kwargs.pop('cache_prefix', 'esipy')
self.esi_meta_cache_key = '%s:app:meta_swagger_url' % self.cache_prefix

cache = kwargs.pop('cache', False)
self.caching = True if cache is not None else False
self.cache = check_cache(cache)
self.datasource = kwargs.pop('datasource', 'tranquility')

self.app = self.__get_or_create_app(
self.meta_url,
self.esi_meta_cache_key
)

def __get_or_create_app(self, app_url, cache_key):
""" Get the app from cache or generate a new one if required """
app = self.cache.get(cache_key, None)
def __get_or_create_app(self, url, cache_key):
""" Get the app from cache or generate a new one if required
if app is None:
app = App.create(app_url)
if self.caching:
self.cache.set(cache_key, app, self.expire)
Because app object doesn't have etag/expiry, we have to make
a head() call before, to have these informations first... """
headers = {"Accept": "application/json"}
app_url = '%s?datasource=%s' % (url, self.datasource)

cached = self.cache.get(cache_key, (None, None, 0))
if cached is None or len(cached) != 3:
self.cache.invalidate(cache_key)
cached_app, cached_headers, cached_expiry = (cached, None, 0)
else:
cached_app, cached_headers, cached_expiry = cached

if cached_app is not None and cached_headers is not None:
# we didn't set custom expire, use header expiry
if self.expire is None:
expires = cached_headers.get('expires', None)
if expires is not None:

cache_timeout = get_cache_time_left(
cached_headers['expires']
)
if cache_timeout >= 0:
return cached_app

# we set custom expire, check this instead
else:
if self.expire == 0 or cached_expiry >= time.time():
return cached_app

# if we have etags, add the header to use them
etag = cached_headers.get('etag', None)
if etag is not None:
headers['If-None-Match'] = etag

# if nothing makes us use the cache, invalidate it
if ((expires is None or cache_timeout < 0 or
0 < self.expire < time.time()) and etag is None):
self.cache.invalidate(cache_key)

# we are here, we know we have to make a head call...
res = requests.head(app_url, headers=headers)
if res.status_code == 304 and cached_app is not None:
return cached_app

# ok, cache is not accurate, make the full stuff
app = App.create(app_url)
if self.caching:
timeout = 0
if self.expire is not None and self.expire > 0:
timeout = time.time() + self.expire
self.cache.set(cache_key, (app, res.headers, timeout))

return app

Expand Down
40 changes: 13 additions & 27 deletions esipy/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
""" Cache objects for EsiPy """
import hashlib
import logging
import time

try:
import pickle
Expand All @@ -26,8 +25,8 @@ class BaseCache(object):
the cache methods used in esipy
"""

def set(self, key, value, timeout=300):
""" Set a value in the cache. If timeout=(None): never expires """
def set(self, key, value):
""" Set a value in the cache. """
raise NotImplementedError

def get(self, key, default=None):
Expand Down Expand Up @@ -64,9 +63,8 @@ def __del__(self):
"""
self._cache.close()

def set(self, key, value, timeout=300):
expire_time = None if timeout == 0 else timeout
self._cache.set(_hash(key), value, expire=expire_time)
def set(self, key, value):
self._cache.set(_hash(key), value)

def get(self, key, default=None):
return self._cache.get(_hash(key), default)
Expand All @@ -82,19 +80,10 @@ def __init__(self):
self._dict = {}

def get(self, key, default=None):
cache_val = self._dict.get(key, (None, 0))
return self._dict.get(key, default)

if cache_val[1] is not None and cache_val[1] < time.time():
self.invalidate(key)
return default
return cache_val[0]

def set(self, key, value, timeout=300):
if timeout is None or timeout == 0:
expire_time = None
else:
expire_time = timeout + time.time()
self._dict[key] = (value, expire_time)
def set(self, key, value):
self._dict[key] = value

def invalidate(self, key):
self._dict.pop(key, None)
Expand All @@ -108,9 +97,9 @@ def __init__(self):
self._dict = {}

def get(self, key, default=None):
return None
return default

def set(self, key, value, timeout=300):
def set(self, key, value):
pass

def invalidate(self, key):
Expand All @@ -136,9 +125,8 @@ def get(self, key, default=None):
value = self._mc.get(_hash(key))
return value if value is not None else default

def set(self, key, value, timeout=300):
expire_time = 0 if timeout is None else timeout
return self._mc.set(_hash(key), value, expire_time)
def set(self, key, value):
return self._mc.set(_hash(key), value)

def invalidate(self, key):
return self._mc.delete(_hash(key))
Expand All @@ -162,10 +150,8 @@ def get(self, key, default=None):
value = self._r.get(_hash(key))
return pickle.loads(value) if value is not None else default

def set(self, key, value, timeout=300):
if timeout is None or timeout == 0:
return self._r.set(_hash(key), pickle.dumps(value))
return self._r.setex(_hash(key), pickle.dumps(value), timeout)
def set(self, key, value):
return self._r.set(_hash(key), pickle.dumps(value))

def invalidate(self, key):
return self._r.delete(_hash(key))
Loading

0 comments on commit a131251

Please sign in to comment.