New Upstream Release - python-dogpile.cache

Ready changes

Summary

Merged new upstream version: 1.2.2 (was: 1.2.1).

Resulting package

Built on 2023-08-21T09:02 (took 8m6s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases python-dogpile.cache-docapt install -t fresh-releases python3-dogpile.cache

Lintian Result

Diff

diff --git a/LICENSE b/LICENSE
index ff6e570..693219c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright 2005-2022 Michael Bayer.
+Copyright 2005-2023 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 --git a/debian/changelog b/debian/changelog
index ee87ca2..ad80903 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+python-dogpile.cache (1.2.2-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 21 Aug 2023 08:55:03 -0000
+
 python-dogpile.cache (1.1.8-2) unstable; urgency=medium
 
   * Uploading to unstable.
diff --git a/debian/patches/no-intersphinx.patch b/debian/patches/no-intersphinx.patch
index a629092..b1f1c69 100644
--- a/debian/patches/no-intersphinx.patch
+++ b/debian/patches/no-intersphinx.patch
@@ -4,9 +4,11 @@ Author: Thomas Goirand <zigo@debian.org>
 Forwarded: no
 Last-Update: 2020-09-02
 
---- a/docs/build/conf.py	2020-09-02 13:39:55.857891290 +0200
-+++ b/docs/build/conf.py	2020-09-02 13:40:22.081832983 +0200
-@@ -34,7 +34,6 @@
+Index: python-dogpile.cache.git/docs/build/conf.py
+===================================================================
+--- python-dogpile.cache.git.orig/docs/build/conf.py
++++ python-dogpile.cache.git/docs/build/conf.py
+@@ -34,7 +34,6 @@ if True:
  # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
  extensions = [
      "sphinx.ext.autodoc",
diff --git a/debian/patches/remove-non-deterministic-tests.patch b/debian/patches/remove-non-deterministic-tests.patch
index 07cbd42..f2f6df6 100644
--- a/debian/patches/remove-non-deterministic-tests.patch
+++ b/debian/patches/remove-non-deterministic-tests.patch
@@ -5,11 +5,11 @@ Bug-Debian: https://bugs.debian.org/861173
 Forwarded: no
 Last-Update: 2020-03-07
 
-Index: python-dogpile.cache/tests/cache/test_memcached_backend.py
+Index: python-dogpile.cache.git/tests/cache/test_memcached_backend.py
 ===================================================================
---- python-dogpile.cache.orig/tests/cache/test_memcached_backend.py
-+++ python-dogpile.cache/tests/cache/test_memcached_backend.py
-@@ -327,44 +327,3 @@ class MemcachedArgstest(TestCase):
+--- python-dogpile.cache.git.orig/tests/cache/test_memcached_backend.py
++++ python-dogpile.cache.git/tests/cache/test_memcached_backend.py
+@@ -498,44 +498,3 @@ class MemcachedArgstest(TestCase):
          backend.set("foo", "bar")
          eq_(backend._clients.memcached.canary, [{"min_compress_len": 20}])
  
@@ -54,10 +54,10 @@ Index: python-dogpile.cache/tests/cache/test_memcached_backend.py
 -
 -        gc.collect()
 -        eq_(MockClient.number_of_clients(), 0)
-Index: python-dogpile.cache/tests/test_lock.py
+Index: python-dogpile.cache.git/tests/test_lock.py
 ===================================================================
---- python-dogpile.cache.orig/tests/test_lock.py
-+++ python-dogpile.cache/tests/test_lock.py
+--- python-dogpile.cache.git.orig/tests/test_lock.py
++++ python-dogpile.cache.git/tests/test_lock.py
 @@ -24,10 +24,6 @@ class ConcurrencyTest(TestCase):
      def test_quick(self):
          self._test_multi(10, 2, 0.5, 50, 0.05, 0.1)
diff --git a/docs/build/_static/nature_override.css b/docs/build/_static/nature_override.css
index 33c0d05..57798ad 100644
--- a/docs/build/_static/nature_override.css
+++ b/docs/build/_static/nature_override.css
@@ -14,3 +14,11 @@
 	font-style: italic;
 }
 
+div.documentwrapper div.bodywrapper { margin-left: 350px;}
+div.document div.sphinxsidebar { width: 350px; }
+
+div.sphinxsidebarwrapper div {
+    overflow: auto;
+}
+
+
diff --git a/docs/build/changelog.rst b/docs/build/changelog.rst
index 74c1b6d..98b8235 100644
--- a/docs/build/changelog.rst
+++ b/docs/build/changelog.rst
@@ -2,6 +2,45 @@
 Changelog
 =========
 
+.. changelog::
+    :version: 1.2.2
+    :released: Sat Jul 8 2023
+
+    .. change::
+        :tags: bug, typing
+        :tickets: 240
+
+        Made use of pep-673 ``Self`` type for method chained methods such as
+        :meth:`.CacheRegion.configure` and :meth:`.ProxyBackend.wrap`. Pull request
+        courtesy Viicos.
+
+.. changelog::
+    :version: 1.2.1
+    :released: Sat May 20 2023
+
+    .. change::
+        :tags: bug, typing
+        :tickets: 238
+
+        Added py.typed file to root so that typing tools such as Mypy recognize
+        dogpile as typed. Pull request courtesy Daverball.
+
+.. changelog::
+    :version: 1.2.0
+    :released: Wed Apr 26 2023
+
+    .. change::
+        :tags: feature, region
+        :tickets: 236
+
+        Added new construct :class:`.api.CantDeserializeException` which can be
+        raised by user-defined deserializer functions which would be passed to
+        :paramref:`.CacheRegion.deserializer`, to indicate a cache value that can't
+        be deserialized and therefore should be regenerated. This can allow an
+        application that's been updated to gracefully re-cache old items that were
+        persisted from a previous version of the application. Pull request courtesy
+        Simon Hewitt.
+
 .. changelog::
     :version: 1.1.8
     :released: Fri Jul 8 2022
diff --git a/docs/build/conf.py b/docs/build/conf.py
index 4276787..a0580f6 100644
--- a/docs/build/conf.py
+++ b/docs/build/conf.py
@@ -65,7 +65,7 @@ master_doc = "index"
 
 # General information about the project.
 project = "dogpile.cache"
-copyright = "2011-2022 Mike Bayer"
+copyright = "2011-2023 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 @@ copyright = "2011-2022 Mike Bayer"
 # The short X.Y version.
 version = dogpile.__version__
 # The full version, including alpha/beta/rc tags.
-release = "1.1.8"
+release = "1.2.2"
 
 
 # The language for content autogenerated by Sphinx. Refer to documentation
diff --git a/dogpile/__init__.py b/dogpile/__init__.py
index 2367ae0..e4b57bf 100644
--- a/dogpile/__init__.py
+++ b/dogpile/__init__.py
@@ -1,4 +1,4 @@
-__version__ = "1.1.8"
+__version__ = "1.2.2"
 
 from .lock import Lock  # noqa
 from .lock import NeedRegenerationException  # noqa
diff --git a/dogpile/cache/api.py b/dogpile/cache/api.py
index 0717d43..d8436ca 100644
--- a/dogpile/cache/api.py
+++ b/dogpile/cache/api.py
@@ -9,6 +9,8 @@ from typing import Optional
 from typing import Sequence
 from typing import Union
 
+from ..util.typing import Self
+
 
 class NoValue:
     """Describe a missing cache value.
@@ -18,7 +20,7 @@ class NoValue:
     """
 
     @property
-    def payload(self):
+    def payload(self) -> Self:
         return self
 
     def __repr__(self):
@@ -51,6 +53,15 @@ Serializer = Callable[[ValuePayload], bytes]
 Deserializer = Callable[[bytes], ValuePayload]
 
 
+class CantDeserializeException(Exception):
+    """Exception indicating deserialization failed, and that caching
+    should proceed to re-generate a value
+
+    .. versionadded:: 1.2.0
+
+    """
+
+
 class CacheMutex(abc.ABC):
     """Describes a mutexing object with acquire and release methods.
 
@@ -181,7 +192,9 @@ class CacheBackend:
         raise NotImplementedError()
 
     @classmethod
-    def from_config_dict(cls, config_dict, prefix):
+    def from_config_dict(
+        cls, config_dict: Mapping[str, Any], prefix: str
+    ) -> Self:
         prefix_len = len(prefix)
         return cls(
             dict(
diff --git a/dogpile/cache/proxy.py b/dogpile/cache/proxy.py
index bf6e296..cd6120b 100644
--- a/dogpile/cache/proxy.py
+++ b/dogpile/cache/proxy.py
@@ -9,7 +9,6 @@ base backend.
 .. versionadded:: 0.5.0  Added support for the :class:`.ProxyBackend` class.
 
 """
-
 from typing import Mapping
 from typing import Optional
 from typing import Sequence
@@ -20,6 +19,7 @@ from .api import CacheBackend
 from .api import CacheMutex
 from .api import KeyType
 from .api import SerializedReturnType
+from ..util.typing import Self
 
 
 class ProxyBackend(CacheBackend):
@@ -67,7 +67,7 @@ class ProxyBackend(CacheBackend):
     def __init__(self, *arg, **kw):
         pass
 
-    def wrap(self, backend: CacheBackend) -> "ProxyBackend":
+    def wrap(self, backend: CacheBackend) -> Self:
         """Take a backend as an argument and setup the self.proxied property.
         Return an object that be used as a backend by a :class:`.CacheRegion`
         object.
diff --git a/dogpile/cache/region.py b/dogpile/cache/region.py
index ef0dbc4..7952157 100644
--- a/dogpile/cache/region.py
+++ b/dogpile/cache/region.py
@@ -27,6 +27,7 @@ from .api import BackendFormatted
 from .api import CachedValue
 from .api import CacheMutex
 from .api import CacheReturnType
+from .api import CantDeserializeException
 from .api import KeyType
 from .api import MetaDataType
 from .api import NO_VALUE
@@ -45,6 +46,7 @@ from ..util import coerce_string_conf
 from ..util import memoized_property
 from ..util import NameRegistry
 from ..util import PluginLoader
+from ..util.typing import Self
 
 value_version = 2
 """An integer placed in the :class:`.CachedValue`
@@ -328,7 +330,17 @@ class CacheRegion:
      deserializer recommended by the backend will be used.   Typical
      deserializers include ``pickle.dumps`` and ``json.dumps``.
 
-     .. versionadded:: 1.1.0
+     Deserializers can raise a :class:`.api.CantDeserializeException` if they
+     are unable to deserialize the value from the backend, indicating
+     deserialization failed and that caching should proceed to re-generate
+     a value.  This allows an application that has been updated to gracefully
+     re-cache old items which were persisted by a previous version of the
+     application and can no longer be successfully deserialized.
+
+     .. versionadded:: 1.1.0 added "deserializer" parameter
+
+     .. versionadded:: 1.2.0 added support for
+        :class:`.api.CantDeserializeException`
 
     :param async_creation_runner:  A callable that, when specified,
      will be passed to and called by dogpile.lock when
@@ -415,7 +427,7 @@ class CacheRegion:
         wrap: Sequence[Union[ProxyBackend, Type[ProxyBackend]]] = (),
         replace_existing_backend: bool = False,
         region_invalidator: Optional[RegionInvalidationStrategy] = None,
-    ) -> "CacheRegion":
+    ) -> Self:
         """Configure a :class:`.CacheRegion`.
 
         The :class:`.CacheRegion` itself
@@ -1219,8 +1231,12 @@ class CacheRegion:
 
         bytes_metadata, _, bytes_payload = byte_value.partition(b"|")
         metadata = json.loads(bytes_metadata)
-        payload = self.deserializer(bytes_payload)
-        return CachedValue(payload, metadata)
+        try:
+            payload = self.deserializer(bytes_payload)
+        except CantDeserializeException:
+            return NO_VALUE
+        else:
+            return CachedValue(payload, metadata)
 
     def _serialize_cached_value_elements(
         self, payload: ValuePayload, metadata: MetaDataType
@@ -1247,7 +1263,8 @@ class CacheRegion:
         return self._serialize_cached_value_elements(payload, metadata)
 
     def _serialized_cached_value(self, value: CachedValue) -> BackendFormatted:
-        """Return a backend formatted representation of a :class:`.CachedValue`.
+        """Return a backend formatted representation of a
+        :class:`.CachedValue`.
 
         If a serializer is in use then this will return a string representation
         with the value formatted by the serializer.
diff --git a/dogpile/py.typed b/dogpile/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/dogpile/util/typing.py b/dogpile/util/typing.py
new file mode 100644
index 0000000..218c429
--- /dev/null
+++ b/dogpile/util/typing.py
@@ -0,0 +1,6 @@
+import sys
+
+if sys.version_info >= (3, 11):
+    from typing import Self
+else:
+    from typing_extensions import Self  # noqa: F401
diff --git a/setup.cfg b/setup.cfg
index 319c4b9..1818a23 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -24,9 +24,11 @@ project_urls =
 install_requires =
   decorator>=4.0.0
   stevedore>=3.0.0
+  typing_extensions>=4.0.1;python_version<'3.11'
 zip_safe = False
 packages = find:
 python_requires = >=3.6
+include_package_data = True
 package_dir =
     =.
 
@@ -38,6 +40,9 @@ exclude =
 [options.exclude_package_data]
 '' = tests*
 
+[options.package_data]
+* = py.typed
+
 [options.entry_points]
 mako.cache =
     dogpile.cache = dogpile.cache.plugins.mako_cache:MakoPlugin
diff --git a/tests/cache/_fixtures.py b/tests/cache/_fixtures.py
index 9e71f8f..fd4688a 100644
--- a/tests/cache/_fixtures.py
+++ b/tests/cache/_fixtures.py
@@ -14,12 +14,17 @@ from dogpile.cache import CacheRegion
 from dogpile.cache import register_backend
 from dogpile.cache.api import CacheBackend
 from dogpile.cache.api import CacheMutex
+from dogpile.cache.api import CantDeserializeException
 from dogpile.cache.api import NO_VALUE
 from dogpile.cache.region import _backend_loader
 from . import assert_raises_message
 from . import eq_
 
 
+def gen_some_key():
+    return f"some_key_{random.randint(1, 100000)}"
+
+
 class _GenericBackendFixture(object):
     @classmethod
     def setup_class(cls):
@@ -32,12 +37,13 @@ class _GenericBackendFixture(object):
         cls._check_backend_available(backend)
 
     def tearDown(self):
+        some_key = gen_some_key()
         if self._region_inst:
             for key in self._keys:
                 self._region_inst.delete(key)
             self._keys.clear()
         elif self._backend_inst:
-            self._backend_inst.delete("some_key")
+            self._backend_inst.delete(some_key)
 
     @classmethod
     def _check_backend_available(cls, backend):
@@ -93,22 +99,26 @@ class _GenericBackendFixture(object):
 class _GenericBackendTest(_GenericBackendFixture, TestCase):
     def test_backend_get_nothing(self):
         backend = self._backend()
-        eq_(backend.get_serialized("some_key"), NO_VALUE)
+        some_key = gen_some_key()
+        eq_(backend.get_serialized(some_key), NO_VALUE)
 
     def test_backend_delete_nothing(self):
         backend = self._backend()
-        backend.delete("some_key")
+        some_key = gen_some_key()
+        backend.delete(some_key)
 
     def test_backend_set_get_value(self):
         backend = self._backend()
-        backend.set_serialized("some_key", b"some value")
-        eq_(backend.get_serialized("some_key"), b"some value")
+        some_key = gen_some_key()
+        backend.set_serialized(some_key, b"some value")
+        eq_(backend.get_serialized(some_key), b"some value")
 
     def test_backend_delete(self):
         backend = self._backend()
-        backend.set_serialized("some_key", b"some value")
-        backend.delete("some_key")
-        eq_(backend.get_serialized("some_key"), NO_VALUE)
+        some_key = gen_some_key()
+        backend.set_serialized(some_key, b"some value")
+        backend.delete(some_key)
+        eq_(backend.get_serialized(some_key), NO_VALUE)
 
     def test_region_is_key_locked(self):
         reg = self._region()
@@ -127,8 +137,9 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
 
     def test_region_set_get_value(self):
         reg = self._region()
-        reg.set("some key", "some value")
-        eq_(reg.get("some key"), "some value")
+        some_key = gen_some_key()
+        reg.set(some_key, "some value")
+        eq_(reg.get(some_key), "some value")
 
     def test_region_set_multiple_values(self):
         reg = self._region()
@@ -201,8 +212,9 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
 
     def test_region_set_get_nothing(self):
         reg = self._region()
-        reg.delete_multi(["some key"])
-        eq_(reg.get("some key"), NO_VALUE)
+        some_key = gen_some_key()
+        reg.delete_multi([some_key])
+        eq_(reg.get(some_key), NO_VALUE)
 
     def test_region_creator(self):
         reg = self._region()
@@ -210,7 +222,8 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
         def creator():
             return "some value"
 
-        eq_(reg.get_or_create("some key", creator), "some value")
+        some_key = gen_some_key()
+        eq_(reg.get_or_create(some_key, creator), "some value")
 
     @pytest.mark.time_intensive
     def test_threaded_dogpile(self):
@@ -220,6 +233,7 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
         reg = self._region(config_args={"expiration_time": 0.25})
         lock = Lock()
         canary = []
+        some_key = gen_some_key()
 
         def creator():
             ack = lock.acquire(False)
@@ -231,7 +245,7 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
 
         def f():
             for x in range(5):
-                reg.get_or_create("some key", creator)
+                reg.get_or_create(some_key, creator)
                 time.sleep(0.5)
 
         threads = [Thread(target=f) for i in range(10)]
@@ -252,8 +266,9 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
         With "distributed" locks, this is not 100% the case.
 
         """
