https://github.com/festinuz/gecaso
Generalized Caching Solution
https://github.com/festinuz/gecaso
cache cache-storage python-3-5 python-3-6 python3
Last synced: 3 months ago
JSON representation
Generalized Caching Solution
- Host: GitHub
- URL: https://github.com/festinuz/gecaso
- Owner: festinuz
- License: mit
- Created: 2017-07-13T11:47:53.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2017-07-26T14:04:40.000Z (almost 8 years ago)
- Last Synced: 2025-03-10T19:55:20.911Z (4 months ago)
- Topics: cache, cache-storage, python-3-5, python-3-6, python3
- Language: Python
- Size: 39.1 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Gecaso
[](https://badge.fury.io/py/gecaso) [](https://travis-ci.org/festinuz/gecaso)
> Gecaso allows you to cache any function with ease.## Table of contents
- [Features](#features)
- [Examples](#examples)
+ [Using default gecaso storages](#using-default-gecaso-storages)
+ [Creating custom storage](#creating-custom-storage)
- [Installation](#installation)
- [Usage Guide](#usage-guide)
+ ["gecaso.cached" function](#gecasocached-function)
+ ["gecaso.BaseStorage" class](#gecasobasestorage-class)
+ [Helper functions](#helper-functions)
+ [Default storages](#default-storages)
* [Storage creation](#storage-creation)## Features
* **Simple outside**: Requires little to no code to start caching. Plug in and enjoy.
* **Complex inside**: Worry not about dog-pile effect or the varying key size.
* **Asyncio-ready**: Works out of the box for both functions and coroutines. Any back-end can be used asynchronously.
* **Flexible Caching**: Data can be cached per function to different back-ends and with different parameters.
* **Extensible Back-end**: Create a custom storage for any backend with minimal effort.## Examples
#### Using default gecaso storages
```python
import gecaso@gecaso.cached(LRUStorage(maxsize=16), ttl=100)
def long_and_boring_function(time_to_sleep):
time.sleep(time_to_sleep)
return f'I have slept for {time_to_sleep} second(s)!'
```#### Creating custom storage
Lets say you want to cache the result of some of your functions using Redis. All you need to do is write a simple class in which you specify the steps for setting and getting data from redis.1) Create a Redis storage:
```python
import redis
import gecasoclass RedisStorage(gecaso.BaseStorage):
def __init__(self, redis_url):
self._storage = redis.from_url(redis_url)async def get(self, key):
value, params = gecaso.unpack(self._storage[key])
return valueasync def set(self, key, value, **params):
self._storage[key] = gecaso.pack(value, **params)async def remove(self, *keys):
self._storage.remove(*keys)redis_storage = RedisStorage('valid_redis_url')
```
2) Set your cache for any function you want:```python
@gecaso.cached(redis_storage, some_additional_cool_param='Hell yeah!')
def long_and_boring_function(time_to_sleep):
time.sleep(time_to_sleep)
return f'I have slept for {time_to_sleep} second(s)!'
```## Installation
Install gecaso with pip:
```
pip install gecaso
```
Note that at the time, gecaso only supports versions of python that are >=3.5## Usage Guide
Gecaso was created to be a simple solution that can be easily extended to cover any needs of its users. Below is everything there is to know about using Gecaso.#### "gecaso.cached" function
This function is a wrapper that helps to set up cache for any synchronus or asynchronous function. It takes single positional argument, which must be an instance of class that is inherited from **BaseStorage**. It can also optionally be provided with a keyword argument **loop** which must be an instance of an event loop. Has two keyword arguments: **\_loop** (event loop used by wrapper) and **\_hash_key** (default is "True"; if true, key will have fixed size of 65 symbols). Any additional keyword arguments provided will be passed to every specified storage with every **set** call.#### "gecaso.BaseStorage" class
Any storage provided to "cached" function should be inherited from this class. Base storage has 6 methods.* **get(self, key)**: Abstract method that should be overridden. Must be asynchronous. MUST raise KeyError if key is not present in storage. If data was packed using **gecaso.pack** function before being stored, it must be unpacked using **gecaso.unpack** function.
* **set(self, key, value, \*\*params)**: Abstract method that should be overridden. Must be asynchronous. It is recommended to pack provided value using **gecaso.pack** function before storing it in storage.
* **remove(self, \*keys)**: Abstract method that should be overridden. Must be asynchronous. Should delete every key that is passed in *keys* parameter and exists in storage.
#### Helper functions
* **gecaso.pack(value, \*\*params)**: Returns representation of object with fields named *data* and *params* as bytes object. Useful when creating a custom storage as it allows to store almost anything as 'bytes'.* **gecaso.unpack(value)**: Unpacks bytes object that was packed with **pack** method and returns *tuple(data, params)*.
#### Default storages
* **gecaso.MemoryStorage** storages all the data in RAM. Can be used as a default storage.
* **gecaso.LRUStorage** is a simplified implementation that provides LRU cache functionality. Storage passed to its *\_\_init\_\_()* method will be used used to store values. This effectively allows to wrap any preexisting storage in *gecaso.LRUStorage* to get LRU cache functionality for that storage.### Storage creation
The process of using gecaso library usually includes creating a storage that fits your specific task the most. Here is a step by step example that should help you understand this process.Lets say that we want to have a simple in-memory cache. Here are the steps we would take:
1) Import gecaso and create the base of our class:
```python
import gecasoclass LocalMemoryStorage(gecaso.BaseStorage):
def __init__(self):
self._storage = dict() # Python's dict is a nice basic storage of data
```2) Override async methods **set**, **get** and **remove** of gecaso.BaseStorage:
```python
async def set(self, key, value): # We don't want any additional parameters
params = dict()
self._storage[key] = gecaso.pack(value, **params)async def get(self, key):
self.data = self._storage[key] # If key is not present this will raise KeyError
value, params = gecaso.unpack(self._storage[key])
return valueasync def remove(self, *keys):
for key in keys:
self._storage.pop(key, None) # Not going to throw error if some of the keys do not exists
```And now we're done!
After the storage class has been created, all that is left to do is create an instance of this class and provide it to **cached** decorator whenever it is being called:```python
local_storage = LocalMemoryStorage()@gecaso.cached(local_storage)
def foo(bar):
pass
```