Cache Keys
Cache keys for the @cache_results decorator.
A cache key must be the same every time for equal arguments, in every process, and different for different ones. This module turns a decorated function and its arguments into such a key:
normalize()converts arguments into JSON-ready values. Dicts and lists stay JSON objects and arrays, sets are sorted and tagged, classes and dataclasses are tagged with their qualified names.CacheKeyEncoderserializes the values that JSON doesn’t know, such as datetimes, Decimals and UUIDs, and refuses everything else.str()of an arbitrary object is not a safe key: two model rows with the same name would share one entry, and<Foo object at 0x...>changes in every process.make_key()hashes the result into a key that names the function.
This module depends only on Django and the standard library. Projects add
types by subclassing CacheKeyEncoder and naming the subclass in the
KEY_ENCODER entry of the CACHE_RESULTS setting (see
cache_results.conf).
- exception cache_results.keys.CacheKeyArgumentError[source]
Bases:
TypeErrorAn argument of a cached function can’t be part of a cache key.
- class cache_results.keys.CacheKeyEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)[source]
Bases:
DjangoJSONEncoderStrict JSON encoder for cache keys.
It encodes what
django.core.serializers.json.DjangoJSONEncoderknows (datetimes, dates, times, timedeltas, Decimals, UUIDs and lazy translation strings). Any other object raisesCacheKeyArgumentError, so that the call runs uncached rather than be cached under an unsafe key. (Sets, classes and dataclasses never reach the encoder:normalize()has already converted them.)To support another type, subclass it and override
default(), then name the subclass inCACHE_RESULTS["KEY_ENCODER"]:class MyCacheKeyEncoder(CacheKeyEncoder): def default(self, o): if isinstance(o, Money): return {"__money__": [str(o.amount), o.currency]} return super().default(o)
- default(o)[source]
Encode one value that JSON doesn’t know.
- Parameters:
o (object) – The value.
- Returns:
A JSON-serializable representation of
o.- Return type:
- Raises:
CacheKeyArgumentError – If
ohas no safe representation.
- cache_results.keys.bind_arguments(func: Callable, args: tuple, kwargs: dict) tuple[tuple, dict][source]
Bind arguments to the function’s signature, with its defaults applied.
f(1, b=2),f(a=1, b=2)andf(1)(whenbdefaults to 2) then produce the same key. Otherwise a function and itsinvalidate()could silently compute different keys depending on how each was called.
- cache_results.keys.describe_key_error(error: Exception) str[source]
Return a short description of why a key couldn’t be made, without argument values.
- Parameters:
error (Exception) – The exception that
make_key()raised.- Returns:
The description.
- Return type:
- cache_results.keys.dumps(obj: object, encoder: type[CacheKeyEncoder] = <class 'cache_results.keys.CacheKeyEncoder'>) str[source]
Serialize a normalized value into compact, canonical JSON text.
- Parameters:
obj (object) – A value returned by
normalize().encoder (type[CacheKeyEncoder]) – The JSON encoder.
- Returns:
The JSON text, with sorted keys.
- Return type:
- Raises:
CacheKeyArgumentError – If a value can’t be part of a key.
- cache_results.keys.make_key(func: Callable, args: tuple, kwargs: dict, encoder: type[CacheKeyEncoder] = <class 'cache_results.keys.CacheKeyEncoder'>, prefix: str = '') str[source]
Return the cache key of one call of a decorated function.
The key is the prefix, the function’s module and qualified name, and a 32-character SHA-256 hash of its bound, normalized and serialized arguments, e.g.
myapp.views.lookup()_3f0c....- Parameters:
func (Callable) – The decorated function.
args (tuple) – The positional arguments.
kwargs (dict) – The keyword arguments.
encoder (type[CacheKeyEncoder]) – The JSON encoder for the arguments.
prefix (str) – Text that starts every key, e.g. to version them.
- Returns:
The cache key.
- Return type:
- Raises:
CacheKeyArgumentError – If an argument can’t be part of a key.
ValueError – If an argument contains a circular reference, or a value that the encoder refuses, such as a timezone-aware time.
RecursionError – If an argument is nested too deeply.
- cache_results.keys.normalize(obj: object, encoder: type[CacheKeyEncoder] = <class 'cache_results.keys.CacheKeyEncoder'>) object[source]
Convert an argument into a JSON-ready value that is the same for equal arguments.
Dicts and lists are kept as JSON objects and arrays, so that
{"a": 1}and[("a", 1)]don’t share a key. Sets are sorted by the JSON text of their members, because their iteration order changes from one process to the next, and tagged, so that they don’t share a key with a list. A class, e.g. theclsof a classmethod, is identified by its module and qualified name. A dataclass instance is identified by its class and its fields, so that frozen value objects can be arguments.- Parameters:
obj (object) – An argument of the decorated function.
encoder (type[CacheKeyEncoder]) – The JSON encoder, used to sort set members.
- Returns:
The normalized value.
- Return type:
- Raises:
CacheKeyArgumentError – If a set member can’t be part of a key.