soia-client 1.1.4__py3-none-any.whl → 1.1.6__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.
Potentially problematic release.
This version of soia-client might be problematic. Click here for more details.
- soia/_impl/arrays.py +63 -10
- soia/_impl/binary.py +270 -0
- soia/_impl/enums.py +246 -42
- soia/_impl/optionals.py +51 -10
- soia/_impl/primitives.py +181 -25
- soia/_impl/repr.py +1 -1
- soia/_impl/serializer.py +41 -18
- soia/_impl/service.py +1 -3
- soia/_impl/service_client.py +1 -2
- soia/_impl/structs.py +315 -89
- soia/_impl/timestamp.py +4 -5
- soia/_impl/type_adapter.py +38 -4
- soia/_module_initializer.py +1 -2
- {soia_client-1.1.4.dist-info → soia_client-1.1.6.dist-info}/METADATA +1 -1
- soia_client-1.1.6.dist-info/RECORD +28 -0
- soia_client-1.1.4.dist-info/RECORD +0 -27
- {soia_client-1.1.4.dist-info → soia_client-1.1.6.dist-info}/WHEEL +0 -0
- {soia_client-1.1.4.dist-info → soia_client-1.1.6.dist-info}/licenses/LICENSE +0 -0
- {soia_client-1.1.4.dist-info → soia_client-1.1.6.dist-info}/top_level.txt +0 -0
soia/_impl/primitives.py
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
import base64
|
|
2
|
+
import struct
|
|
2
3
|
from collections.abc import Callable
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
from typing import Any, Final, final
|
|
5
6
|
|
|
7
|
+
from soia import _spec, reflection
|
|
8
|
+
from soia._impl.binary import (
|
|
9
|
+
decode_bool,
|
|
10
|
+
decode_float,
|
|
11
|
+
decode_int32,
|
|
12
|
+
decode_int64,
|
|
13
|
+
decode_uint64,
|
|
14
|
+
encode_float32,
|
|
15
|
+
encode_float64,
|
|
16
|
+
encode_int32,
|
|
17
|
+
encode_int64,
|
|
18
|
+
encode_length_prefix,
|
|
19
|
+
encode_uint64,
|
|
20
|
+
)
|
|
6
21
|
from soia._impl.function_maker import Expr, ExprLike
|
|
7
22
|
from soia._impl.timestamp import Timestamp
|
|
8
|
-
from soia._impl.type_adapter import TypeAdapter
|
|
9
|
-
|
|
10
|
-
from soia import _spec, reflection
|
|
23
|
+
from soia._impl.type_adapter import ByteStream, TypeAdapter, T
|
|
11
24
|
|
|
12
25
|
|
|
13
|
-
class AbstractPrimitiveAdapter(TypeAdapter):
|
|
26
|
+
class AbstractPrimitiveAdapter(TypeAdapter[T]):
|
|
14
27
|
@final
|
|
15
28
|
def finalize(
|
|
16
29
|
self,
|
|
@@ -25,8 +38,12 @@ class AbstractPrimitiveAdapter(TypeAdapter):
|
|
|
25
38
|
) -> None:
|
|
26
39
|
pass
|
|
27
40
|
|
|
41
|
+
@final
|
|
42
|
+
def frozen_class_of_struct(self) -> type | None:
|
|
43
|
+
return None
|
|
44
|
+
|
|
28
45
|
|
|
29
|
-
class _BoolAdapter(AbstractPrimitiveAdapter):
|
|
46
|
+
class _BoolAdapter(AbstractPrimitiveAdapter[bool]):
|
|
30
47
|
def default_expr(self) -> ExprLike:
|
|
31
48
|
return "False"
|
|
32
49
|
|
|
@@ -46,9 +63,24 @@ class _BoolAdapter(AbstractPrimitiveAdapter):
|
|
|
46
63
|
else:
|
|
47
64
|
return Expr.join("(1 if ", in_expr, " else 0)")
|
|
48
65
|
|
|
49
|
-
def from_json_expr(
|
|
66
|
+
def from_json_expr(
|
|
67
|
+
self, json_expr: ExprLike, keep_unrecognized_expr: ExprLike
|
|
68
|
+
) -> Expr:
|
|
50
69
|
return Expr.join("(True if ", json_expr, " else False)")
|
|
51
70
|
|
|
71
|
+
@staticmethod
|
|
72
|
+
def encode(
|
|
73
|
+
value: bool,
|
|
74
|
+
buffer: bytearray,
|
|
75
|
+
) -> None:
|
|
76
|
+
buffer.append(1 if value else 0)
|
|
77
|
+
|
|
78
|
+
def encode_fn(self) -> Callable[[bool, bytearray], None]:
|
|
79
|
+
return _BoolAdapter.encode
|
|
80
|
+
|
|
81
|
+
def decode_fn(self) -> Callable[[ByteStream], bool]:
|
|
82
|
+
return decode_bool
|
|
83
|
+
|
|
52
84
|
def get_type(self) -> reflection.Type:
|
|
53
85
|
return reflection.PrimitiveType(
|
|
54
86
|
kind="primitive",
|
|
@@ -56,11 +88,11 @@ class _BoolAdapter(AbstractPrimitiveAdapter):
|
|
|
56
88
|
)
|
|
57
89
|
|
|
58
90
|
|
|
59
|
-
BOOL_ADAPTER: Final[TypeAdapter] = _BoolAdapter()
|
|
91
|
+
BOOL_ADAPTER: Final[TypeAdapter[bool]] = _BoolAdapter()
|
|
60
92
|
|
|
61
93
|
|
|
62
94
|
@dataclass(frozen=True)
|
|
63
|
-
class _AbstractIntAdapter(AbstractPrimitiveAdapter):
|
|
95
|
+
class _AbstractIntAdapter(AbstractPrimitiveAdapter[int]):
|
|
64
96
|
"""Type adapter implementation for int32, int64 and uint64."""
|
|
65
97
|
|
|
66
98
|
def default_expr(self) -> ExprLike:
|
|
@@ -73,7 +105,9 @@ class _AbstractIntAdapter(AbstractPrimitiveAdapter):
|
|
|
73
105
|
def is_not_default_expr(self, arg_expr: ExprLike, attr_expr: ExprLike) -> ExprLike:
|
|
74
106
|
return arg_expr
|
|
75
107
|
|
|
76
|
-
def from_json_expr(
|
|
108
|
+
def from_json_expr(
|
|
109
|
+
self, json_expr: ExprLike, keep_unrecognized_expr: ExprLike
|
|
110
|
+
) -> Expr:
|
|
77
111
|
# Must accept float inputs and string inputs and turn them into ints.
|
|
78
112
|
return Expr.join(
|
|
79
113
|
"(0).__class__(",
|
|
@@ -95,6 +129,12 @@ class _Int32Adapter(_AbstractIntAdapter):
|
|
|
95
129
|
" < 2147483647 else 2147483647)",
|
|
96
130
|
)
|
|
97
131
|
|
|
132
|
+
def encode_fn(self) -> Callable[[int, bytearray], None]:
|
|
133
|
+
return encode_int32
|
|
134
|
+
|
|
135
|
+
def decode_fn(self) -> Callable[[ByteStream], int]:
|
|
136
|
+
return decode_int32
|
|
137
|
+
|
|
98
138
|
def get_type(self) -> reflection.Type:
|
|
99
139
|
return reflection.PrimitiveType(
|
|
100
140
|
kind="primitive",
|
|
@@ -121,6 +161,12 @@ class _Int64Adapter(_AbstractIntAdapter):
|
|
|
121
161
|
def to_json_expr(self, in_expr: ExprLike, readable: bool) -> Expr:
|
|
122
162
|
return Expr.join(Expr.local("int64_to_json", _int64_to_json), "(", in_expr, ")")
|
|
123
163
|
|
|
164
|
+
def encode_fn(self) -> Callable[[int, bytearray], None]:
|
|
165
|
+
return encode_int64
|
|
166
|
+
|
|
167
|
+
def decode_fn(self) -> Callable[[ByteStream], int]:
|
|
168
|
+
return decode_int64
|
|
169
|
+
|
|
124
170
|
def get_type(self) -> reflection.Type:
|
|
125
171
|
return reflection.PrimitiveType(
|
|
126
172
|
kind="primitive",
|
|
@@ -146,6 +192,12 @@ class _Uint64Adapter(_AbstractIntAdapter):
|
|
|
146
192
|
Expr.local("uint64_to_json", _uint64_to_json), "(", in_expr, ")"
|
|
147
193
|
)
|
|
148
194
|
|
|
195
|
+
def encode_fn(self) -> Callable[[int, bytearray], None]:
|
|
196
|
+
return encode_uint64
|
|
197
|
+
|
|
198
|
+
def decode_fn(self) -> Callable[[ByteStream], int]:
|
|
199
|
+
return decode_uint64
|
|
200
|
+
|
|
149
201
|
def get_type(self) -> reflection.Type:
|
|
150
202
|
return reflection.PrimitiveType(
|
|
151
203
|
kind="primitive",
|
|
@@ -153,13 +205,13 @@ class _Uint64Adapter(_AbstractIntAdapter):
|
|
|
153
205
|
)
|
|
154
206
|
|
|
155
207
|
|
|
156
|
-
INT32_ADAPTER: Final[TypeAdapter] = _Int32Adapter()
|
|
157
|
-
INT64_ADAPTER: Final[TypeAdapter] = _Int64Adapter()
|
|
158
|
-
UINT64_ADAPTER: Final[TypeAdapter] = _Uint64Adapter()
|
|
208
|
+
INT32_ADAPTER: Final[TypeAdapter[int]] = _Int32Adapter()
|
|
209
|
+
INT64_ADAPTER: Final[TypeAdapter[int]] = _Int64Adapter()
|
|
210
|
+
UINT64_ADAPTER: Final[TypeAdapter[int]] = _Uint64Adapter()
|
|
159
211
|
|
|
160
212
|
|
|
161
213
|
@dataclass(frozen=True)
|
|
162
|
-
class _AbstractFloatAdapter(AbstractPrimitiveAdapter):
|
|
214
|
+
class _AbstractFloatAdapter(AbstractPrimitiveAdapter[float]):
|
|
163
215
|
"""Type adapter implementation for float32 and float64."""
|
|
164
216
|
|
|
165
217
|
def default_expr(self) -> ExprLike:
|
|
@@ -174,14 +226,22 @@ class _AbstractFloatAdapter(AbstractPrimitiveAdapter):
|
|
|
174
226
|
def to_json_expr(self, in_expr: ExprLike, readable: bool) -> ExprLike:
|
|
175
227
|
return in_expr
|
|
176
228
|
|
|
177
|
-
def from_json_expr(
|
|
229
|
+
def from_json_expr(
|
|
230
|
+
self, json_expr: ExprLike, keep_unrecognized_expr: ExprLike
|
|
231
|
+
) -> Expr:
|
|
178
232
|
return Expr.join("(", json_expr, " + 0.0)")
|
|
179
233
|
|
|
234
|
+
def decode_fn(self) -> Callable[[ByteStream], float]:
|
|
235
|
+
return decode_float
|
|
236
|
+
|
|
180
237
|
|
|
181
238
|
@dataclass(frozen=True)
|
|
182
239
|
class _Float32Adapter(_AbstractFloatAdapter):
|
|
183
240
|
"""Type adapter implementation for float32."""
|
|
184
241
|
|
|
242
|
+
def encode_fn(self) -> Callable[[float, bytearray], None]:
|
|
243
|
+
return encode_float32
|
|
244
|
+
|
|
185
245
|
def get_type(self) -> reflection.Type:
|
|
186
246
|
return reflection.PrimitiveType(
|
|
187
247
|
kind="primitive",
|
|
@@ -191,7 +251,10 @@ class _Float32Adapter(_AbstractFloatAdapter):
|
|
|
191
251
|
|
|
192
252
|
@dataclass(frozen=True)
|
|
193
253
|
class _Float64Adapter(_AbstractFloatAdapter):
|
|
194
|
-
"""Type adapter implementation for
|
|
254
|
+
"""Type adapter implementation for float64."""
|
|
255
|
+
|
|
256
|
+
def encode_fn(self) -> Callable[[float, bytearray], None]:
|
|
257
|
+
return encode_float64
|
|
195
258
|
|
|
196
259
|
def get_type(self) -> reflection.Type:
|
|
197
260
|
return reflection.PrimitiveType(
|
|
@@ -200,11 +263,16 @@ class _Float64Adapter(_AbstractFloatAdapter):
|
|
|
200
263
|
)
|
|
201
264
|
|
|
202
265
|
|
|
203
|
-
FLOAT32_ADAPTER: Final[TypeAdapter] = _Float32Adapter()
|
|
204
|
-
FLOAT64_ADAPTER: Final[TypeAdapter] = _Float64Adapter()
|
|
266
|
+
FLOAT32_ADAPTER: Final[TypeAdapter[float]] = _Float32Adapter()
|
|
267
|
+
FLOAT64_ADAPTER: Final[TypeAdapter[float]] = _Float64Adapter()
|
|
205
268
|
|
|
206
269
|
|
|
207
|
-
|
|
270
|
+
def _clamp_unix_millis(unix_millis: int) -> int:
|
|
271
|
+
"""Clamp unix milliseconds to valid range for JavaScript dates."""
|
|
272
|
+
return max(-8640000000000000, min(unix_millis, 8640000000000000))
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class _TimestampAdapter(AbstractPrimitiveAdapter[Timestamp]):
|
|
208
276
|
def default_expr(self) -> Expr:
|
|
209
277
|
return Expr.local("_EPOCH", Timestamp.EPOCH)
|
|
210
278
|
|
|
@@ -233,10 +301,34 @@ class _TimestampAdapter(AbstractPrimitiveAdapter):
|
|
|
233
301
|
else:
|
|
234
302
|
return Expr.join(in_expr, ".unix_millis")
|
|
235
303
|
|
|
236
|
-
def from_json_expr(
|
|
304
|
+
def from_json_expr(
|
|
305
|
+
self, json_expr: ExprLike, keep_unrecognized_expr: ExprLike
|
|
306
|
+
) -> Expr:
|
|
237
307
|
fn = Expr.local("_timestamp_from_json", _timestamp_from_json)
|
|
238
308
|
return Expr.join(fn, "(", json_expr, ")")
|
|
239
309
|
|
|
310
|
+
@staticmethod
|
|
311
|
+
def encode(
|
|
312
|
+
value: Timestamp,
|
|
313
|
+
buffer: bytearray,
|
|
314
|
+
) -> None:
|
|
315
|
+
unix_millis = _clamp_unix_millis(value.unix_millis)
|
|
316
|
+
if unix_millis == 0:
|
|
317
|
+
buffer.append(0)
|
|
318
|
+
else:
|
|
319
|
+
buffer.append(239)
|
|
320
|
+
buffer.extend(struct.pack("<q", unix_millis))
|
|
321
|
+
|
|
322
|
+
def encode_fn(self) -> Callable[[Timestamp, bytearray], None]:
|
|
323
|
+
return _TimestampAdapter.encode
|
|
324
|
+
|
|
325
|
+
@staticmethod
|
|
326
|
+
def decode(stream: ByteStream) -> Timestamp:
|
|
327
|
+
return Timestamp(unix_millis=_clamp_unix_millis(decode_int64(stream)))
|
|
328
|
+
|
|
329
|
+
def decode_fn(self) -> Callable[[ByteStream], Timestamp]:
|
|
330
|
+
return _TimestampAdapter.decode
|
|
331
|
+
|
|
240
332
|
def get_type(self) -> reflection.Type:
|
|
241
333
|
return reflection.PrimitiveType(
|
|
242
334
|
kind="primitive",
|
|
@@ -251,10 +343,10 @@ def _timestamp_from_json(json: Any) -> Timestamp:
|
|
|
251
343
|
return Timestamp(unix_millis=json["unix_millis"])
|
|
252
344
|
|
|
253
345
|
|
|
254
|
-
TIMESTAMP_ADAPTER: Final[TypeAdapter] = _TimestampAdapter()
|
|
346
|
+
TIMESTAMP_ADAPTER: Final[TypeAdapter[Timestamp]] = _TimestampAdapter()
|
|
255
347
|
|
|
256
348
|
|
|
257
|
-
class _StringAdapter(AbstractPrimitiveAdapter):
|
|
349
|
+
class _StringAdapter(AbstractPrimitiveAdapter[str]):
|
|
258
350
|
def default_expr(self) -> ExprLike:
|
|
259
351
|
return '""'
|
|
260
352
|
|
|
@@ -267,9 +359,42 @@ class _StringAdapter(AbstractPrimitiveAdapter):
|
|
|
267
359
|
def to_json_expr(self, in_expr: ExprLike, readable: bool) -> ExprLike:
|
|
268
360
|
return in_expr
|
|
269
361
|
|
|
270
|
-
def from_json_expr(
|
|
362
|
+
def from_json_expr(
|
|
363
|
+
self, json_expr: ExprLike, keep_unrecognized_expr: ExprLike
|
|
364
|
+
) -> Expr:
|
|
271
365
|
return Expr.join("('' + (", json_expr, " or ''))")
|
|
272
366
|
|
|
367
|
+
@staticmethod
|
|
368
|
+
def encode(
|
|
369
|
+
value: str,
|
|
370
|
+
buffer: bytearray,
|
|
371
|
+
) -> None:
|
|
372
|
+
if not value:
|
|
373
|
+
buffer.append(242)
|
|
374
|
+
else:
|
|
375
|
+
buffer.append(243)
|
|
376
|
+
bytes_data = value.encode("utf-8")
|
|
377
|
+
length = len(bytes_data)
|
|
378
|
+
encode_length_prefix(length, buffer)
|
|
379
|
+
buffer.extend(bytes_data)
|
|
380
|
+
|
|
381
|
+
def encode_fn(self) -> Callable[[str, bytearray], None]:
|
|
382
|
+
return _StringAdapter.encode
|
|
383
|
+
|
|
384
|
+
@staticmethod
|
|
385
|
+
def decode(stream: ByteStream) -> str:
|
|
386
|
+
wire = stream.read(1)[0]
|
|
387
|
+
if wire == 242:
|
|
388
|
+
return ""
|
|
389
|
+
else:
|
|
390
|
+
# Should be wire 243
|
|
391
|
+
length = decode_int64(stream)
|
|
392
|
+
bytes_data = stream.read(length)
|
|
393
|
+
return bytes_data.decode("utf-8")
|
|
394
|
+
|
|
395
|
+
def decode_fn(self) -> Callable[[ByteStream], str]:
|
|
396
|
+
return _StringAdapter.decode
|
|
397
|
+
|
|
273
398
|
def get_type(self) -> reflection.Type:
|
|
274
399
|
return reflection.PrimitiveType(
|
|
275
400
|
kind="primitive",
|
|
@@ -280,7 +405,7 @@ class _StringAdapter(AbstractPrimitiveAdapter):
|
|
|
280
405
|
STRING_ADAPTER: Final[TypeAdapter] = _StringAdapter()
|
|
281
406
|
|
|
282
407
|
|
|
283
|
-
class _BytesAdapter(AbstractPrimitiveAdapter):
|
|
408
|
+
class _BytesAdapter(AbstractPrimitiveAdapter[bytes]):
|
|
284
409
|
def default_expr(self) -> ExprLike:
|
|
285
410
|
return 'b""'
|
|
286
411
|
|
|
@@ -302,11 +427,42 @@ class _BytesAdapter(AbstractPrimitiveAdapter):
|
|
|
302
427
|
").decode('utf-8')",
|
|
303
428
|
)
|
|
304
429
|
|
|
305
|
-
def from_json_expr(
|
|
430
|
+
def from_json_expr(
|
|
431
|
+
self, json_expr: ExprLike, keep_unrecognized_expr: ExprLike
|
|
432
|
+
) -> Expr:
|
|
306
433
|
return Expr.join(
|
|
307
434
|
Expr.local("b64decode", base64.b64decode), "(", json_expr, ' or "")'
|
|
308
435
|
)
|
|
309
436
|
|
|
437
|
+
@staticmethod
|
|
438
|
+
def encode(
|
|
439
|
+
value: bytes,
|
|
440
|
+
buffer: bytearray,
|
|
441
|
+
) -> None:
|
|
442
|
+
if len(value) == 0:
|
|
443
|
+
buffer.append(244)
|
|
444
|
+
else:
|
|
445
|
+
buffer.append(245)
|
|
446
|
+
length = len(value)
|
|
447
|
+
encode_length_prefix(length, buffer)
|
|
448
|
+
buffer.extend(value)
|
|
449
|
+
|
|
450
|
+
def encode_fn(self) -> Callable[[bytes, bytearray], None]:
|
|
451
|
+
return _BytesAdapter.encode
|
|
452
|
+
|
|
453
|
+
@staticmethod
|
|
454
|
+
def decode(stream: ByteStream) -> bytes:
|
|
455
|
+
wire = stream.read_wire()
|
|
456
|
+
if wire in (0, 244):
|
|
457
|
+
return b""
|
|
458
|
+
else:
|
|
459
|
+
# Should be wire 245
|
|
460
|
+
length = decode_int64(stream)
|
|
461
|
+
return stream.read(length)
|
|
462
|
+
|
|
463
|
+
def decode_fn(self) -> Callable[[ByteStream], bytes]:
|
|
464
|
+
return _BytesAdapter.decode
|
|
465
|
+
|
|
310
466
|
def get_type(self) -> reflection.Type:
|
|
311
467
|
return reflection.PrimitiveType(
|
|
312
468
|
kind="primitive",
|
|
@@ -314,4 +470,4 @@ class _BytesAdapter(AbstractPrimitiveAdapter):
|
|
|
314
470
|
)
|
|
315
471
|
|
|
316
472
|
|
|
317
|
-
BYTES_ADAPTER: Final[TypeAdapter] = _BytesAdapter()
|
|
473
|
+
BYTES_ADAPTER: Final[TypeAdapter[bytes]] = _BytesAdapter()
|
soia/_impl/repr.py
CHANGED
soia/_impl/serializer.py
CHANGED
|
@@ -5,11 +5,10 @@ from functools import cached_property
|
|
|
5
5
|
from typing import Any, Generic, TypeVar, cast, final
|
|
6
6
|
from weakref import WeakValueDictionary
|
|
7
7
|
|
|
8
|
+
from soia import reflection
|
|
8
9
|
from soia._impl.function_maker import Expr, LineSpan, make_function
|
|
9
10
|
from soia._impl.never import Never
|
|
10
|
-
from soia._impl.type_adapter import TypeAdapter
|
|
11
|
-
|
|
12
|
-
from soia import reflection
|
|
11
|
+
from soia._impl.type_adapter import ByteStream, TypeAdapter
|
|
13
12
|
|
|
14
13
|
T = TypeVar("T")
|
|
15
14
|
|
|
@@ -22,26 +21,33 @@ class Serializer(Generic[T]):
|
|
|
22
21
|
"_to_dense_json_fn",
|
|
23
22
|
"_to_readable_json_fn",
|
|
24
23
|
"_from_json_fn",
|
|
24
|
+
"_encode_fn",
|
|
25
|
+
"_decode_fn",
|
|
25
26
|
"__dict__",
|
|
26
27
|
)
|
|
27
28
|
|
|
28
|
-
_adapter: TypeAdapter
|
|
29
|
+
_adapter: TypeAdapter[T]
|
|
29
30
|
_to_dense_json_fn: Callable[[T], Any]
|
|
30
31
|
_to_readable_json_fn: Callable[[T], Any]
|
|
31
|
-
_from_json_fn: Callable[[Any], T]
|
|
32
|
+
_from_json_fn: Callable[[Any, bool], T]
|
|
33
|
+
_encode_fn: Callable[[T, bytearray], None]
|
|
34
|
+
_decode_fn: Callable[[ByteStream], T]
|
|
32
35
|
|
|
33
36
|
def __init__(self, adapter: Never):
|
|
34
37
|
# Use Never (^) as a trick to make the constructor internal.
|
|
35
|
-
|
|
38
|
+
as_adapter = cast(TypeAdapter[T], adapter)
|
|
39
|
+
object.__setattr__(self, "_adapter", as_adapter)
|
|
36
40
|
object.__setattr__(
|
|
37
|
-
self, "_to_dense_json_fn", _make_to_json_fn(
|
|
41
|
+
self, "_to_dense_json_fn", _make_to_json_fn(as_adapter, readable=False)
|
|
38
42
|
)
|
|
39
43
|
object.__setattr__(
|
|
40
44
|
self,
|
|
41
45
|
"_to_readable_json_fn",
|
|
42
|
-
_make_to_json_fn(
|
|
46
|
+
_make_to_json_fn(as_adapter, readable=True),
|
|
43
47
|
)
|
|
44
|
-
object.__setattr__(self, "_from_json_fn", _make_from_json_fn(
|
|
48
|
+
object.__setattr__(self, "_from_json_fn", _make_from_json_fn(as_adapter))
|
|
49
|
+
object.__setattr__(self, "_encode_fn", as_adapter.encode_fn())
|
|
50
|
+
object.__setattr__(self, "_decode_fn", as_adapter.decode_fn())
|
|
45
51
|
|
|
46
52
|
def to_json(self, input: T, *, readable=False) -> Any:
|
|
47
53
|
if readable:
|
|
@@ -55,11 +61,26 @@ class Serializer(Generic[T]):
|
|
|
55
61
|
else:
|
|
56
62
|
return jsonlib.dumps(self._to_dense_json_fn(input), separators=(",", ":"))
|
|
57
63
|
|
|
58
|
-
def from_json(self, json: Any) -> T:
|
|
59
|
-
return self._from_json_fn(json)
|
|
64
|
+
def from_json(self, json: Any, keep_unrecognized_fields: bool = False) -> T:
|
|
65
|
+
return self._from_json_fn(json, keep_unrecognized_fields)
|
|
66
|
+
|
|
67
|
+
def from_json_code(
|
|
68
|
+
self, json_code: str, keep_unrecognized_fields: bool = False
|
|
69
|
+
) -> T:
|
|
70
|
+
return self._from_json_fn(jsonlib.loads(json_code), keep_unrecognized_fields)
|
|
60
71
|
|
|
61
|
-
def
|
|
62
|
-
|
|
72
|
+
def to_bytes(self, input: T) -> bytes:
|
|
73
|
+
buffer = bytearray(b"soia")
|
|
74
|
+
self._encode_fn(input, buffer)
|
|
75
|
+
return bytes(buffer)
|
|
76
|
+
|
|
77
|
+
def from_bytes(self, bytes: bytes, keep_unrecognized_fields: bool = False) -> T:
|
|
78
|
+
if bytes.startswith(b"soia"):
|
|
79
|
+
stream = ByteStream(
|
|
80
|
+
bytes, position=4, keep_unrecognized_fields=keep_unrecognized_fields
|
|
81
|
+
)
|
|
82
|
+
return self._decode_fn(stream)
|
|
83
|
+
return self.from_json_code(bytes.decode("utf-8"))
|
|
63
84
|
|
|
64
85
|
@cached_property
|
|
65
86
|
def type_descriptor(self) -> reflection.TypeDescriptor:
|
|
@@ -83,13 +104,13 @@ _type_adapter_to_serializer: WeakValueDictionary[TypeAdapter, Serializer] = (
|
|
|
83
104
|
)
|
|
84
105
|
|
|
85
106
|
|
|
86
|
-
def make_serializer(adapter: TypeAdapter) -> Serializer:
|
|
107
|
+
def make_serializer(adapter: TypeAdapter[T]) -> Serializer[T]:
|
|
87
108
|
return _type_adapter_to_serializer.setdefault(
|
|
88
109
|
adapter, Serializer(cast(Never, adapter))
|
|
89
110
|
)
|
|
90
111
|
|
|
91
112
|
|
|
92
|
-
def _make_to_json_fn(adapter: TypeAdapter, readable: bool) -> Callable[[
|
|
113
|
+
def _make_to_json_fn(adapter: TypeAdapter[T], readable: bool) -> Callable[[T], Any]:
|
|
93
114
|
return make_function(
|
|
94
115
|
name="to_json",
|
|
95
116
|
params=["input"],
|
|
@@ -105,11 +126,13 @@ def _make_to_json_fn(adapter: TypeAdapter, readable: bool) -> Callable[[Any], An
|
|
|
105
126
|
)
|
|
106
127
|
|
|
107
128
|
|
|
108
|
-
def _make_from_json_fn(adapter: TypeAdapter) -> Callable[[Any],
|
|
129
|
+
def _make_from_json_fn(adapter: TypeAdapter[T]) -> Callable[[Any, bool], T]:
|
|
109
130
|
return make_function(
|
|
110
131
|
name="from_json",
|
|
111
|
-
params=["json"],
|
|
132
|
+
params=["json", "keep_unrecognized_fields"],
|
|
112
133
|
body=[
|
|
113
|
-
LineSpan.join(
|
|
134
|
+
LineSpan.join(
|
|
135
|
+
"return ", adapter.from_json_expr("json", "keep_unrecognized_fields")
|
|
136
|
+
),
|
|
114
137
|
],
|
|
115
138
|
)
|
soia/_impl/service.py
CHANGED
|
@@ -130,9 +130,7 @@ class _HandleRequestFlow(Generic[Request, Response, RequestHeaders, ResponseHead
|
|
|
130
130
|
try:
|
|
131
131
|
req_body_json = json.loads(self.req_body)
|
|
132
132
|
except json.JSONDecodeError:
|
|
133
|
-
return RawServiceResponse(
|
|
134
|
-
"bad request: invalid JSON", "bad-request"
|
|
135
|
-
)
|
|
133
|
+
return RawServiceResponse("bad request: invalid JSON", "bad-request")
|
|
136
134
|
method = req_body_json.get("method", ())
|
|
137
135
|
if method == ():
|
|
138
136
|
return RawServiceResponse(
|
soia/_impl/service_client.py
CHANGED