Redis GET SET EX TTL mock in Python

A thread-safe Python class mimicking Redis GET, SET with EX, and TTL commands for in-memory testing.

Easy Python 3.9+ Aug 9, 2026 Caching & Redis 13 views 0 copies

Python code

48 lines
Python 3.9+
import time
import threading
from typing import Optional, Callable


class RedisTTLMock:
    def __init__(self):
        self._store: dict[str, tuple[str, float]] = {}
        self._lock = threading.Lock()

    def set(self, key: str, value: str, ex: Optional[int] = None) -> bool:
        expiry = time.time() + ex if ex is not None else float("inf")
        with self._lock:
            self._store[key] = (value, expiry)
        return True

    def get(self, key: str) -> Optional[str]:
        with self._lock:
            entry = self._store.get(key)
            if entry is None:
                return None
            value, expiry = entry
            if time.time() > expiry:
                del self._store[key]
                return None
            return value

    def ttl(self, key: str) -> int:
        with self._lock:
            entry = self._store.get(key)
            if entry is None:
                return -2
            _, expiry = entry
            remaining = expiry - time.time()
            if remaining <= 0:
                del self._store[key]
                return -2
            return int(remaining)


if __name__ == "__main__":
    r = RedisTTLMock()
    r.set("greeting", "hello", ex=2)
    print(r.get("greeting"))  # hello
    print(r.ttl("greeting"))  # 2
    time.sleep(3)
    print(r.get("greeting"))  # None
    print(r.ttl("greeting"))  # -2

Output

stdout
hello
2
None
-2

How it works

This mock uses a dictionary to store each key's value and expiry timestamp. The set method stores the value and calculates an expiration time using time.time() + ex (or infinity if no TTL). get checks the expiry before returning the value; expired keys are deleted to keep the store clean. TTL returns -2 for missing keys, -1 for keys without expiry (infinity), and the remaining seconds otherwise. A lock ensures thread safety for concurrent access.

Common mistakes

  • Forgetting to convert TTL to integer, possibly returning a float.
  • Not handling the case when TTL is not set (infinity) – TTL should return -1.
  • Not deleting expired keys, causing stale data to linger.
  • Using time.sleep in tests instead of mocking time to avoid slow tests.

Variations

  1. Use `unittest.mock` to replace actual Redis calls with a MagicMock.
  2. Use a real Redis server with `redis-py` in test containers for integration tests.

Real-world use cases

  • Unit testing caching logic without spinning up a Redis instance in CI pipelines.
  • Simulating cache expiration behavior in a local development environment.
  • Teaching or demonstrating Redis TTL semantics in an educational setting.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Caching & Redis

Related tutorials and quizzes for this topic.