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,654 @@
1
+ """Redis string 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 Optional
14
+
15
+ from ...tracing._context import active_ctx_bytes
16
+ from ._base import CommandInterface, TypedCommand
17
+ from ._values import U, T, Value, encode, decode, decode_optional
18
+ from typing import overload, Literal
19
+
20
+
21
+ class _GetCommand(TypedCommand[T]):
22
+ """A callable GET command with selectable value decoding."""
23
+
24
+ def __getitem__(self, value_type: type[U]) -> _GetCommand[U]:
25
+ """Select the value type for this command.
26
+
27
+ Use get[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 _GetCommand(self._get_handle, value_type)
40
+
41
+ async def __call__(self, key: str) -> Optional[T]:
42
+ """Return the string value stored at a key.
43
+
44
+ Args:
45
+ key: The database key, without an Encore key prefix.
46
+
47
+ Returns:
48
+ The decoded value, or None if the key does not exist.
49
+
50
+ Raises:
51
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
52
+ argument is str.
53
+ ValueError: A stored value cannot be parsed as int or float.
54
+ EncoreError: Redis rejects the command or the request fails.
55
+ """
56
+ result = await self._get_handle().string_get(key, source=active_ctx_bytes())
57
+ return decode_optional(result, self._value_type)
58
+
59
+
60
+ class _GetrangeCommand(TypedCommand[T]):
61
+ """A callable GETRANGE command with selectable value decoding."""
62
+
63
+ def __getitem__(self, value_type: type[U]) -> _GetrangeCommand[U]:
64
+ """Select the value type for this command.
65
+
66
+ Use getrange[T](...) to decode stored values as T. Selecting a type does
67
+ not open a connection or change the decoder of an existing command.
68
+
69
+ Args:
70
+ value_type: bytes, str, int, float, or a class implementing
71
+ RedisValue.
72
+
73
+ Returns:
74
+ An independent command with the same arguments and the selected
75
+ decoder. Keys and other command metadata retain their existing
76
+ types.
77
+ """
78
+ return _GetrangeCommand(self._get_handle, value_type)
79
+
80
+ async def __call__(self, key: str, start: int, end: int) -> T:
81
+ """Return a range of bytes from a string.
82
+
83
+ Args:
84
+ key: The database key, without an Encore key prefix.
85
+ start: The inclusive starting index; negative values count from the
86
+ end.
87
+ end: The inclusive ending index; negative values count from the end.
88
+
89
+ Returns:
90
+ The selected bytes decoded using the command's type argument.
91
+ Missing keys yield an empty byte range before decoding. Indices
92
+ always refer to bytes.
93
+
94
+ Raises:
95
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
96
+ argument is str.
97
+ ValueError: A stored value cannot be parsed as int or float.
98
+ EncoreError: Redis rejects the command or the request fails.
99
+ """
100
+ result = await self._get_handle().string_getrange(
101
+ key, start, end, source=active_ctx_bytes()
102
+ )
103
+ return decode(result, self._value_type)
104
+
105
+
106
+ class _MgetCommand(TypedCommand[T]):
107
+ """A callable MGET command with selectable value decoding."""
108
+
109
+ def __getitem__(self, value_type: type[U]) -> _MgetCommand[U]:
110
+ """Select the value type for this command.
111
+
112
+ Use mget[T](...) to decode stored values as T. Selecting a type does not
113
+ open a connection or change the decoder of an existing command.
114
+
115
+ Args:
116
+ value_type: bytes, str, int, float, or a class implementing
117
+ RedisValue.
118
+
119
+ Returns:
120
+ An independent command with the same arguments and the selected
121
+ decoder. Keys and other command metadata retain their existing
122
+ types.
123
+ """
124
+ return _MgetCommand(self._get_handle, value_type)
125
+
126
+ async def __call__(self, key: str, *keys: str) -> list[Optional[T]]:
127
+ """Return string values in the requested key order.
128
+
129
+ Args:
130
+ key: The first database key, without an Encore prefix.
131
+ *keys: Additional database keys, without Encore prefixes.
132
+
133
+ Returns:
134
+ One value per key, with None for missing keys or non-string values.
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
+ keys = (key, *keys)
143
+ result = await self._get_handle().string_mget(keys, source=active_ctx_bytes())
144
+ return [decode_optional(value, self._value_type) for value in result]
145
+
146
+
147
+ class _GetdelCommand(TypedCommand[T]):
148
+ """A callable GETDEL command with selectable value decoding."""
149
+
150
+ def __getitem__(self, value_type: type[U]) -> _GetdelCommand[U]:
151
+ """Select the value type for this command.
152
+
153
+ Use getdel[T](...) to decode stored values as T. Selecting a type does
154
+ not open a connection or change the decoder of an existing command.
155
+
156
+ Args:
157
+ value_type: bytes, str, int, float, or a class implementing
158
+ RedisValue.
159
+
160
+ Returns:
161
+ An independent command with the same arguments and the selected
162
+ decoder. Keys and other command metadata retain their existing
163
+ types.
164
+ """
165
+ return _GetdelCommand(self._get_handle, value_type)
166
+
167
+ async def __call__(self, key: str) -> Optional[T]:
168
+ """Return a string value and delete its key atomically.
169
+
170
+ Redis executes the command before its result is decoded. A decoding
171
+ error does not undo the command's effects.
172
+
173
+ Args:
174
+ key: The database key, without an Encore key prefix.
175
+
176
+ Returns:
177
+ The decoded previous value, or None if the key does not exist.
178
+
179
+ Raises:
180
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
181
+ argument is str.
182
+ ValueError: A stored value cannot be parsed as int or float.
183
+ EncoreError: Redis rejects the command or the request fails.
184
+ """
185
+ result = await self._get_handle().string_getdel(key, source=active_ctx_bytes())
186
+ return decode_optional(result, self._value_type)
187
+
188
+
189
+ class _GetexCommand(TypedCommand[T]):
190
+ """A callable GETEX command with selectable value decoding."""
191
+
192
+ def __getitem__(self, value_type: type[U]) -> _GetexCommand[U]:
193
+ """Select the value type for this command.
194
+
195
+ Use getex[T](...) to decode stored values as T. Selecting a type does
196
+ not open a connection or change the decoder of an existing command.
197
+
198
+ Args:
199
+ value_type: bytes, str, int, float, or a class implementing
200
+ RedisValue.
201
+
202
+ Returns:
203
+ An independent command with the same arguments and the selected
204
+ decoder. Keys and other command metadata retain their existing
205
+ types.
206
+ """
207
+ return _GetexCommand(self._get_handle, value_type)
208
+
209
+ async def __call__(
210
+ self,
211
+ key: str,
212
+ *,
213
+ ex: int | None = None,
214
+ px: int | None = None,
215
+ exat: int | None = None,
216
+ pxat: int | None = None,
217
+ persist: bool = False,
218
+ ) -> Optional[T]:
219
+ """Return a string value and optionally change its expiry.
220
+
221
+ With no expiry option, the current expiration is unchanged.
222
+
223
+ Redis executes the command before its result is decoded. A decoding
224
+ error does not undo the command's effects.
225
+
226
+ Args:
227
+ key: The database key, without an Encore key prefix.
228
+ ex: The lifetime in seconds; mutually exclusive with other expiry
229
+ options.
230
+ px: The lifetime in milliseconds; mutually exclusive with other
231
+ expiry options.
232
+ exat: The expiration time in Unix seconds; mutually exclusive with
233
+ other expiry options.
234
+ pxat: The expiration time in Unix milliseconds; mutually exclusive
235
+ with other expiry options.
236
+ persist: Whether to remove the expiry; mutually exclusive with
237
+ expiry options.
238
+
239
+ Returns:
240
+ The decoded value, or None if the key does not exist.
241
+
242
+ Raises:
243
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
244
+ argument is str.
245
+ ValueError: A stored value cannot be parsed as int or float.
246
+ EncoreError: Redis rejects the command or the request fails.
247
+ """
248
+ result = await self._get_handle().string_getex(
249
+ key,
250
+ ex=ex,
251
+ px=px,
252
+ exat=exat,
253
+ pxat=pxat,
254
+ persist=persist,
255
+ source=active_ctx_bytes(),
256
+ )
257
+ return decode_optional(result, self._value_type)
258
+
259
+
260
+ class _SetCommand(TypedCommand[T]):
261
+ """A callable SET command with selectable value decoding."""
262
+
263
+ def __getitem__(self, value_type: type[U]) -> _SetCommand[U]:
264
+ """Select the value type for this command.
265
+
266
+ Use set[T](...) to decode stored values as T. Selecting a type does not
267
+ open a connection or change the decoder of an existing command.
268
+
269
+ Args:
270
+ value_type: bytes, str, int, float, or a class implementing
271
+ RedisValue.
272
+
273
+ Returns:
274
+ An independent command with the same arguments and the selected
275
+ decoder. Keys and other command metadata retain their existing
276
+ types.
277
+ """
278
+ return _SetCommand(self._get_handle, value_type)
279
+
280
+ @overload
281
+ async def __call__(
282
+ self,
283
+ key: str,
284
+ value: Value,
285
+ *,
286
+ ex: int | None = None,
287
+ px: int | None = None,
288
+ exat: int | None = None,
289
+ pxat: int | None = None,
290
+ keepttl: bool = False,
291
+ nx: bool = False,
292
+ xx: bool = False,
293
+ get: Literal[True],
294
+ ) -> Optional[T]: ...
295
+
296
+ @overload
297
+ async def __call__(
298
+ self,
299
+ key: str,
300
+ value: Value,
301
+ *,
302
+ ex: int | None = None,
303
+ px: int | None = None,
304
+ exat: int | None = None,
305
+ pxat: int | None = None,
306
+ keepttl: bool = False,
307
+ nx: bool = False,
308
+ xx: bool = False,
309
+ get: bool = False,
310
+ ) -> T | bytes | None: ...
311
+
312
+ async def __call__(
313
+ self,
314
+ key: str,
315
+ value: Value,
316
+ *,
317
+ ex: int | None = None,
318
+ px: int | None = None,
319
+ exat: int | None = None,
320
+ pxat: int | None = None,
321
+ keepttl: bool = False,
322
+ nx: bool = False,
323
+ xx: bool = False,
324
+ get: bool = False,
325
+ ) -> T | bytes | None:
326
+ """Set a string value, optionally checking existence or setting expiry.
327
+
328
+ Without an expiry option or keepttl=True, a successful write removes any
329
+ existing expiry. A non-bytes type argument requires get=True;
330
+ conditional-write status replies remain bytes.
331
+
332
+ Redis executes the command before its result is decoded. A decoding
333
+ error does not undo the command's effects.
334
+
335
+ Args:
336
+ key: The database key, without an Encore key prefix.
337
+ value: The value to encode and store.
338
+ ex: The lifetime in seconds; mutually exclusive with other expiry
339
+ options.
340
+ px: The lifetime in milliseconds; mutually exclusive with other
341
+ expiry options.
342
+ exat: The expiration time in Unix seconds; mutually exclusive with
343
+ other expiry options.
344
+ pxat: The expiration time in Unix milliseconds; mutually exclusive
345
+ with other expiry options.
346
+ keepttl: Whether to retain the existing expiry; mutually exclusive
347
+ with explicit expiry options.
348
+ nx: Only set the value if the key is missing; incompatible with xx.
349
+ xx: Only set the value if the key exists; incompatible with nx.
350
+ get: Whether to return the previous string value.
351
+
352
+ Returns:
353
+ With get=True, the previous string value or None if missing, even
354
+ when an existence condition prevents the write. Otherwise, b"OK" for
355
+ a successful conditional write, None for a failed condition, and
356
+ None for an unconditional write.
357
+
358
+ Raises:
359
+ UnicodeDecodeError: A value is not valid UTF-8 when the type
360
+ argument is str.
361
+ ValueError: A stored value cannot be parsed as int or float.
362
+ EncoreError: Redis rejects the command or the request fails.
363
+ """
364
+ if self._value_type is not bytes and not get:
365
+ raise ValueError("A non-bytes type argument requires get=True for SET")
366
+ result = await self._get_handle().string_set(
367
+ key,
368
+ encode(value),
369
+ ex=ex,
370
+ px=px,
371
+ exat=exat,
372
+ pxat=pxat,
373
+ keepttl=keepttl,
374
+ nx=nx,
375
+ xx=xx,
376
+ get=get,
377
+ source=active_ctx_bytes(),
378
+ )
379
+ return decode_optional(result, self._value_type) if get else result
380
+
381
+
382
+ class ReadOnlyInterface(CommandInterface):
383
+ """Commands available through a read-only database handle."""
384
+
385
+ @property
386
+ def get(self) -> _GetCommand[bytes]:
387
+ """The callable GET command.
388
+
389
+ Use get[T](...) to select the decoded value type. Plain calls keep
390
+ stored values as bytes; keys and command metadata are unchanged.
391
+ """
392
+ return _GetCommand(self._get_handle, bytes)
393
+
394
+ @property
395
+ def getrange(self) -> _GetrangeCommand[bytes]:
396
+ """The callable GETRANGE command.
397
+
398
+ Use getrange[T](...) to select the decoded value type. Plain calls keep
399
+ stored values as bytes; keys and command metadata are unchanged.
400
+ """
401
+ return _GetrangeCommand(self._get_handle, bytes)
402
+
403
+ @property
404
+ def mget(self) -> _MgetCommand[bytes]:
405
+ """The callable MGET command.
406
+
407
+ Use mget[T](...) to select the decoded value type. Plain calls keep
408
+ stored values as bytes; keys and command metadata are unchanged.
409
+ """
410
+ return _MgetCommand(self._get_handle, bytes)
411
+
412
+ async def strlen(self, key: str) -> int:
413
+ """Return the length of a stored string in bytes.
414
+
415
+ Args:
416
+ key: The database key, without an Encore key prefix.
417
+
418
+ Returns:
419
+ The byte length, or zero if the key does not exist.
420
+
421
+ Raises:
422
+ EncoreError: Redis rejects the command or the request fails.
423
+ """
424
+ return await self._get_handle().string_strlen(key, source=active_ctx_bytes())
425
+
426
+
427
+ class Interface(ReadOnlyInterface):
428
+ """Read and write commands."""
429
+
430
+ async def append(self, key: str, value: Value) -> int:
431
+ """Append bytes to a string, creating it if needed.
432
+
433
+ Args:
434
+ key: The database key, without an Encore key prefix.
435
+ value: The value to encode and store.
436
+
437
+ Returns:
438
+ The resulting string length in bytes.
439
+
440
+ Raises:
441
+ EncoreError: Redis rejects the command or the request fails.
442
+ """
443
+ return await self._get_handle().string_append(
444
+ key, encode(value), source=active_ctx_bytes()
445
+ )
446
+
447
+ async def decr(self, key: str) -> int:
448
+ """Subtract one from an integer string, starting from zero if missing.
449
+
450
+ Args:
451
+ key: The database key, without an Encore key prefix.
452
+
453
+ Returns:
454
+ The integer value after the decrement.
455
+
456
+ Raises:
457
+ EncoreError: Redis rejects the command or the request fails.
458
+ """
459
+ return await self._get_handle().string_decr(key, source=active_ctx_bytes())
460
+
461
+ async def decrby(self, key: str, amount: int) -> int:
462
+ """Subtract an amount from an integer string.
463
+
464
+ Args:
465
+ key: The database key, without an Encore key prefix.
466
+ amount: The amount to subtract; negative values add.
467
+
468
+ Returns:
469
+ The integer value after the decrement; a missing key starts at zero.
470
+
471
+ Raises:
472
+ EncoreError: Redis rejects the command or the request fails.
473
+ """
474
+ return await self._get_handle().string_decrby(
475
+ key, amount, source=active_ctx_bytes()
476
+ )
477
+
478
+ @property
479
+ def getdel(self) -> _GetdelCommand[bytes]:
480
+ """The callable GETDEL command.
481
+
482
+ Use getdel[T](...) to select the decoded value type. Plain calls keep
483
+ stored values as bytes; keys and command metadata are unchanged.
484
+ """
485
+ return _GetdelCommand(self._get_handle, bytes)
486
+
487
+ @property
488
+ def getex(self) -> _GetexCommand[bytes]:
489
+ """The callable GETEX command.
490
+
491
+ Use getex[T](...) to select the decoded value type. Plain calls keep
492
+ stored values as bytes; keys and command metadata are unchanged.
493
+ """
494
+ return _GetexCommand(self._get_handle, bytes)
495
+
496
+ async def incr(self, key: str) -> int:
497
+ """Add one to an integer string, starting from zero if missing.
498
+
499
+ Args:
500
+ key: The database key, without an Encore key prefix.
501
+
502
+ Returns:
503
+ The integer value after the increment.
504
+
505
+ Raises:
506
+ EncoreError: Redis rejects the command or the request fails.
507
+ """
508
+ return await self._get_handle().string_incr(key, source=active_ctx_bytes())
509
+
510
+ async def incrby(self, key: str, amount: int) -> int:
511
+ """Add an amount to an integer string.
512
+
513
+ Args:
514
+ key: The database key, without an Encore key prefix.
515
+ amount: The amount to add; negative values subtract.
516
+
517
+ Returns:
518
+ The integer value after the increment; a missing key starts at zero.
519
+
520
+ Raises:
521
+ EncoreError: Redis rejects the command or the request fails.
522
+ """
523
+ return await self._get_handle().string_incrby(
524
+ key, amount, source=active_ctx_bytes()
525
+ )
526
+
527
+ async def incrbyfloat(self, key: str, amount: float) -> float:
528
+ """Add an amount to a numeric string.
529
+
530
+ Args:
531
+ key: The database key, without an Encore key prefix.
532
+ amount: The amount to add; negative values subtract.
533
+
534
+ Returns:
535
+ The numeric value after the increment; a missing key starts at zero.
536
+
537
+ Raises:
538
+ EncoreError: Redis rejects the command or the request fails.
539
+ """
540
+ return await self._get_handle().string_incrbyfloat(
541
+ key, amount, source=active_ctx_bytes()
542
+ )
543
+
544
+ async def mset(self, item: tuple[str, Value], *items: tuple[str, Value]) -> None:
545
+ """Set multiple string values atomically, replacing existing values.
546
+
547
+ Args:
548
+ item: The first (key, value) pair.
549
+ *items: Additional tuples of the same shape, in order.
550
+
551
+ Raises:
552
+ EncoreError: Redis rejects the command or the request fails.
553
+ """
554
+ items = (item, *items)
555
+ return await self._get_handle().string_mset(
556
+ [(field, encode(value)) for field, value in items],
557
+ source=active_ctx_bytes(),
558
+ )
559
+
560
+ async def msetnx(self, item: tuple[str, Value], *items: tuple[str, Value]) -> bool:
561
+ """Set multiple string values only if none of the keys exist.
562
+
563
+ Args:
564
+ item: The first (key, value) pair.
565
+ *items: Additional tuples of the same shape, in order.
566
+
567
+ Returns:
568
+ True if all values were set; False if any key exists and nothing
569
+ changed.
570
+
571
+ Raises:
572
+ EncoreError: Redis rejects the command or the request fails.
573
+ """
574
+ items = (item, *items)
575
+ return await self._get_handle().string_msetnx(
576
+ [(field, encode(value)) for field, value in items],
577
+ source=active_ctx_bytes(),
578
+ )
579
+
580
+ async def psetex(self, key: str, milliseconds: int, value: Value) -> None:
581
+ """Set a string value with a lifetime in milliseconds.
582
+
583
+ Args:
584
+ key: The database key, without an Encore key prefix.
585
+ milliseconds: The positive lifetime in milliseconds.
586
+ value: The value to encode and store.
587
+
588
+ Raises:
589
+ EncoreError: Redis rejects the command or the request fails.
590
+ """
591
+ return await self._get_handle().string_psetex(
592
+ key, milliseconds, encode(value), source=active_ctx_bytes()
593
+ )
594
+
595
+ @property
596
+ def set(self) -> _SetCommand[bytes]:
597
+ """The callable SET command.
598
+
599
+ Use set[T](...) to select the decoded value type. Plain calls keep
600
+ stored values as bytes; keys and command metadata are unchanged.
601
+ Selecting a non-bytes type requires get=True and decodes the previous
602
+ value.
603
+ """
604
+ return _SetCommand(self._get_handle, bytes)
605
+
606
+ async def setex(self, key: str, seconds: int, value: Value) -> None:
607
+ """Set a string value with a lifetime in seconds.
608
+
609
+ Args:
610
+ key: The database key, without an Encore key prefix.
611
+ seconds: The positive lifetime in seconds.
612
+ value: The value to encode and store.
613
+
614
+ Raises:
615
+ EncoreError: Redis rejects the command or the request fails.
616
+ """
617
+ return await self._get_handle().string_setex(
618
+ key, seconds, encode(value), source=active_ctx_bytes()
619
+ )
620
+
621
+ async def setnx(self, key: str, value: Value) -> bool:
622
+ """Set a string value only if the key does not exist.
623
+
624
+ Args:
625
+ key: The database key, without an Encore key prefix.
626
+ value: The value to encode and store.
627
+
628
+ Returns:
629
+ True if the value was set; False if the key already exists.
630
+
631
+ Raises:
632
+ EncoreError: Redis rejects the command or the request fails.
633
+ """
634
+ return await self._get_handle().string_setnx(
635
+ key, encode(value), source=active_ctx_bytes()
636
+ )
637
+
638
+ async def setrange(self, key: str, offset: int, value: Value) -> int:
639
+ """Overwrite bytes starting at an offset, padding gaps with zero bytes.
640
+
641
+ Args:
642
+ key: The database key, without an Encore key prefix.
643
+ offset: The nonnegative byte offset at which to begin writing.
644
+ value: The value to encode and store.
645
+
646
+ Returns:
647
+ The resulting string length in bytes.
648
+
649
+ Raises:
650
+ EncoreError: Redis rejects the command or the request fails.
651
+ """
652
+ return await self._get_handle().string_setrange(
653
+ key, offset, encode(value), source=active_ctx_bytes()
654
+ )
@@ -0,0 +1,19 @@
1
+ """OpenTelemetry tracing recorded by the Encore runtime.
2
+
3
+ Importing encore installs the tracer provider and W3C propagator as the
4
+ OpenTelemetry globals.
5
+
6
+ Typical usage example:
7
+
8
+ from opentelemetry import trace
9
+
10
+ tracer = trace.get_tracer(__name__)
11
+
12
+ async def get_user(user_id: int):
13
+ with tracer.start_as_current_span("load user"):
14
+ return await db.query("SELECT * FROM users WHERE id = $1", user_id).one()
15
+
16
+ HTTP and framework tracing comes from the standard
17
+ ``opentelemetry-instrumentation-*`` packages, e.g.
18
+ ``FastAPIInstrumentor().instrument_app(app)``.
19
+ """
@@ -0,0 +1,27 @@
1
+ """Span contexts as the runtime's 25-byte buffers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from opentelemetry import context as context_api
6
+ from opentelemetry import trace
7
+
8
+ from ._encode import ctx_bytes
9
+ from ._span import Span
10
+
11
+
12
+ def span_ctx_bytes(span: trace.Span) -> bytes | None:
13
+ """The 25-byte context of ``span``; ``None`` when invalid."""
14
+ if isinstance(span, Span):
15
+ return span.ctx_bytes
16
+ sc = span.get_span_context()
17
+ return ctx_bytes(sc) if sc.is_valid else None
18
+
19
+
20
+ def active_ctx_bytes(context: context_api.Context | None = None) -> bytes | None:
21
+ """Return the active span context as 25 bytes, or None if invalid.
22
+
23
+ Args:
24
+ context: The OpenTelemetry context to inspect, or None to use the
25
+ current context.
26
+ """
27
+ return span_ctx_bytes(trace.get_current_span(context))