Skip to content

alviezhang/zcache

Repository files navigation

ZCache

This project is a community version of Tache.

THIS PROJECT IS STILL WIP, PLEASE DON'T USE

ZCache is a caching framework for Python. It is designed with the following goals in mind:

  • Support for Python 3.7+
  • Support for caching common functions/instance methods/class methods/static methods
  • Support for Batch Batch Caching
  • Support for Tag-based caching and invalidation
  • Support for explicitly declaring key formats based on parameters

Github Repo

Features

  • Cache null by default to prevent penetration
  • Tag-based batch cache invalidation
  • Batch caching
  • Support YAML, JSON, PICKLE multiple backend serializer

Documention

Getting Started

Basic usage

import random
import fakeredis
from zcache import RedisCache

redis_client = fakeredis.FakeStrictRedis()
cache = RedisCache(conn=redis_client, format="JSON")

@cache.cached()
def add(a, b):
    return a + b + random.randint(1,100)

result1 = add(5, 6)
# Cache value is not changed
assert add(5, 6) == result1
# Invalidate cached value
add.invalidate(5, 6)
assert add(5, 6) != result1

Tag-based batch cache invalidation

The tag can be fixed or dynamic, where the dynamic parameter represents the position of the argument in the function.

When a tag is invalidated, it means that all cache with the same tag under this function are all invalidated.

@cache.cached(tags=["a:{0}"])
def add(a, b):
    return a + b + random.randint(1,100)

result1 = add(5, 6)
result2 = add(5, 7)
add.invalidate_tag("a:5")
assert result1 != add(5, 6)
assert result2 != add(5, 7)

Refresh cache

When refresh is called, the cache is refreshed and the latest value is returned.

class A(object):

    def __init__(self):
        self.extra = 0

    @cache.cached()
    def add(self, a, b):
        self.extra += 1
        return a + b + self.extra

a = A()
assert a.add(5, 6) == 12
assert a.extra == 1
assert a.add.refresh(5, 6) == 13
assert a.extra == 2

Batch cache mode

@cache.batch()
def get_comments(*comment_ids):
    return [get_comment(c) for c in comment_ids]

get_comments(1,2,3,4,5) # no cache
get_comments(2,3,4,5,6) # get 2,3,4,5 from cache, call 6 first then cache
get_comments.invalidate(3,4,5) # invalidate 3,4,5

Explicitly Specify Keys

ZCache allows you to explicitly specify rules for cache keys, so that the generated keys will remain unchanged regardless of code refactoring.

class B:

    def __init__(self):
        self.count = 0

    @cache.cached("counter.B.add|{0}-{1}")
    def add(self, a, b):
        self.count += 1
        return a + b + self.count

Note

We support classmethod/staticmethod keywords, but you must put classmethod inner when use it.

class AC(object):

    @cache.cached()
    @classmethod
    def add(cls, a, b):
        return a + b + random.randint(1,100)

We also support namespaces. The default rule for key generation is namespace:module.classname.func|arg1-arg2|tag1-tag2, where namespace is empty, and classname is also empty if it does not exist.

class A(object):
    @cache.cache(namespace="v1")
    def add(self, a, b):
        return db.execute(sql).fetchone()

In this example, if the database fields change, the namespace can be modified in such a way that the old and new code use different cached results.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages