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.
- encore/__init__.py +43 -0
- encore/cron/__init__.py +50 -0
- encore/internal/__init__.py +1 -0
- encore/internal/_loader.py +79 -0
- encore/internal/_native.pyi +734 -0
- encore/internal/lazy.py +35 -0
- encore/internal/runtime.py +133 -0
- encore/internal/startup.py +24 -0
- encore/logs/__init__.py +19 -0
- encore/logs/_console.py +155 -0
- encore/logs/_runtime.py +56 -0
- encore/meta/__init__.py +228 -0
- encore/metrics/__init__.py +390 -0
- encore/pubsub/__init__.py +425 -0
- encore/py.typed +0 -0
- encore/secrets/__init__.py +139 -0
- encore/shutdown/__init__.py +164 -0
- encore/storage/__init__.py +5 -0
- encore/storage/objects/__init__.py +396 -0
- encore/storage/postgres/__init__.py +737 -0
- encore/storage/redis/__init__.py +200 -0
- encore/storage/redis/_base.py +42 -0
- encore/storage/redis/_responses.py +150 -0
- encore/storage/redis/_values.py +189 -0
- encore/storage/redis/bitmap.py +142 -0
- encore/storage/redis/generic.py +367 -0
- encore/storage/redis/geo.py +508 -0
- encore/storage/redis/hash.py +504 -0
- encore/storage/redis/json.py +614 -0
- encore/storage/redis/list.py +511 -0
- encore/storage/redis/pubsub.py +276 -0
- encore/storage/redis/set.py +570 -0
- encore/storage/redis/sorted_set.py +753 -0
- encore/storage/redis/stream.py +773 -0
- encore/storage/redis/string.py +654 -0
- encore/tracing/__init__.py +19 -0
- encore/tracing/_context.py +27 -0
- encore/tracing/_encode.py +351 -0
- encore/tracing/_provider.py +62 -0
- encore/tracing/_span.py +226 -0
- encore/tracing/_tracer.py +93 -0
- encore_dev-2.0.0a7.dist-info/METADATA +791 -0
- encore_dev-2.0.0a7.dist-info/RECORD +44 -0
- 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))
|