Python implementation of redis API, can be used for testing purposes
npx @tessl/cli install tessl/pypi-fakeredis@2.31.00
# FakeRedis
1
2
A comprehensive Python implementation of the Redis API that provides enhanced versions of the redis-py Python bindings for Redis. It enables running tests requiring Redis, Valkey, DragonflyDB, or KeyDB servers without an actual server. FakeRedis supports all Redis functionality including advanced features such as RedisJSON, RedisBloom, GeoCommands, Time Series, and more.
3
4
## Package Information
5
6
- **Package Name**: fakeredis
7
- **Language**: Python
8
- **Installation**: `pip install fakeredis`
9
- **License**: BSD-3-Clause
10
- **Documentation**: https://fakeredis.moransoftware.ca/
11
12
## Core Imports
13
14
```python
15
import fakeredis
16
```
17
18
Common usage patterns:
19
20
```python
21
from fakeredis import FakeRedis, FakeServer
22
```
23
24
For async support:
25
26
```python
27
from fakeredis import FakeAsyncRedis
28
```
29
30
For Redis Stack extensions:
31
32
```python
33
from fakeredis.stack import JSONCommandsMixin
34
```
35
36
## Basic Usage
37
38
```python
39
import fakeredis
40
41
# Create a fake Redis client (drop-in replacement for redis.Redis)
42
redis_client = fakeredis.FakeRedis()
43
44
# Basic key-value operations
45
redis_client.set('key', 'value')
46
value = redis_client.get('key')
47
print(value.decode()) # 'value'
48
49
# Hash operations
50
redis_client.hmset('user:1', {'name': 'John', 'email': 'john@example.com'})
51
user_data = redis_client.hgetall('user:1')
52
53
# List operations
54
redis_client.lpush('tasks', 'task1', 'task2', 'task3')
55
tasks = redis_client.lrange('tasks', 0, -1)
56
57
# Set operations
58
redis_client.sadd('tags', 'python', 'redis', 'testing')
59
tags = redis_client.smembers('tags')
60
61
# Async usage
62
import asyncio
63
async def async_example():
64
async_client = fakeredis.FakeAsyncRedis()
65
await async_client.set('async_key', 'async_value')
66
value = await async_client.get('async_key')
67
return value
68
69
# Run async example
70
# result = asyncio.run(async_example())
71
```
72
73
## Architecture
74
75
FakeRedis follows a modular architecture that ensures Redis compatibility:
76
77
- **FakeServer**: Central server instance managing databases, connections, script cache, and pub/sub state
78
- **FakeRedis/FakeAsyncRedis**: Main client classes inheriting from redis-py with fake connection handling
79
- **Command Mixins**: Modular implementation of Redis commands organized by data type (strings, hashes, lists, etc.)
80
- **Data Models**: Redis-compatible data structures (Hash, ZSet, XStream, TimeSeries, etc.)
81
- **Stack Extensions**: Optional modules providing RedisStack functionality (JSON, Bloom filters, Time Series, etc.)
82
- **Protocol Layer**: RESP protocol implementation with socket emulation for full compatibility
83
84
This architecture allows FakeRedis to maintain exact Redis behavior while providing a lightweight, dependency-minimal solution for testing Redis-dependent applications.
85
86
## Capabilities
87
88
### Core Redis Clients
89
90
Main client classes that provide drop-in replacements for redis-py clients with full Redis command compatibility and server emulation.
91
92
```python { .api }
93
class FakeRedis(redis.Redis):
94
def __init__(
95
self,
96
server: Optional[FakeServer] = None,
97
version: VersionType = (7,),
98
server_type: ServerType = "redis",
99
lua_modules: Optional[Dict[str, Any]] = None,
100
**kwargs
101
): ...
102
103
@classmethod
104
def from_url(cls, url: str, **kwargs) -> Self: ...
105
106
class FakeAsyncRedis(redis.asyncio.Redis):
107
def __init__(
108
self,
109
server: Optional[FakeServer] = None,
110
version: VersionType = (7,),
111
server_type: ServerType = "redis",
112
lua_modules: Optional[Dict[str, Any]] = None,
113
**kwargs
114
): ...
115
116
@classmethod
117
def from_url(cls, url: str, **kwargs) -> Self: ...
118
119
class FakeStrictRedis(redis.StrictRedis):
120
def __init__(self, **kwargs): ...
121
122
@classmethod
123
def from_url(cls, url: str, **kwargs) -> Self: ...
124
```
125
126
[Core Redis Clients](./core-clients.md)
127
128
### Server Management
129
130
Server instances that manage Redis state, databases, and connections with support for different Redis-compatible server types.
131
132
```python { .api }
133
class FakeServer:
134
def __init__(
135
self,
136
version: VersionType = (7,),
137
server_type: ServerType = "redis",
138
config: Optional[Dict[bytes, bytes]] = None
139
): ...
140
141
def get_server(self) -> FakeServer: ...
142
def get_next_client_id(self) -> int: ...
143
144
class TcpFakeServer:
145
def __init__(
146
self,
147
server_address: Tuple[str, int],
148
server_type: ServerType = "redis",
149
server_version: VersionType = (8, 0)
150
): ...
151
```
152
153
[Server Management](./server-management.md)
154
155
### String Operations
156
157
Redis string data type operations including get/set, increment/decrement, and multi-key operations.
158
159
```python { .api }
160
def get(self, name: KeyT) -> Optional[bytes]: ...
161
def set(
162
self,
163
name: KeyT,
164
value: EncodableT,
165
ex: Optional[ExpiryT] = None,
166
px: Optional[ExpiryT] = None,
167
nx: bool = False,
168
xx: bool = False,
169
keepttl: bool = False,
170
get: bool = False,
171
exat: Optional[AbsExpiryT] = None,
172
pxat: Optional[AbsExpiryT] = None
173
) -> Optional[bytes]: ...
174
def mget(self, keys: Sequence[KeyT]) -> List[Optional[bytes]]: ...
175
def mset(self, mapping: Mapping[AnyKeyT, EncodableT]) -> bool: ...
176
def incr(self, name: KeyT, amount: int = 1) -> int: ...
177
def decr(self, name: KeyT, amount: int = 1) -> int: ...
178
```
179
180
[String Operations](./string-operations.md)
181
182
### Bitmap Operations
183
184
Redis bitmap operations for efficient bit-level manipulation of string values with counting, positioning, and bitwise operations.
185
186
```python { .api }
187
def getbit(self, key: KeyT, offset: int) -> int: ...
188
def setbit(self, key: KeyT, offset: int, value: int) -> int: ...
189
def bitpos(self, key: KeyT, bit: int, *args: bytes) -> int: ...
190
def bitcount(self, key: KeyT, *args: bytes) -> int: ...
191
def bitop(self, op_name: bytes, dst: KeyT, *keys: KeyT) -> int: ...
192
def bitfield(self, key: KeyT, *args: bytes) -> List[Optional[int]]: ...
193
```
194
195
[Bitmap Operations](./bitmap-operations.md)
196
197
### Hash Operations
198
199
Redis hash data type operations for field-value mappings within keys.
200
201
```python { .api }
202
def hget(self, name: KeyT, key: str) -> Optional[bytes]: ...
203
def hgetall(self, name: KeyT) -> Dict[bytes, bytes]: ...
204
def hset(
205
self,
206
name: KeyT,
207
key: Optional[str] = None,
208
value: Optional[EncodableT] = None,
209
mapping: Optional[Mapping[AnyKeyT, EncodableT]] = None
210
) -> int: ...
211
def hmget(self, name: KeyT, keys: Sequence[str]) -> List[Optional[bytes]]: ...
212
def hincrby(self, name: KeyT, key: str, amount: int = 1) -> int: ...
213
def hdel(self, name: KeyT, *keys: str) -> int: ...
214
```
215
216
[Hash Operations](./hash-operations.md)
217
218
### List Operations
219
220
Redis list data type operations for ordered collections with push/pop operations from both ends.
221
222
```python { .api }
223
def lpush(self, name: KeyT, *values: EncodableT) -> int: ...
224
def rpush(self, name: KeyT, *values: EncodableT) -> int: ...
225
def lpop(self, name: KeyT, count: Optional[int] = None) -> Union[Optional[bytes], List[bytes]]: ...
226
def rpop(self, name: KeyT, count: Optional[int] = None) -> Union[Optional[bytes], List[bytes]]: ...
227
def lrange(self, name: KeyT, start: int, end: int) -> List[bytes]: ...
228
def llen(self, name: KeyT) -> int: ...
229
def blpop(self, keys: Sequence[KeyT], timeout: int = 0) -> Optional[Tuple[bytes, bytes]]: ...
230
def brpop(self, keys: Sequence[KeyT], timeout: int = 0) -> Optional[Tuple[bytes, bytes]]: ...
231
```
232
233
[List Operations](./list-operations.md)
234
235
### Set Operations
236
237
Redis set data type operations for unordered collections of unique elements with set algebra operations.
238
239
```python { .api }
240
def sadd(self, name: KeyT, *values: EncodableT) -> int: ...
241
def smembers(self, name: KeyT) -> Set[bytes]: ...
242
def sismember(self, name: KeyT, value: EncodableT) -> bool: ...
243
def srem(self, name: KeyT, *values: EncodableT) -> int: ...
244
def scard(self, name: KeyT) -> int: ...
245
def sinter(self, keys: Sequence[KeyT]) -> Set[bytes]: ...
246
def sunion(self, keys: Sequence[KeyT]) -> Set[bytes]: ...
247
def sdiff(self, keys: Sequence[KeyT]) -> Set[bytes]: ...
248
```
249
250
[Set Operations](./set-operations.md)
251
252
### Sorted Set Operations
253
254
Redis sorted set data type operations for ordered collections with numeric scores enabling range queries and ranking.
255
256
```python { .api }
257
def zadd(
258
self,
259
name: KeyT,
260
mapping: Mapping[AnyKeyT, EncodableT],
261
nx: bool = False,
262
xx: bool = False,
263
ch: bool = False,
264
incr: bool = False,
265
gt: bool = False,
266
lt: bool = False
267
) -> Union[int, Optional[float]]: ...
268
def zrange(
269
self,
270
name: KeyT,
271
start: int,
272
end: int,
273
desc: bool = False,
274
withscores: bool = False,
275
score_cast_func: Callable[[bytes], Any] = float,
276
byscore: bool = False,
277
bylex: bool = False,
278
offset: Optional[int] = None,
279
num: Optional[int] = None
280
) -> Union[List[bytes], List[Tuple[bytes, float]]]: ...
281
def zrank(self, name: KeyT, value: EncodableT) -> Optional[int]: ...
282
def zscore(self, name: KeyT, value: EncodableT) -> Optional[float]: ...
283
```
284
285
[Sorted Set Operations](./sorted-set-operations.md)
286
287
### Stream Operations
288
289
Redis 5.0+ streams for append-only log data structures with consumer group support for distributed processing.
290
291
```python { .api }
292
def xadd(
293
self,
294
name: KeyT,
295
fields: Dict[AnyKeyT, EncodableT],
296
id: str = "*",
297
maxlen: Optional[int] = None,
298
approximate: bool = True,
299
nomkstream: bool = False,
300
minid: Optional[str] = None,
301
limit: Optional[int] = None
302
) -> str: ...
303
def xread(
304
self,
305
streams: Dict[KeyT, Union[str, int]],
306
count: Optional[int] = None,
307
block: Optional[int] = None
308
) -> List[Tuple[bytes, List[Tuple[bytes, Dict[bytes, bytes]]]]]: ...
309
def xgroup_create(
310
self,
311
name: KeyT,
312
groupname: str,
313
id: str = "$",
314
mkstream: bool = False,
315
entries_read: Optional[int] = None
316
) -> bool: ...
317
```
318
319
[Stream Operations](./stream-operations.md)
320
321
### Pub/Sub Operations
322
323
Redis publish/subscribe messaging with support for channels, pattern subscriptions, and shard channels.
324
325
```python { .api }
326
def publish(self, channel: KeyT, message: EncodableT) -> int: ...
327
def pubsub_channels(self, pattern: str = "*") -> List[bytes]: ...
328
def pubsub_numsub(self, *args: KeyT) -> List[Tuple[bytes, int]]: ...
329
330
class PubSub:
331
def subscribe(self, *args: KeyT) -> None: ...
332
def psubscribe(self, *args: str) -> None: ...
333
def unsubscribe(self, *args: KeyT) -> None: ...
334
def punsubscribe(self, *args: str) -> None: ...
335
def get_message(self, ignore_subscribe_messages: bool = False, timeout: float = 0.0) -> Optional[Dict[str, Any]]: ...
336
```
337
338
[Pub/Sub Operations](./pubsub-operations.md)
339
340
### Geospatial Operations
341
342
Redis geospatial operations for location-based data with geographic indexing and radius queries.
343
344
```python { .api }
345
def geoadd(
346
self,
347
name: KeyT,
348
values: Sequence[Union[Tuple[float, float, EncodableT], Tuple[EncodableT, float, float]]],
349
nx: bool = False,
350
xx: bool = False,
351
ch: bool = False
352
) -> int: ...
353
def geodist(
354
self,
355
name: KeyT,
356
place1: EncodableT,
357
place2: EncodableT,
358
unit: Optional[str] = None
359
) -> Optional[float]: ...
360
def georadius(
361
self,
362
name: KeyT,
363
longitude: float,
364
latitude: float,
365
radius: float,
366
unit: str = "m",
367
withdist: bool = False,
368
withcoord: bool = False,
369
withhash: bool = False,
370
count: Optional[int] = None,
371
sort: Optional[str] = None,
372
store: Optional[KeyT] = None,
373
store_dist: Optional[KeyT] = None
374
) -> List[Union[bytes, List[Union[bytes, float, Tuple[float, float], int]]]]: ...
375
```
376
377
[Geospatial Operations](./geospatial-operations.md)
378
379
### Generic Key Operations
380
381
Generic Redis operations that work across all data types including expiration, pattern matching, and key management.
382
383
```python { .api }
384
def delete(self, *names: KeyT) -> int: ...
385
def exists(self, *names: KeyT) -> int: ...
386
def expire(self, name: KeyT, time: ExpiryT) -> bool: ...
387
def expireat(self, name: KeyT, when: AbsExpiryT) -> bool: ...
388
def keys(self, pattern: str = "*") -> List[bytes]: ...
389
def rename(self, src: KeyT, dst: KeyT) -> bool: ...
390
def ttl(self, name: KeyT) -> int: ...
391
def type(self, name: KeyT) -> bytes: ...
392
def scan(
393
self,
394
cursor: int = 0,
395
match: Optional[str] = None,
396
count: Optional[int] = None,
397
_type: Optional[str] = None
398
) -> Tuple[int, List[bytes]]: ...
399
```
400
401
[Generic Key Operations](./generic-operations.md)
402
403
### Transaction Operations
404
405
Redis transaction support with MULTI/EXEC commands and optimistic locking via WATCH.
406
407
```python { .api }
408
def multi(self) -> None: ...
409
def execute(self) -> List[Any]: ...
410
def discard(self) -> None: ...
411
def watch(self, *names: KeyT) -> bool: ...
412
def unwatch(self) -> bool: ...
413
414
class Pipeline:
415
def __enter__(self) -> Pipeline: ...
416
def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...
417
def execute(self, raise_on_error: bool = True) -> List[Any]: ...
418
```
419
420
[Transaction Operations](./transaction-operations.md)
421
422
### Lua Scripting
423
424
Redis Lua scripting support with script caching and execution.
425
426
```python { .api }
427
def eval(
428
self,
429
script: str,
430
numkeys: int,
431
*keys_and_args: KeyT
432
) -> Any: ...
433
def evalsha(
434
self,
435
sha: str,
436
numkeys: int,
437
*keys_and_args: KeyT
438
) -> Any: ...
439
def script_load(self, script: str) -> str: ...
440
def script_exists(self, *args: str) -> List[bool]: ...
441
def script_flush(self, sync_type: Optional[str] = None) -> bool: ...
442
```
443
444
[Lua Scripting](./lua-scripting.md)
445
446
### Server Operations
447
448
Redis server management commands including database operations, configuration, and information retrieval.
449
450
```python { .api }
451
def info(self, section: Optional[str] = None) -> Dict[str, Any]: ...
452
def dbsize(self) -> int: ...
453
def flushdb(self, asynchronous: bool = False) -> bool: ...
454
def flushall(self, asynchronous: bool = False) -> bool: ...
455
def config_get(self, pattern: str = "*") -> Dict[bytes, bytes]: ...
456
def config_set(self, name: str, value: EncodableT) -> bool: ...
457
def time(self) -> Tuple[str, str]: ...
458
def client_list(self, _type: Optional[str] = None, client_id: Optional[int] = None) -> str: ...
459
```
460
461
[Server Operations](./server-operations.md)
462
463
### Redis Stack Extensions
464
465
Optional Redis Stack module implementations providing advanced data structures and capabilities.
466
467
```python { .api }
468
# JSON operations (requires jsonpath-ng)
469
def json_get(self, name: KeyT, *args: str) -> Any: ...
470
def json_set(self, name: KeyT, path: str, obj: Any, nx: bool = False, xx: bool = False) -> Optional[bool]: ...
471
472
# Bloom Filter operations (requires pyprobables)
473
def bf_add(self, key: KeyT, item: EncodableT) -> bool: ...
474
def bf_exists(self, key: KeyT, item: EncodableT) -> bool: ...
475
476
# Time Series operations
477
def ts_add(
478
self,
479
key: KeyT,
480
timestamp: Union[int, str],
481
value: float,
482
retention_msecs: Optional[int] = None,
483
uncompressed: Optional[bool] = None,
484
chunk_size: Optional[int] = None,
485
on_duplicate: Optional[str] = None
486
) -> int: ...
487
```
488
489
[Redis Stack Extensions](./stack-extensions.md)
490
491
### Valkey Support
492
493
Optional Valkey client implementations for compatibility with Valkey servers (requires valkey package).
494
495
```python { .api }
496
class FakeValkey(valkey.Valkey):
497
def __init__(self, **kwargs): ...
498
499
@classmethod
500
def from_url(cls, url: str, **kwargs) -> Self: ...
501
502
class FakeAsyncValkey(valkey.asyncio.Valkey):
503
def __init__(self, **kwargs): ...
504
505
@classmethod
506
def from_url(cls, url: str, **kwargs) -> Self: ...
507
```
508
509
[Valkey Support](./valkey-support.md)
510
511
## Types
512
513
```python { .api }
514
# Core type aliases
515
VersionType = Tuple[int, ...]
516
ServerType = Literal["redis", "dragonfly", "valkey"]
517
KeyT = Union[str, bytes]
518
EncodableT = Union[bytes, float, int, str]
519
ExpiryT = Union[int, timedelta]
520
AbsExpiryT = Union[datetime, int]
521
AnyKeyT = Union[str, bytes, memoryview]
522
523
# Server configuration
524
class FakeServer:
525
def __init__(
526
self,
527
version: VersionType = (7,),
528
server_type: ServerType = "redis",
529
config: Optional[Dict[bytes, bytes]] = None
530
): ...
531
532
# Response types
533
class SimpleString:
534
"""Redis simple string response type"""
535
pass
536
537
# Client info model
538
class ClientInfo:
539
id: int
540
addr: str
541
laddr: str
542
fd: int
543
name: str
544
idle: int
545
flags: str
546
db: int
547
sub: int
548
psub: int
549
ssub: int
550
multi: int
551
qbuf: int
552
qbuf_free: int
553
argv_mem: int
554
multi_mem: int
555
rbs: int
556
rbp: int
557
obl: int
558
oll: int
559
omem: int
560
tot_mem: int
561
events: str
562
cmd: str
563
user: str
564
redir: int
565
resp: int
566
567
# Stream models
568
class StreamEntryKey(NamedTuple):
569
millis_time: int
570
sequence_number: int
571
572
# Time series models
573
class TimeSeriesRule:
574
dest_key: str
575
aggregation_type: str
576
bucket_size_msec: int
577
alignment_timestamp: Optional[int] = None
578
579
# Access control
580
class AccessControlList:
581
def authenticate(self, username: str, password: str) -> bool: ...
582
def get_user(self, username: str) -> Optional[Dict[str, Any]]: ...
583
```