encore-dev 2.0.0a7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. encore/__init__.py +43 -0
  2. encore/cron/__init__.py +50 -0
  3. encore/internal/__init__.py +1 -0
  4. encore/internal/_loader.py +79 -0
  5. encore/internal/_native.pyi +734 -0
  6. encore/internal/lazy.py +35 -0
  7. encore/internal/runtime.py +133 -0
  8. encore/internal/startup.py +24 -0
  9. encore/logs/__init__.py +19 -0
  10. encore/logs/_console.py +155 -0
  11. encore/logs/_runtime.py +56 -0
  12. encore/meta/__init__.py +228 -0
  13. encore/metrics/__init__.py +390 -0
  14. encore/pubsub/__init__.py +425 -0
  15. encore/py.typed +0 -0
  16. encore/secrets/__init__.py +139 -0
  17. encore/shutdown/__init__.py +164 -0
  18. encore/storage/__init__.py +5 -0
  19. encore/storage/objects/__init__.py +396 -0
  20. encore/storage/postgres/__init__.py +737 -0
  21. encore/storage/redis/__init__.py +200 -0
  22. encore/storage/redis/_base.py +42 -0
  23. encore/storage/redis/_responses.py +150 -0
  24. encore/storage/redis/_values.py +189 -0
  25. encore/storage/redis/bitmap.py +142 -0
  26. encore/storage/redis/generic.py +367 -0
  27. encore/storage/redis/geo.py +508 -0
  28. encore/storage/redis/hash.py +504 -0
  29. encore/storage/redis/json.py +614 -0
  30. encore/storage/redis/list.py +511 -0
  31. encore/storage/redis/pubsub.py +276 -0
  32. encore/storage/redis/set.py +570 -0
  33. encore/storage/redis/sorted_set.py +753 -0
  34. encore/storage/redis/stream.py +773 -0
  35. encore/storage/redis/string.py +654 -0
  36. encore/tracing/__init__.py +19 -0
  37. encore/tracing/_context.py +27 -0
  38. encore/tracing/_encode.py +351 -0
  39. encore/tracing/_provider.py +62 -0
  40. encore/tracing/_span.py +226 -0
  41. encore/tracing/_tracer.py +93 -0
  42. encore_dev-2.0.0a7.dist-info/METADATA +791 -0
  43. encore_dev-2.0.0a7.dist-info/RECORD +44 -0
  44. encore_dev-2.0.0a7.dist-info/WHEEL +4 -0
