Skip to content

Commit

Permalink
Merge pull request #11 from dyus/master
Browse files Browse the repository at this point in the history
add support for python3.10
  • Loading branch information
Bahus committed Oct 13, 2022
2 parents 7d4c984 + 9ba5f8c commit 5948dd9
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 170 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ CACHES={
'KEY_PREFIX': 'custom_prefix',
},
'memcached': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': '127.0.0.1:11211',
'KEY_PREFIX': 'memcached',
}
Expand Down
5 changes: 1 addition & 4 deletions easy_cache/abc.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import
from abc import ABCMeta, abstractmethod
import six

from easy_cache.core import DEFAULT_TIMEOUT, NOT_FOUND


@six.add_metaclass(ABCMeta)
class AbstractCacheInstance(object):
class AbstractCacheInstance(object, metaclass=ABCMeta):
"""All custom cache instances (clients) should
inherit this class.
"""
Expand Down
77 changes: 31 additions & 46 deletions easy_cache/compat.py
Original file line number Diff line number Diff line change
@@ -1,72 +1,57 @@
# -*- coding: utf-8 -*-
"""
Compatibility between Python versions
"""
from collections import namedtuple
import inspect
import sys
import six


PY3 = six.PY3
PY34 = sys.version_info[0:2] == (3, 4)
PY35 = sys.version_info[0:2] >= (3, 5)
from inspect import Parameter


def force_text(obj, encoding='utf-8'):
if isinstance(obj, six.text_type):
if isinstance(obj, str):
return obj
elif not isinstance(obj, six.binary_type):
return six.text_type(obj)
elif not isinstance(obj, bytes):
return str(obj)

try:
return six.text_type(obj, encoding=encoding)
return str(obj, encoding=encoding)
except UnicodeDecodeError:
return obj.decode(encoding)


def force_binary(obj, encoding='utf-8'):
if isinstance(obj, six.binary_type):
if isinstance(obj, bytes):
return obj
elif not isinstance(obj, six.text_type):
return six.binary_type(obj)
elif not isinstance(obj, str):
return bytes(obj)

try:
if PY3:
return six.binary_type(obj, encoding=encoding)
return six.binary_type(obj)
return bytes(obj, encoding=encoding)
except UnicodeEncodeError:
return obj.encode(encoding)


if PY3:
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
from inspect import Parameter
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')


def getargspec(func):
signature = inspect.signature(func)
def getargspec(func):
signature = inspect.signature(func)

args = []
varargs = None
keywords = None
defaults = []
args = []
varargs = None
keywords = None
defaults = []

for param in signature.parameters.values(): # type: Parameter
if param.kind == Parameter.VAR_POSITIONAL:
varargs = param.name
elif param.kind in (
Parameter.POSITIONAL_ONLY,
Parameter.KEYWORD_ONLY,
Parameter.POSITIONAL_OR_KEYWORD):
args.append(param.name)
elif param.kind == Parameter.VAR_KEYWORD:
keywords = param.name
for param in signature.parameters.values(): # type: Parameter
if param.kind == Parameter.VAR_POSITIONAL:
varargs = param.name
elif param.kind in (
Parameter.POSITIONAL_ONLY,
Parameter.KEYWORD_ONLY,
Parameter.POSITIONAL_OR_KEYWORD):
args.append(param.name)
elif param.kind == Parameter.VAR_KEYWORD:
keywords = param.name

# noinspection PyProtectedMember
if param.default is not inspect._empty:
defaults.append(param.default)
# noinspection PyProtectedMember
if param.default is not inspect._empty:
defaults.append(param.default)

return ArgSpec(args, varargs, keywords, tuple(defaults))
else:
def getargspec(func):
return inspect.getargspec(func)
return ArgSpec(args, varargs, keywords, tuple(defaults))
7 changes: 3 additions & 4 deletions easy_cache/contrib/redis_cache.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
import six
import json
from easy_cache import create_cache_key
from easy_cache.abc import AbstractCacheInstance
Expand All @@ -24,15 +23,15 @@ def make_key(self, key):
return create_cache_key(self.prefix, key)

