Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-dogpile.cache for
openSUSE:Factory checked in at 2021-09-06 15:57:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-dogpile.cache (Old)
and /work/SRC/openSUSE:Factory/.python-dogpile.cache.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-dogpile.cache"
Mon Sep 6 15:57:59 2021 rev:32 rq:916952 version:1.1.4
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-dogpile.cache/python-dogpile.cache.changes
2021-06-25 15:02:13.016215909 +0200
+++
/work/SRC/openSUSE:Factory/.python-dogpile.cache.new.1899/python-dogpile.cache.changes
2021-09-06 15:58:12.589292715 +0200
@@ -1,0 +2,19 @@
+Mon Sep 6 04:29:32 UTC 2021 - Steve Kowalik <[email protected]>
+
+- Update to 1.1.4:
+ * [usecase] [memcached] Added support for pymemcache socket keepalive
+ and retrying client.
+ * [bug] [general] Fixed Python 3.10 deprecation warning involving
+ threading. Pull request
+ * [bug] [regression] [tests] Repaired the test suite to work with the
+ 5.x series of the decorator module, which now appears to make use of
+ the __signature__ attribute.
+ * [bug] [regression] Fixed regression where ProxyBackend was missing
+ several methods that were added as part of the 1.1 release.
+ * [feature] [region] Added new region method CacheRegion.key_is_locked().
+ Returns True if the given key is subject to the dogpile lock, which
+ would indicate that the generator function is running at that time.
+ * [feature] [memcached] Added support for the pymemcache backend, using
+ the "dogpile.cache.pymemcache" backend identifier.
+
+-------------------------------------------------------------------
Old:
----
dogpile.cache-1.1.3.tar.gz
New:
----
dogpile.cache-1.1.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-dogpile.cache.spec ++++++
--- /var/tmp/diff_new_pack.9poagK/_old 2021-09-06 15:58:13.121292592 +0200
+++ /var/tmp/diff_new_pack.9poagK/_new 2021-09-06 15:58:13.125292592 +0200
@@ -19,13 +19,12 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%global pythons python3
Name: python-dogpile.cache
-Version: 1.1.3
+Version: 1.1.4
Release: 0
%define modname dogpile.cache
-%define modver 1_1_1
+%define modver 1_1_4
Summary: A caching front-end based on the Dogpile lock
License: BSD-3-Clause
-Group: Development/Languages/Python
URL: https://github.com/sqlalchemy/dogpile.cache
Source:
https://github.com/sqlalchemy/%{modname}/archive/rel_%{modver}.tar.gz#/%{modname}-%{version}.tar.gz
BuildRequires: %{python_module Mako}
@@ -67,6 +66,6 @@
%license LICENSE
%doc README.rst
%{python_sitelib}/dogpile
-%{python_sitelib}/dogpile.cache-1.1.1-py%{python_version}.egg-info
+%{python_sitelib}/dogpile.cache-%{version}-py%{python_version}.egg-info
%changelog
++++++ dogpile.cache-1.1.3.tar.gz -> dogpile.cache-1.1.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/.pre-commit-config.yaml
new/dogpile.cache-rel_1_1_4/.pre-commit-config.yaml
--- old/dogpile.cache-rel_1_1_1/.pre-commit-config.yaml 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/.pre-commit-config.yaml 2021-09-02
16:42:13.000000000 +0200
@@ -2,24 +2,26 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/python/black
- rev: 20.8b1
+ rev: 21.5b1
hooks:
- id: black
- repo: https://github.com/sqlalchemyorg/zimports
- rev: master
+ rev: v0.4.1
hooks:
- id: zimports
+ args:
+ - --keep-unused-type-checking
- repo: https://github.com/pycqa/flake8
- rev: master
+ rev: 3.9.2
hooks:
- id: flake8
additional_dependencies:
- flake8-import-order
- flake8-builtins
- - flake8-docstrings
+ - flake8-docstrings>=1.3.1
- flake8-rst-docstrings
- - pydocstyle<4.0.0
+ - pydocstyle
- pygments
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/LICENSE
new/dogpile.cache-rel_1_1_4/LICENSE
--- old/dogpile.cache-rel_1_1_1/LICENSE 2020-11-23 14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/LICENSE 2021-09-02 16:42:13.000000000 +0200
@@ -1,4 +1,4 @@
-Copyright 2005-2020 Michael Bayer.
+Copyright 2005-2021 Michael Bayer.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/docs/build/changelog.rst
new/dogpile.cache-rel_1_1_4/docs/build/changelog.rst
--- old/dogpile.cache-rel_1_1_1/docs/build/changelog.rst 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/docs/build/changelog.rst 2021-09-02
16:42:13.000000000 +0200
@@ -3,6 +3,70 @@
=========
.. changelog::
+ :version: 1.1.4
+ :released: Thu Sep 2 2021
+
+ .. change::
+ :tags: bug, general
+ :tickets: 203
+
+ Fixed Python 3.10 deprecation warning involving threading. Pull request
+ courtesy Karthikeyan Singaravelan.
+
+ .. change::
+ :tags: usecase, memcached
+
+ Added support for pymemcache socket keepalive and retrying client.
+
+ .. seealso::
+
+ :paramref:`.PyMemcacheBackend.socket_keepalive`
+
+ :paramref:`.PyMemcacheBackend.enable_retry_client`
+
+.. changelog::
+ :version: 1.1.3
+ :released: Thu May 20 2021
+
+ .. change::
+ :tags: bug, regression, tests
+
+ Repaired the test suite to work with the 5.x series of the
``decorator``
+ module, which now appears to make use of the ``__signature__``
attribute.
+
+ .. change::
+ :tags: bug, regression
+ :tickets: 202
+
+ Fixed regression where :class:`.ProxyBackend` was missing several
methods
+ that were added as part of the 1.1 release.
+
+.. changelog::
+ :version: 1.1.2
+ :released: Tue Jan 26 2021
+
+ .. change::
+ :tags: feature, region
+ :tickets: 101
+
+ Added new region method :meth:`.CacheRegion.key_is_locked`. Returns
True if
+ the given key is subject to the dogpile lock, which would indicate
that the
+ generator function is running at that time. Pull request courtesy
Bastien
+ Gerard.
+
+ .. change::
+ :tags: feature, memcached
+ :tickets: 134
+
+ Added support for the pymemcache backend, using the
+ ``"dogpile.cache.pymemcache"`` backend identifier. Pull request
courtesy
+ Mois??s Guimar??es de Medeiros.
+
+ .. seealso::
+
+ :class:`.PyMemcacheBackend`
+
+.. changelog::
:version: 1.1.1
:released: Mon Nov 23 2020
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/docs/build/conf.py
new/dogpile.cache-rel_1_1_4/docs/build/conf.py
--- old/dogpile.cache-rel_1_1_1/docs/build/conf.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/docs/build/conf.py 2021-09-02
16:42:13.000000000 +0200
@@ -39,7 +39,7 @@
"sphinx_paramlinks",
]
-changelog_sections = ["feature", "bug"]
+changelog_sections = ["feature", "usecase", "bug"]
changelog_render_ticket = (
"https://github.com/sqlalchemy/dogpile.cache/issues/%s"
@@ -65,7 +65,7 @@
# General information about the project.
project = "dogpile.cache"
-copyright = "2011-2020 Mike Bayer"
+copyright = "2011-2021 Mike Bayer"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -74,7 +74,7 @@
# The short X.Y version.
version = dogpile.__version__
# The full version, including alpha/beta/rc tags.
-release = "1.1.1"
+release = "1.1.4"
# The language for content autogenerated by Sphinx. Refer to documentation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/dogpile/__init__.py
new/dogpile.cache-rel_1_1_4/dogpile/__init__.py
--- old/dogpile.cache-rel_1_1_1/dogpile/__init__.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/__init__.py 2021-09-02
16:42:13.000000000 +0200
@@ -1,4 +1,4 @@
-__version__ = "1.1.1"
+__version__ = "1.1.4"
from .lock import Lock # noqa
from .lock import NeedRegenerationException # noqa
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/dogpile/cache/api.py
new/dogpile.cache-rel_1_1_4/dogpile/cache/api.py
--- old/dogpile.cache-rel_1_1_1/dogpile/cache/api.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/cache/api.py 2021-09-02
16:42:13.000000000 +0200
@@ -85,6 +85,17 @@
raise NotImplementedError()
+ @abc.abstractmethod
+ def locked(self) -> bool:
+ """Check if the mutex was acquired.
+
+ :return: true if the lock is acquired.
+
+ .. versionadded:: 1.1.2
+
+ """
+ raise NotImplementedError()
+
@classmethod
def __subclasshook__(cls, C):
return hasattr(C, "acquire") and hasattr(C, "release")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/dogpile.cache-rel_1_1_1/dogpile/cache/backends/__init__.py
new/dogpile.cache-rel_1_1_4/dogpile/cache/backends/__init__.py
--- old/dogpile.cache-rel_1_1_1/dogpile/cache/backends/__init__.py
2020-11-23 14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/cache/backends/__init__.py
2021-09-02 16:42:13.000000000 +0200
@@ -25,6 +25,11 @@
"MemcachedBackend",
)
register_backend(
+ "dogpile.cache.pymemcache",
+ "dogpile.cache.backends.memcached",
+ "PyMemcacheBackend",
+)
+register_backend(
"dogpile.cache.memory", "dogpile.cache.backends.memory", "MemoryBackend"
)
register_backend(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/dogpile.cache-rel_1_1_1/dogpile/cache/backends/memcached.py
new/dogpile.cache-rel_1_1_4/dogpile/cache/backends/memcached.py
--- old/dogpile.cache-rel_1_1_1/dogpile/cache/backends/memcached.py
2020-11-23 14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/cache/backends/memcached.py
2021-09-02 16:42:13.000000000 +0200
@@ -12,25 +12,30 @@
import typing
from typing import Any
from typing import Mapping
+import warnings
from ..api import CacheBackend
from ..api import NO_VALUE
from ... import util
+
if typing.TYPE_CHECKING:
+ import bmemcached
import memcache
import pylibmc
- import bmemcached
+ import pymemcache
else:
# delayed import
- memcache = None
- pylibmc = None
- bmemcached = None
+ bmemcached = None # noqa F811
+ memcache = None # noqa F811
+ pylibmc = None # noqa F811
+ pymemcache = None # noqa F811
__all__ = (
"GenericMemcachedBackend",
"MemcachedBackend",
"PylibmcBackend",
+ "PyMemcacheBackend",
"BMemcachedBackend",
"MemcachedLock",
)
@@ -58,6 +63,10 @@
if i < 15:
i += 1
+ def locked(self):
+ client = self.client_fn()
+ return client.get(self.key) is not None
+
def release(self):
client = self.client_fn()
client.delete(self.key)
@@ -188,7 +197,11 @@
def get_multi(self, keys):
values = self.client.get_multi(keys)
- return [NO_VALUE if key not in values else values[key] for key in keys]
+
+ return [
+ NO_VALUE if val is None else val
+ for val in [values.get(key, NO_VALUE) for key in keys]
+ ]
def set(self, key, value):
self.client.set(key, value, **self.set_arguments)
@@ -223,9 +236,6 @@
super(MemcacheArgs, self).__init__(arguments)
-pylibmc = None
-
-
class PylibmcBackend(MemcacheArgs, GenericMemcachedBackend):
"""A backend for the
`pylibmc <http://sendapatch.se/projects/pylibmc/index.html>`_
@@ -275,9 +285,6 @@
)
-memcache = None
-
-
class MemcachedBackend(MemcacheArgs, GenericMemcachedBackend):
"""A backend using the standard
`Python-memcached <http://www.tummy.com/Community/software/\
@@ -306,9 +313,6 @@
return memcache.Client(self.url)
-bmemcached = None
-
-
class BMemcachedBackend(GenericMemcachedBackend):
"""A backend for the
`python-binary-memcached <https://github.com/jaysonsantos/\
@@ -321,16 +325,6 @@
SASL is a standard for adding authentication mechanisms
to protocols in a way that is protocol independent.
- SSL/TLS is a security layer on end-to-end communication.
- It provides following benefits:
-
- * Encryption: Data is encrypted on the wire between
- Memcached client and server.
- * Authentication: Optionally, both server and client
- authenticate each other.
- * Integrity: Data is not tampered or altered when
- transmitted between client and server
-
A typical configuration using username/password::
from dogpile.cache import make_region
@@ -417,3 +411,179 @@
"""python-binary-memcached api does not implements delete_multi"""
for key in keys:
self.delete(key)
+
+
+class PyMemcacheBackend(GenericMemcachedBackend):
+ """A backend for the
+ `pymemcache <https://github.com/pinterest/pymemcache>`_
+ memcached client.
+
+ A comprehensive, fast, pure Python memcached client
+
+ .. versionadded:: 1.1.2
+
+ pymemcache supports the following features:
+
+ * Complete implementation of the memcached text protocol.
+ * Configurable timeouts for socket connect and send/recv calls.
+ * Access to the "noreply" flag, which can significantly increase
+ the speed of writes.
+ * Flexible, simple approach to serialization and deserialization.
+ * The (optional) ability to treat network and memcached errors as
+ cache misses.
+
+ dogpile.cache uses the ``HashClient`` from pymemcache in order to reduce
+ API differences when compared to other memcached client drivers.
+ This allows the user to provide a single server or a list of memcached
+ servers.
+
+ Arguments which can be passed to the ``arguments``
+ dictionary include:
+
+ :param tls_context: optional TLS context, will be used for
+ TLS connections.
+
+ A typical configuration using tls_context::
+
+ import ssl
+ from dogpile.cache import make_region
+
+ ctx = ssl.create_default_context(cafile="/path/to/my-ca.pem")
+
+ region = make_region().configure(
+ 'dogpile.cache.pymemcache',
+ expiration_time = 3600,
+ arguments = {
+ 'url':["127.0.0.1"],
+ 'tls_context':ctx,
+ }
+ )
+
+ .. seealso::
+
+ `<https://docs.python.org/3/library/ssl.html>`_ - additional TLS
+ documentation.
+
+ :param serde: optional "serde". Defaults to
+ ``pymemcache.serde.pickle_serde``.
+
+ :param default_noreply: defaults to False. When set to True this flag
+ enables the pymemcache "noreply" feature. See the pymemcache
+ documentation for further details.
+
+ :param socket_keepalive: optional socket keepalive, will be used for
+ TCP keepalive configuration. Use of this parameter requires pymemcache
+ 3.5.0 or greater. This parameter
+ accepts a
+ `pymemcache.client.base.KeepAliveOpts
+
<https://pymemcache.readthedocs.io/en/latest/apidoc/pymemcache.client.base.html#pymemcache.client.base.KeepaliveOpts>`_
+ object.
+
+ A typical configuration using ``socket_keepalive``::
+
+ from pymemcache import KeepaliveOpts
+ from dogpile.cache import make_region
+
+ # Using the default keepalive configuration
+ socket_keepalive = KeepaliveOpts()
+
+ region = make_region().configure(
+ 'dogpile.cache.pymemcache',
+ expiration_time = 3600,
+ arguments = {
+ 'url':["127.0.0.1"],
+ 'socket_keepalive': socket_keepalive
+ }
+ )
+
+ .. versionadded:: 1.1.4 - added support for ``socket_keepalive``.
+
+ :param enable_retry_client: optional flag to enable retry client
+ mechanisms to handle failure. Defaults to False. When set to ``True``,
+ the :paramref:`.PyMemcacheBackend.retry_attempts` parameter must also
+ be set, along with optional parameters
+ :paramref:`.PyMemcacheBackend.retry_delay`.
+ :paramref:`.PyMemcacheBackend.retry_for`,
+ :paramref:`.PyMemcacheBackend.do_not_retry_for`.
+
+ .. seealso::
+
+
`<https://pymemcache.readthedocs.io/en/latest/getting_started.html#using-the-built-in-retrying-mechanism>`_
-
+ in the pymemcache documentation
+
+ .. versionadded:: 1.1.4
+
+ :param retry_attempts: how many times to attempt an action before
+ failing. Must be 1 or above. Defaults to None.
+
+ .. versionadded:: 1.1.4
+
+ :param retry_delay: optional int|float, how many seconds to sleep between
+ each attempt. Defaults to None.
+
+ .. versionadded:: 1.1.4
+
+ :param retry_for: optional None|tuple|set|list, what exceptions to
+ allow retries for. Will allow retries for all exceptions if None.
+ Example: ``(MemcacheClientError, MemcacheUnexpectedCloseError)``
+ Accepts any class that is a subclass of Exception. Defaults to None.
+
+ .. versionadded:: 1.1.4
+
+ :param do_not_retry_for: optional None|tuple|set|list, what
+ exceptions should be retried. Will not block retries for any Exception if
+ None. Example: ``(IOError, MemcacheIllegalInputError)``
+ Accepts any class that is a subclass of Exception. Defaults to None.
+
+ .. versionadded:: 1.1.4
+
+ """ # noqa E501
+
+ def __init__(self, arguments):
+ super().__init__(arguments)
+
+ self.serde = arguments.get("serde", pymemcache.serde.pickle_serde)
+ self.default_noreply = arguments.get("default_noreply", False)
+ self.tls_context = arguments.get("tls_context", None)
+ self.socket_keepalive = arguments.get("socket_keepalive", None)
+ self.enable_retry_client = arguments.get("enable_retry_client", False)
+ self.retry_attempts = arguments.get("retry_attempts", None)
+ self.retry_delay = arguments.get("retry_delay", None)
+ self.retry_for = arguments.get("retry_for", None)
+ self.do_not_retry_for = arguments.get("do_not_retry_for", None)
+ if (
+ self.retry_delay is not None
+ or self.retry_attempts is not None
+ or self.retry_for is not None
+ or self.do_not_retry_for is not None
+ ) and not self.enable_retry_client:
+ warnings.warn(
+ "enable_retry_client is not set; retry options "
+ "will be ignored"
+ )
+
+ def _imports(self):
+ global pymemcache
+ import pymemcache
+
+ def _create_client(self):
+ _kwargs = {
+ "serde": self.serde,
+ "default_noreply": self.default_noreply,
+ "tls_context": self.tls_context,
+ }
+ if self.socket_keepalive is not None:
+ _kwargs.update({"socket_keepalive": self.socket_keepalive})
+
+ client = pymemcache.client.hash.HashClient(self.url, **_kwargs)
+
+ if self.enable_retry_client:
+ return pymemcache.client.retrying.RetryingClient(
+ client,
+ attempts=self.retry_attempts,
+ retry_delay=self.retry_delay,
+ retry_for=self.retry_for,
+ do_not_retry_for=self.do_not_retry_for,
+ )
+
+ return client
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/dogpile.cache-rel_1_1_1/dogpile/cache/backends/null.py
new/dogpile.cache-rel_1_1_4/dogpile/cache/backends/null.py
--- old/dogpile.cache-rel_1_1_1/dogpile/cache/backends/null.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/cache/backends/null.py 2021-09-02
16:42:13.000000000 +0200
@@ -24,6 +24,9 @@
def release(self):
pass
+ def locked(self):
+ return False
+
class NullBackend(CacheBackend):
"""A "null" backend that effectively disables all cache operations.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/dogpile.cache-rel_1_1_1/dogpile/cache/backends/redis.py
new/dogpile.cache-rel_1_1_4/dogpile/cache/backends/redis.py
--- old/dogpile.cache-rel_1_1_1/dogpile/cache/backends/redis.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/cache/backends/redis.py 2021-09-02
16:42:13.000000000 +0200
@@ -18,7 +18,7 @@
import redis
else:
# delayed import
- redis = None
+ redis = None # noqa F811
__all__ = ("RedisBackend", "RedisSentinelBackend")
@@ -173,11 +173,7 @@
def set_serialized(self, key, value):
if self.redis_expiration_time:
- self.writer_client.setex(
- key,
- self.redis_expiration_time,
- value,
- )
+ self.writer_client.setex(key, self.redis_expiration_time, value)
else:
self.writer_client.set(key, value)
@@ -283,7 +279,7 @@
"distributed_lock": True,
"thread_local_lock": False,
**arguments,
- },
+ }
)
def _imports(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/dogpile/cache/proxy.py
new/dogpile.cache-rel_1_1_4/dogpile/cache/proxy.py
--- old/dogpile.cache-rel_1_1_1/dogpile/cache/proxy.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/cache/proxy.py 2021-09-02
16:42:13.000000000 +0200
@@ -19,6 +19,7 @@
from .api import CacheBackend
from .api import CacheMutex
from .api import KeyType
+from .api import SerializedReturnType
class ProxyBackend(CacheBackend):
@@ -101,3 +102,17 @@
def get_mutex(self, key: KeyType) -> Optional[CacheMutex]:
return self.proxied.get_mutex(key)
+
+ def get_serialized(self, key: KeyType) -> SerializedReturnType:
+ return self.proxied.get_serialized(key)
+
+ def get_serialized_multi(
+ self, keys: Sequence[KeyType]
+ ) -> Sequence[SerializedReturnType]:
+ return self.proxied.get_serialized_multi(keys)
+
+ def set_serialized(self, key: KeyType, value: bytes) -> None:
+ self.proxied.set_serialized(key, value)
+
+ def set_serialized_multi(self, mapping: Mapping[KeyType, bytes]) -> None:
+ self.proxied.set_serialized_multi(mapping)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/dogpile/cache/region.py
new/dogpile.cache-rel_1_1_4/dogpile/cache/region.py
--- old/dogpile.cache-rel_1_1_1/dogpile/cache/region.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/cache/region.py 2021-09-02
16:42:13.000000000 +0200
@@ -554,6 +554,9 @@
def release(self):
self.lock.release()
+ def locked(self):
+ return self.lock.locked()
+
def _create_mutex(self, key):
mutex = self.backend.get_mutex(key)
if mutex is not None:
@@ -865,6 +868,17 @@
return True
+ def key_is_locked(self, key: KeyType) -> bool:
+ """Return True if a particular cache key is currently being generated
+ within the dogpile lock.
+
+ .. versionadded:: 1.1.2
+
+ """
+ mutex = self._mutex(key)
+ locked: bool = mutex.locked()
+ return locked
+
def get_or_create(
self,
key: KeyType,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/dogpile/util/compat.py
new/dogpile.cache-rel_1_1_4/dogpile/util/compat.py
--- old/dogpile.cache-rel_1_1_1/dogpile/util/compat.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/util/compat.py 2021-09-02
16:42:13.000000000 +0200
@@ -28,6 +28,11 @@
"""
+ # if a Signature is already present, as is the case with newer
+ # "decorator" package, defer back to built in
+ if hasattr(func, "__signature__"):
+ return inspect.getfullargspec(func)
+
if inspect.ismethod(func):
func = func.__func__
if not inspect.isfunction(func):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/dogpile/util/langhelpers.py
new/dogpile.cache-rel_1_1_4/dogpile/util/langhelpers.py
--- old/dogpile.cache-rel_1_1_1/dogpile/util/langhelpers.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/util/langhelpers.py 2021-09-02
16:42:13.000000000 +0200
@@ -149,3 +149,10 @@
# the thread ident and unlock.
del self.keys[current_thread]
self.mutex.release()
+
+ def locked(self):
+ current_thread = threading.get_ident()
+ keys = self.keys.get(current_thread)
+ if keys is None:
+ return False
+ return self.key in keys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/dogpile.cache-rel_1_1_1/dogpile/util/readwrite_lock.py
new/dogpile.cache-rel_1_1_4/dogpile/util/readwrite_lock.py
--- old/dogpile.cache-rel_1_1_1/dogpile/util/readwrite_lock.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/dogpile/util/readwrite_lock.py 2021-09-02
16:42:13.000000000 +0200
@@ -62,10 +62,10 @@
# check if we are the last asynchronous reader thread
# out the door.
if self.async_ == 0:
- # yes. so if a sync operation is waiting, notifyAll to wake
+ # yes. so if a sync operation is waiting, notify_all to wake
# it up
if self.current_sync_operation is not None:
- self.condition.notifyAll()
+ self.condition.notify_all()
elif self.async_ < 0:
raise LockError(
"Synchronizer error - too many "
@@ -95,7 +95,7 @@
# establish ourselves as the current sync
# this indicates to other read/write operations
# that they should wait until this is None again
- self.current_sync_operation = threading.currentThread()
+ self.current_sync_operation = threading.current_thread()
# now wait again for asyncs to finish
if self.async_ > 0:
@@ -117,7 +117,7 @@
"""Release the 'write' lock."""
self.condition.acquire()
try:
- if self.current_sync_operation is not threading.currentThread():
+ if self.current_sync_operation is not threading.current_thread():
raise LockError(
"Synchronizer error - current thread doesn't "
"have the write lock"
@@ -128,7 +128,7 @@
self.current_sync_operation = None
# tell everyone to get ready
- self.condition.notifyAll()
+ self.condition.notify_all()
log.debug("%s released write lock", self)
finally:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/tests/cache/_fixtures.py
new/dogpile.cache-rel_1_1_4/tests/cache/_fixtures.py
--- old/dogpile.cache-rel_1_1_1/tests/cache/_fixtures.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/tests/cache/_fixtures.py 2021-09-02
16:42:13.000000000 +0200
@@ -6,6 +6,7 @@
from threading import Thread
import time
from unittest import TestCase
+import uuid
import pytest
@@ -109,6 +110,21 @@
backend.delete("some_key")
eq_(backend.get_serialized("some_key"), NO_VALUE)
+ def test_region_is_key_locked(self):
+ reg = self._region()
+ random_key = str(uuid.uuid1())
+ assert not reg.get(random_key)
+ eq_(reg.key_is_locked(random_key), False)
+ # ensures that calling key_is_locked doesn't acquire the lock
+ eq_(reg.key_is_locked(random_key), False)
+
+ mutex = reg.backend.get_mutex(random_key)
+ if mutex:
+ mutex.acquire()
+ eq_(reg.key_is_locked(random_key), True)
+ mutex.release()
+ eq_(reg.key_is_locked(random_key), False)
+
def test_region_set_get_value(self):
reg = self._region()
reg.set("some key", "some value")
@@ -229,7 +245,17 @@
@pytest.mark.time_intensive
def test_threaded_get_multi(self):
+ """This test is testing that when we get inside the "creator" for
+ a certain key, there are no other "creators" running at all for
+ that key.
+
+ With "distributed" locks, this is not 100% the case.
+
+ """
reg = self._region(config_args={"expiration_time": 0.25})
+ backend_mutex = reg.backend.get_mutex("some_key")
+ is_custom_mutex = backend_mutex is not None
+
locks = dict((str(i), Lock()) for i in range(11))
canary = collections.defaultdict(list)
@@ -274,8 +300,12 @@
t.join()
assert sum([len(v) for v in canary.values()]) > 10
- for l in canary.values():
- assert False not in l
+
+ # for non-custom mutex, check that we never had two creators
+ # running at once
+ if not is_custom_mutex:
+ for l in canary.values():
+ assert False not in l
def test_region_delete(self):
reg = self._region()
@@ -293,19 +323,24 @@
# with very slow processing missing a timeout, as is often the
# case with this particular test
- reg = self._region(config_args={"expiration_time": 0.75})
+ expire_time = 1.00
+
+ reg = self._region(config_args={"expiration_time": expire_time})
counter = itertools.count(1)
def creator():
return "some value %d" % next(counter)
eq_(reg.get_or_create("some key", creator), "some value 1")
- time.sleep(0.85)
+ time.sleep(expire_time + (0.2 * expire_time))
# expiration is definitely hit
- eq_(reg.get("some key", ignore_expiration=True), "some value 1")
+ post_expiration = reg.get("some key", ignore_expiration=True)
+ if post_expiration is not NO_VALUE:
+ eq_(post_expiration, "some value 1")
+
eq_(reg.get_or_create("some key", creator), "some value 2")
- # this line needs to run less the .75 sec before the previous
+ # this line needs to run less the expire_time sec before the previous
# two or it hits the expiration
eq_(reg.get("some key"), "some value 2")
@@ -387,11 +422,15 @@
backend = self._backend()
mutex = backend.get_mutex("foo")
+ assert not mutex.locked()
ac = mutex.acquire()
assert ac
ac2 = mutex.acquire(False)
+ assert mutex.locked()
assert not ac2
mutex.release()
+ assert not mutex.locked()
+
ac3 = mutex.acquire()
assert ac3
mutex.release()
@@ -470,6 +509,9 @@
def release(self):
return
+ def locked(self):
+ return False
+
class MockBackend(CacheBackend):
def __init__(self, arguments):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/dogpile.cache-rel_1_1_1/tests/cache/test_dbm_backend.py
new/dogpile.cache-rel_1_1_4/tests/cache/test_dbm_backend.py
--- old/dogpile.cache-rel_1_1_1/tests/cache/test_dbm_backend.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/tests/cache/test_dbm_backend.py 2021-09-02
16:42:13.000000000 +0200
@@ -2,6 +2,7 @@
import sys
from dogpile.cache.backends.file import AbstractFileLock
+from dogpile.cache.proxy import ProxyBackend
from dogpile.util.readwrite_lock import ReadWriteMutex
from . import assert_raises_message
from ._fixtures import _GenericBackendTest
@@ -53,6 +54,15 @@
}
+class DBMBackendProxyTest(_GenericBackendTest):
+ backend = "dogpile.cache.dbm"
+
+ config_args = {
+ "arguments": {"filename": test_fname, "lock_factory": MutexLock},
+ "wrap": [ProxyBackend],
+ }
+
+
class DBMBackendSerializerTest(
_GenericSerializerTest, DBMBackendConditionTest
):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/dogpile.cache-rel_1_1_1/tests/cache/test_memcached_backend.py
new/dogpile.cache-rel_1_1_4/tests/cache/test_memcached_backend.py
--- old/dogpile.cache-rel_1_1_1/tests/cache/test_memcached_backend.py
2020-11-23 14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/tests/cache/test_memcached_backend.py
2021-09-02 16:42:13.000000000 +0200
@@ -2,11 +2,13 @@
import ssl
from threading import Thread
import time
+from unittest import mock
from unittest import TestCase
import weakref
import pytest
+from dogpile.cache import make_region
from dogpile.cache.backends.memcached import GenericMemcachedBackend
from dogpile.cache.backends.memcached import MemcachedBackend
from dogpile.cache.backends.memcached import PylibmcBackend
@@ -141,9 +143,6 @@
):
backend = "dogpile.cache.bmemcached"
- def test_threaded_get_multi(self):
- pytest.skip("failing on bmemcached right now")
-
class BMemcachedTLSTest(_NonDistributedTLSMemcachedTest):
backend = "dogpile.cache.bmemcached"
@@ -169,6 +168,65 @@
backend = "dogpile.cache.bmemcached"
+class PyMemcacheTest(_NonDistributedMemcachedTest):
+ backend = "dogpile.cache.pymemcache"
+
+ def test_pymemcache_enable_retry_client_not_set(self):
+ with mock.patch("warnings.warn") as warn_mock:
+ _ = make_region().configure(
+ "dogpile.cache.pymemcache",
+ arguments={"url": "foo", "retry_attempts": 2},
+ )
+ eq_(
+ warn_mock.mock_calls[0],
+ mock.call(
+ "enable_retry_client is not set; retry options "
+ "will be ignored"
+ ),
+ )
+
+
+class PyMemcacheDistributedWithTimeoutTest(
+ _DistributedMemcachedWithTimeoutTest
+):
+ backend = "dogpile.cache.pymemcache"
+
+
+class PyMemcacheTLSTest(_NonDistributedTLSMemcachedTest):
+ backend = "dogpile.cache.pymemcache"
+
+
+class PyMemcacheDistributedTest(_DistributedMemcachedTest):
+ backend = "dogpile.cache.pymemcache"
+
+
+class PyMemcacheDistributedMutexTest(_DistributedMemcachedMutexTest):
+ backend = "dogpile.cache.pymemcache"
+
+
+class PyMemcacheDistributedMutexWithTimeoutTest(
+ _DistributedMemcachedMutexWithTimeoutTest
+):
+ backend = "dogpile.cache.pymemcache"
+
+
+class PyMemcacheSerializerTest(
+ _GenericSerializerTest, _NonDistributedMemcachedTest
+):
+ backend = "dogpile.cache.pymemcache"
+
+
+class PyMemcacheRetryTest(_NonDistributedMemcachedTest):
+ backend = "dogpile.cache.pymemcache"
+ config_args = {
+ "arguments": {
+ "url": MEMCACHED_URL,
+ "enable_retry_client": True,
+ "retry_attempts": 3,
+ }
+ }
+
+
class MemcachedTest(_NonDistributedMemcachedTest):
backend = "dogpile.cache.memcached"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/tests/cache/test_region.py
new/dogpile.cache-rel_1_1_4/tests/cache/test_region.py
--- old/dogpile.cache-rel_1_1_1/tests/cache/test_region.py 2020-11-23
14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/tests/cache/test_region.py 2021-09-02
16:42:13.000000000 +0200
@@ -202,6 +202,11 @@
eq_(reg.get_or_create("some key", creator), "some value")
+ def test_key_is_locked(self):
+ reg = self._region()
+
+ eq_(reg.key_is_locked("some key"), False)
+
def test_multi_creator(self):
reg = self._region()
@@ -752,7 +757,7 @@
class UsedKeysProxy(ProxyBackend):
- """ Keep a counter of hose often we set a particular key"""
+ """Keep a counter of hose often we set a particular key"""
def __init__(self, *args, **kwargs):
super(ProxyBackendTest.UsedKeysProxy, self).__init__(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/dogpile.cache-rel_1_1_1/tox.ini
new/dogpile.cache-rel_1_1_4/tox.ini
--- old/dogpile.cache-rel_1_1_1/tox.ini 2020-11-23 14:51:14.000000000 +0100
+++ new/dogpile.cache-rel_1_1_4/tox.ini 2021-09-02 16:42:13.000000000 +0200
@@ -38,6 +38,7 @@
{memcached}: python-memcached
{memcached}: python-binary-memcached>=0.29.0
{memcached}: pifpaf>=2.5.0
+ {memcached}: pymemcache>=3.5.0
{redis}: redis
{redis}: pifpaf
{redis_sentinel}: redis
@@ -54,9 +55,13 @@
basepython = python3
deps=
mypy
+ types-decorator
+ types-redis
redis
Mako
decorator
+ types-redis
+ types-decorator
commands = mypy ./dogpile/
# thanks to https://julien.danjou.info/the-best-flake8-extensions/
@@ -70,4 +75,7 @@
flake8-rst-docstrings
# used by flake8-rst-docstrings
pygments
-commands = flake8 ./dogpile/ ./tests/ setup.py {posargs}
+ black==21.5b1
+commands =
+ flake8 ./dogpile/ ./tests/ setup.py {posargs}
+ black --check .