Migrating from diskcache 5.6.3

Replace the dependency and the imports. Cache directories need no changes:

$ pip install diskcache-community
import diskcache_community as diskcache       # was: import diskcache
from diskcache_community import Cache          # was: from diskcache import Cache

diskcache-community keeps the public API of diskcache 5.6.3, the cache.db schema, the file layout, the serialization modes, the persisted settings and the memoize key format. A directory written by 5.6.3 opens with the fork, and a directory written by the fork opens with 5.6.3. The fork needs Python 3.10 or later and has no runtime dependencies.

Steps

  1. Change the dependency. Replace diskcache with diskcache-community in pyproject.toml, requirements.txt or wherever the project declares it:

    dependencies = [
        "diskcache-community>=5.8",
    ]
    
  2. Change every import. The package is imported as diskcache_community. Find the imports with:

    $ grep -rn "diskcache" --include="*.py" .
    

    Change the imports of exceptions and warnings as well as the containers. When the upstream package stays installed, except diskcache.Timeout does not catch the Timeout that a diskcache_community cache raises, because the two packages define separate classes. The same goes for Disk subclasses: base them on diskcache_community.Disk or diskcache_community.JSONDisk.

  3. Change the Django settings. Name the backend 'diskcache_community.DjangoCache'. A DISK option names 'diskcache_community.SafeDisk' or the import path of your own disk class:

    CACHES = {
        'default': {
            'BACKEND': 'diskcache_community.DjangoCache',
            'LOCATION': '/var/tmp/django_cache',
            'SHARDS': 8,
        }
    }
    
  4. Run the tests. Existing cache directories open as they are, so a test suite or a staging environment that uses a cache written by 5.6.3 is a good check.

When another dependency still needs diskcache

The fork never touches the upstream diskcache package, so both can be installed in the same environment. Each library uses the package it imports, and the objects of one are not instances of the other’s classes: pass diskcache_community caches only to code that imports diskcache_community, and catch the exceptions of the package that created the cache.

A library that wants to work with either package can import whichever is installed:

try:
    import diskcache_community as diskcache
except ImportError:
    import diskcache

Scanners keep reporting CVE-2025-69872 while the upstream package is installed. Run pip show diskcache to see whether it is, and, with pipdeptree installed, pipdeptree -r -p diskcache to see which dependency requires it.

What behaves differently

These changes from 5.6.3 can be noticed by an application. The CHANGELOG.md in the repository lists every change.

  • New directories are created with mode 0700. That includes missing parent directories and the value subdirectories. Existing directories keep their permissions. If several users share a cache directory, create it with the permissions you want before the first cache opens it.

  • Read-only caches. A cache whose database or directory is not writable opens read-only instead of failing, as does Cache(directory, read_only=True). Reads work and every write raises ReadOnlyError, a subclass of sqlite3.OperationalError. Opening an existing cache writes nothing unless a setting differs from the stored one.

  • SQLite builds compiled with SQLITE_DQS=0 work. On the first open with write access, the fork rewrites the Settings triggers of an older cache to use single-quoted literals. 5.6.3 reads the rewritten triggers as well.

  • Memoize and ignored parameters. A parameter named in ignore is now ignored whether it is passed by keyword or by position. Calls that passed an ignored parameter by position get a new key, so their first call after the upgrade is a miss. All other keys are unchanged.

  • Connections and fork. The SQLite connections of threads that have exited are closed by close and when the cache is garbage collected. A child process created with fork() opens new connections instead of using the parent’s.

  • FanoutCache. hasattr works on a FanoutCache, and get and pop return the documented tuple when a shard times out.

  • Default disk. The disk arguments default to None, which means the type default_disk returns. That is Disk, as before, unless the process sets DISKCACHE_DISK or calls configure.

The fork also adds features that change nothing until you use them: SafeDisk for caches that untrusted users can write to, store_time=True on get, iterkeys(tag=...) and Disk.with_options for entries that cannot be read. To close CVE-2025-69872 after migrating, see Fix CVE-2025-69872 in diskcache.

Going back

Install diskcache==5.6.3 and change the imports back. Cache directories written by the fork open with 5.6.3, including entries written through SafeDisk, which are ordinary pickles. A disk class of your own needs an equivalent subclass of diskcache.Disk.