redis/README.md
2026-06-29 23:07:02 -04:00

3.5 KiB

redis

Async Redis wrapper over redis-py's asyncio client — a small, config-free, fail-loud key/value + hash + ttl surface with a raw escape hatch for everything else. First of the datastore trio (redis / psql / mysql), a sibling of the mongo lib.

Import name ≠ repo name. The repo/distribution is redis, but you import redis_store — the driver package owns the redis import namespace, so the lib can't also be redis. Install resolves redis.git; code does from redis_store import RedisDB.

Install

requirements.txt:

redis_store @ git+ssh://git@git.rethinkstudios.io/rethink-public/redis.git@v0.1.1

Direct:

pip install "redis_store @ git+ssh://git@git.rethinkstudios.io/rethink-public/redis.git@v0.1.1"

Pulls redis>=5 (redis-py, which ships the asyncio client — not the dead standalone aioredis).

Drop the @v0.1.1 suffix from the line above to install the latest unpinned.

Usage

from redis_store import RedisDB

# construction is sync and opens no socket; connect() pings to fail loud on bad config
kv = await RedisDB(host="localhost", port=6379, db=0, password=None).connect()

await kv.set("user:1:name", "ada", ex=3600)   # ex = ttl seconds (optional)
name = await kv.get("user:1:name")            # "ada"   (None if absent)
await kv.incr("hits")                          # atomic counter -> int

await kv.hset("user:1", mapping={"name": "ada", "role": "admin"})
role = await kv.hget("user:1", "role")        # "admin"
everything = await kv.hgetall("user:1")        # {"name": "ada", "role": "admin"}

await kv.close()                               # on shutdown

Context-manager form:

async with RedisDB(host="localhost") as kv:
    await kv.incr("hits")

One client/pool per process — build it once, attach it to your app (app.kv = ...), share it.

Type contract

decode_responses=True by default: keys and string values come back as str (and None for an absent key). Pass decode_responses=False at construction for raw bytes. Counters and counts (incr/decr/exists/ttl) always return int regardless.

Error contract — fail loud

Unlike the mongo lib (which log-and-swallows, returning a safe default), this lib re-raises. Every wrapped method catches the driver's RedisError, logs it via logging.getLogger(__name__), and raises. A None / [] / {} return is only ever a real result (absent key, empty hash) — never a swallowed failure. So a caller can trust that no exception means the op succeeded.

For anything not wrapped — pipelines, pub/sub, scan, Lua, transactions — use the raw escape hatch:

async with kv.client.pipeline() as pipe:
    await pipe.set("a", 1).set("b", 2).execute()

kv.client is the underlying redis.asyncio.Redis: full driver surface, raises, nothing swallowed.

Surface

  • key/value: get, set (optional ex ttl), delete, exists, incr, decr
  • hash: hget, hset (single key/value or mapping=), hgetall, hdel
  • expiry/ttl: expire, ttl (driver sentinels pass through: -1 no expiry, -2 key absent)
  • raw: client property → redis.asyncio.Redis

Pub/sub and a pipeline() wrapper are intentionally not wrapped yet — the raw client covers them; they'll be added when a consumer needs the ergonomics.

Versioning

Releases are tagged vX.Y.Z. The install line above pins a release; drop the @vX.Y.Z suffix to install the latest unpinned. Pin deliberately for reproducible installs.