Skip to content

An async redis client for python with minimal API

License

Notifications You must be signed in to change notification settings

gebirgslok/reddish

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

reddish - an redis client for sockets and trio with minimal api

PyPI Build Status

Features

  • both sync and async API
  • sync api using the standard library socket module (TPC, TPC+TLS, Unix domain sockets)
  • async/await using trio's stream primitives (TCP, TCP+TLS, Unix domain sockets)
  • minimal api so you don't have to relearn how to write redis commands
  • supports all redis commands including modules except SUBSCRIBE, PSUBSCRIBE and MONITOR 1
  • parses responses back into python types if you like (powered by pydantic)
  • works with every redis version and supports both RESP2and RESP3 protocols

Installation

pip install reddish  # install just with support for socket
pip install reddish[trio]  # install with support for trio

Minimal Example - sync version

import socket
from reddish.socket import Redis, Command

redis = Redis(socket.create_connection(('localhost', 6379)))

assert b'PONG' == redis.execute(Command('PING'))

Minimal Example - async version

import trio
from reddish.trio import Redis, Command

redis = Redis(await trio.open_tcp_stream('localhost', 6379))

assert b'PONG' == await redis.execute(Command('PING'))

Usage

Command with a fixed number of arguments

# simple command without any arguments
Command('PING')

# commands with positional arguments
Command('ECHO {}', 'hello world')

# commands with keyword arguments
Command('SET {key} {value}', key='foo', value=42)

Command with response parsing

# return response unchanged from redis
assert b'42' == await redis.execute(Command('ECHO {}', 42))

# parse response as type
assert 42 == await redis.execute(Command('ECHO {}', 42).into(int))

# use any type that works with pydantic
from pydantic import Json
import json

data = json.dumps({'alice': 30, 'bob': 42})
response == await redis.execute(Command('ECHO {}', data).into(Json))
assert response == json.loads(data)

Command with variadic arguments

from reddish.trio import Args

# inlining arguments
Command('DEL {keys}', keys=Args(['foo', 'bar']))  # DEL foo bar

# inlining pairwise arguments 
data = {'name': 'bob', 'age': 42}
Command('XADD foo * {fields}', fields=Args.from_dict(data))  # XADD foo * name bob age 42

Pipelining commands

foo, bar = await redis.execute_many(Command('GET', 'foo'), Command('GET', 'bar'))

Transactions

from reddish.trio import MultiExec

tx = MultiExec(
    Command('ECHO {}', 'foo'),
    Command('ECHO {}', 'bar')
)

foo, bar = await redis.execute(tx)

# pipelining together with transactions
[foo, bar], baz = await redis.execute_many(tx, Command('ECHO {}', 'baz'))

Footnotes

  1. Commands like SUBSCRIBE or MONITOR take over the redis connection for listeting to new events barring regular commands from being issued over the connection.

About

An async redis client for python with minimal API

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Python 100.0%