@@ -0,0 +1,504 @@
1
+ """Redis hash commands.
2
+
3
+ Keys are strings without Encore prefixes. Values accept bytes, str, int, float,
4
+ or
5
+ RedisValue implementations; value reads default to bytes. Use command[T](...) to
6
+ decode values as T. Custom encoding and decoding errors propagate to the caller.
7
+ Repeated arguments are variadic. Individual commands document their reply
8
+ shapes and any option-dependent behavior.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import Any, Optional
14
+
15
+ from ...tracing._context import active_ctx_bytes
16
+ from ._base import CommandInterface, TypedCommand
17
+ from ._values import T, Value, encode, decode, decode_optional, U
18
+ from . import _responses
19
+
20
+
21
+ class _HgetCommand(TypedCommand[T]):
22
+ """A callable HGET command with selectable value decoding."""
23
+
24
+ def __getitem__(self, value_type: type[U]) -> _HgetCommand[U]:
25
+ """Select the value type for this command.
26
+
27
+ Use hget[T](...) to decode stored values as T. Selecting a type does not
28
+ open a connection or change the decoder of an existing command.
29
+
30
+ Args:
31
+ value_type: bytes, str, int, float, or a class implementing
32
+ RedisValue.
33
+
34
+ Returns:
35
+ An independent command with the same arguments and the selected
36
+ decoder. Keys and other command metadata retain their existing
37
+ types.
38
+ """
39
+ return _HgetCommand(self._get_handle, value_type)
40
+
41
+ async def __call__(self, key: str, field: str) -> Optional[T]:
42
+ """Return a hash field's value.
43
+
44
+ Args:
45
+ key: The database key, without an Encore key prefix.
46
+ field: The hash field name.
47
+
48
+ Returns:
49
+ The decoded value, or None if the key or field does not exist.
50
+
51
+ Raises:
52
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
53
+ argument is str.
54
+ ValueError: A stored value cannot be parsed as int or float.
55
+ EncoreError: Redis rejects the command or the request fails.
56
+ """
57
+ result = await self._get_handle().hash_hget(
58
+ key, field, source=active_ctx_bytes()
59
+ )
60
+ return decode_optional(result, self._value_type)
61
+
62
+
63
+ class _HgetallCommand(TypedCommand[T]):
64
+ """A callable HGETALL command with selectable value decoding."""
65
+
66
+ def __getitem__(self, value_type: type[U]) -> _HgetallCommand[U]:
67
+ """Select the value type for this command.
68
+
69
+ Use hgetall[T](...) to decode stored values as T. Selecting a type does
70
+ not open a connection or change the decoder of an existing command.
71
+
72
+ Args:
73
+ value_type: bytes, str, int, float, or a class implementing
74
+ RedisValue.
75
+
76
+ Returns:
77
+ An independent command with the same arguments and the selected
78
+ decoder. Keys and other command metadata retain their existing
79
+ types.
80
+ """
81
+ return _HgetallCommand(self._get_handle, value_type)
82
+
83
+ async def __call__(self, key: str) -> dict[bytes, T]:
84
+ """Return all fields and values in a hash.
85
+
86
+ Args:
87
+ key: The database key, without an Encore key prefix.
88
+
89
+ Returns:
90
+ A dictionary of byte field names to decoded values; empty if the key
91
+ is missing.
92
+
93
+ Raises:
94
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
95
+ argument is str.
96
+ ValueError: A stored value cannot be parsed as int or float.
97
+ EncoreError: Redis rejects the command or the request fails.
98
+ """
99
+ result = await self._get_handle().hash_hgetall(key, source=active_ctx_bytes())
100
+ return {
101
+ field: decode(value, self._value_type) for field, value in result.items()
102
+ }
103
+
104
+
105
+ class _HmgetCommand(TypedCommand[T]):
106
+ """A callable HMGET command with selectable value decoding."""
107
+
108
+ def __getitem__(self, value_type: type[U]) -> _HmgetCommand[U]:
109
+ """Select the value type for this command.
110
+
111
+ Use hmget[T](...) to decode stored values as T. Selecting a type does
112
+ not open a connection or change the decoder of an existing command.
113
+
114
+ Args:
115
+ value_type: bytes, str, int, float, or a class implementing
116
+ RedisValue.
117
+
118
+ Returns:
119
+ An independent command with the same arguments and the selected
120
+ decoder. Keys and other command metadata retain their existing
121
+ types.
122
+ """
123
+ return _HmgetCommand(self._get_handle, value_type)
124
+
125
+ async def __call__(self, key: str, field: str, *fields: str) -> list[Optional[T]]:
126
+ """Return hash values in the requested field order.
127
+
128
+ Args:
129
+ key: The database key, without an Encore key prefix.
130
+ field: The first hash field name.
131
+ *fields: Additional hash field names, in order.
132
+
133
+ Returns:
134
+ One value per field, with None for missing fields or a missing key.
135
+
136
+ Raises:
137
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
138
+ argument is str.
139
+ ValueError: A stored value cannot be parsed as int or float.
140
+ EncoreError: Redis rejects the command or the request fails.
141
+ """
142
+ fields = (field, *fields)
143
+ result = await self._get_handle().hash_hmget(
144
+ key, fields, source=active_ctx_bytes()
145
+ )
146
+ return [decode_optional(value, self._value_type) for value in result]
147
+
148
+
149
+ class _HrandfieldCommand(TypedCommand[T]):
150
+ """A callable HRANDFIELD command with selectable value decoding."""
151
+
152
+ def __getitem__(self, value_type: type[U]) -> _HrandfieldCommand[U]:
153
+ """Select the value type for this command.
154
+
155
+ Use hrandfield[T](...) to decode stored values as T. Selecting a type
156
+ does not open a connection or change the decoder of an existing command.
157
+
158
+ Args:
159
+ value_type: bytes, str, int, float, or a class implementing
160
+ RedisValue.
161
+
162
+ Returns:
163
+ An independent command with the same arguments and the selected
164
+ decoder. Keys and other command metadata retain their existing
165
+ types.
166
+ """
167
+ return _HrandfieldCommand(self._get_handle, value_type)
168
+
169
+ async def __call__(
170
+ self, key: str, *, count: int | None = None, withvalues: bool = False
171
+ ) -> Any:
172
+ """Choose random fields from a hash.
173
+
174
+ Args:
175
+ key: The database key, without an Encore key prefix.
176
+ count: Without count, return one random item. A positive count
177
+ selects distinct items; a negative count allows repeats and
178
+ requests abs(count) items.
179
+ withvalues: Whether to include field values; requires count.
180
+
181
+ Returns:
182
+ Without count, a byte field name or None if the key is missing. With
183
+ count, a list of byte field names. With withvalues=True, alternating
184
+ field names and decoded values in RESP2, or nested field/value pairs
185
+ in RESP3. Only values are decoded.
186
+
187
+ Raises:
188
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
189
+ argument is str.
190
+ ValueError: A stored value cannot be parsed as int or float.
191
+ EncoreError: Redis rejects the command or the request fails.
192
+ """
193
+ result = await self._get_handle().hash_hrandfield(
194
+ key, count=count, withvalues=withvalues, source=active_ctx_bytes()
195
+ )
196
+ return _responses.fields(result, self._value_type) if withvalues else result
197
+
198
+
199
+ class _HscanCommand(TypedCommand[T]):
200
+ """A callable HSCAN command with selectable value decoding."""
201
+
202
+ def __getitem__(self, value_type: type[U]) -> _HscanCommand[U]:
203
+ """Select the value type for this command.
204
+
205
+ Use hscan[T](...) to decode stored values as T. Selecting a type does
206
+ not open a connection or change the decoder of an existing command.
207
+
208
+ Args:
209
+ value_type: bytes, str, int, float, or a class implementing
210
+ RedisValue.
211
+
212
+ Returns:
213
+ An independent command with the same arguments and the selected
214
+ decoder. Keys and other command metadata retain their existing
215
+ types.
216
+ """
217
+ return _HscanCommand(self._get_handle, value_type)
218
+
219
+ async def __call__(
220
+ self,
221
+ key: str,
222
+ cursor: int,
223
+ *,
224
+ pattern: str | None = None,
225
+ count: int | None = None,
226
+ ) -> tuple[int, dict[bytes, T]]:
227
+ """Read a batch of hash fields and values using a scan cursor.
228
+
229
+ Continue with the returned cursor until it is zero. Scans may return
230
+ duplicates and do not provide a snapshot while data changes.
231
+
232
+ Args:
233
+ key: The database key, without an Encore key prefix.
234
+ cursor: Zero to start an iteration, or the cursor from the previous
235
+ call.
236
+ pattern: A Redis glob pattern to filter results, or None for no
237
+ filter.
238
+ count: A hint for work per call, not a result limit; None uses the
239
+ server default.
240
+
241
+ Returns:
242
+ A tuple (cursor, fields), where cursor is the next scan cursor and
243
+ fields is a dictionary from byte field names to decoded values. A
244
+ zero cursor ends the iteration; an empty batch does not.
245
+
246
+ Raises:
247
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
248
+ argument is str.
249
+ ValueError: A stored value cannot be parsed as int or float.
250
+ EncoreError: Redis rejects the command or the request fails.
251
+ """
252
+ result = await self._get_handle().hash_hscan(
253
+ key, cursor, pattern=pattern, count=count, source=active_ctx_bytes()
254
+ )
255
+ return (
256
+ result[0],
257
+ {
258
+ field: decode(value, self._value_type)
259
+ for field, value in result[1].items()
260
+ },
261
+ )
262
+
263
+
264
+ class _HvalsCommand(TypedCommand[T]):
265
+ """A callable HVALS command with selectable value decoding."""
266
+
267
+ def __getitem__(self, value_type: type[U]) -> _HvalsCommand[U]:
268
+ """Select the value type for this command.
269
+
270
+ Use hvals[T](...) to decode stored values as T. Selecting a type does
271
+ not open a connection or change the decoder of an existing command.
272
+
273
+ Args:
274
+ value_type: bytes, str, int, float, or a class implementing
275
+ RedisValue.
276
+
277
+ Returns:
278
+ An independent command with the same arguments and the selected
279
+ decoder. Keys and other command metadata retain their existing
280
+ types.
281
+ """
282
+ return _HvalsCommand(self._get_handle, value_type)
283
+
284
+ async def __call__(self, key: str) -> list[T]:
285
+ """Return all values in a hash.
286
+
287
+ Args:
288
+ key: The database key, without an Encore key prefix.
289
+
290
+ Returns:
291
+ Decoded values, in unspecified order; empty if the key is missing.
292
+
293
+ Raises:
294
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
295
+ argument is str.
296
+ ValueError: A stored value cannot be parsed as int or float.
297
+ EncoreError: Redis rejects the command or the request fails.
298
+ """
299
+ result = await self._get_handle().hash_hvals(key, source=active_ctx_bytes())
300
+ return [decode(value, self._value_type) for value in result]
301
+
302
+
303
+ class ReadOnlyInterface(CommandInterface):
304
+ """Commands available through a read-only database handle."""
305
+
306
+ async def hexists(self, key: str, field: str) -> bool:
307
+ """Check whether a hash contains a field.
308
+
309
+ Args:
310
+ key: The database key, without an Encore key prefix.
311
+ field: The hash field name.
312
+
313
+ Returns:
314
+ True if the field exists, otherwise False.
315
+
316
+ Raises:
317
+ EncoreError: Redis rejects the command or the request fails.
318
+ """
319
+ return await self._get_handle().hash_hexists(
320
+ key, field, source=active_ctx_bytes()
321
+ )
322
+
323
+ @property
324
+ def hget(self) -> _HgetCommand[bytes]:
325
+ """The callable HGET command.
326
+
327
+ Use hget[T](...) to select the decoded value type. Plain calls keep
328
+ stored values as bytes; keys and command metadata are unchanged.
329
+ """
330
+ return _HgetCommand(self._get_handle, bytes)
331
+
332
+ @property
333
+ def hgetall(self) -> _HgetallCommand[bytes]:
334
+ """The callable HGETALL command.
335
+
336
+ Use hgetall[T](...) to select the decoded value type. Plain calls keep
337
+ stored values as bytes; keys and command metadata are unchanged.
338
+ """
339
+ return _HgetallCommand(self._get_handle, bytes)
340
+
341
+ async def hkeys(self, key: str) -> list[bytes]:
342
+ """Return all field names in a hash.
343
+
344
+ Args:
345
+ key: The database key, without an Encore key prefix.
346
+
347
+ Returns:
348
+ Field names as bytes, in unspecified order; empty if the key is
349
+ missing.
350
+
351
+ Raises:
352
+ EncoreError: Redis rejects the command or the request fails.
353
+ """
354
+ return await self._get_handle().hash_hkeys(key, source=active_ctx_bytes())
355
+
356
+ async def hlen(self, key: str) -> int:
357
+ """Return the number of fields in a hash.
358
+
359
+ Args:
360
+ key: The database key, without an Encore key prefix.
361
+
362
+ Returns:
363
+ The number of fields, or zero if the key is missing.
364
+
365
+ Raises:
366
+ EncoreError: Redis rejects the command or the request fails.
367
+ """
368
+ return await self._get_handle().hash_hlen(key, source=active_ctx_bytes())
369
+
370
+ @property
371
+ def hmget(self) -> _HmgetCommand[bytes]:
372
+ """The callable HMGET command.
373
+
374
+ Use hmget[T](...) to select the decoded value type. Plain calls keep
375
+ stored values as bytes; keys and command metadata are unchanged.
376
+ """
377
+ return _HmgetCommand(self._get_handle, bytes)
378
+
379
+ @property
380
+ def hrandfield(self) -> _HrandfieldCommand[bytes]:
381
+ """The callable HRANDFIELD command.
382
+
383
+ Use hrandfield[T](...) to select the decoded value type. Plain calls
384
+ keep stored values as bytes; keys and command metadata are unchanged.
385
+ """
386
+ return _HrandfieldCommand(self._get_handle, bytes)
387
+
388
+ @property
389
+ def hscan(self) -> _HscanCommand[bytes]:
390
+ """The callable HSCAN command.
391
+
392
+ Use hscan[T](...) to select the decoded value type. Plain calls keep
393
+ stored values as bytes; keys and command metadata are unchanged.
394
+ """
395
+ return _HscanCommand(self._get_handle, bytes)
396
+
397
+ @property
398
+ def hvals(self) -> _HvalsCommand[bytes]:
399
+ """The callable HVALS command.
400
+
401
+ Use hvals[T](...) to select the decoded value type. Plain calls keep
402
+ stored values as bytes; keys and command metadata are unchanged.
403
+ """
404
+ return _HvalsCommand(self._get_handle, bytes)
405
+
406
+
407
+ class Interface(ReadOnlyInterface):
408
+ """Read and write commands."""
409
+
410
+ async def hdel(self, key: str, field: str, *fields: str) -> int:
411
+ """Delete fields from a hash.
412
+
413
+ Args:
414
+ key: The database key, without an Encore key prefix.
415
+ field: The first hash field name.
416
+ *fields: Additional hash field names, in order.
417
+
418
+ Returns:
419
+ The number of fields removed; missing fields are ignored.
420
+
421
+ Raises:
422
+ EncoreError: Redis rejects the command or the request fails.
423
+ """
424
+ fields = (field, *fields)
425
+ return await self._get_handle().hash_hdel(
426
+ key, fields, source=active_ctx_bytes()
427
+ )
428
+
429
+ async def hincrby(self, key: str, field: str, amount: int) -> int:
430
+ """Add an integer to a hash field, starting from zero if missing.
431
+
432
+ Args:
433
+ key: The database key, without an Encore key prefix.
434
+ field: The hash field name.
435
+ amount: The amount to add; negative values subtract.
436
+
437
+ Returns:
438
+ The integer value after the increment.
439
+
440
+ Raises:
441
+ EncoreError: Redis rejects the command or the request fails.
442
+ """
443
+ return await self._get_handle().hash_hincrby(
444
+ key, field, amount, source=active_ctx_bytes()
445
+ )
446
+
447
+ async def hincrbyfloat(self, key: str, field: str, amount: float) -> float:
448
+ """Add a number to a hash field, starting from zero if missing.
449
+
450
+ Args:
451
+ key: The database key, without an Encore key prefix.
452
+ field: The hash field name.
453
+ amount: The amount to add; negative values subtract.
454
+
455
+ Returns:
456
+ The numeric value after the increment.
457
+
458
+ Raises:
459
+ EncoreError: Redis rejects the command or the request fails.
460
+ """
461
+ return await self._get_handle().hash_hincrbyfloat(
462
+ key, field, amount, source=active_ctx_bytes()
463
+ )
464
+
465
+ async def hset(
466
+ self, key: str, item: tuple[str, Value], *items: tuple[str, Value]
467
+ ) -> int:
468
+ """Set hash fields, replacing existing values.
469
+
470
+ Args:
471
+ key: The database key, without an Encore key prefix.
472
+ item: The first (field name, value) pair.
473
+ *items: Additional tuples of the same shape, in order.
474
+
475
+ Returns:
476
+ The number of newly added fields, excluding updated fields.
477
+
478
+ Raises:
479
+ EncoreError: Redis rejects the command or the request fails.
480
+ """
481
+ items = (item, *items)
482
+ return await self._get_handle().hash_hset(
483
+ key,
484
+ [(field, encode(value)) for field, value in items],
485
+ source=active_ctx_bytes(),
486
+ )
487
+
488
+ async def hsetnx(self, key: str, field: str, value: Value) -> bool:
489
+ """Set a hash field only if it does not already exist.
490
+
491
+ Args:
492
+ key: The database key, without an Encore key prefix.
493
+ field: The hash field name.
494
+ value: The value to encode and store.
495
+
496
+ Returns:
497
+ True if the field was added, otherwise False.
498
+
499
+ Raises:
500
+ EncoreError: Redis rejects the command or the request fails.
501
+ """
502
+ return await self._get_handle().hash_hsetnx(
503
+ key, field, encode(value), source=active_ctx_bytes()
504
+ )