def load_value(self, value):
if isinstance(value, six.binary_type):
if isinstance(value, bytes):
value = force_text(value)
elif value is None:
return value
return self.serializer.loads(value)

# noinspection PyMethodMayBeStatic
def dump_value(self, value):
if isinstance(value, six.binary_type):
if isinstance(value, bytes):
return value

return force_binary(self.serializer.dumps(value))
Expand Down Expand Up @@ -74,7 +73,7 @@ def set_many(self, data_dict, timeout=DEFAULT_TIMEOUT):
pipe = self.client.pipeline()
pipe.mset(
{self.make_key(key): self.dump_value(value)
for key, value in six.iteritems(data_dict)}
for key, value in iter(data_dict.items())}
)

if timeout:
Expand Down
36 changes: 17 additions & 19 deletions easy_cache/core.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import collections
from collections import abc
import inspect
import logging
import os
Expand Down Expand Up @@ -106,15 +106,15 @@ def set_default(self, cache_instance):

# setters
def set_cache_key_delimiter(delimiter):
if not isinstance(delimiter, six.string_types):
if not isinstance(delimiter, str):
raise TypeError('Invalid delimiter type, string required')

global CACHE_KEY_DELIMITER
CACHE_KEY_DELIMITER = force_text(delimiter)


def set_tag_key_prefix(prefix):
if not isinstance(prefix, six.string_types):
if not isinstance(prefix, str):
raise TypeError('Invalid tag prefix type, string required')

global TAG_KEY_PREFIX
Expand All @@ -139,7 +139,7 @@ def invalidate_cache_prefix(prefix, cache_instance=None, cache_alias=None):


def invalidate_cache_tags(tags, cache_instance=None, cache_alias=None):
if isinstance(tags, six.string_types):
if isinstance(tags, str):
tags = [tags]

_cache = TaggedCacheProxy(cache_instance or caches[cache_alias or DEFAULT_CACHE_ALIAS])
Expand All @@ -150,7 +150,7 @@ def create_cache_key(*parts):
""" Generate cache key using global delimiter char """
if len(parts) == 1:
parts = parts[0]
if isinstance(parts, six.string_types):
if isinstance(parts, str):
parts = [parts]

return CACHE_KEY_DELIMITER.join(force_text(p) for p in parts)
Expand All @@ -169,7 +169,7 @@ def compare_dicts(d1, d2):
return dict(d1) == dict(d2)


class MetaCallable(collections.Mapping):
class MetaCallable(abc.Mapping):
""" Object contains meta information about method or function decorated with ecached,
passed arguments, returned results, signature description and so on.
"""
Expand Down Expand Up @@ -362,7 +362,7 @@ def update_arguments(self, args, kwargs):
if self.instance:
# first argument in args is "self"
args = (self.instance, ) + args
elif self.klass:
elif self.klass and not type(self.function) == staticmethod:
# firs argument in args is "cls"
args = (self.klass, ) + args

Expand Down Expand Up @@ -446,7 +446,7 @@ def _format(self, template, meta):
if isinstance(template, (staticmethod, classmethod)):
template = template.__func__

if isinstance(template, collections.Callable):
if isinstance(template, abc.Callable):
if self._check_if_meta_required(template):
return template(meta)
else:
Expand All @@ -456,7 +456,7 @@ def _format(self, template, meta):
return template

try:
if isinstance(template, six.string_types):
if isinstance(template, str):
return force_text(template).format(**meta.call_args)
elif isinstance(template, (list, tuple, set)):
return [force_text(t).format(**meta.call_args) for t in template]
Expand Down Expand Up @@ -495,7 +495,10 @@ def collect_meta(self, args, kwargs, returned_value=NOT_SET):
meta.scope = self.scope

