Skip to content

API reference

Everything in redis_lua_py.__all__. The package is small on purpose: one decorator, one annotation, two namespaces, and the errors.

from redis_lua_py import Key, call, cjson, redis, script
from redis_lua_py import BoundScript, CompiledScript

script

def script(
    func: Callable[..., R] | None = None,
    /,
    *,
    name: str | None = None,
    header: bool = True,
) -> CompiledScript[R] | Callable[[Callable[..., R]], CompiledScript[R]]

Compile a function into a Redis Lua script. Usable bare or called:

@script
def touch(key: Key) -> int: ...


@script(name="touch_v2", header=False)
def touch(key: Key) -> int: ...
Parameter Meaning
name overrides the name in the generated header and in errors
header False drops the provenance comment entirely, for anyone who wants the script body and nothing else

Parameters annotated Key become KEYS, in declaration order; every other parameter becomes ARGV. See Keys and arguments.

The return annotation describes what the caller gets back, and is carried through to the call: -> int makes the script a CompiledScript[int]. The compiler itself does not read it. See What the caller gets.

Define scripts at module level, where they compile once at import.

Raises UnsupportedSyntax at decoration time, pointing at the line at fault, if the body strays outside the supported subset.

Key

class Key(str)

Marks a parameter as a Redis key. A str subclass, so it is inert at runtime and the annotation is the whole of it.

Getting this right matters: Redis Cluster routes a script by its declared keys, so a key passed as an argument will be invisible to the router.

redis

The script namespace. redis.incr(key) becomes redis.call('INCR', key); underscores split into subcommand tokens, so redis.script_load(x) becomes redis.call('SCRIPT', 'LOAD', x).

Names are checked at compile time against Redis' own command table; redis.call(...) itself is never checked and is the escape hatch. See Calling Redis commands.

The compiler identifies the namespace by value rather than by the name it is imported under, so every alias works and nothing is reserved.

call

An alias of redis, for modules that would rather not rename anything.

cjson

The JSON library Redis exposes to scripts: cjson.encode and cjson.decode, which pass through under their own names.

CompiledScript

class CompiledScript(Generic[R])

What @script returns. Calling it runs EVALSHA and falls back to EVAL the first time, or whenever the server has dropped the script from its cache.

script(client, /, *positional, **keyword) -> R              # sync client
script(client, /, *positional, **keyword) -> Awaitable[R]   # async client
Attribute Type What it is
name str the script's name, in the header and in errors
lua str the full Lua source, exactly as sent to Redis
params tuple[str, ...] every parameter, in declaration order
keys tuple[str, ...] the parameters annotated Key
args tuple[str, ...] everything else
doc str \| None the function's docstring
source str where it was defined, repo-relative

bind

def bind(self, client) -> BoundScript[R]              # sync client
def bind(self, client) -> BoundScript[Awaitable[R]]   # async client

Attach a client, so calls do not have to pass one. See Binding a client.

BoundScript

class BoundScript(Generic[T])

A script with its client already attached, produced by bind. The type parameter is what a call returns: the script's own return type for a sync client, an awaitable of it for an async one.

bound(*positional, **keyword) -> T

Exposes name, lua, params, keys, args and doc from the script it wraps, and leaves that script usable against any other client.

Errors and warnings

CompileError, UnsupportedSyntax, ScriptArgumentError, RedisLuaError, RedisLuaWarning and NilTruncationWarning have their own page.