Keys

Why Key classes?

The advantage of making cache keys first class objects:

  1. Encapsulate all the logic for calculating the key in one place

  2. Allow for typechecking return values from the cache

  3. Make it possible to control compression, namespacing, etc in one place

A note on “key paths”

Pyappcache is designed around the idea of “key paths” that are predictable and similar to unix paths, such as users/54/likes, which might store user number 54’s likes. Predictable key paths aid debugging - you can always guess where to look when using the cache separately from pyappcache.

Pyappcache caches will also prefix key paths with some custom key path, to allow multiple different uses of the same cache without each clobbering the other’s namespace.

How to create your own key classes

Three different ways, from most straightforward to most complex.

Option 1: Simple string keys

If you just want to use a string as your key, you can use SimpleStringKey directly.

class pyappcache.keys.SimpleStringKey(key_str)

A simple, string-based Key.

__init__(key_str)

Create a key based on a string

from pyappcache.keys import SimpleStringKey

death_star_location = SimpleStringKey("death-star-location")
cache.set(death_star_location, "near alderaan")

... # later...
where_is_it_now = cache.get(death_star_location)

Option 2: Subclasses of BaseKey

If you want to have something more complicated, you can often get started by subclassing BaseKey.

class pyappcache.keys.BaseKey(*args, **kwds)

An abstract baseclass suitable (but not required) for subclassing to create many class:~Key instances.

To use, subclass and override cache_key_segments(). To get progressively more functionality, you can also override namespace_key() and should_compress().

abstract cache_key_segments()

Return segments of the whole key path. For example [“a”, “b”, “c”] - the key segments will be prepended with the Cache’s own prefix and then joined with slashes, similar to unix paths.

Return type:

Sequence[str]

This abstract base class is designed to make it quick as possible to create a new key class - just override cache_key_segments and you’re ready to go.

from pyappcache.keys import BaseKey
from some_orm_layer import BigORMObj

class BigORMObjKey(BaseKey):
    def __init__(self, big_orm_obj):
        self.big_orm_obj = big_orm_obj

    def cache_key_segments(self):
        return str(big_orm_obj.id)

Option 3: Create your own Keys from scratch

If you want full flexibilty you need only define three special methods to allow any object to act as a Key.

class pyappcache.keys.Key(*args, **kwds)

The “protocol” for keys. Define the same methods as this class, and you have created a key which will work with pyappcache.

namespace_key()

If this is a namespaced key, this method returns the key to the namespace that should be used - otherwise None.

Return type:

Optional[Key[Any]]

should_compress(python_obj, as_bytes)

This method passes the original Python object and the serialised bytes version of it in order to allow this method to decide whether compression should be used.

This allows for this method to take Python level attributes/methods and the size of the bytestring into account when making a decision.

Returns True if compression should be applied, False if not.

Return type:

bool

cache_key_segments()

Return segments of the whole key path. For example [“a”, “b”, “c”] - the key segments will be prepended with the Cache’s own prefix and then joined with slashes, similar to unix paths.

Return type:

Sequence[str]