Skip to content

Commit 8758043

Browse files
committed
Add unittest
1 parent 01f7d49 commit 8758043

File tree

8 files changed

+216
-4
lines changed

8 files changed

+216
-4
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
__pycache__
22
*.pyc
3-
test*.py
43
dist
54
*.egg-info

README.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Redis cache for Python
22

3-
- Simple python redis cache library, mostly used as distributed caching, where application servers is in separated processes such as Gunicorn workers, K8s replicas.
3+
- Simple python redis cache library, mostly used as [distributed caching](https://redis.com/glossary/distributed-caching), where application servers is in separated processes such as Gunicorn workers, K8s replicas, .etc..
44
- **Asyncio Support for FastAPI, Starlette**
55

66
## Requirements
@@ -45,4 +45,53 @@ print(result)
4545
# [4, 10, 18]
4646
```
4747

48+
**Asynchronous with asyncio**
49+
50+
```python
51+
import asyncio
52+
from py_redis_cache.asyncio import AsyncRedisCache
53+
54+
# init redis_cache instance and connection
55+
redis_cache = AsyncRedisCache(
56+
host="127.0.0.1",
57+
port=6379,
58+
verbose=1 # Turn on logging for demonstration, set to 0 for silent caching
59+
)
60+
61+
@redis_cache.aio_cache(ttl=10) # Expire after 10 seconds
62+
async def heavy_compute(a: list, b: list):
63+
length = max(len(a), len(b))
64+
c = [[]] * length
65+
for i in range(length):
66+
c[i] = a[i] * b[i]
67+
return c
68+
69+
async def test_async_cache():
70+
result = await heavy_compute([1, 2, 3], [4, 5, 6])
71+
print(result)
72+
73+
# Now the result is cached
74+
result2 = await heavy_compute([1, 2, 3], [4, 5, 6])
75+
76+
print(result2)
77+
78+
loop = asyncio.get_event_loop()
79+
loop.run_until_complete(test_async_cache())
80+
81+
# Cache added, key=redis_cache::11=__main__.heavy_compute(a=[1, 2, 3].b=[4, 5, 6]), size=0.000Kb
82+
# [4, 10, 18]
83+
# Cache hit, key=redis_cache::11=__main__.heavy_compute(a=[1, 2, 3].b=[4, 5, 6])
84+
# [4, 10, 18]
85+
```
86+
87+
## Advanced usage
88+
4889
for further examples and use cases please visit [examples](examples)
90+
91+
## Testing
92+
93+
**NOTE**: Please make sure you have redis running on `127.0.0.1:6379` to run test.
94+
95+
```bash
96+
$ python3 -m unittest discover tests
97+
```

examples/simple/async.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Example of caching async functions
2+
3+
import sys
4+
sys.path.append(".")
5+
import asyncio
6+
from py_redis_cache.asyncio import AsyncRedisCache
7+
8+
# init redis_cache instance and connection
9+
redis_cache = AsyncRedisCache(
10+
host="127.0.0.1",
11+
port=6379,
12+
verbose=1 # Turn on logging for demonstration, set to 0 for silent caching
13+
)
14+
15+
@redis_cache.aio_cache(ttl=10) # Expire after 10 seconds
16+
async def heavy_compute(a: list, b: list):
17+
length = max(len(a), len(b))
18+
c = [[]] * length
19+
for i in range(length):
20+
c[i] = a[i] * b[i]
21+
return c
22+
23+
async def test_async_cache():
24+
result = await heavy_compute([1, 2, 3], [4, 5, 6])
25+
print(result)
26+
27+
# Now the result is cached
28+
result2 = await heavy_compute([1, 2, 3], [4, 5, 6])
29+
30+
print(result2)
31+
32+
loop = asyncio.get_event_loop()
33+
loop.run_until_complete(test_async_cache())
File renamed without changes.

py_redis_cache/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
current_aio_redis_cache = None
1818

1919
class Singleton(type):
20+
disable = False
2021
_instances = {}
2122
def __call__(cls, *args, **kwargs):
2223
from .asyncio import AsyncRedisCache
@@ -27,11 +28,16 @@ def __call__(cls, *args, **kwargs):
2728
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
2829
if not is_aio_redis:
2930
current_redis_cache = cls._instances[cls]
30-
print("SET", current_redis_cache)
3131
else:
3232
current_aio_redis_cache = cls._instances[cls]
33-
print("SET AIO", current_aio_redis_cache)
33+
34+
if cls.disable:
35+
return cls._instances.pop(cls)
3436
return cls._instances[cls]
37+
38+
@classmethod
39+
def clear_instance(cls):
40+
cls._instances = {}
3541

3642

3743
class RedisCache(metaclass=Singleton):

tests/test_cache.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import os
2+
import time
3+
import unittest
4+
from py_redis_cache import RedisCache, Singleton
5+
6+
7+
class TestRedisCache(unittest.TestCase):
8+
9+
def test_simple_cache(self):
10+
# Enable Singleton for testing this case
11+
redis_cache = RedisCache()
12+
redis_cache2 = RedisCache()
13+
14+
assert redis_cache is redis_cache2 # Sample object
15+
16+
def test_ttl(self):
17+
redis_cache = RedisCache()
18+
19+
@redis_cache.cache(ttl=1)
20+
def add_two(a, b):
21+
return a + b + time.time()
22+
23+
result = add_two(1, 2)
24+
result_2 = add_two(1, 2)
25+
26+
assert result == result_2 # Should cached
27+
28+
time.sleep(1.1) # Cache will expire after 1 seconds
29+
30+
assert result != add_two(1, 2)
31+
32+
def test_kwargs(self):
33+
redis_cache = RedisCache()
34+
35+
@redis_cache.cache(ttl=1)
36+
def add_two(a, b):
37+
return a + b + time.time()
38+
39+
result = add_two(1, 2)
40+
result_2 = add_two(1, b=2)
41+
result_3 = add_two(a=1, b=2)
42+
assert result == result_2 == result_3
43+
44+
45+
if __name__ == '__main__':
46+
unittest.main()

tests/test_connection.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Test redis cache connection from environment variable or argument passing to
2+
# RedisCache
3+
import os
4+
import unittest
5+
from py_redis_cache import RedisCache, Singleton
6+
from redis.exceptions import ConnectionError
7+
8+
9+
class TestRedisCacheConnection(unittest.TestCase):
10+
11+
def test_connect_via_host_port(self):
12+
# Disable Singleton for testing
13+
Singleton.disable = True
14+
redis_cache = RedisCache(host="127.0.0.1", port=6379)
15+
assert redis_cache.client.ping() is True
16+
17+
def test_connect_via_host_port_wrong(self):
18+
# Redis does not listening on port 6380
19+
Singleton.disable = True
20+
redis_cache = RedisCache(
21+
host="127.0.0.1",
22+
port=99999,
23+
)
24+
self.assertRaises(
25+
ConnectionError,
26+
redis_cache.client.ping
27+
)
28+
29+
def test_connect_via_url(self):
30+
Singleton.disable = True
31+
redis_cache = RedisCache(redis_url="redis://127.0.0.1:6379")
32+
assert redis_cache.client.ping() is True
33+
34+
def test_connect_via_env(self):
35+
Singleton.disable = True
36+
os.environ["REDIS_URL"] = "redis://127.0.0.1:6379"
37+
# Provide incorrect host, port to demostrate passing redis_url via Env possible
38+
redis_cache = RedisCache(host="fakehost", port=1)
39+
os.environ["REDIS_URL"] = "" # Reset
40+
assert redis_cache.client.ping() is True
41+
42+
os.environ["REDIS_CACHE_URL"] = "redis://127.0.0.1:6379"
43+
# Provide incorrect host, port to demostrate passing redis_url via Env possible
44+
redis_cache = RedisCache(host="fakehost", port=1)
45+
os.environ["REDIS_CACHE_URL"] = "" # Reset
46+
assert redis_cache.client.ping() is True
47+
48+
49+
if __name__ == '__main__':
50+
unittest.main()

tests/test_singleton.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import os
2+
import unittest
3+
from py_redis_cache import RedisCache, Singleton
4+
5+
6+
class TestRedisCacheConnection(unittest.TestCase):
7+
8+
def test_two_calls(self):
9+
# Enable Singleton for testing this case
10+
Singleton.disable = False
11+
12+
redis_cache = RedisCache()
13+
redis_cache2 = RedisCache()
14+
15+
assert redis_cache is redis_cache2 # Sample object
16+
17+
def test_current_redis_cache(self):
18+
# Enable Singleton for testing this case
19+
Singleton.disable = False
20+
21+
redis_cache = RedisCache()
22+
23+
from py_redis_cache import current_redis_cache
24+
25+
assert redis_cache is current_redis_cache # Sample object
26+
27+
28+
if __name__ == '__main__':
29+
unittest.main()

0 commit comments

Comments
 (0)