try:
meta.call_args = inspect.getcallargs(self.function, *args, **kwargs)
signature = inspect.signature(self.function)
bound_args = signature.bind(*args, **kwargs).arguments
bound_args.update(default_kwargs)
meta.call_args = bound_args
except TypeError:
# sometimes not all required parameters are provided, just ignore them
meta.call_args = meta.kwargs
Expand All @@ -519,19 +522,14 @@ def refresh_cache(self, *args, **kwargs):
self.set_cached_value(cache_key, callable_meta)
return value

def __unicode__(self):
def __str__(self):
return (
'<Cached: callable="{}", cache_key="{}", timeout={}>'.format(
get_function_path(self.function, self.scope),
get_function_path(self.cache_key_template),
self.timeout)
)

def __str__(self):
if six.PY2:
return force_binary(self.__unicode__())
return self.__unicode__()

def __repr__(self):
try:
return self.__str__()
Expand Down Expand Up @@ -591,7 +589,7 @@ def invalidate_cache_by_tags(self, tags=(), *args, **kwargs):
raise ValueError('Tags were not specified, nothing to invalidate')

def to_set(obj):
return set([obj] if isinstance(obj, six.string_types) else obj)
return set([obj] if isinstance(obj, str) else obj)

callable_meta = self.collect_meta(args, kwargs)
all_tags = to_set(self._format(self.tags, callable_meta))
Expand Down Expand Up @@ -630,8 +628,8 @@ def set_cached_value(self, cache_key, callable_meta, **extra):

return super(TaggedCached, self).set_cached_value(cache_key, callable_meta, tags=tags)

def __unicode__(self):
return six.text_type(
def __str__(self):
return str(
'<TaggedCached: callable="{}", cache_key="{}", tags="{}", prefix="{}", '
'timeout={}>'.format(
get_function_path(self.function, self.scope),
Expand Down
7 changes: 3 additions & 4 deletions easy_cache/decorators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
import collections
import six
from collections import abc
from functools import update_wrapper

from easy_cache.core import Cached, TaggedCached, DEFAULT_TIMEOUT, META_ACCEPTED_ATTR
Expand Down Expand Up @@ -75,7 +74,7 @@ def wrapper(self):
self._instance = None
self._class = None
else:
wrapped = six.get_method_function(wrapped)
wrapped = wrapped.__func__
else:
wrapped = self._func

Expand All @@ -90,7 +89,7 @@ def wrapper(self):
def __call__(self, func):
self._func = func

if isinstance(func, collections.Callable):
if isinstance(func, abc.Callable):
return self.wrapper()

return self
Expand Down
9 changes: 3 additions & 6 deletions easy_cache/utils.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import six


def get_function_path(function, bound_to=None):
"""Get received function path (as string), to import function later
with `import_string`.
"""
if isinstance(function, six.string_types):
if isinstance(function, str):
return function

# static and class methods
Expand All @@ -27,12 +24,12 @@ def get_function_path(function, bound_to=None):

if not bound_to:
try:
bound_to = six.get_method_self(function)
bound_to = function.__self__
except AttributeError:
pass

if bound_to:
if isinstance(bound_to, six.class_types):
if isinstance(bound_to, type):
func_path.append(bound_to.__name__)
else:
func_path.append(bound_to.__class__.__name__)
Expand Down
10 changes: 5 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def get_long_description():
'mock',
'psutil',
'python-memcached',
'pymemcache',
'redis',
'pylibmc',
'tox-pyenv',
Expand All @@ -43,17 +44,16 @@ def get_long_description():
'Environment :: Web Environment',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Topic :: Software Development :: Libraries :: Python Modules',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License'
],
long_description=get_long_description(),
long_description_content_type='text/markdown',
requires=['six'],
install_requires=['six'],
tests_require=tests_require,
extras_require={
'tests': tests_require,
Expand Down
Loading

0 comments on commit 5948dd9

Please sign in to comment.