Skip to content

v5.8.2

Choose a tag to compare

@github-actions github-actions released this 02 Nov 22:33
· 12 commits to master since this release
897fa65

Adds SafeJSONDisk and SafeDisk.with_numpy(), keeps float NaN values, and makes get and set faster. The cache.db schema and the file layout are unchanged.

Security

  • SafeJSONDisk stores JSON like JSONDisk, reads and writes the same files, and never reads a pickle. JSONDisk writes only JSON but inherits the pickle reads of Disk, so a crafted row still ran code and a crafted path could still delete a file outside the cache. SafeJSONDisk refuses pickled keys and values without parsing them and confines paths as SafeDisk does (PR #33).

  • SafeDisk.with_numpy() returns a SafeDisk subclass that stores numpy arrays in the .npy format instead of pickling them, through pickle's persistent IDs, anywhere in a value including inside classes allowed with with_types, which combines with it in either order, as with_options does. numpy scalars read back as the same type. Reading a large array takes no second copy of it. Headers are checked against the data, so forged arrays are refused rather than raising MemoryError, and every forged entry raises UnpicklingError or reads as a miss with on_error='miss'. Object arrays, ndarray subclasses and arrays the reader would refuse raise TypeError at write time. Entries holding numpy data can't be read by other disks, including a plain SafeDisk, or by 5.6.3, which raise UnpicklingError. numpy stays optional, and SafeDisk without with_numpy() still refuses it; its with_types error now points to with_numpy() (PR #34).

  • DISKCACHE_SAFE_TYPES and DISKCACHE_SAFE_MODULES now apply when DISKCACHE_DISK names a SafeDisk subclass, not only with safe (PR #34).

Fixes

  • Cache.get is as fast on a hit as in 5.6.3 again; since 5.7.0 it was about 5% slower (PR #35).
  • A float NaN stored as a value is kept, on every disk. It was written to SQLite, which stores NaN as NULL, so it read back as None. It is now stored as a pickle, which 5.6.3 reads too (PR #34).
  • memoize_stampede works with SafeDisk: the key of its early recomputation marker held the internal ENOVAL constant, which SafeDisk refuses, so a call raised TypeError once a cached value neared expiry (PR #32).

Performance

  • Cache.get is about 15% faster on a hit and 12% on a miss, and DjangoCache.get about 16%: a plain lookup reads only the value columns, on a cursor reused per thread (PR #38).
  • Cache.set is about 15% faster, and DjangoCache.set about 17%: each write runs fewer SQL statements and less Python (PR #37).

Packaging

  • The package installs on Python 3.8 and later (PR #36).