Skip to content

Commit

Permalink
Merge pull request #219 from gergelypolonkai/remove-init-functions
Browse files Browse the repository at this point in the history
Move cache factory functionality into the cache backend classes.
  • Loading branch information
sh4nks authored Feb 20, 2021
2 parents b5fa578 + d6c43b5 commit cb8bb61
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 120 deletions.
23 changes: 12 additions & 11 deletions flask_caching/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from flask import current_app, request, url_for, Flask
from werkzeug.utils import import_string
from datetime import timedelta
from flask_caching.backends.base import BaseCache
from flask_caching.backends.simplecache import SimpleCache
from markupsafe import Markup
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
Expand Down Expand Up @@ -215,28 +216,28 @@ def init_app(self, app: Flask, config=None) -> None:
def _set_cache(self, app: Flask, config) -> None:
import_me = config["CACHE_TYPE"]
if "." not in import_me:
from . import backends

try:
cache_obj = getattr(backends, import_me)
except AttributeError:
raise ImportError(
"%s is not a valid Flask-Caching backend" % (import_me)
)
else:
cache_obj = import_string(import_me)
warnings.warn(
"Using the initialization functions in flask_caching.backend "
"is deprecated. Use the a full path to backend classes "
"directly.",
category=DeprecationWarning)
import_me = type(self).__module__ + '.backends.' + import_me

cache_factory = import_string(import_me)
cache_args = config["CACHE_ARGS"][:]
cache_options = {"default_timeout": config["CACHE_DEFAULT_TIMEOUT"]}

if isinstance(cache_factory, BaseCache):
cache_factory = cache_factory.factory

if config["CACHE_OPTIONS"]:
cache_options.update(config["CACHE_OPTIONS"])

if not hasattr(app, "extensions"):
app.extensions = {}

