# Caches
A Python caching library that gives a similar interface to standard Python data structures like Dict and Set but is backed by [Redis](https://redis.io).
Caches has been used in production for years across many different products, handling millions of requests.
## How to use
Caches relies on setting the environment variable `CACHES_DSN`:
redis://localhost/0
If you want to cache things using more than one Redis server, you can actually set multiple environment variables and specify the `caches.interface.Redis` class you want to use:
# redis1 uses the standard Redis interface
export CACHES_DSN_1=redis://somedomain.com/0#redis1
# redis2 uses a custom interface child class
export CACHES_DSN_2=custom.interface.Redis://someotherdomain.com/0#redis2
After you've set the environment variable, then you just need to import caches in your code:
```python
import caches
```
Caches will take care of parsing the and DSN urls and creating the associated Redis connections automatically, so after importing, Caches will be ready to use.
### Interface
All Caches caching classes have a similar interface, their constructor takes a key and data:
```python
c = Cache(['foo', 'bar', 'che'])
print c.key # foo.bar.che
```
If you would like to init your cache object with a value, use the `data` `**kwarg`:
```python
c = Cache('foo', data="boom!")
print c.key # foo
print c # "boom!"
```
Each Caches base caching class is meant to be extended so you can set some parameters:
* **serialize** -- boolean -- True if you want all values pickled, False if you don't (ie, you're caching ints or strings or something).
* **prefix** -- string -- This will be prepended to the key args you pass into the constructor.
* **ttl** -- integer -- time to live, how many seconds to cache the value. 0 (default) means cache forever.
* **connection_name** -- string -- if you have more than one caches DSN then you can use this to set the name of the connection you want (the name of the connection is the `#connection_name` fragment of a DSN url).
```python
class MyIntCache(Cache):
serialize = False # don't bother to serialize values since we're storing ints
prefix = "MyIntCache" # every key will have this prefix, change to invalidate all currently cached values
ttl = 7200 # store each int for 2 hours
```
### Cache Classes
#### Cache
This is the traditional caching object, it sets a value into a key:
```python
c = Cache('foo')
c.data = 5 # cache 5
c += 10 # increment 5 by 10, store 15 in the cache
c.clear()
print(c) # None
```
#### DictCache
This caching object acts more or less like a Python [dictionary](http://docs.python.org/3/library/stdtypes.html#mapping-types-dict):
```python
c = DictCache('foo')
c['bar'] = 'b'
c['che'] = 'c'
for key, val in c.items():
print(key, val) # will print "bar b" and then "che c"
```
#### SetCache
This caching object acts more or less like a Python [set](http://docs.python.org/2/library/stdtypes.html#set):
```python
c = SetCache('foo')
c.add('bar')
c.add('che')
print('che' in c) # True
```
#### SortedSetCache
This caching object acts more or less like a Python [set](http://docs.python.org/2/library/stdtypes.html#set) but has some changes:
* The `add()` method takes a tuple `(score, elem)`
* The `pop()` method will pop off the lowest score from the set, and pops a tuple `(score, elem)`
* An `rpop()` method allows you to pop the highest score from the set.
* Iterating through the set results in tuples of `(score, elem)`, not just elem like in a normal set or the `SetCache`.
```python
c = SortedSetCache('foo')
c.add((1, 'bar'))
c.add((10, 'che'))
print('che' in c) # True
print(c.pop()) # (1, bar)
```
#### SentinelCache
Handy for gated access:
```python
c = SentinelCache('foo')
if not c:
print("sentinel value isn't set so do this")
if not c:
print("sentinel value is now set so this will never run")
```
### Decorator
Caches exposes a decorator to make caching the return value of a function easy. This only works for `Cache` derived caching.
The `cached` decorator can accept a caching class and also a key function (similar to the python [built-in `sorted()` function](http://docs.python.org/2/library/functions.html#sorted) key argument), except caches key argument returns a list that can be passed to the constructor of the caching class as `*args`.
```python
import functools
from caches import Cache
@Cache.cached(key="some_cache_key")
def foo(*args):
return functools.reduce(lambda x, y: x+y, args)
foo(1, 2) # will compute the value and cache the return value
foo(1, 2) # return value from cache
foo(1, 2, 3) # uh-oh, wrong value, our key was too static
```
Let's try again, this time with a dynamic key
```python
@Cache.cached(key=lambda *args: args)
def foo(*args):
return functools.reduce(lambda x, y: x+y, args)
foo(1, 2) # compute and cache, key func returned [1, 2]
foo(1, 2) # grabbed from cache
foo(1, 2, 3) # compute and cache because our key func returned [1, 2, 3]
```
What about custom caches classes?
```python
class CustomCache(Cache): pass
@CustomCache.cached(key=lambda *args: args)
def foo(*args):
return functools.reduce(lambda x, y: x+y, args)
```
## Install
Use pip from pypi:
pip install caches
or from source using pip:
pip install -U "git+https://github.com/jaymon/caches#egg=caches"
Raw data
{
"_id": null,
"home_page": "http://github.com/jaymon/caches",
"name": "caches",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "",
"author": "Jay Marcyes",
"author_email": "jay@marcyes.com",
"download_url": "https://files.pythonhosted.org/packages/fb/f5/1c64afd453f69396ecbb64e838659bd61dc1cc064c52c372737426a952c0/caches-3.0.0.tar.gz",
"platform": null,
"description": "# Caches\n\nA Python caching library that gives a similar interface to standard Python data structures like Dict and Set but is backed by [Redis](https://redis.io).\n\nCaches has been used in production for years across many different products, handling millions of requests.\n\n\n## How to use\n\nCaches relies on setting the environment variable `CACHES_DSN`:\n\n redis://localhost/0\n\nIf you want to cache things using more than one Redis server, you can actually set multiple environment variables and specify the `caches.interface.Redis` class you want to use:\n\n # redis1 uses the standard Redis interface\n export CACHES_DSN_1=redis://somedomain.com/0#redis1\n \n # redis2 uses a custom interface child class\n export CACHES_DSN_2=custom.interface.Redis://someotherdomain.com/0#redis2\n\nAfter you've set the environment variable, then you just need to import caches in your code:\n\n```python\nimport caches\n```\n\nCaches will take care of parsing the and DSN urls and creating the associated Redis connections automatically, so after importing, Caches will be ready to use.\n\n\n### Interface\n\nAll Caches caching classes have a similar interface, their constructor takes a key and data:\n\n```python\nc = Cache(['foo', 'bar', 'che'])\nprint c.key # foo.bar.che\n```\n\nIf you would like to init your cache object with a value, use the `data` `**kwarg`:\n\n```python\nc = Cache('foo', data=\"boom!\")\nprint c.key # foo\nprint c # \"boom!\"\n```\n\nEach Caches base caching class is meant to be extended so you can set some parameters:\n\n* **serialize** -- boolean -- True if you want all values pickled, False if you don't (ie, you're caching ints or strings or something).\n\n* **prefix** -- string -- This will be prepended to the key args you pass into the constructor.\n\n* **ttl** -- integer -- time to live, how many seconds to cache the value. 0 (default) means cache forever.\n\n* **connection_name** -- string -- if you have more than one caches DSN then you can use this to set the name of the connection you want (the name of the connection is the `#connection_name` fragment of a DSN url).\n\n```python\nclass MyIntCache(Cache):\n serialize = False # don't bother to serialize values since we're storing ints\n prefix = \"MyIntCache\" # every key will have this prefix, change to invalidate all currently cached values\n ttl = 7200 # store each int for 2 hours\n```\n\n### Cache Classes\n\n\n#### Cache\n\nThis is the traditional caching object, it sets a value into a key:\n\n```python\nc = Cache('foo')\nc.data = 5 # cache 5\nc += 10 # increment 5 by 10, store 15 in the cache\n\nc.clear()\nprint(c) # None\n```\n\n\n#### DictCache\n\nThis caching object acts more or less like a Python [dictionary](http://docs.python.org/3/library/stdtypes.html#mapping-types-dict):\n\n```python\nc = DictCache('foo')\nc['bar'] = 'b'\nc['che'] = 'c'\nfor key, val in c.items():\n print(key, val) # will print \"bar b\" and then \"che c\"\n```\n\n\n#### SetCache\n\nThis caching object acts more or less like a Python [set](http://docs.python.org/2/library/stdtypes.html#set):\n\n```python\nc = SetCache('foo')\nc.add('bar')\nc.add('che')\nprint('che' in c) # True\n```\n\n\n#### SortedSetCache\n\nThis caching object acts more or less like a Python [set](http://docs.python.org/2/library/stdtypes.html#set) but has some changes:\n\n* The `add()` method takes a tuple `(score, elem)`\n* The `pop()` method will pop off the lowest score from the set, and pops a tuple `(score, elem)`\n* An `rpop()` method allows you to pop the highest score from the set.\n* Iterating through the set results in tuples of `(score, elem)`, not just elem like in a normal set or the `SetCache`.\n\n```python\nc = SortedSetCache('foo')\nc.add((1, 'bar'))\nc.add((10, 'che'))\nprint('che' in c) # True\nprint(c.pop()) # (1, bar)\n```\n\n\n#### SentinelCache\n\nHandy for gated access:\n\n```python\nc = SentinelCache('foo')\n\nif not c:\n print(\"sentinel value isn't set so do this\")\n\nif not c:\n print(\"sentinel value is now set so this will never run\")\n```\n\n\n### Decorator\n\nCaches exposes a decorator to make caching the return value of a function easy. This only works for `Cache` derived caching.\n\nThe `cached` decorator can accept a caching class and also a key function (similar to the python [built-in `sorted()` function](http://docs.python.org/2/library/functions.html#sorted) key argument), except caches key argument returns a list that can be passed to the constructor of the caching class as `*args`.\n\n```python\nimport functools\nfrom caches import Cache\n\n@Cache.cached(key=\"some_cache_key\")\ndef foo(*args):\n return functools.reduce(lambda x, y: x+y, args)\n\nfoo(1, 2) # will compute the value and cache the return value\nfoo(1, 2) # return value from cache\n\nfoo(1, 2, 3) # uh-oh, wrong value, our key was too static\n```\n\nLet's try again, this time with a dynamic key\n\n```python\n@Cache.cached(key=lambda *args: args)\ndef foo(*args):\n return functools.reduce(lambda x, y: x+y, args)\n\nfoo(1, 2) # compute and cache, key func returned [1, 2]\nfoo(1, 2) # grabbed from cache\nfoo(1, 2, 3) # compute and cache because our key func returned [1, 2, 3]\n```\n\nWhat about custom caches classes?\n\n```python\nclass CustomCache(Cache): pass\n\n@CustomCache.cached(key=lambda *args: args)\ndef foo(*args):\n return functools.reduce(lambda x, y: x+y, args)\n```\n\n\n## Install\n\nUse pip from pypi:\n\n pip install caches\n\nor from source using pip:\n\n pip install -U \"git+https://github.com/jaymon/caches#egg=caches\"\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python caching backed by Redis",
"version": "3.0.0",
"project_urls": {
"Homepage": "http://github.com/jaymon/caches"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "fbf51c64afd453f69396ecbb64e838659bd61dc1cc064c52c372737426a952c0",
"md5": "d73e14eb8766e6d8f149b00e2128155c",
"sha256": "060b29ed769789497a7c3e58ca4e0eafca0240eeb77a73a3b8544cbf1358b593"
},
"downloads": -1,
"filename": "caches-3.0.0.tar.gz",
"has_sig": false,
"md5_digest": "d73e14eb8766e6d8f149b00e2128155c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 20169,
"upload_time": "2023-07-12T20:33:55",
"upload_time_iso_8601": "2023-07-12T20:33:55.848956Z",
"url": "https://files.pythonhosted.org/packages/fb/f5/1c64afd453f69396ecbb64e838659bd61dc1cc064c52c372737426a952c0/caches-3.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-07-12 20:33:55",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "jaymon",
"github_project": "caches",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "caches"
}