jsoncompat 0.4.3__cp315-cp315-win_amd64.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.
- jsoncompat/__init__.py +576 -0
- jsoncompat/_native.cp315-win_amd64.pyd +0 -0
- jsoncompat/_native.pyi +10 -0
- jsoncompat/codegen/__init__.py +4 -0
- jsoncompat/codegen/dataclasses.py +857 -0
- jsoncompat/codegen/serialization.py +242 -0
- jsoncompat/py.typed +1 -0
- jsoncompat-0.4.3.dist-info/METADATA +176 -0
- jsoncompat-0.4.3.dist-info/RECORD +11 -0
- jsoncompat-0.4.3.dist-info/WHEEL +4 -0
- jsoncompat-0.4.3.dist-info/sboms/jsoncompat_py.cyclonedx.json +5870 -0
jsoncompat/__init__.py
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import importlib.machinery
|
|
5
|
+
import importlib.util
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
import threading
|
|
9
|
+
import warnings
|
|
10
|
+
from collections.abc import Mapping
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import TYPE_CHECKING, Any, Callable, Literal, NoReturn, Protocol, cast
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from jsoncompat._native import (
|
|
16
|
+
JSONCOMPAT_MISSING as JSONCOMPAT_MISSING,
|
|
17
|
+
JsoncompatMissingType as JsoncompatMissingType,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
RoleLiteral = Literal["serializer", "deserializer", "both"]
|
|
21
|
+
type JsonValue = (
|
|
22
|
+
None
|
|
23
|
+
| bool
|
|
24
|
+
| int
|
|
25
|
+
| float
|
|
26
|
+
| str
|
|
27
|
+
| list["JsonValue"]
|
|
28
|
+
| tuple["JsonValue", ...]
|
|
29
|
+
| dict[str, "JsonValue"]
|
|
30
|
+
)
|
|
31
|
+
CheckCompatFn = Callable[[str, str, RoleLiteral], bool]
|
|
32
|
+
GenerateValueFn = Callable[[str, int], str]
|
|
33
|
+
IsValidFn = Callable[[str, str], bool]
|
|
34
|
+
GeneratorForFn = Callable[[str], "Generator"]
|
|
35
|
+
ValidatorForFn = Callable[[str], "Validator"]
|
|
36
|
+
DeserializeJsonFn = Callable[[str | bytes], "JsonValue"]
|
|
37
|
+
SerializeJsonFn = Callable[["JsonValue"], str]
|
|
38
|
+
CompileModelRuntimesFn = Callable[
|
|
39
|
+
[
|
|
40
|
+
list[tuple[type[Any], int]],
|
|
41
|
+
list[tuple[Any, ...]],
|
|
42
|
+
type[tuple[Any, ...]],
|
|
43
|
+
type[Mapping[Any, Any]],
|
|
44
|
+
],
|
|
45
|
+
list["ModelRuntime"],
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Generator(Protocol):
|
|
50
|
+
def generate_value(self, depth: int = 5) -> str: ...
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Validator(Protocol):
|
|
54
|
+
def is_valid_json(self, instance_json: str) -> bool: ...
|
|
55
|
+
def is_valid_value(self, instance: JsonValue) -> bool: ...
|
|
56
|
+
def _is_valid_borrowed_value(self, instance: JsonValue) -> bool: ...
|
|
57
|
+
def parse_json(self, payload: str | bytes) -> tuple[bool, JsonValue]: ...
|
|
58
|
+
def serialize_json(self, instance: JsonValue) -> str | None: ...
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ModelRuntime(Protocol):
|
|
62
|
+
def construct_kwargs(
|
|
63
|
+
self,
|
|
64
|
+
kwargs: dict[str, Any],
|
|
65
|
+
*,
|
|
66
|
+
skip_validation: bool = False,
|
|
67
|
+
) -> Any: ...
|
|
68
|
+
|
|
69
|
+
def from_value(
|
|
70
|
+
self,
|
|
71
|
+
value: JsonValue,
|
|
72
|
+
*,
|
|
73
|
+
skip_validation: bool = False,
|
|
74
|
+
) -> Any: ...
|
|
75
|
+
|
|
76
|
+
def deserialize(
|
|
77
|
+
self,
|
|
78
|
+
payload: str | bytes,
|
|
79
|
+
*,
|
|
80
|
+
skip_validation: bool = False,
|
|
81
|
+
) -> Any: ...
|
|
82
|
+
|
|
83
|
+
def to_value(
|
|
84
|
+
self,
|
|
85
|
+
instance: Any,
|
|
86
|
+
*,
|
|
87
|
+
skip_validation: bool = False,
|
|
88
|
+
) -> JsonValue: ...
|
|
89
|
+
|
|
90
|
+
def serialize(
|
|
91
|
+
self,
|
|
92
|
+
instance: Any,
|
|
93
|
+
*,
|
|
94
|
+
skip_validation: bool = False,
|
|
95
|
+
) -> str: ...
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class NativeModule(Protocol):
|
|
99
|
+
JSONCOMPAT_MISSING: Any
|
|
100
|
+
JsoncompatMissingType: type[Any]
|
|
101
|
+
|
|
102
|
+
def check_compat(
|
|
103
|
+
self,
|
|
104
|
+
old_schema_json: str,
|
|
105
|
+
new_schema_json: str,
|
|
106
|
+
role: RoleLiteral,
|
|
107
|
+
) -> bool: ...
|
|
108
|
+
|
|
109
|
+
def generate_value(self, schema_json: str, depth: int) -> str: ...
|
|
110
|
+
|
|
111
|
+
def generator_for(self, schema_json: str) -> Generator: ...
|
|
112
|
+
|
|
113
|
+
def validator_for(self, schema_json: str) -> Validator: ...
|
|
114
|
+
|
|
115
|
+
def deserialize_json(self, payload: str | bytes) -> JsonValue: ...
|
|
116
|
+
|
|
117
|
+
def serialize_json(self, value: JsonValue) -> str: ...
|
|
118
|
+
|
|
119
|
+
def compile_model_runtimes(
|
|
120
|
+
self,
|
|
121
|
+
model_roots: list[tuple[type[Any], int]],
|
|
122
|
+
descriptors: list[tuple[Any, ...]],
|
|
123
|
+
frozen_list_type: type[tuple[Any, ...]],
|
|
124
|
+
frozen_dict_type: type[Mapping[Any, Any]],
|
|
125
|
+
) -> list[ModelRuntime]: ...
|
|
126
|
+
|
|
127
|
+
def is_valid(self, schema_json: str, instance_json: str) -> bool: ...
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class Role:
|
|
131
|
+
SERIALIZER: RoleLiteral = "serializer"
|
|
132
|
+
DESERIALIZER: RoleLiteral = "deserializer"
|
|
133
|
+
BOTH: RoleLiteral = "both"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _missing_check_compat(
|
|
137
|
+
old_schema_json: str,
|
|
138
|
+
new_schema_json: str,
|
|
139
|
+
role: RoleLiteral,
|
|
140
|
+
) -> NoReturn:
|
|
141
|
+
_ = (old_schema_json, new_schema_json, role)
|
|
142
|
+
raise ModuleNotFoundError(
|
|
143
|
+
"jsoncompat._native is unavailable. Install the built jsoncompat wheel "
|
|
144
|
+
"before calling check_compat()."
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _missing_generate_value(schema_json: str, depth: int) -> NoReturn:
|
|
149
|
+
_ = (schema_json, depth)
|
|
150
|
+
raise ModuleNotFoundError(
|
|
151
|
+
"jsoncompat._native is unavailable. Install the built jsoncompat wheel "
|
|
152
|
+
"before calling generate_value()."
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _missing_generator_for(schema_json: str) -> NoReturn:
|
|
157
|
+
_ = schema_json
|
|
158
|
+
raise ModuleNotFoundError(
|
|
159
|
+
"jsoncompat._native is unavailable. Install the built jsoncompat wheel "
|
|
160
|
+
"before calling generator_for()."
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _missing_is_valid(schema_json: str, instance_json: str) -> NoReturn:
|
|
165
|
+
_ = (schema_json, instance_json)
|
|
166
|
+
raise ModuleNotFoundError(
|
|
167
|
+
"jsoncompat._native is unavailable. Install the built jsoncompat wheel "
|
|
168
|
+
"before calling is_valid()."
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _missing_validator_for(schema_json: str) -> NoReturn:
|
|
173
|
+
_ = schema_json
|
|
174
|
+
raise ModuleNotFoundError(
|
|
175
|
+
"jsoncompat._native is unavailable. Install the built jsoncompat wheel "
|
|
176
|
+
"before calling validator_for()."
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _missing_deserialize_json(payload: str | bytes) -> NoReturn:
|
|
181
|
+
_ = payload
|
|
182
|
+
raise ModuleNotFoundError(
|
|
183
|
+
"jsoncompat._native is unavailable. Install the built jsoncompat wheel "
|
|
184
|
+
"before deserializing JSON."
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _missing_serialize_json(value: JsonValue) -> NoReturn:
|
|
189
|
+
_ = value
|
|
190
|
+
raise ModuleNotFoundError(
|
|
191
|
+
"jsoncompat._native is unavailable. Install the built jsoncompat wheel "
|
|
192
|
+
"before serializing JSON."
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _missing_compile_model_runtimes(
|
|
197
|
+
model_roots: list[tuple[type[Any], int]],
|
|
198
|
+
descriptors: list[tuple[Any, ...]],
|
|
199
|
+
frozen_list_type: type[tuple[Any, ...]],
|
|
200
|
+
frozen_dict_type: type[Mapping[Any, Any]],
|
|
201
|
+
) -> NoReturn:
|
|
202
|
+
_ = (model_roots, descriptors, frozen_list_type, frozen_dict_type)
|
|
203
|
+
raise ModuleNotFoundError(
|
|
204
|
+
"jsoncompat._native is unavailable. Install the built jsoncompat wheel "
|
|
205
|
+
"before constructing generated models."
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _load_repo_native() -> NativeModule:
|
|
210
|
+
package_dir = Path(__file__).resolve().parent
|
|
211
|
+
repo_root = package_dir.parent.parent
|
|
212
|
+
target_roots = [repo_root / "target"]
|
|
213
|
+
if cargo_target_dir := os.environ.get("CARGO_TARGET_DIR"):
|
|
214
|
+
target_roots.insert(0, Path(cargo_target_dir).expanduser())
|
|
215
|
+
|
|
216
|
+
native_profile = os.environ.get("JSONCOMPAT_NATIVE_PROFILE")
|
|
217
|
+
if native_profile is None:
|
|
218
|
+
build_dirs = ("debug", "release")
|
|
219
|
+
elif native_profile in {"debug", "release"}:
|
|
220
|
+
build_dirs = (native_profile,)
|
|
221
|
+
else:
|
|
222
|
+
raise ValueError("JSONCOMPAT_NATIVE_PROFILE must be 'debug' or 'release'")
|
|
223
|
+
|
|
224
|
+
for target_root in target_roots:
|
|
225
|
+
for build_dir in build_dirs:
|
|
226
|
+
for filename in (
|
|
227
|
+
"libjsoncompat.dylib",
|
|
228
|
+
"libjsoncompat.so",
|
|
229
|
+
"jsoncompat.dll",
|
|
230
|
+
):
|
|
231
|
+
native_path = target_root / build_dir / "deps" / filename
|
|
232
|
+
if not native_path.exists():
|
|
233
|
+
continue
|
|
234
|
+
|
|
235
|
+
loader = importlib.machinery.ExtensionFileLoader(
|
|
236
|
+
"jsoncompat._native",
|
|
237
|
+
str(native_path),
|
|
238
|
+
)
|
|
239
|
+
spec = importlib.util.spec_from_file_location(
|
|
240
|
+
"jsoncompat._native",
|
|
241
|
+
str(native_path),
|
|
242
|
+
loader=loader,
|
|
243
|
+
)
|
|
244
|
+
if spec is None or spec.loader is None:
|
|
245
|
+
continue
|
|
246
|
+
|
|
247
|
+
module = importlib.util.module_from_spec(spec)
|
|
248
|
+
sys.modules[spec.name] = module
|
|
249
|
+
spec.loader.exec_module(module)
|
|
250
|
+
return cast(NativeModule, module)
|
|
251
|
+
|
|
252
|
+
raise ModuleNotFoundError("jsoncompat._native")
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _has_reusable_schema_api(module: object) -> bool:
|
|
256
|
+
validator = getattr(module, "Validator", None)
|
|
257
|
+
model_runtime = getattr(module, "ModelRuntime", None)
|
|
258
|
+
return (
|
|
259
|
+
hasattr(module, "generator_for")
|
|
260
|
+
and hasattr(module, "validator_for")
|
|
261
|
+
and hasattr(module, "deserialize_json")
|
|
262
|
+
and hasattr(module, "serialize_json")
|
|
263
|
+
and hasattr(module, "compile_model_runtimes")
|
|
264
|
+
and hasattr(module, "JSONCOMPAT_MISSING")
|
|
265
|
+
and hasattr(module, "JsoncompatMissingType")
|
|
266
|
+
and hasattr(validator, "is_valid_json")
|
|
267
|
+
and hasattr(validator, "is_valid_value")
|
|
268
|
+
and hasattr(validator, "_is_valid_borrowed_value")
|
|
269
|
+
and hasattr(validator, "parse_json")
|
|
270
|
+
and hasattr(validator, "serialize_json")
|
|
271
|
+
and hasattr(model_runtime, "construct_kwargs")
|
|
272
|
+
and hasattr(model_runtime, "from_value")
|
|
273
|
+
and hasattr(model_runtime, "deserialize")
|
|
274
|
+
and hasattr(model_runtime, "to_value")
|
|
275
|
+
and hasattr(model_runtime, "serialize")
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
_force_repo_native = os.environ.get("JSONCOMPAT_NATIVE_PROFILE") is not None
|
|
280
|
+
|
|
281
|
+
try:
|
|
282
|
+
if _force_repo_native:
|
|
283
|
+
_native_module = _load_repo_native()
|
|
284
|
+
else:
|
|
285
|
+
_native_module = cast(
|
|
286
|
+
NativeModule,
|
|
287
|
+
importlib.import_module("jsoncompat._native"),
|
|
288
|
+
)
|
|
289
|
+
except ModuleNotFoundError as error:
|
|
290
|
+
if _force_repo_native:
|
|
291
|
+
raise
|
|
292
|
+
if error.name != "jsoncompat._native":
|
|
293
|
+
raise
|
|
294
|
+
try:
|
|
295
|
+
_repo_native = _load_repo_native()
|
|
296
|
+
except ModuleNotFoundError:
|
|
297
|
+
_native_symbols: NativeModule | None = None
|
|
298
|
+
_check_compat_native: CheckCompatFn = _missing_check_compat
|
|
299
|
+
_generate_value_native: GenerateValueFn = _missing_generate_value
|
|
300
|
+
_generator_for_native: GeneratorForFn = _missing_generator_for
|
|
301
|
+
_validator_for_native: ValidatorForFn = _missing_validator_for
|
|
302
|
+
_deserialize_json_native: DeserializeJsonFn = _missing_deserialize_json
|
|
303
|
+
_serialize_json_native: SerializeJsonFn = _missing_serialize_json
|
|
304
|
+
_compile_model_runtimes_native: CompileModelRuntimesFn = (
|
|
305
|
+
_missing_compile_model_runtimes
|
|
306
|
+
)
|
|
307
|
+
_is_valid_native: IsValidFn = _missing_is_valid
|
|
308
|
+
else:
|
|
309
|
+
_native_symbols = _repo_native
|
|
310
|
+
_check_compat_native = _repo_native.check_compat
|
|
311
|
+
_generate_value_native = _repo_native.generate_value
|
|
312
|
+
_generator_for_native = _repo_native.generator_for
|
|
313
|
+
_validator_for_native = _repo_native.validator_for
|
|
314
|
+
_deserialize_json_native = _repo_native.deserialize_json
|
|
315
|
+
_serialize_json_native = _repo_native.serialize_json
|
|
316
|
+
_compile_model_runtimes_native = _repo_native.compile_model_runtimes
|
|
317
|
+
_is_valid_native = _repo_native.is_valid
|
|
318
|
+
else:
|
|
319
|
+
if not _force_repo_native and not _has_reusable_schema_api(_native_module):
|
|
320
|
+
_native_module = _load_repo_native()
|
|
321
|
+
_native_symbols = _native_module
|
|
322
|
+
_check_compat_native = _native_module.check_compat
|
|
323
|
+
_generate_value_native = _native_module.generate_value
|
|
324
|
+
_generator_for_native = _native_module.generator_for
|
|
325
|
+
_validator_for_native = _native_module.validator_for
|
|
326
|
+
_deserialize_json_native = _native_module.deserialize_json
|
|
327
|
+
_serialize_json_native = _native_module.serialize_json
|
|
328
|
+
_compile_model_runtimes_native = _native_module.compile_model_runtimes
|
|
329
|
+
_is_valid_native = _native_module.is_valid
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
if not TYPE_CHECKING:
|
|
333
|
+
if _native_symbols is None:
|
|
334
|
+
# Ellipsis is Python's native, unforgeable singleton. It keeps source-only
|
|
335
|
+
# imports usable without maintaining a second missing-value implementation;
|
|
336
|
+
# installed wheels replace both names with the native jsoncompat singleton.
|
|
337
|
+
JsoncompatMissingType = type(Ellipsis)
|
|
338
|
+
JSONCOMPAT_MISSING = Ellipsis
|
|
339
|
+
else:
|
|
340
|
+
JsoncompatMissingType = _native_symbols.JsoncompatMissingType
|
|
341
|
+
JSONCOMPAT_MISSING = _native_symbols.JSONCOMPAT_MISSING
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def check_compat(
|
|
345
|
+
old_schema_json: str,
|
|
346
|
+
new_schema_json: str,
|
|
347
|
+
role: RoleLiteral = "both",
|
|
348
|
+
) -> bool:
|
|
349
|
+
check_compat_native = _check_compat_native
|
|
350
|
+
return check_compat_native(old_schema_json, new_schema_json, role)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def generate_value(schema_json: str, depth: int = 5) -> str:
|
|
354
|
+
warnings.warn(
|
|
355
|
+
"jsoncompat.generate_value(schema_json, depth) is deprecated; "
|
|
356
|
+
"use jsoncompat.generator_for(schema_json).generate_value(depth) instead.",
|
|
357
|
+
DeprecationWarning,
|
|
358
|
+
stacklevel=2,
|
|
359
|
+
)
|
|
360
|
+
generate_value_native = _generate_value_native
|
|
361
|
+
return generate_value_native(schema_json, depth)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
class _ThreadLocalGenerator:
|
|
365
|
+
__slots__ = ("_local", "_schema_json")
|
|
366
|
+
|
|
367
|
+
def __init__(self, schema_json: str) -> None:
|
|
368
|
+
self._schema_json = schema_json
|
|
369
|
+
self._local = threading.local()
|
|
370
|
+
self._local.native = _generator_for_native(schema_json)
|
|
371
|
+
|
|
372
|
+
def _native(self) -> Generator:
|
|
373
|
+
native = getattr(self._local, "native", None)
|
|
374
|
+
if native is None:
|
|
375
|
+
native = _generator_for_native(self._schema_json)
|
|
376
|
+
self._local.native = native
|
|
377
|
+
return cast(Generator, native)
|
|
378
|
+
|
|
379
|
+
def generate_value(self, depth: int = 5) -> str:
|
|
380
|
+
return self._native().generate_value(depth)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
class _ThreadLocalValidator:
|
|
384
|
+
__slots__ = ("_local", "_schema_json")
|
|
385
|
+
|
|
386
|
+
def __init__(self, schema_json: str) -> None:
|
|
387
|
+
self._schema_json = schema_json
|
|
388
|
+
self._local = threading.local()
|
|
389
|
+
self._local.native = _validator_for_native(schema_json)
|
|
390
|
+
|
|
391
|
+
def _native(self) -> Validator:
|
|
392
|
+
native = getattr(self._local, "native", None)
|
|
393
|
+
if native is None:
|
|
394
|
+
native = _validator_for_native(self._schema_json)
|
|
395
|
+
self._local.native = native
|
|
396
|
+
return cast(Validator, native)
|
|
397
|
+
|
|
398
|
+
def is_valid_json(self, instance_json: str) -> bool:
|
|
399
|
+
return self._native().is_valid_json(instance_json)
|
|
400
|
+
|
|
401
|
+
def is_valid_value(self, instance: JsonValue) -> bool:
|
|
402
|
+
return self._native().is_valid_value(instance)
|
|
403
|
+
|
|
404
|
+
def _is_valid_borrowed_value(self, instance: JsonValue) -> bool:
|
|
405
|
+
return self._native()._is_valid_borrowed_value( # pyright: ignore[reportPrivateUsage]
|
|
406
|
+
instance
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
def parse_json(self, payload: str | bytes) -> tuple[bool, JsonValue]:
|
|
410
|
+
return self._native().parse_json(payload)
|
|
411
|
+
|
|
412
|
+
def serialize_json(self, instance: JsonValue) -> str | None:
|
|
413
|
+
return self._native().serialize_json(instance)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def generator_for(schema_json: str) -> Generator:
|
|
417
|
+
return _ThreadLocalGenerator(schema_json)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def validator_for(schema_json: str) -> Validator:
|
|
421
|
+
return _ThreadLocalValidator(schema_json)
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def deserialize_json_value(payload: str | bytes) -> JsonValue:
|
|
425
|
+
deserialize_json_native = _deserialize_json_native
|
|
426
|
+
return deserialize_json_native(payload)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def serialize_json_value(value: JsonValue) -> str:
|
|
430
|
+
serialize_json_native = _serialize_json_native
|
|
431
|
+
return serialize_json_native(value)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
class _ThreadLocalModelRuntimeGroup:
|
|
435
|
+
__slots__ = (
|
|
436
|
+
"_descriptors",
|
|
437
|
+
"_frozen_dict_type",
|
|
438
|
+
"_frozen_list_type",
|
|
439
|
+
"_local",
|
|
440
|
+
"_model_roots",
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
def __init__(
|
|
444
|
+
self,
|
|
445
|
+
model_roots: list[tuple[type[Any], int]],
|
|
446
|
+
descriptors: list[tuple[Any, ...]],
|
|
447
|
+
frozen_list_type: type[tuple[Any, ...]],
|
|
448
|
+
frozen_dict_type: type[Mapping[Any, Any]],
|
|
449
|
+
) -> None:
|
|
450
|
+
self._model_roots = tuple(model_roots)
|
|
451
|
+
self._descriptors = tuple(descriptors)
|
|
452
|
+
self._frozen_list_type = frozen_list_type
|
|
453
|
+
self._frozen_dict_type = frozen_dict_type
|
|
454
|
+
self._local = threading.local()
|
|
455
|
+
self._local.runtimes = self._compile()
|
|
456
|
+
|
|
457
|
+
def _compile(self) -> tuple[ModelRuntime, ...]:
|
|
458
|
+
return tuple(
|
|
459
|
+
_compile_model_runtimes_native(
|
|
460
|
+
list(self._model_roots),
|
|
461
|
+
list(self._descriptors),
|
|
462
|
+
self._frozen_list_type,
|
|
463
|
+
self._frozen_dict_type,
|
|
464
|
+
)
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
def runtime(self, index: int) -> ModelRuntime:
|
|
468
|
+
runtimes = getattr(self._local, "runtimes", None)
|
|
469
|
+
if runtimes is None:
|
|
470
|
+
runtimes = self._compile()
|
|
471
|
+
self._local.runtimes = runtimes
|
|
472
|
+
return cast(tuple[ModelRuntime, ...], runtimes)[index]
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
class _ThreadLocalModelRuntime:
|
|
476
|
+
__slots__ = ("_group", "_index")
|
|
477
|
+
|
|
478
|
+
def __init__(self, group: _ThreadLocalModelRuntimeGroup, index: int) -> None:
|
|
479
|
+
self._group = group
|
|
480
|
+
self._index = index
|
|
481
|
+
|
|
482
|
+
def _native(self) -> ModelRuntime:
|
|
483
|
+
return self._group.runtime(self._index)
|
|
484
|
+
|
|
485
|
+
def construct_kwargs(
|
|
486
|
+
self,
|
|
487
|
+
kwargs: dict[str, Any],
|
|
488
|
+
*,
|
|
489
|
+
skip_validation: bool = False,
|
|
490
|
+
) -> Any:
|
|
491
|
+
return self._native().construct_kwargs(
|
|
492
|
+
kwargs,
|
|
493
|
+
skip_validation=skip_validation,
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
def from_value(
|
|
497
|
+
self,
|
|
498
|
+
value: JsonValue,
|
|
499
|
+
*,
|
|
500
|
+
skip_validation: bool = False,
|
|
501
|
+
) -> Any:
|
|
502
|
+
return self._native().from_value(value, skip_validation=skip_validation)
|
|
503
|
+
|
|
504
|
+
def deserialize(
|
|
505
|
+
self,
|
|
506
|
+
payload: str | bytes,
|
|
507
|
+
*,
|
|
508
|
+
skip_validation: bool = False,
|
|
509
|
+
) -> Any:
|
|
510
|
+
return self._native().deserialize(payload, skip_validation=skip_validation)
|
|
511
|
+
|
|
512
|
+
def to_value(
|
|
513
|
+
self,
|
|
514
|
+
instance: Any,
|
|
515
|
+
*,
|
|
516
|
+
skip_validation: bool = False,
|
|
517
|
+
) -> JsonValue:
|
|
518
|
+
return self._native().to_value(
|
|
519
|
+
instance,
|
|
520
|
+
skip_validation=skip_validation,
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
def serialize(
|
|
524
|
+
self,
|
|
525
|
+
instance: Any,
|
|
526
|
+
*,
|
|
527
|
+
skip_validation: bool = False,
|
|
528
|
+
) -> str:
|
|
529
|
+
return self._native().serialize(
|
|
530
|
+
instance,
|
|
531
|
+
skip_validation=skip_validation,
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def compile_model_runtimes(
|
|
536
|
+
model_roots: list[tuple[type[Any], int]],
|
|
537
|
+
descriptors: list[tuple[Any, ...]],
|
|
538
|
+
frozen_list_type: type[tuple[Any, ...]],
|
|
539
|
+
frozen_dict_type: type[Mapping[Any, Any]],
|
|
540
|
+
) -> list[ModelRuntime]:
|
|
541
|
+
group = _ThreadLocalModelRuntimeGroup(
|
|
542
|
+
model_roots,
|
|
543
|
+
descriptors,
|
|
544
|
+
frozen_list_type,
|
|
545
|
+
frozen_dict_type,
|
|
546
|
+
)
|
|
547
|
+
return [
|
|
548
|
+
_ThreadLocalModelRuntime(group, index) for index in range(len(model_roots))
|
|
549
|
+
]
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def is_valid(schema_json: str, instance_json: str) -> bool:
|
|
553
|
+
warnings.warn(
|
|
554
|
+
"jsoncompat.is_valid(schema_json, instance_json) is deprecated; "
|
|
555
|
+
"use jsoncompat.validator_for(schema_json).is_valid_json(instance_json) instead.",
|
|
556
|
+
DeprecationWarning,
|
|
557
|
+
stacklevel=2,
|
|
558
|
+
)
|
|
559
|
+
is_valid_native = _is_valid_native
|
|
560
|
+
return is_valid_native(schema_json, instance_json)
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
__all__ = [
|
|
564
|
+
"Role",
|
|
565
|
+
"RoleLiteral",
|
|
566
|
+
"JsonValue",
|
|
567
|
+
"Generator",
|
|
568
|
+
"JSONCOMPAT_MISSING",
|
|
569
|
+
"JsoncompatMissingType",
|
|
570
|
+
"Validator",
|
|
571
|
+
"check_compat",
|
|
572
|
+
"generate_value",
|
|
573
|
+
"generator_for",
|
|
574
|
+
"is_valid",
|
|
575
|
+
"validator_for",
|
|
576
|
+
]
|
|
Binary file
|
jsoncompat/_native.pyi
ADDED