app.extensions.setdefault("cache", {})
app.extensions["cache"][self] = cache_obj(
app.extensions["cache"][self] = cache_factory(
app, config, cache_args, cache_options
)
self.app = app
Expand Down
118 changes: 11 additions & 107 deletions flask_caching/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@
# TODO: Rename to "redis" when python2 support is removed
from flask_caching.backends.rediscache import RedisCache, RedisSentinelCache, RedisClusterCache
from flask_caching.backends.simplecache import SimpleCache

try:
from flask_caching.backends.uwsgicache import UWSGICache

has_UWSGICache = True
except ImportError:
has_UWSGICache = False
from flask_caching.backends.uwsgicache import UWSGICache


__all__ = (
Expand All @@ -45,133 +39,43 @@


def null(app, config, args, kwargs):
return NullCache()
return NullCache.factory(app, config, args, kwargs)


def simple(app, config, args, kwargs):
kwargs.update(
dict(
threshold=config["CACHE_THRESHOLD"],
ignore_errors=config["CACHE_IGNORE_ERRORS"],
)
)
return SimpleCache(*args, **kwargs)

return SimpleCache.factory(app, config, args, kwargs)

def filesystem(app, config, args, kwargs):
args.insert(0, config["CACHE_DIR"])
kwargs.update(
dict(
threshold=config["CACHE_THRESHOLD"],
ignore_errors=config["CACHE_IGNORE_ERRORS"],
)
)
return FileSystemCache(*args, **kwargs)
return FileSystemCache.factory(app, config, args, kwargs)


def redis(app, config, args, kwargs):
try:
from redis import from_url as redis_from_url
except ImportError:
raise RuntimeError("no redis module found")

kwargs.update(
dict(
host=config.get("CACHE_REDIS_HOST", "localhost"),
port=config.get("CACHE_REDIS_PORT", 6379),
)
)
password = config.get("CACHE_REDIS_PASSWORD")
if password:
kwargs["password"] = password

key_prefix = config.get("CACHE_KEY_PREFIX")
if key_prefix:
kwargs["key_prefix"] = key_prefix

db_number = config.get("CACHE_REDIS_DB")
if db_number:
kwargs["db"] = db_number

redis_url = config.get("CACHE_REDIS_URL")
if redis_url:
kwargs["host"] = redis_from_url(redis_url, db=kwargs.pop("db", None))

return RedisCache(*args, **kwargs)
return RedisCache.factory(app, config, args, kwargs)


def redissentinel(app, config, args, kwargs):
kwargs.update(
dict(
sentinels=config.get(
"CACHE_REDIS_SENTINELS", [("127.0.0.1", 26379)]
),
master=config.get("CACHE_REDIS_SENTINEL_MASTER", "mymaster"),
password=config.get("CACHE_REDIS_PASSWORD", None),
sentinel_password=config.get("CACHE_REDIS_SENTINEL_PASSWORD", None),
key_prefix=config.get("CACHE_KEY_PREFIX", None),
db=config.get("CACHE_REDIS_DB", 0),
)
)

return RedisSentinelCache(*args, **kwargs)
return RedisSentinelCache.factory(app, config, args, kwargs)


def rediscluster(app, config, args, kwargs):
kwargs.update(
dict(cluster=config.get("CACHE_REDIS_CLUSTER", ""),
password=config.get("CACHE_REDIS_PASSWORD", ""),
default_timeout=config.get("CACHE_DEFAULT_TIMEOUT", 300),
key_prefix=config.get("CACHE_KEY_PREFIX", "")))
return RedisClusterCache(*args, **kwargs)
return RedisClusterCache.factory(app, config, args, kwargs)


def uwsgi(app, config, args, kwargs):
if not has_UWSGICache:
raise NotImplementedError(
"UWSGICache backend is not available, "
"you should upgrade werkzeug module."
)
# The name of the caching instance to connect to, for
# example: mycache@localhost:3031, defaults to an empty string, which
# means uWSGI will cache in the local instance. If the cache is in the
# same instance as the werkzeug app, you only have to provide the name of
# the cache.
uwsgi_cache_name = config.get("CACHE_UWSGI_NAME", "")
kwargs.update(dict(cache=uwsgi_cache_name))
return UWSGICache(*args, **kwargs)
return UWSGICache.factory(app, config, args, kwargs)


def memcached(app, config, args, kwargs):
args.append(config["CACHE_MEMCACHED_SERVERS"])
kwargs.update(dict(key_prefix=config["CACHE_KEY_PREFIX"]))
return MemcachedCache(*args, **kwargs)
return MemcachedCache.factory(app, config, args, kwargs)


def gaememcached(app, config, args, kwargs):
return memcached(app, config, args, kwargs)


def saslmemcached(app, config, args, kwargs):
args.append(config["CACHE_MEMCACHED_SERVERS"])
kwargs.update(
dict(
username=config["CACHE_MEMCACHED_USERNAME"],
password=config["CACHE_MEMCACHED_PASSWORD"],
key_prefix=config["CACHE_KEY_PREFIX"],
)
)
return SASLMemcachedCache(*args, **kwargs)
return SASLMemcachedCache.factory(app, config, args, kwargs)


def spreadsaslmemcached(app, config, args, kwargs):
args.append(config["CACHE_MEMCACHED_SERVERS"])
kwargs.update(
dict(
username=config.get("CACHE_MEMCACHED_USERNAME"),
password=config.get("CACHE_MEMCACHED_PASSWORD"),
key_prefix=config.get("CACHE_KEY_PREFIX"),
)
)

return SpreadSASLMemcachedCache(*args, **kwargs)
return SpreadSASLMemcachedCache.factory(app, config, args, kwargs)
4 changes: 4 additions & 0 deletions flask_caching/backends/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def __init__(self, default_timeout=300):
self.default_timeout = default_timeout
self.ignore_errors = False

@classmethod
def factory(cls, app, config, args, kwargs):
return cls()

def _normalize_timeout(self, timeout):
if timeout is None:
timeout = self.default_timeout
Expand Down
11 changes: 11 additions & 0 deletions flask_caching/backends/filesystemcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ def __init__(
if self._threshold != 0:
self._update_count(value=len(self._list_dir()))

@classmethod
def factory(cls, app, config, args, kwargs):
args.insert(0, config["CACHE_DIR"])
kwargs.update(
dict(
threshold=config["CACHE_THRESHOLD"],
ignore_errors=config["CACHE_IGNORE_ERRORS"],
)
)
return cls(*args, **kwargs)

@property
def _file_count(self):
return self.get(self._fs_count_file) or 0
Expand Down
31 changes: 31 additions & 0 deletions flask_caching/backends/memcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ def __init__(self, servers=None, default_timeout=300, key_prefix=None):

self.key_prefix = key_prefix or None

@classmethod
def factory(cls, app, config, args, kwargs):
args.append(config["CACHE_MEMCACHED_SERVERS"])
kwargs.update(dict(key_prefix=config["CACHE_KEY_PREFIX"]))
return cls(*args, **kwargs)

def _normalize_key(self, key):
key = str(key)
if self.key_prefix:
Expand Down Expand Up @@ -246,6 +252,18 @@ def __init__(

self.key_prefix = key_prefix

@classmethod
def factory(cls, app, config, args, kwargs):
args.append(config["CACHE_MEMCACHED_SERVERS"])
kwargs.update(
dict(
username=config["CACHE_MEMCACHED_USERNAME"],
password=config["CACHE_MEMCACHED_PASSWORD"],
key_prefix=config["CACHE_KEY_PREFIX"],
)
)
return cls(*args, **kwargs)


class SpreadSASLMemcachedCache(SASLMemcachedCache):
"""Simple Subclass of SASLMemcached client that will spread the value
Expand All @@ -266,6 +284,19 @@ def __init__(self, *args, **kwargs):
self.maxchunk = kwargs.get("maxchunk", 32)
super(SpreadSASLMemcachedCache, self).__init__(*args, **kwargs)

@classmethod
def factory(cls, app, config, args, kwargs):
args.append(config["CACHE_MEMCACHED_SERVERS"])
kwargs.update(
dict(
username=config.get("CACHE_MEMCACHED_USERNAME"),
password=config.get("CACHE_MEMCACHED_PASSWORD"),
key_prefix=config.get("CACHE_KEY_PREFIX"),
)
)

return cls(*args, **kwargs)

def delete(self, key):
for skey in self._genkeys(key):
super(SpreadSASLMemcachedCache, self).delete(skey)
Expand Down
62 changes: 60 additions & 2 deletions flask_caching/backends/rediscache.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,37 @@ def __init__(
self._write_client = self._read_clients = client
self.key_prefix = key_prefix or ""

@classmethod
def factory(cls, app, config, args, kwargs):
try:
from redis import from_url as redis_from_url
except ImportError:
raise RuntimeError("no redis module found")

kwargs.update(
dict(
host=config.get("CACHE_REDIS_HOST", "localhost"),
port=config.get("CACHE_REDIS_PORT", 6379),
)
)
password = config.get("CACHE_REDIS_PASSWORD")
if password:
kwargs["password"] = password

key_prefix = config.get("CACHE_KEY_PREFIX")
if key_prefix:
kwargs["key_prefix"] = key_prefix

db_number = config.get("CACHE_REDIS_DB")
if db_number:
kwargs["db"] = db_number

redis_url = config.get("CACHE_REDIS_URL")
if redis_url:
kwargs["host"] = redis_from_url(redis_url, db=kwargs.pop("db", None))

return cls(*args, **kwargs)

def _get_prefix(self):
return (
self.key_prefix
Expand Down Expand Up @@ -276,7 +307,25 @@ def __init__(
self._read_clients = sentinel.slave_for(master)

self.key_prefix = key_prefix or ""


@classmethod
def factory(cls, app, config, args, kwargs):
kwargs.update(
dict(
sentinels=config.get(
"CACHE_REDIS_SENTINELS", [("127.0.0.1", 26379)]
),
master=config.get("CACHE_REDIS_SENTINEL_MASTER", "mymaster"),
password=config.get("CACHE_REDIS_PASSWORD", None),
sentinel_password=config.get("CACHE_REDIS_SENTINEL_PASSWORD", None),
key_prefix=config.get("CACHE_KEY_PREFIX", None),
db=config.get("CACHE_REDIS_DB", 0),
)
)

return cls(*args, **kwargs)


class RedisClusterCache(RedisCache):
"""Uses the Redis key-value store as a cache backend.
Expand Down Expand Up @@ -327,10 +376,19 @@ def __init__(self,
# Skips the check of cluster-require-full-coverage config,
# useful for clusters without the CONFIG command (like aws)
skip_full_coverage_check = kwargs.pop('skip_full_coverage_check', True)

cluster = RedisCluster(startup_nodes=startup_nodes,
password=password,
skip_full_coverage_check=skip_full_coverage_check,
**kwargs)
self._write_client = self._read_clients = cluster
self.key_prefix = key_prefix

@classmethod
def factory(cls, app, config, args, kwargs):
kwargs.update(
dict(cluster=config.get("CACHE_REDIS_CLUSTER", ""),
password=config.get("CACHE_REDIS_PASSWORD", ""),
default_timeout=config.get("CACHE_DEFAULT_TIMEOUT", 300),
key_prefix=config.get("CACHE_KEY_PREFIX", "")))
return cls(*args, **kwargs)
10 changes: 10 additions & 0 deletions flask_caching/backends/simplecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ def __init__(self, threshold=500, default_timeout=300, ignore_errors=False):
self._threshold = threshold
self.ignore_errors = ignore_errors

@classmethod
def factory(cls, app, config, args, kwargs):
kwargs.update(
dict(
threshold=config["CACHE_THRESHOLD"],
ignore_errors=config["CACHE_IGNORE_ERRORS"],
)
)
return cls(*args, **kwargs)

def _prune(self):
if len(self._cache) > self._threshold:
now = time()
Expand Down
Loading

0 comments on commit cb8bb61

Please sign in to comment.