docs
0
# Generic Operations
1
2
Redis generic key operations providing functionality that works across all data types. These operations include key management, expiration handling, pattern matching, and utility functions for working with Redis keys regardless of their underlying data type.
3
4
## Capabilities
5
6
### Key Existence and Management
7
8
Core functions for testing key existence, deletion, and basic key information.
9
10
```python { .api }
11
def exists(self, *names: KeyT) -> ResponseT: ...
12
13
def delete(self, *names: KeyT) -> ResponseT: ...
14
# Note: delete() is the method name, but del_() is also available for Python keyword compatibility
15
16
def del_(self, *names: KeyT) -> ResponseT: ...
17
18
def unlink(self, *names: KeyT) -> ResponseT: ...
19
20
def type(self, name: KeyT) -> ResponseT: ...
21
22
def touch(self, *names: KeyT) -> ResponseT: ...
23
24
def randomkey(self) -> Optional[bytes]: ...
25
26
def dbsize(self) -> ResponseT: ...
27
```
28
29
### Key Expiration
30
31
Functions for setting, checking, and managing key expiration times.
32
33
```python { .api }
34
def expire(self, name: KeyT, time: ExpiryT) -> ResponseT: ...
35
36
def expireat(self, name: KeyT, when: AbsExpiryT) -> ResponseT: ...
37
38
def pexpire(self, name: KeyT, time: ExpiryT) -> ResponseT: ...
39
40
def pexpireat(self, name: KeyT, when: AbsExpiryT) -> ResponseT: ...
41
42
def ttl(self, name: KeyT) -> ResponseT: ...
43
44
def pttl(self, name: KeyT) -> ResponseT: ...
45
46
def persist(self, name: KeyT) -> ResponseT: ...
47
```
48
49
### Key Movement and Renaming
50
51
Functions for moving keys between databases and renaming operations.
52
53
```python { .api }
54
def move(self, name: KeyT, db: int) -> ResponseT: ...
55
56
def rename(self, src: KeyT, dst: KeyT) -> ResponseT: ...
57
58
def renamenx(self, src: KeyT, dst: KeyT) -> ResponseT: ...
59
60
def copy(
61
self,
62
source: KeyT,
63
destination: KeyT,
64
destination_db: Optional[int] = None,
65
replace: bool = False
66
) -> ResponseT: ...
67
```
68
69
### Pattern Matching and Scanning
70
71
Functions for finding keys by patterns and iterating through keyspaces.
72
73
```python { .api }
74
def keys(self, pattern: PatternT = "*") -> List[bytes]: ...
75
76
def scan(
77
self,
78
cursor: int = 0,
79
match: Optional[PatternT] = None,
80
count: Optional[int] = None,
81
_type: Optional[str] = None
82
) -> ResponseT: ...
83
84
def scan_iter(
85
self,
86
match: Optional[PatternT] = None,
87
count: Optional[int] = None,
88
_type: Optional[str] = None
89
) -> Iterator[bytes]: ...
90
```
91
92
### Sorting and Object Information
93
94
Functions for sorting data and inspecting object properties.
95
96
```python { .api }
97
def sort(
98
self,
99
name: KeyT,
100
start: Optional[int] = None,
101
num: Optional[int] = None,
102
by: Optional[str] = None,
103
get: Optional[Union[KeyT, List[KeyT]]] = None,
104
desc: bool = False,
105
alpha: bool = False,
106
store: Optional[KeyT] = None,
107
groups: bool = False
108
) -> Union[List[bytes], int]: ...
109
110
def object(self, infotype: str, key: KeyT) -> ResponseT: ...
111
112
def memory_usage(self, key: KeyT, samples: Optional[int] = None) -> Optional[int]: ...
113
```
114
115
### Serialization
116
117
Functions for dumping and restoring key data.
118
119
```python { .api }
120
def dump(self, name: KeyT) -> Optional[bytes]: ...
121
122
def restore(
123
self,
124
name: KeyT,
125
ttl: int,
126
value: bytes,
127
replace: bool = False,
128
absttl: bool = False,
129
idletime: Optional[int] = None,
130
frequency: Optional[int] = None
131
) -> ResponseT: ...
132
```
133
134
## Usage Examples
135
136
### Basic Key Operations
137
138
```python
139
import fakeredis
140
141
client = fakeredis.FakeRedis()
142
143
# Set some test data
144
client.set('user:1', 'alice')
145
client.hset('profile:1', 'name', 'Alice')
146
client.lpush('messages:1', 'hello', 'world')
147
148
# Check if keys exist
149
exists_count = client.exists('user:1', 'user:2', 'profile:1')
150
print(f"Existing keys: {exists_count}") # 2
151
152
# Check individual key existence
153
if client.exists('user:1'):
154
print("User 1 exists")
155
156
# Get key types
157
user_type = client.type('user:1')
158
profile_type = client.type('profile:1')
159
messages_type = client.type('messages:1')
160
print(f"Types: {user_type.decode()}, {profile_type.decode()}, {messages_type.decode()}")
161
162
# Delete keys
163
deleted_count = client.delete('user:1', 'nonexistent_key')
164
print(f"Deleted keys: {deleted_count}") # 1
165
166
# Get database size
167
size = client.dbsize()
168
print(f"Database size: {size} keys")
169
170
# Get random key
171
random_key = client.randomkey()
172
if random_key:
173
print(f"Random key: {random_key.decode()}")
174
```
175
176
### Key Expiration Management
177
178
```python
179
import fakeredis
180
import time
181
182
client = fakeredis.FakeRedis()
183
184
# Set key with expiration
185
client.set('session:abc123', 'user_data')
186
client.expire('session:abc123', 30) # Expires in 30 seconds
187
188
# Check time to live
189
ttl_seconds = client.ttl('session:abc123')
190
print(f"TTL: {ttl_seconds} seconds")
191
192
# Set expiration with millisecond precision
193
client.set('temp:data', 'temporary')
194
client.pexpire('temp:data', 5000) # Expires in 5000 milliseconds (5 seconds)
195
196
ttl_ms = client.pttl('temp:data')
197
print(f"TTL: {ttl_ms} milliseconds")
198
199
# Set absolute expiration time
200
future_timestamp = int(time.time()) + 60 # 1 minute from now
201
client.set('scheduled:task', 'task_data')
202
client.expireat('scheduled:task', future_timestamp)
203
204
# Remove expiration (make key persistent)
205
client.persist('scheduled:task')
206
new_ttl = client.ttl('scheduled:task')
207
print(f"TTL after persist: {new_ttl}") # -1 means no expiration
208
209
# Touch keys to update last access time
210
client.set('key1', 'value1')
211
client.set('key2', 'value2')
212
touched = client.touch('key1', 'key2', 'nonexistent')
213
print(f"Touched keys: {touched}") # 2
214
```
215
216
### Pattern Matching and Key Discovery
217
218
```python
219
import fakeredis
220
221
client = fakeredis.FakeRedis()
222
223
# Setup test data with patterns
224
test_data = {
225
'user:1:name': 'alice',
226
'user:1:email': 'alice@example.com',
227
'user:2:name': 'bob',
228
'user:2:email': 'bob@example.com',
229
'session:abc': 'session_data_1',
230
'session:xyz': 'session_data_2',
231
'config:app:debug': 'true',
232
'config:db:host': 'localhost'
233
}
234
235
for key, value in test_data.items():
236
client.set(key, value)
237
238
# Find all user keys
239
user_keys = client.keys('user:*')
240
print("User keys:", [key.decode() for key in user_keys])
241
242
# Find user names specifically
243
user_names = client.keys('user:*:name')
244
print("User name keys:", [key.decode() for key in user_names])
245
246
# Find session keys
247
session_keys = client.keys('session:*')
248
print("Session keys:", [key.decode() for key in session_keys])
249
250
# Use character classes in patterns
251
config_keys = client.keys('config:*:*')
252
print("Config keys:", [key.decode() for key in config_keys])
253
254
# Find keys with single character wildcards
255
user_1_keys = client.keys('user:1:*')
256
print("User 1 keys:", [key.decode() for key in user_1_keys])
257
```
258
259
### Scanning Large Keyspaces
260
261
```python
262
import fakeredis
263
264
client = fakeredis.FakeRedis()
265
266
# Create many keys for demonstration
267
for i in range(1000):
268
client.set(f'key_{i}', f'value_{i}')
269
if i % 100 == 0:
270
client.set(f'special_key_{i}', f'special_value_{i}')
271
272
# Scan all keys efficiently
273
cursor = 0
274
all_keys = []
275
276
while True:
277
cursor, keys = client.scan(cursor=cursor, count=100)
278
all_keys.extend([key.decode() for key in keys])
279
if cursor == 0:
280
break
281
282
print(f"Total keys found: {len(all_keys)}")
283
284
# Scan with pattern matching
285
special_keys = []
286
for key in client.scan_iter(match='special_key_*', count=50):
287
special_keys.append(key.decode())
288
289
print(f"Special keys found: {len(special_keys)}")
290
291
# Scan by type (Redis 6.0+)
292
string_keys = []
293
for key in client.scan_iter(_type='string', count=100):
294
string_keys.append(key.decode())
295
296
print(f"String type keys: {len(string_keys)}")
297
```
298
299
### Key Renaming and Movement
300
301
```python
302
import fakeredis
303
304
client = fakeredis.FakeRedis()
305
306
# Setup test data
307
client.set('old_key', 'important_data')
308
client.set('temp_key', 'temporary_data')
309
310
# Rename key (overwrites destination if exists)
311
client.rename('old_key', 'new_key')
312
313
# Verify rename
314
if not client.exists('old_key') and client.exists('new_key'):
315
print("Key renamed successfully")
316
317
# Conditional rename (only if destination doesn't exist)
318
result = client.renamenx('temp_key', 'new_key') # Will fail because new_key exists
319
print(f"Conditional rename result: {result}") # 0 (failed)
320
321
result = client.renamenx('temp_key', 'unique_key') # Will succeed
322
print(f"Conditional rename result: {result}") # 1 (success)
323
324
# Copy keys (Redis 6.2+)
325
client.set('source', 'data_to_copy')
326
copied = client.copy('source', 'destination')
327
print(f"Copy result: {copied}") # 1 if successful
328
329
# Copy with replace option
330
copied = client.copy('source', 'destination', replace=True)
331
print(f"Copy with replace: {copied}")
332
333
# Move keys between databases (if multiple databases supported)
334
# Note: FakeRedis typically operates on a single database
335
# client.select(0)
336
# client.set('moveable_key', 'data')
337
# moved = client.move('moveable_key', 1) # Move to database 1
338
```
339
340
### Key Sorting
341
342
```python
343
import fakeredis
344
345
client = fakeredis.FakeRedis()
346
347
# Create a list to sort
348
client.lpush('numbers', '30', '10', '50', '20', '40')
349
350
# Sort numerically (default)
351
sorted_numbers = client.sort('numbers')
352
print("Sorted numbers:", [num.decode() for num in sorted_numbers])
353
354
# Sort in descending order
355
sorted_desc = client.sort('numbers', desc=True)
356
print("Descending:", [num.decode() for num in sorted_desc])
357
358
# Sort alphabetically
359
client.lpush('words', 'zebra', 'apple', 'banana', 'cherry')
360
sorted_alpha = client.sort('words', alpha=True)
361
print("Sorted words:", [word.decode() for word in sorted_alpha])
362
363
# Sort with limit
364
limited_sort = client.sort('numbers', start=0, num=3)
365
print("Top 3:", [num.decode() for num in limited_sort])
366
367
# Sort and store result
368
client.sort('numbers', store='sorted_numbers')
369
stored_result = client.lrange('sorted_numbers', 0, -1)
370
print("Stored result:", [num.decode() for num in stored_result])
371
```
372
373
### Advanced Sorting with External Keys
374
375
```python
376
import fakeredis
377
378
client = fakeredis.FakeRedis()
379
380
# Setup data for advanced sorting
381
users = ['user:1', 'user:2', 'user:3']
382
client.lpush('users', *users)
383
384
# Set up external sort keys (scores)
385
client.set('score:user:1', '85')
386
client.set('score:user:2', '92')
387
client.set('score:user:3', '78')
388
389
# Set up data to retrieve
390
client.set('name:user:1', 'Alice')
391
client.set('name:user:2', 'Bob')
392
client.set('name:user:3', 'Charlie')
393
394
# Sort users by their scores
395
sorted_by_score = client.sort('users', by='score:*')
396
print("Users sorted by score:", [user.decode() for user in sorted_by_score])
397
398
# Sort and get additional data
399
sorted_with_names = client.sort('users', by='score:*', get=['name:*', 'score:*'])
400
print("Sorted with names and scores:")
401
for i in range(0, len(sorted_with_names), 2):
402
name = sorted_with_names[i].decode()
403
score = sorted_with_names[i + 1].decode()
404
print(f" {name}: {score}")
405
```
406
407
### Object Information and Memory Usage
408
409
```python
410
import fakeredis
411
412
client = fakeredis.FakeRedis()
413
414
# Create various data structures
415
client.set('simple_string', 'hello world')
416
client.hset('user_hash', 'name', 'Alice', 'age', '30', 'email', 'alice@example.com')
417
client.lpush('number_list', *[str(i) for i in range(100)])
418
419
# Get object information (encoding, idle time, etc.)
420
try:
421
encoding = client.object('encoding', 'simple_string')
422
print(f"String encoding: {encoding}")
423
except:
424
print("Object command not fully supported in this Redis version")
425
426
# Get memory usage (Redis 4.0+)
427
try:
428
string_memory = client.memory_usage('simple_string')
429
hash_memory = client.memory_usage('user_hash')
430
list_memory = client.memory_usage('number_list')
431
432
print(f"Memory usage:")
433
print(f" String: {string_memory} bytes")
434
print(f" Hash: {hash_memory} bytes")
435
print(f" List: {list_memory} bytes")
436
except:
437
print("Memory usage command not available")
438
```
439
440
### Serialization and Backup
441
442
```python
443
import fakeredis
444
445
client = fakeredis.FakeRedis()
446
447
# Create some data
448
client.set('backup_test', 'important_data')
449
client.hset('user_profile', 'name', 'Alice', 'age', '30')
450
client.lpush('activity_log', 'login', 'view_page', 'logout')
451
452
# Dump key data for backup
453
string_dump = client.dump('backup_test')
454
hash_dump = client.dump('user_profile')
455
list_dump = client.dump('activity_log')
456
457
print(f"Dump sizes: string={len(string_dump)}, hash={len(hash_dump)}, list={len(list_dump)}")
458
459
# Delete original keys
460
client.delete('backup_test', 'user_profile', 'activity_log')
461
462
# Restore from dumps
463
if string_dump:
464
client.restore('backup_test_restored', 0, string_dump)
465
if hash_dump:
466
client.restore('user_profile_restored', 0, hash_dump)
467
if list_dump:
468
client.restore('activity_log_restored', 0, list_dump)
469
470
# Verify restoration
471
restored_string = client.get('backup_test_restored')
472
restored_hash = client.hgetall('user_profile_restored')
473
restored_list = client.lrange('activity_log_restored', 0, -1)
474
475
print(f"Restored string: {restored_string.decode()}")
476
print(f"Restored hash: {restored_hash}")
477
print(f"Restored list: {[item.decode() for item in restored_list]}")
478
```
479
480
### Pattern: Key Expiration Manager
481
482
```python
483
import fakeredis
484
import time
485
486
class ExpirationManager:
487
def __init__(self, client):
488
self.client = client
489
490
def set_with_expiry(self, key, value, seconds):
491
"""Set key with expiration"""
492
self.client.set(key, value)
493
return self.client.expire(key, seconds)
494
495
def extend_expiry(self, key, additional_seconds):
496
"""Extend existing expiration"""
497
current_ttl = self.client.ttl(key)
498
if current_ttl > 0:
499
return self.client.expire(key, current_ttl + additional_seconds)
500
return False
501
502
def get_expiring_keys(self, pattern='*', threshold_seconds=60):
503
"""Find keys expiring within threshold"""
504
expiring_keys = []
505
for key in self.client.scan_iter(match=pattern):
506
ttl = self.client.ttl(key.decode())
507
if 0 < ttl <= threshold_seconds:
508
expiring_keys.append((key.decode(), ttl))
509
return expiring_keys
510
511
def refresh_if_expiring(self, key, threshold=60, extension=300):
512
"""Refresh key expiration if it's expiring soon"""
513
ttl = self.client.ttl(key)
514
if 0 < ttl <= threshold:
515
self.client.expire(key, extension)
516
return True
517
return False
518
519
# Usage
520
client = fakeredis.FakeRedis()
521
exp_manager = ExpirationManager(client)
522
523
# Set keys with different expiration times
524
exp_manager.set_with_expiry('session:user1', 'session_data', 30)
525
exp_manager.set_with_expiry('cache:page1', 'cached_content', 300)
526
exp_manager.set_with_expiry('temp:file1', 'temp_data', 10)
527
528
# Find keys expiring soon
529
expiring = exp_manager.get_expiring_keys(threshold_seconds=120)
530
print("Keys expiring within 2 minutes:")
531
for key, ttl in expiring:
532
print(f" {key}: {ttl} seconds")
533
534
# Extend session expiry
535
extended = exp_manager.extend_expiry('session:user1', 300)
536
print(f"Extended session expiry: {extended}")
537
```
538
539
### Pattern: Key Namespace Manager
540
541
```python
542
import fakeredis
543
544
class NamespaceManager:
545
def __init__(self, client, namespace):
546
self.client = client
547
self.namespace = namespace
548
self.separator = ':'
549
550
def _key(self, key):
551
"""Add namespace prefix to key"""
552
return f"{self.namespace}{self.separator}{key}"
553
554
def set(self, key, value, **kwargs):
555
"""Set value in namespace"""
556
return self.client.set(self._key(key), value, **kwargs)
557
558
def get(self, key):
559
"""Get value from namespace"""
560
return self.client.get(self._key(key))
561
562
def delete(self, *keys):
563
"""Delete keys from namespace"""
564
namespaced_keys = [self._key(key) for key in keys]
565
return self.client.delete(*namespaced_keys)
566
567
def exists(self, key):
568
"""Check if key exists in namespace"""
569
return self.client.exists(self._key(key))
570
571
def keys(self, pattern='*'):
572
"""Get all keys in namespace matching pattern"""
573
full_pattern = f"{self.namespace}{self.separator}{pattern}"
574
keys = self.client.keys(full_pattern)
575
# Remove namespace prefix from results
576
prefix_len = len(self.namespace) + len(self.separator)
577
return [key[prefix_len:].decode() for key in keys]
578
579
def clear_namespace(self):
580
"""Delete all keys in this namespace"""
581
pattern = f"{self.namespace}{self.separator}*"
582
keys = self.client.keys(pattern)
583
if keys:
584
return self.client.delete(*keys)
585
return 0
586
587
def scan_iter(self, pattern='*'):
588
"""Iterate over keys in namespace"""
589
full_pattern = f"{self.namespace}{self.separator}{pattern}"
590
prefix_len = len(self.namespace) + len(self.separator)
591
592
for key in self.client.scan_iter(match=full_pattern):
593
yield key[prefix_len:].decode()
594
595
# Usage
596
client = fakeredis.FakeRedis()
597
598
# Create namespace managers for different applications
599
user_cache = NamespaceManager(client, 'user_cache')
600
session_store = NamespaceManager(client, 'sessions')
601
config_store = NamespaceManager(client, 'config')
602
603
# Use namespaced operations
604
user_cache.set('user:123', 'user_data')
605
session_store.set('sess_abc', 'session_data')
606
config_store.set('debug_mode', 'true')
607
608
# Keys are automatically namespaced
609
print("User cache keys:", user_cache.keys())
610
print("Session keys:", session_store.keys())
611
print("Config keys:", config_store.keys())
612
613
# Check actual keys in Redis
614
all_keys = client.keys('*')
615
print("All keys in Redis:", [key.decode() for key in all_keys])
616
617
# Clear specific namespace
618
cleared = user_cache.clear_namespace()
619
print(f"Cleared {cleared} keys from user_cache namespace")
620
```