+        some_key = gen_some_key()
         reg = self._region(config_args={"expiration_time": 0.25})
-        backend_mutex = reg.backend.get_mutex("some_key")
+        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))
@@ -309,10 +324,11 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
 
     def test_region_delete(self):
         reg = self._region()
-        reg.set("some key", "some value")
-        reg.delete("some key")
-        reg.delete("some key")
-        eq_(reg.get("some key"), NO_VALUE)
+        some_key = gen_some_key()
+        reg.set(some_key, "some value")
+        reg.delete(some_key)
+        reg.delete(some_key)
+        eq_(reg.get(some_key), NO_VALUE)
 
     @pytest.mark.time_intensive
     def test_region_expire(self):
@@ -323,6 +339,7 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
         # with very slow processing missing a timeout, as is often the
         # case with this particular test
 
+        some_key = gen_some_key()
         expire_time = 1.00
 
         reg = self._region(config_args={"expiration_time": expire_time})
@@ -331,18 +348,18 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
         def creator():
             return "some value %d" % next(counter)
 
-        eq_(reg.get_or_create("some key", creator), "some value 1")
+        eq_(reg.get_or_create(some_key, creator), "some value 1")
         time.sleep(expire_time + (0.2 * expire_time))
         # expiration is definitely hit
-        post_expiration = reg.get("some key", ignore_expiration=True)
+        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")
+        eq_(reg.get_or_create(some_key, creator), "some value 2")
 
         # 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")
