vtjson 2.1.5__py3-none-any.whl → 2.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.
- vtjson/vtjson.py +113 -53
- {vtjson-2.1.5.dist-info → vtjson-2.1.6.dist-info}/METADATA +4 -4
- vtjson-2.1.6.dist-info/RECORD +9 -0
- {vtjson-2.1.5.dist-info → vtjson-2.1.6.dist-info}/WHEEL +1 -1
- vtjson-2.1.5.dist-info/RECORD +0 -9
- {vtjson-2.1.5.dist-info → vtjson-2.1.6.dist-info}/AUTHORS +0 -0
- {vtjson-2.1.5.dist-info → vtjson-2.1.6.dist-info}/LICENSE +0 -0
- {vtjson-2.1.5.dist-info → vtjson-2.1.6.dist-info}/top_level.txt +0 -0
vtjson/vtjson.py
CHANGED
|
@@ -10,9 +10,9 @@ import types
|
|
|
10
10
|
import typing
|
|
11
11
|
import urllib.parse
|
|
12
12
|
import warnings
|
|
13
|
-
from collections.abc import Sequence, Sized
|
|
13
|
+
from collections.abc import Sequence, Set, Sized
|
|
14
14
|
from dataclasses import dataclass
|
|
15
|
-
from typing import Any, Callable, Mapping, Type, TypeVar, Union, cast
|
|
15
|
+
from typing import Any, Callable, Container, Mapping, Type, TypeVar, Union, cast
|
|
16
16
|
|
|
17
17
|
try:
|
|
18
18
|
from typing import Literal
|
|
@@ -121,7 +121,7 @@ class SchemaError(Exception):
|
|
|
121
121
|
pass
|
|
122
122
|
|
|
123
123
|
|
|
124
|
-
__version__ = "2.1.
|
|
124
|
+
__version__ = "2.1.6"
|
|
125
125
|
|
|
126
126
|
|
|
127
127
|
@dataclass
|
|
@@ -153,6 +153,16 @@ skip_first = Apply(skip_first=True)
|
|
|
153
153
|
_dns_resolver: dns.resolver.Resolver | None = None
|
|
154
154
|
|
|
155
155
|
|
|
156
|
+
def _generic_name(origin: type, args: tuple[object, ...]) -> str:
|
|
157
|
+
def to_name(c: object) -> str:
|
|
158
|
+
if hasattr(c, "__name__"):
|
|
159
|
+
return str(c.__name__)
|
|
160
|
+
else:
|
|
161
|
+
return str(c)
|
|
162
|
+
|
|
163
|
+
return to_name(origin) + "[" + ",".join([to_name(arg) for arg in args]) + "]"
|
|
164
|
+
|
|
165
|
+
|
|
156
166
|
def _get_type_hints(schema: object) -> dict[str, object]:
|
|
157
167
|
if not supports_structural:
|
|
158
168
|
raise SchemaError(
|
|
@@ -1141,14 +1151,14 @@ def _compile(
|
|
|
1141
1151
|
)
|
|
1142
1152
|
elif origin == tuple:
|
|
1143
1153
|
ret = _Tuple(typing.get_args(schema), _deferred_compiles=_deferred_compiles)
|
|
1144
|
-
elif isinstance(origin, type) and issubclass(origin,
|
|
1145
|
-
ret =
|
|
1146
|
-
typing.get_args(schema)
|
|
1154
|
+
elif isinstance(origin, type) and issubclass(origin, Mapping):
|
|
1155
|
+
ret = _Mapping(
|
|
1156
|
+
typing.get_args(schema),
|
|
1147
1157
|
type_schema=origin,
|
|
1148
1158
|
_deferred_compiles=_deferred_compiles,
|
|
1149
1159
|
)
|
|
1150
|
-
elif isinstance(origin, type) and issubclass(origin,
|
|
1151
|
-
ret =
|
|
1160
|
+
elif isinstance(origin, type) and issubclass(origin, Container):
|
|
1161
|
+
ret = _Container(
|
|
1152
1162
|
typing.get_args(schema),
|
|
1153
1163
|
type_schema=origin,
|
|
1154
1164
|
_deferred_compiles=_deferred_compiles,
|
|
@@ -1169,7 +1179,7 @@ def _compile(
|
|
|
1169
1179
|
ret = _sequence(schema, _deferred_compiles=_deferred_compiles)
|
|
1170
1180
|
elif isinstance(schema, Mapping):
|
|
1171
1181
|
ret = _dict(schema, _deferred_compiles=_deferred_compiles)
|
|
1172
|
-
elif isinstance(schema,
|
|
1182
|
+
elif isinstance(schema, Set):
|
|
1173
1183
|
ret = _set(schema, _deferred_compiles=_deferred_compiles)
|
|
1174
1184
|
else:
|
|
1175
1185
|
ret = _const(schema)
|
|
@@ -1841,13 +1851,10 @@ class _sequence(compiled_schema):
|
|
|
1841
1851
|
def __init__(
|
|
1842
1852
|
self,
|
|
1843
1853
|
schema: Sequence[object],
|
|
1844
|
-
type_schema: type | None = None,
|
|
1854
|
+
# type_schema: type | None = None,
|
|
1845
1855
|
_deferred_compiles: _mapping | None = None,
|
|
1846
1856
|
) -> None:
|
|
1847
|
-
|
|
1848
|
-
self.type_schema = type(schema)
|
|
1849
|
-
else:
|
|
1850
|
-
self.type_schema = type_schema
|
|
1857
|
+
self.type_schema = type(schema)
|
|
1851
1858
|
self.schema = [
|
|
1852
1859
|
_compile(o, _deferred_compiles=_deferred_compiles)
|
|
1853
1860
|
for o in schema
|
|
@@ -1980,13 +1987,9 @@ class _dict(compiled_schema):
|
|
|
1980
1987
|
def __init__(
|
|
1981
1988
|
self,
|
|
1982
1989
|
schema: Mapping[object, object],
|
|
1983
|
-
type_schema: type | None = None,
|
|
1984
1990
|
_deferred_compiles: _mapping | None = None,
|
|
1985
1991
|
) -> None:
|
|
1986
|
-
|
|
1987
|
-
self.type_schema = type(schema)
|
|
1988
|
-
else:
|
|
1989
|
-
self.type_schema = type_schema
|
|
1992
|
+
self.type_schema = type(schema)
|
|
1990
1993
|
self.min_keys = set()
|
|
1991
1994
|
self.const_keys = set()
|
|
1992
1995
|
self.other_keys = set()
|
|
@@ -2059,15 +2062,18 @@ class _dict(compiled_schema):
|
|
|
2059
2062
|
|
|
2060
2063
|
|
|
2061
2064
|
class _set(compiled_schema):
|
|
2065
|
+
type_schema: Type[Set[object]]
|
|
2062
2066
|
schema: compiled_schema
|
|
2063
|
-
schema_:
|
|
2067
|
+
schema_: Set[object]
|
|
2064
2068
|
|
|
2065
2069
|
def __init__(
|
|
2066
|
-
self,
|
|
2070
|
+
self,
|
|
2071
|
+
schema: Set[object],
|
|
2072
|
+
_deferred_compiles: _mapping | None = None,
|
|
2067
2073
|
) -> None:
|
|
2074
|
+
self.type_schema = type(schema)
|
|
2068
2075
|
self.schema_ = schema
|
|
2069
2076
|
if len(schema) == 0:
|
|
2070
|
-
self.schema = _const(set())
|
|
2071
2077
|
setattr(self, "__validate__", self.__validate_empty_set__)
|
|
2072
2078
|
elif len(schema) == 1:
|
|
2073
2079
|
self.schema = _compile(
|
|
@@ -2084,7 +2090,11 @@ class _set(compiled_schema):
|
|
|
2084
2090
|
strict: bool = True,
|
|
2085
2091
|
subs: Mapping[str, object] = {},
|
|
2086
2092
|
) -> str:
|
|
2087
|
-
|
|
2093
|
+
if not isinstance(object_, self.type_schema):
|
|
2094
|
+
return _wrong_type_message(object_, name, self.type_schema.__name__)
|
|
2095
|
+
if len(object_) != 0:
|
|
2096
|
+
return f"{name} (value:{_c(object_)}) is not empty"
|
|
2097
|
+
return ""
|
|
2088
2098
|
|
|
2089
2099
|
def __validate_singleton__(
|
|
2090
2100
|
self,
|
|
@@ -2094,7 +2104,7 @@ class _set(compiled_schema):
|
|
|
2094
2104
|
subs: Mapping[str, object] = {},
|
|
2095
2105
|
) -> str:
|
|
2096
2106
|
if not isinstance(object_, set):
|
|
2097
|
-
return _wrong_type_message(object_, name,
|
|
2107
|
+
return _wrong_type_message(object_, name, self.type_schema.__name__)
|
|
2098
2108
|
for i, o in enumerate(object_):
|
|
2099
2109
|
name_ = f"{name}{{{i}}}"
|
|
2100
2110
|
v = self.schema.__validate__(o, name=name_, strict=True, subs=subs)
|
|
@@ -2109,8 +2119,8 @@ class _set(compiled_schema):
|
|
|
2109
2119
|
strict: bool = True,
|
|
2110
2120
|
subs: Mapping[str, object] = {},
|
|
2111
2121
|
) -> str:
|
|
2112
|
-
if not isinstance(object_,
|
|
2113
|
-
return _wrong_type_message(object_, name,
|
|
2122
|
+
if not isinstance(object_, self.type_schema):
|
|
2123
|
+
return _wrong_type_message(object_, name, self.type_schema.__name__)
|
|
2114
2124
|
for i, o in enumerate(object_):
|
|
2115
2125
|
name_ = f"{name}{{{i}}}"
|
|
2116
2126
|
v = self.schema.__validate__(o, name=name_, strict=True, subs=subs)
|
|
@@ -2182,24 +2192,6 @@ class _Union(compiled_schema):
|
|
|
2182
2192
|
)
|
|
2183
2193
|
|
|
2184
2194
|
|
|
2185
|
-
class _List(compiled_schema):
|
|
2186
|
-
def __init__(
|
|
2187
|
-
self,
|
|
2188
|
-
schema: object,
|
|
2189
|
-
type_schema: type | None = None,
|
|
2190
|
-
_deferred_compiles: _mapping | None = None,
|
|
2191
|
-
) -> None:
|
|
2192
|
-
setattr(
|
|
2193
|
-
self,
|
|
2194
|
-
"__validate__",
|
|
2195
|
-
_sequence(
|
|
2196
|
-
[schema, ...],
|
|
2197
|
-
type_schema=type_schema,
|
|
2198
|
-
_deferred_compiles=_deferred_compiles,
|
|
2199
|
-
).__validate__,
|
|
2200
|
-
)
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
2195
|
class _Tuple(compiled_schema):
|
|
2204
2196
|
def __init__(
|
|
2205
2197
|
self, schema: tuple[object, ...], _deferred_compiles: _mapping | None = None
|
|
@@ -2211,21 +2203,89 @@ class _Tuple(compiled_schema):
|
|
|
2211
2203
|
)
|
|
2212
2204
|
|
|
2213
2205
|
|
|
2214
|
-
class
|
|
2206
|
+
class _Mapping(compiled_schema):
|
|
2207
|
+
type_schema: Type[Mapping[object, object]]
|
|
2208
|
+
key: compiled_schema
|
|
2209
|
+
value: compiled_schema
|
|
2210
|
+
__name__: str
|
|
2211
|
+
|
|
2215
2212
|
def __init__(
|
|
2216
2213
|
self,
|
|
2217
2214
|
schema: tuple[object, ...],
|
|
2218
|
-
type_schema: type
|
|
2215
|
+
type_schema: type,
|
|
2219
2216
|
_deferred_compiles: _mapping | None = None,
|
|
2220
2217
|
) -> None:
|
|
2218
|
+
if len(schema) != 2:
|
|
2219
|
+
raise SchemaError("Number of arguments of mapping is not two")
|
|
2221
2220
|
k, v = schema
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2221
|
+
self.key = _compile(k, _deferred_compiles=_deferred_compiles)
|
|
2222
|
+
self.value = _compile(v, _deferred_compiles=_deferred_compiles)
|
|
2223
|
+
self.type_schema = type_schema
|
|
2224
|
+
self.__name__ = _generic_name(type_schema, schema)
|
|
2225
|
+
|
|
2226
|
+
def __validate__(
|
|
2227
|
+
self,
|
|
2228
|
+
object_: object,
|
|
2229
|
+
name: str = "object",
|
|
2230
|
+
strict: bool = True,
|
|
2231
|
+
subs: Mapping[str, object] = {},
|
|
2232
|
+
) -> str:
|
|
2233
|
+
|
|
2234
|
+
if not isinstance(object_, self.type_schema):
|
|
2235
|
+
return _wrong_type_message(object_, name, self.__name__)
|
|
2236
|
+
|
|
2237
|
+
for k, v in object_.items():
|
|
2238
|
+
_name = f"{name}[{repr(k)}]"
|
|
2239
|
+
message = self.key.__validate__(k, name=str(k), strict=strict, subs=subs)
|
|
2240
|
+
if message != "":
|
|
2241
|
+
return f"{_name} is not in the schema"
|
|
2242
|
+
message = self.value.__validate__(v, name=_name, strict=strict, subs=subs)
|
|
2243
|
+
if message != "":
|
|
2244
|
+
return message
|
|
2245
|
+
|
|
2246
|
+
return ""
|
|
2247
|
+
|
|
2248
|
+
|
|
2249
|
+
class _Container(compiled_schema):
|
|
2250
|
+
type_schema: Type[Mapping[object, object]]
|
|
2251
|
+
schema: compiled_schema
|
|
2252
|
+
__name__: str
|
|
2253
|
+
|
|
2254
|
+
def __init__(
|
|
2255
|
+
self,
|
|
2256
|
+
schema: tuple[object, ...],
|
|
2257
|
+
type_schema: type,
|
|
2258
|
+
_deferred_compiles: _mapping | None = None,
|
|
2259
|
+
) -> None:
|
|
2260
|
+
if len(schema) != 1:
|
|
2261
|
+
raise SchemaError("Number of arguments of Generic type is not one")
|
|
2262
|
+
self.schema = _compile(schema[0], _deferred_compiles=_deferred_compiles)
|
|
2263
|
+
self.type_schema = type_schema
|
|
2264
|
+
self.__name__ = _generic_name(type_schema, schema)
|
|
2265
|
+
|
|
2266
|
+
def __validate__(
|
|
2267
|
+
self,
|
|
2268
|
+
object_: object,
|
|
2269
|
+
name: str = "object",
|
|
2270
|
+
strict: bool = True,
|
|
2271
|
+
subs: Mapping[str, object] = {},
|
|
2272
|
+
) -> str:
|
|
2273
|
+
|
|
2274
|
+
if not isinstance(object_, self.type_schema):
|
|
2275
|
+
return _wrong_type_message(object_, name, self.type_schema.__name__)
|
|
2276
|
+
|
|
2277
|
+
try:
|
|
2278
|
+
for i, o in enumerate(object_):
|
|
2279
|
+
_name = f"{name}[{i}]"
|
|
2280
|
+
message = self.schema.__validate__(
|
|
2281
|
+
o, name=_name, strict=strict, subs=subs
|
|
2282
|
+
)
|
|
2283
|
+
if message != "":
|
|
2284
|
+
return message
|
|
2285
|
+
except Exception as e:
|
|
2286
|
+
return _wrong_type_message(object_, name, self.__name__, explanation=str(e))
|
|
2287
|
+
|
|
2288
|
+
return ""
|
|
2229
2289
|
|
|
2230
2290
|
|
|
2231
2291
|
class _NewType(compiled_schema):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vtjson
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.6
|
|
4
4
|
Summary: A lightweight package for validating JSON like Python objects
|
|
5
5
|
Author-email: Michel Van den Bergh <michel.vandenbergh@uhasselt.be>
|
|
6
6
|
Project-URL: Homepage, https://github.com/vdbergh/vtjson
|
|
@@ -168,11 +168,11 @@ A schema can be, in order of precedence:
|
|
|
168
168
|
- A `set`. A set validates an object if the object is a set and the elements of the object are validated by an element of the schema.
|
|
169
169
|
- An arbitrary Python object. Validation is done by checking equality of the schema and the object, except when the schema is `float`, in which case `math.isclose` is used. Below we call such an object a `const schema`.
|
|
170
170
|
|
|
171
|
-
## Validating
|
|
171
|
+
## Validating Mapping
|
|
172
172
|
|
|
173
|
-
For a
|
|
173
|
+
For a Mapping schema containing only `const keys` (i.e. keys corresponding to a `const schema`) the interpretation is obvious (see the introductory example above). Below we discuss the validation of an object against a Mapping schema in the general case.
|
|
174
174
|
|
|
175
|
-
- First we verify that the object is
|
|
175
|
+
- First we verify that the type of the object is a subtype of the type of the schema. If not then validation fails.
|
|
176
176
|
- We verify that all non-optional const keys of the schema are also keys of the object. If this is not the case then validation fails.
|
|
177
177
|
- Now we make a list of all the keys of the schema (both optional and non-optional). The result will be called the `key list` below.
|
|
178
178
|
- The object will pass validation if all its keys pass validation. We next discuss how to validate a particular key of the object.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
vtjson/__init__.py,sha256=oLX4JH6_R7dYtTiGfBG3pQGR21IArspifdmZilbuGOw,68
|
|
2
|
+
vtjson/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
vtjson/vtjson.py,sha256=UO58eUc0yShJ9Nm8zvhc3egHUzfLcLXdlj2TpKxtmYE,69567
|
|
4
|
+
vtjson-2.1.6.dist-info/AUTHORS,sha256=qmxaXxaIO-YPNHJAZ0dcCrnPCs1x9ocbtMksiy4i80M,21
|
|
5
|
+
vtjson-2.1.6.dist-info/LICENSE,sha256=n7xW-zX8xBLHzCdqWIMRuMzBD_ACLcNCwio0LEkKt1o,1077
|
|
6
|
+
vtjson-2.1.6.dist-info/METADATA,sha256=-PFoASAchEaDMOxJfx8icFTmVMxbfLFEkK9btIfWn28,24054
|
|
7
|
+
vtjson-2.1.6.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
|
8
|
+
vtjson-2.1.6.dist-info/top_level.txt,sha256=9DlSF3l63igcvnYPcj117F2hzOW4Nx0N-JBoW3jjBZM,7
|
|
9
|
+
vtjson-2.1.6.dist-info/RECORD,,
|
vtjson-2.1.5.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
vtjson/__init__.py,sha256=oLX4JH6_R7dYtTiGfBG3pQGR21IArspifdmZilbuGOw,68
|
|
2
|
-
vtjson/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
vtjson/vtjson.py,sha256=xq5w9FrmPf6ctjLml2To0nEfd5Okm3ijND44GLWarr0,67357
|
|
4
|
-
vtjson-2.1.5.dist-info/AUTHORS,sha256=qmxaXxaIO-YPNHJAZ0dcCrnPCs1x9ocbtMksiy4i80M,21
|
|
5
|
-
vtjson-2.1.5.dist-info/LICENSE,sha256=n7xW-zX8xBLHzCdqWIMRuMzBD_ACLcNCwio0LEkKt1o,1077
|
|
6
|
-
vtjson-2.1.5.dist-info/METADATA,sha256=eALkzFzpWaZECpnduYIsaT1KSCREWw-fTXjLqCbyrjg,24035
|
|
7
|
-
vtjson-2.1.5.dist-info/WHEEL,sha256=a7TGlA-5DaHMRrarXjVbQagU3Man_dCnGIWMJr5kRWo,91
|
|
8
|
-
vtjson-2.1.5.dist-info/top_level.txt,sha256=9DlSF3l63igcvnYPcj117F2hzOW4Nx0N-JBoW3jjBZM,7
|
|
9
|
-
vtjson-2.1.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|