Skip to content
This repository was archived by the owner on Sep 29, 2025. It is now read-only.

Commit 6f9c373

Browse files
committed
feat(pems_data): define a basic Cache class
uses an underlying redis connection
1 parent b89eda9 commit 6f9c373

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

pems_data/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "pems_data"
33
description = "Common data access library for PeMS."
44
dynamic = ["version"]
55
requires-python = ">=3.12"
6-
dependencies = ["boto3==1.39.7", "pandas==2.3.0"]
6+
dependencies = ["boto3==1.39.7", "pandas==2.3.0", "redis==6.2.0"]
77

88
[build-system]
99
requires = ["setuptools>=75", "setuptools_scm>=8"]

pems_data/src/pems_data/cache.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import os
2+
3+
import redis
4+
5+
6+
def redis_connection() -> redis.Redis:
7+
hostname = os.environ.get("REDIS_HOSTNAME", "redis")
8+
port = int(os.environ.get("REDIS_PORT", "6379"))
9+
10+
return redis.Redis(host=hostname, port=port)
11+
12+
13+
class Cache:
14+
"""Basic caching interface for `pems_data`."""
15+
16+
def __init__(self):
17+
self.r = redis_connection()
18+
19+
def is_available(self) -> bool:
20+
return self.r.ping() is True
21+
22+
def get(self, key):
23+
return self.r.get(key)
24+
25+
def set(self, key, value):
26+
self.r.set(key, value)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import redis
2+
import pytest
3+
4+
from pems_data.cache import Cache, redis_connection
5+
6+
7+
class TestRedisConnection:
8+
@pytest.fixture(autouse=True)
9+
def mock_redis(self, mocker):
10+
return mocker.patch("redis.Redis")
11+
12+
def test_redis_connection_default_values(self, mock_redis):
13+
redis_connection()
14+
mock_redis.assert_called_once_with(host="redis", port=6379)
15+
16+
def test_redis_connection_custom_values(self, mock_redis, monkeypatch):
17+
monkeypatch.setenv("REDIS_HOSTNAME", "custom-host")
18+
monkeypatch.setenv("REDIS_PORT", "1234")
19+
20+
redis_connection()
21+
mock_redis.assert_called_once_with(host="custom-host", port=1234)
22+
23+
24+
class TestCache:
25+
@pytest.fixture
26+
def mock_redis_connection(self, mocker):
27+
mock_redis = mocker.patch("pems_data.cache.redis_connection")
28+
mock_redis.return_value = mocker.Mock(spec=redis.Redis)
29+
return mock_redis.return_value
30+
31+
@pytest.fixture
32+
def cache(self, mock_redis_connection):
33+
return Cache()
34+
35+
def test_init_creates_redis_connection(self, mock_redis_connection):
36+
cache = Cache()
37+
assert cache.r == mock_redis_connection
38+
39+
def test_is_available_true(self, cache, mock_redis_connection):
40+
mock_redis_connection.ping.return_value = True
41+
42+
assert cache.is_available() is True
43+
mock_redis_connection.ping.assert_called_once()
44+
45+
def test_is_available_false(self, cache, mock_redis_connection):
46+
mock_redis_connection.ping.return_value = False
47+
48+
assert cache.is_available() is False
49+
mock_redis_connection.ping.assert_called_once()
50+
51+
def test_get(self, cache, mock_redis_connection):
52+
expected = b"test-value"
53+
mock_redis_connection.get.return_value = expected
54+
55+
result = cache.get("test-key")
56+
57+
assert result == expected
58+
mock_redis_connection.get.assert_called_once_with("test-key")
59+
60+
def test_set(self, cache, mock_redis_connection):
61+
cache.set("test-key", "test-value")
62+
63+
mock_redis_connection.set.assert_called_once_with("test-key", "test-value")

0 commit comments

Comments
 (0)