+        eq_(reg.get(some_key), "some value 2")
 
     def test_decorated_fn_functionality(self):
         # test for any quirks in the fn decoration that interact
@@ -370,16 +387,21 @@ class _GenericBackendTest(_GenericBackendFixture, TestCase):
         eq_(my_function(4, 3), 11)
 
     def test_exploding_value_fn(self):
+        some_key = gen_some_key()
         reg = self._region()
 
         def boom():
             raise Exception("boom")
 
         assert_raises_message(
-            Exception, "boom", reg.get_or_create, "some_key", boom
+            Exception, "boom", reg.get_or_create, some_key, boom
         )
 
 
+def raise_cant_deserialize_exception(v):
+    raise CantDeserializeException()
+
+
 class _GenericSerializerTest(TestCase):
     # Inheriting from this class will make test cases
     # use these serialization arguments
@@ -388,6 +410,19 @@ class _GenericSerializerTest(TestCase):
         "deserializer": json.loads,
     }
 
+    def test_serializer_cant_deserialize(self):
+        region = self._region(
+            region_args={
+                "serializer": self.region_args["serializer"],
+                "deserializer": raise_cant_deserialize_exception,
+            }
+        )
+
+        value = {"foo": ["bar", 1, False, None]}
+        region.set("k", value)
+        asserted = region.get("k")
+        eq_(asserted, NO_VALUE)
+
     def test_uses_serializer(self):
         region = self._region()
 

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.2.2.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.2.2.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.2.2.egg-info/entry_points.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.2.2.egg-info/not-zip-safe
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.2.2.egg-info/requires.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.2.2.egg-info/top_level.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile/py.typed
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile/util/typing.py
lrwxrwxrwx  root/root   /usr/share/doc/python-dogpile.cache-doc/html/_static/_sphinx_javascript_frameworks_compat.js -> ../../../../javascript/sphinxdoc/1.0/_sphinx_javascript_frameworks_compat.js
lrwxrwxrwx  root/root   /usr/share/doc/python-dogpile.cache-doc/html/_static/sphinx_highlight.js -> ../../../../javascript/sphinxdoc/1.0/sphinx_highlight.js

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.1.8.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.1.8.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.1.8.egg-info/entry_points.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.1.8.egg-info/not-zip-safe
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.1.8.egg-info/requires.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dogpile.cache-1.1.8.egg-info/top_level.txt

Control files of package python-dogpile.cache-doc: lines which differ (wdiff format)

  • Depends: libjs-sphinxdoc (>= 4.3) 5.2)

Control files of package python3-dogpile.cache: lines which differ (wdiff format)

  • Depends: python3-decorator, python3-mako, python3-stevedore, python3-typing-extensions | python3-supported-min (>> 3.11), python3:any

More details

Full run details