vtjson 2.2.6__py3-none-any.whl → 2.2.8__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 CHANGED
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import datetime
4
+ import functools
5
+ import inspect
4
6
  import ipaddress
5
7
  import math
6
8
  import pathlib
@@ -10,7 +12,7 @@ import types
10
12
  import typing
11
13
  import urllib.parse
12
14
  import warnings
13
- from collections.abc import Sequence, Set, Sized
15
+ from collections.abc import Iterable, Sequence, Set, Sized
14
16
  from dataclasses import dataclass
15
17
  from typing import (
16
18
  Any,
@@ -204,7 +206,7 @@ class SchemaError(Exception):
204
206
  pass
205
207
 
206
208
 
207
- __version__ = "2.2.6"
209
+ __version__ = "2.2.8"
208
210
 
209
211
 
210
212
  @dataclass
@@ -248,14 +250,79 @@ skip_first = Apply(skip_first=True)
248
250
  _dns_resolver: dns.resolver.Resolver | None = None
249
251
 
250
252
 
251
- def _generic_name(origin: type, args: tuple[object, ...]) -> str:
252
- def to_name(c: object) -> str:
253
- if hasattr(c, "__name__"):
254
- return str(c.__name__)
253
+ def _to_name(s: object) -> str:
254
+ if hasattr(s, "__name__"):
255
+ return str(s.__name__)
256
+ else:
257
+ if isinstance(s, str):
258
+ return repr(s)
259
+ elif s == Ellipsis:
260
+ return "..."
255
261
  else:
256
- return str(c)
262
+ return str(s)
263
+
264
+
265
+ def _generic_name(origin: type, args: tuple[object, ...]) -> str:
266
+ return _to_name(origin) + "[" + ",".join([_to_name(arg) for arg in args]) + "]"
267
+
268
+
269
+ def _make_name(
270
+ type: type,
271
+ args: tuple[object, ...],
272
+ kw: dict[str, object],
273
+ defaults: dict[str, object] = {},
274
+ ) -> str:
275
+ arg_list = []
276
+ for a in args:
277
+ arg_list.append(_to_name(a))
278
+ for k, v in kw.items():
279
+ if k not in defaults or v != defaults[k]:
280
+ arg_list.append(f"{k}={_to_name(v)}")
281
+ if len(arg_list) == 0:
282
+ return _to_name(type)
283
+ else:
284
+ return f"{_to_name(type)}({','.join(arg_list)})"
285
+
286
+
287
+ C = TypeVar("C")
288
+
289
+
290
+ def _set__name__(c: type[C]) -> type[C]:
291
+ defaults = {}
292
+ a = inspect.getfullargspec(c.__init__)
293
+ a_defaults: tuple[object, ...] = ()
294
+ if a.defaults is not None:
295
+ a_defaults = a.defaults
296
+
297
+ if a is None or a.args is None:
298
+ raise Exception(f"Could not get signature of {c.__name__}")
299
+ start = len(a.args) - len(a_defaults)
300
+ for i in range(start, len(a.args)):
301
+ defaults[a.args[i]] = a_defaults[i - start]
302
+ __init__org = c.__init__
303
+
304
+ @functools.wraps(c.__init__)
305
+ def __init__wrapper(self: C, *args: object, **kw: object) -> None:
306
+ setattr(
307
+ self, "__name__", _make_name(self.__class__, args, kw, defaults=defaults)
308
+ )
309
+ return __init__org(self, *args, **kw)
310
+
311
+ @functools.wraps(c.__str__)
312
+ def __str__(self: C) -> str:
313
+ assert hasattr(self, "__name__")
314
+ return str(self.__name__)
315
+
316
+ @functools.wraps(c.__repr__)
317
+ def __repr__(self: C) -> str:
318
+ assert hasattr(self, "__name__")
319
+ return str(self.__name__)
257
320
 
258
- return to_name(origin) + "[" + ",".join([to_name(arg) for arg in args]) + "]"
321
+ setattr(c, "__init__", __init__wrapper)
322
+ setattr(c, "__str__", __str__)
323
+ setattr(c, "__repr__", __repr__)
324
+
325
+ return c
259
326
 
260
327
 
261
328
  def _get_type_hints(schema: object) -> dict[str, object]:
@@ -414,6 +481,7 @@ def make_type(
414
481
  K = TypeVar("K")
415
482
 
416
483
 
484
+ @_set__name__
417
485
  class optional_key(Generic[K]):
418
486
  """
419
487
  Make a key in a Mapping schema optional. In the common case that the key
@@ -424,6 +492,7 @@ class optional_key(Generic[K]):
424
492
 
425
493
  key: K
426
494
  optional: bool
495
+ __name__: str
427
496
 
428
497
  def __init__(self, key: K, _optional: bool = True) -> None:
429
498
  """
@@ -445,6 +514,13 @@ class optional_key(Generic[K]):
445
514
  return hash(self.key)
446
515
 
447
516
 
517
+ # def __str__(self) -> str:
518
+ # return self.__name__
519
+ #
520
+ # def __repr__(self) -> str:
521
+ # return self.__name__
522
+
523
+
448
524
  StringKeyType = TypeVar("StringKeyType", bound=Union[str, optional_key[str]])
449
525
 
450
526
 
@@ -467,6 +543,8 @@ class _union(compiled_schema):
467
543
  strict: bool = True,
468
544
  subs: Mapping[str, object] = {},
469
545
  ) -> str:
546
+ if len(self.schemas) == 0:
547
+ return _wrong_type_message(obj, name, "union()")
470
548
  messages = []
471
549
  for schema in self.schemas:
472
550
  message = schema.__validate__(obj, name=name, strict=strict, subs=subs)
@@ -823,6 +901,7 @@ class set_name(wrapper):
823
901
  )
824
902
 
825
903
 
904
+ @_set__name__
826
905
  class regex(compiled_schema):
827
906
  """
828
907
  This matches the strings which match the given pattern.
@@ -857,10 +936,6 @@ class regex(compiled_schema):
857
936
  if not isinstance(name, str):
858
937
  raise SchemaError(f"The regex name {_c(name)} is not a string")
859
938
  self.__name__ = name
860
- else:
861
- _flags = "" if flags == 0 else f", flags={flags}"
862
- _fullmatch = "" if fullmatch else ", fullmatch=False"
863
- self.__name__ = f"regex({repr(regex)}{_fullmatch}{_flags})"
864
939
 
865
940
  try:
866
941
  self.pattern = re.compile(regex, flags)
@@ -878,7 +953,9 @@ class regex(compiled_schema):
878
953
  subs: Mapping[str, object] = {},
879
954
  ) -> str:
880
955
  if not isinstance(obj, str):
881
- return _wrong_type_message(obj, name, self.__name__)
956
+ return _wrong_type_message(
957
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
958
+ )
882
959
  try:
883
960
  if self.fullmatch and self.pattern.fullmatch(obj):
884
961
  return ""
@@ -889,6 +966,7 @@ class regex(compiled_schema):
889
966
  return _wrong_type_message(obj, name, self.__name__)
890
967
 
891
968
 
969
+ @_set__name__
892
970
  class glob(compiled_schema):
893
971
  """
894
972
  Unix style filename matching. This is implemented using
@@ -910,9 +988,7 @@ class glob(compiled_schema):
910
988
 
911
989
  self.pattern = pattern
912
990
 
913
- if name is None:
914
- self.__name__ = f"glob({repr(pattern)})"
915
- else:
991
+ if name is not None:
916
992
  self.__name__ = name
917
993
 
918
994
  try:
@@ -931,7 +1007,9 @@ class glob(compiled_schema):
931
1007
  subs: Mapping[str, object] = {},
932
1008
  ) -> str:
933
1009
  if not isinstance(obj, str):
934
- return _wrong_type_message(obj, name, self.__name__)
1010
+ return _wrong_type_message(
1011
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
1012
+ )
935
1013
  try:
936
1014
  if pathlib.PurePath(obj).match(self.pattern):
937
1015
  return ""
@@ -941,6 +1019,7 @@ class glob(compiled_schema):
941
1019
  return _wrong_type_message(obj, name, self.__name__, str(e))
942
1020
 
943
1021
 
1022
+ @_set__name__
944
1023
  class magic(compiled_schema):
945
1024
  """
946
1025
  Checks if a buffer (for example a string or a byte array) has the given
@@ -966,9 +1045,7 @@ class magic(compiled_schema):
966
1045
 
967
1046
  self.mime_type = mime_type
968
1047
 
969
- if name is None:
970
- self.__name__ = f"magic({repr(mime_type)})"
971
- else:
1048
+ if name is not None:
972
1049
  self.__name__ = name
973
1050
 
974
1051
  def __validate__(
@@ -979,7 +1056,12 @@ class magic(compiled_schema):
979
1056
  subs: Mapping[str, object] = {},
980
1057
  ) -> str:
981
1058
  if not isinstance(obj, (str, bytes)):
982
- return _wrong_type_message(obj, name, self.__name__)
1059
+ return _wrong_type_message(
1060
+ obj,
1061
+ name,
1062
+ self.__name__,
1063
+ explanation=f"{_c(obj)} is not a string nor bytes",
1064
+ )
983
1065
  try:
984
1066
  objmime_type = magic_.from_buffer(obj, mime=True)
985
1067
  except Exception as e:
@@ -994,6 +1076,7 @@ class magic(compiled_schema):
994
1076
  return ""
995
1077
 
996
1078
 
1079
+ @_set__name__
997
1080
  class div(compiled_schema):
998
1081
  """
999
1082
  This matches the integers `x` such that `(x - remainder) % divisor` == 0.
@@ -1024,13 +1107,7 @@ class div(compiled_schema):
1024
1107
  self.divisor = divisor
1025
1108
  self.remainder = remainder
1026
1109
 
1027
- if name is None:
1028
- _divisor = str(divisor)
1029
- _remainder = ""
1030
- if remainder != 0:
1031
- _remainder = "," + str(remainder)
1032
- self.__name__ = f"div({_divisor+_remainder})"
1033
- else:
1110
+ if name is not None:
1034
1111
  self.__name__ = name
1035
1112
 
1036
1113
  def __validate__(
@@ -1041,13 +1118,16 @@ class div(compiled_schema):
1041
1118
  subs: Mapping[str, object] = {},
1042
1119
  ) -> str:
1043
1120
  if not isinstance(obj, int):
1044
- return _wrong_type_message(obj, name, "int")
1121
+ return _wrong_type_message(
1122
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not an integer"
1123
+ )
1045
1124
  elif (obj - self.remainder) % self.divisor == 0:
1046
1125
  return ""
1047
1126
  else:
1048
1127
  return _wrong_type_message(obj, name, self.__name__)
1049
1128
 
1050
1129
 
1130
+ @_set__name__
1051
1131
  class close_to(compiled_schema):
1052
1132
  """
1053
1133
  This matches the real numbers that are close to `x` in the sense of
@@ -1087,9 +1167,6 @@ class close_to(compiled_schema):
1087
1167
  )
1088
1168
  self.kw["abs_tol"] = abs_tol
1089
1169
 
1090
- kwl = [str(x)] + [f"{k}={v}" for (k, v) in self.kw.items()]
1091
- kwl_ = ",".join(kwl)
1092
- self.__name__ = f"close_to({kwl_})"
1093
1170
  self.x = x
1094
1171
 
1095
1172
  def __validate__(
@@ -1100,19 +1177,23 @@ class close_to(compiled_schema):
1100
1177
  subs: Mapping[str, object] = {},
1101
1178
  ) -> str:
1102
1179
  if not isinstance(obj, (float, int)):
1103
- return _wrong_type_message(obj, name, "number")
1180
+ return _wrong_type_message(
1181
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not an integer"
1182
+ )
1104
1183
  elif math.isclose(obj, self.x, **self.kw):
1105
1184
  return ""
1106
1185
  else:
1107
1186
  return _wrong_type_message(obj, name, self.__name__)
1108
1187
 
1109
1188
 
1189
+ @_set__name__
1110
1190
  class gt(compiled_schema):
1111
1191
  """
1112
1192
  This checks if `object > lb`.
1113
1193
  """
1114
1194
 
1115
1195
  lb: comparable
1196
+ __name__: str
1116
1197
 
1117
1198
  def __init__(self, lb: comparable) -> None:
1118
1199
  """
@@ -1148,12 +1229,14 @@ class gt(compiled_schema):
1148
1229
  return f"{self.message(name, obj)}: {str(e)}"
1149
1230
 
1150
1231
 
1232
+ @_set__name__
1151
1233
  class ge(compiled_schema):
1152
1234
  """
1153
1235
  This checks if `object >= lb`.
1154
1236
  """
1155
1237
 
1156
1238
  lb: comparable
1239
+ __name__: str
1157
1240
 
1158
1241
  def __init__(self, lb: comparable) -> None:
1159
1242
  """
@@ -1189,12 +1272,14 @@ class ge(compiled_schema):
1189
1272
  return f"{self.message(name, obj)}: {str(e)}"
1190
1273
 
1191
1274
 
1275
+ @_set__name__
1192
1276
  class lt(compiled_schema):
1193
1277
  """
1194
1278
  This checks if `object < ub`.
1195
1279
  """
1196
1280
 
1197
1281
  ub: comparable
1282
+ __name__: str
1198
1283
 
1199
1284
  def __init__(self, ub: comparable) -> None:
1200
1285
  """
@@ -1230,12 +1315,14 @@ class lt(compiled_schema):
1230
1315
  return f"{self.message(name, obj)}: {str(e)}"
1231
1316
 
1232
1317
 
1318
+ @_set__name__
1233
1319
  class le(compiled_schema):
1234
1320
  """
1235
1321
  This checks if `object <= ub`.
1236
1322
  """
1237
1323
 
1238
1324
  ub: comparable
1325
+ __name__: str
1239
1326
 
1240
1327
  def __init__(self, ub: comparable) -> None:
1241
1328
  """
@@ -1271,6 +1358,7 @@ class le(compiled_schema):
1271
1358
  return f"{self.message(name, obj)}: {str(e)}"
1272
1359
 
1273
1360
 
1361
+ @_set__name__
1274
1362
  class interval(compiled_schema):
1275
1363
  """
1276
1364
  This checks if `lb <= object <= ub`, provided the comparisons make sense.
@@ -1278,6 +1366,7 @@ class interval(compiled_schema):
1278
1366
 
1279
1367
  lb_s: str
1280
1368
  ub_s: str
1369
+ __name__: str
1281
1370
 
1282
1371
  def __init__(
1283
1372
  self,
@@ -1346,6 +1435,7 @@ class interval(compiled_schema):
1346
1435
  setattr(self, "__validate__", anything().__validate__)
1347
1436
 
1348
1437
 
1438
+ @_set__name__
1349
1439
  class size(compiled_schema):
1350
1440
  """
1351
1441
  Matches the objects (which support `len()` such as strings or lists) whose
@@ -1353,6 +1443,7 @@ class size(compiled_schema):
1353
1443
  """
1354
1444
 
1355
1445
  interval_: interval
1446
+ __name__: str
1356
1447
 
1357
1448
  def __init__(self, lb: int, ub: int | types.EllipsisType | None = None) -> None:
1358
1449
  """
@@ -1625,11 +1716,14 @@ def validate(
1625
1716
  # Some predefined schemas
1626
1717
 
1627
1718
 
1719
+ @_set__name__
1628
1720
  class number(compiled_schema):
1629
1721
  """
1630
1722
  A deprecated alias for `float`.
1631
1723
  """
1632
1724
 
1725
+ __name__: str
1726
+
1633
1727
  def __init__(self) -> None:
1634
1728
  warnings.warn(
1635
1729
  "The schema 'number' is deprecated. Use 'float' instead.",
@@ -1646,14 +1740,20 @@ class number(compiled_schema):
1646
1740
  if isinstance(obj, (int, float)):
1647
1741
  return ""
1648
1742
  else:
1649
- return _wrong_type_message(obj, name, "number")
1743
+ return _wrong_type_message(obj, name, self.__name__)
1650
1744
 
1651
1745
 
1746
+ @_set__name__
1652
1747
  class float_(compiled_schema):
1653
1748
  """
1654
1749
  Schema that only matches floats. Not ints.
1655
1750
  """
1656
1751
 
1752
+ __name__: str
1753
+
1754
+ def __init__(self) -> None:
1755
+ pass
1756
+
1657
1757
  def __validate__(
1658
1758
  self,
1659
1759
  obj: object,
@@ -1664,9 +1764,10 @@ class float_(compiled_schema):
1664
1764
  if isinstance(obj, float):
1665
1765
  return ""
1666
1766
  else:
1667
- return _wrong_type_message(obj, name, "float_")
1767
+ return _wrong_type_message(obj, name, self.__name__)
1668
1768
 
1669
1769
 
1770
+ @_set__name__
1670
1771
  class email(compiled_schema):
1671
1772
  """
1672
1773
  Checks if the object is a valid email address. This uses the package
@@ -1675,6 +1776,7 @@ class email(compiled_schema):
1675
1776
  """
1676
1777
 
1677
1778
  kw: dict[str, Any]
1779
+ __name__: str
1678
1780
 
1679
1781
  def __init__(self, **kw: Any) -> None:
1680
1782
  """
@@ -1695,14 +1797,17 @@ class email(compiled_schema):
1695
1797
  subs: Mapping[str, object] = {},
1696
1798
  ) -> str:
1697
1799
  if not isinstance(obj, str):
1698
- return _wrong_type_message(obj, name, "email", f"{_c(obj)} is not a string")
1800
+ return _wrong_type_message(
1801
+ obj, name, self.__name__, f"{_c(obj)} is not a string"
1802
+ )
1699
1803
  try:
1700
1804
  email_validator.validate_email(obj, **self.kw)
1701
1805
  return ""
1702
1806
  except Exception as e:
1703
- return _wrong_type_message(obj, name, "email", str(e))
1807
+ return _wrong_type_message(obj, name, self.__name__, str(e))
1704
1808
 
1705
1809
 
1810
+ @_set__name__
1706
1811
  class ip_address(compiled_schema):
1707
1812
  """
1708
1813
  Matches ip addresses of the specified version which can be 4, 6 or None.
@@ -1719,10 +1824,7 @@ class ip_address(compiled_schema):
1719
1824
  """
1720
1825
  if version is not None and version not in (4, 6):
1721
1826
  raise SchemaError("version is not 4 or 6")
1722
- if version is None:
1723
- self.__name__ = "ip_address"
1724
- else:
1725
- self.__name__ = f"ip_address(version={version})"
1827
+
1726
1828
  if version == 4:
1727
1829
  self.method = ipaddress.IPv4Address
1728
1830
  elif version == 6:
@@ -1738,7 +1840,12 @@ class ip_address(compiled_schema):
1738
1840
  subs: Mapping[str, object] = {},
1739
1841
  ) -> str:
1740
1842
  if not isinstance(obj, (int, str, bytes)):
1741
- return _wrong_type_message(obj, name, self.__name__)
1843
+ return _wrong_type_message(
1844
+ obj,
1845
+ name,
1846
+ self.__name__,
1847
+ explanation=f"{_c(obj)} is not a string, an int or bytes",
1848
+ )
1742
1849
  try:
1743
1850
  self.method(obj)
1744
1851
  except ValueError as e:
@@ -1746,6 +1853,7 @@ class ip_address(compiled_schema):
1746
1853
  return ""
1747
1854
 
1748
1855
 
1856
+ @_set__name__
1749
1857
  class regex_pattern(compiled_schema):
1750
1858
  """
1751
1859
  Matches valid regular expression patterns
@@ -1754,7 +1862,7 @@ class regex_pattern(compiled_schema):
1754
1862
  __name__: str
1755
1863
 
1756
1864
  def __init__(self) -> None:
1757
- self.__name__ = "regex_pattern"
1865
+ pass
1758
1866
 
1759
1867
  def __validate__(
1760
1868
  self,
@@ -1764,7 +1872,9 @@ class regex_pattern(compiled_schema):
1764
1872
  subs: Mapping[str, object] = {},
1765
1873
  ) -> str:
1766
1874
  if not isinstance(obj, str):
1767
- return _wrong_type_message(obj, name, self.__name__)
1875
+ return _wrong_type_message(
1876
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
1877
+ )
1768
1878
  try:
1769
1879
  re.compile(obj)
1770
1880
  except re.error as e:
@@ -1772,11 +1882,60 @@ class regex_pattern(compiled_schema):
1772
1882
  return ""
1773
1883
 
1774
1884
 
1885
+ @_set__name__
1886
+ class unique(compiled_schema):
1887
+ """
1888
+ Matches containers whose entries do not repeat. We first attempt to convert the
1889
+ object to a set and check its size. If this does not work then we check the
1890
+ entries of the object one by one (this is a quadratic algorithm).
1891
+ """
1892
+
1893
+ __name__: str
1894
+
1895
+ def __init__(self) -> None:
1896
+ pass
1897
+
1898
+ def __validate__(
1899
+ self,
1900
+ obj: object,
1901
+ name: str = "object",
1902
+ strict: bool = True,
1903
+ subs: Mapping[str, object] = {},
1904
+ ) -> str:
1905
+ if not isinstance(obj, Iterable):
1906
+ return _wrong_type_message(
1907
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not iterable"
1908
+ )
1909
+ try:
1910
+ if isinstance(obj, Sized):
1911
+ if len(set(obj)) == len(obj):
1912
+ return ""
1913
+ except Exception:
1914
+ pass
1915
+ try:
1916
+ object_list = []
1917
+ for o in obj:
1918
+ if o in object_list:
1919
+ return _wrong_type_message(
1920
+ obj, name, self.__name__, explanation=f"{_c(o)} is repeated"
1921
+ )
1922
+ object_list.append(o)
1923
+ except Exception as e:
1924
+ return _wrong_type_message(obj, name, self.__name__, explanation=str(e))
1925
+ return ""
1926
+
1927
+
1928
+ @_set__name__
1775
1929
  class url(compiled_schema):
1776
1930
  """
1777
1931
  Matches valid urls.
1778
1932
  """
1779
1933
 
1934
+ __name__: str
1935
+
1936
+ def __init__(self) -> None:
1937
+ pass
1938
+
1780
1939
  def __validate__(
1781
1940
  self,
1782
1941
  obj: object,
@@ -1785,13 +1944,16 @@ class url(compiled_schema):
1785
1944
  subs: Mapping[str, object] = {},
1786
1945
  ) -> str:
1787
1946
  if not isinstance(obj, str):
1788
- return _wrong_type_message(obj, name, "url")
1947
+ return _wrong_type_message(
1948
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
1949
+ )
1789
1950
  result = urllib.parse.urlparse(obj)
1790
1951
  if all([result.scheme, result.netloc]):
1791
1952
  return ""
1792
- return _wrong_type_message(obj, name, "url")
1953
+ return _wrong_type_message(obj, name, self.__name__)
1793
1954
 
1794
1955
 
1956
+ @_set__name__
1795
1957
  class date_time(compiled_schema):
1796
1958
  """
1797
1959
  Without argument this represents an ISO 8601 date-time. The `format`
@@ -1806,10 +1968,6 @@ class date_time(compiled_schema):
1806
1968
  :param format: format string for `strftime`
1807
1969
  """
1808
1970
  self.format = format
1809
- if format is not None:
1810
- self.__name__ = f"date_time({repr(format)})"
1811
- else:
1812
- self.__name__ = "date_time"
1813
1971
 
1814
1972
  def __validate__(
1815
1973
  self,
@@ -1819,7 +1977,9 @@ class date_time(compiled_schema):
1819
1977
  subs: Mapping[str, object] = {},
1820
1978
  ) -> str:
1821
1979
  if not isinstance(obj, str):
1822
- return _wrong_type_message(obj, name, self.__name__)
1980
+ return _wrong_type_message(
1981
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
1982
+ )
1823
1983
  if self.format is not None:
1824
1984
  try:
1825
1985
  datetime.datetime.strptime(obj, self.format)
@@ -1833,11 +1993,17 @@ class date_time(compiled_schema):
1833
1993
  return ""
1834
1994
 
1835
1995
 
1996
+ @_set__name__
1836
1997
  class date(compiled_schema):
1837
1998
  """
1838
1999
  Matches an ISO 8601 date.
1839
2000
  """
1840
2001
 
2002
+ __name__: str
2003
+
2004
+ def __init__(self) -> None:
2005
+ pass
2006
+
1841
2007
  def __validate__(
1842
2008
  self,
1843
2009
  obj: object,
@@ -1846,19 +2012,27 @@ class date(compiled_schema):
1846
2012
  subs: Mapping[str, object] = {},
1847
2013
  ) -> str:
1848
2014
  if not isinstance(obj, str):
1849
- return _wrong_type_message(obj, name, "date")
2015
+ return _wrong_type_message(
2016
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
2017
+ )
1850
2018
  try:
1851
2019
  datetime.date.fromisoformat(obj)
1852
2020
  except Exception as e:
1853
- return _wrong_type_message(obj, name, "date", str(e))
2021
+ return _wrong_type_message(obj, name, self.__name__, str(e))
1854
2022
  return ""
1855
2023
 
1856
2024
 
2025
+ @_set__name__
1857
2026
  class time(compiled_schema):
1858
2027
  """
1859
2028
  Matches an ISO 8601 time.
1860
2029
  """
1861
2030
 
2031
+ __name__: str
2032
+
2033
+ def __init__(self) -> None:
2034
+ pass
2035
+
1862
2036
  def __validate__(
1863
2037
  self,
1864
2038
  obj: object,
@@ -1867,19 +2041,27 @@ class time(compiled_schema):
1867
2041
  subs: Mapping[str, object] = {},
1868
2042
  ) -> str:
1869
2043
  if not isinstance(obj, str):
1870
- return _wrong_type_message(obj, name, "date")
2044
+ return _wrong_type_message(
2045
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
2046
+ )
1871
2047
  try:
1872
2048
  datetime.time.fromisoformat(obj)
1873
2049
  except Exception as e:
1874
- return _wrong_type_message(obj, name, "time", str(e))
2050
+ return _wrong_type_message(obj, name, self.__name__, str(e))
1875
2051
  return ""
1876
2052
 
1877
2053
 
2054
+ @_set__name__
1878
2055
  class nothing(compiled_schema):
1879
2056
  """
1880
2057
  Matches nothing.
1881
2058
  """
1882
2059
 
2060
+ __name__: str
2061
+
2062
+ def __init__(self) -> None:
2063
+ pass
2064
+
1883
2065
  def __validate__(
1884
2066
  self,
1885
2067
  obj: object,
@@ -1887,14 +2069,20 @@ class nothing(compiled_schema):
1887
2069
  strict: bool = True,
1888
2070
  subs: Mapping[str, object] = {},
1889
2071
  ) -> str:
1890
- return _wrong_type_message(obj, name, "nothing")
2072
+ return _wrong_type_message(obj, name, self.__name__)
1891
2073
 
1892
2074
 
2075
+ @_set__name__
1893
2076
  class anything(compiled_schema):
1894
2077
  """
1895
2078
  Matchess anything.
1896
2079
  """
1897
2080
 
2081
+ __name__: str
2082
+
2083
+ def __init__(self) -> None:
2084
+ pass
2085
+
1898
2086
  def __validate__(
1899
2087
  self,
1900
2088
  obj: object,
@@ -1905,6 +2093,7 @@ class anything(compiled_schema):
1905
2093
  return ""
1906
2094
 
1907
2095
 
2096
+ @_set__name__
1908
2097
  class domain_name(compiled_schema):
1909
2098
  """
1910
2099
  Checks if the object is a valid domain name.
@@ -1923,16 +2112,6 @@ class domain_name(compiled_schema):
1923
2112
  self.re_ascii = re.compile(r"[\x00-\x7F]*")
1924
2113
  self.ascii_only = ascii_only
1925
2114
  self.resolve = resolve
1926
- arg_string = ""
1927
- if not ascii_only:
1928
- arg_string += ", ascii_only=False"
1929
- if resolve:
1930
- arg_string += ", resolve=True"
1931
- if arg_string != "":
1932
- arg_string = arg_string[2:]
1933
- self.__name__ = (
1934
- "domain_name" if not arg_string else f"domain_name({arg_string})"
1935
- )
1936
2115
 
1937
2116
  def __validate__(
1938
2117
  self,
@@ -1942,7 +2121,9 @@ class domain_name(compiled_schema):
1942
2121
  subs: Mapping[str, object] = {},
1943
2122
  ) -> str:
1944
2123
  if not isinstance(obj, str):
1945
- return _wrong_type_message(obj, name, self.__name__)
2124
+ return _wrong_type_message(
2125
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
2126
+ )
1946
2127
  if self.ascii_only:
1947
2128
  if not self.re_ascii.fullmatch(obj):
1948
2129
  return _wrong_type_message(
@@ -1961,6 +2142,7 @@ class domain_name(compiled_schema):
1961
2142
  return ""
1962
2143
 
1963
2144
 
2145
+ @_set__name__
1964
2146
  class at_least_one_of(compiled_schema):
1965
2147
  """
1966
2148
  This represents a dictionary with a least one key among a collection of
@@ -1975,8 +2157,6 @@ class at_least_one_of(compiled_schema):
1975
2157
  :param args: a collection of keys
1976
2158
  """
1977
2159
  self.args = args
1978
- args_s = [repr(a) for a in args]
1979
- self.__name__ = f"{self.__class__.__name__}({','.join(args_s)})"
1980
2160
 
1981
2161
  def __validate__(
1982
2162
  self,
@@ -1986,7 +2166,9 @@ class at_least_one_of(compiled_schema):
1986
2166
  subs: Mapping[str, object] = {},
1987
2167
  ) -> str:
1988
2168
  if not isinstance(obj, Mapping):
1989
- return _wrong_type_message(obj, name, self.__name__)
2169
+ return _wrong_type_message(
2170
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a Mapping"
2171
+ )
1990
2172
  try:
1991
2173
  if any([a in obj for a in self.args]):
1992
2174
  return ""
@@ -1996,6 +2178,7 @@ class at_least_one_of(compiled_schema):
1996
2178
  return _wrong_type_message(obj, name, self.__name__, str(e))
1997
2179
 
1998
2180
 
2181
+ @_set__name__
1999
2182
  class at_most_one_of(compiled_schema):
2000
2183
  """
2001
2184
  This represents an dictionary with at most one key among a collection of
@@ -2010,8 +2193,6 @@ class at_most_one_of(compiled_schema):
2010
2193
  :param args: a collection of keys
2011
2194
  """
2012
2195
  self.args = args
2013
- args_s = [repr(a) for a in args]
2014
- self.__name__ = f"{self.__class__.__name__}({','.join(args_s)})"
2015
2196
 
2016
2197
  def __validate__(
2017
2198
  self,
@@ -2021,7 +2202,9 @@ class at_most_one_of(compiled_schema):
2021
2202
  subs: Mapping[str, object] = {},
2022
2203
  ) -> str:
2023
2204
  if not isinstance(obj, Mapping):
2024
- return _wrong_type_message(obj, name, self.__name__)
2205
+ return _wrong_type_message(
2206
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a Mapping"
2207
+ )
2025
2208
  try:
2026
2209
  if sum([a in obj for a in self.args]) <= 1:
2027
2210
  return ""
@@ -2031,6 +2214,7 @@ class at_most_one_of(compiled_schema):
2031
2214
  return _wrong_type_message(obj, name, self.__name__, str(e))
2032
2215
 
2033
2216
 
2217
+ @_set__name__
2034
2218
  class one_of(compiled_schema):
2035
2219
  """
2036
2220
  This represents a dictionary with exactly one key among a collection of
@@ -2045,8 +2229,6 @@ class one_of(compiled_schema):
2045
2229
  :param args: a collection of keys
2046
2230
  """
2047
2231
  self.args = args
2048
- args_s = [repr(a) for a in args]
2049
- self.__name__ = f"{self.__class__.__name__}({','.join(args_s)})"
2050
2232
 
2051
2233
  def __validate__(
2052
2234
  self,
@@ -2056,7 +2238,9 @@ class one_of(compiled_schema):
2056
2238
  subs: Mapping[str, object] = {},
2057
2239
  ) -> str:
2058
2240
  if not isinstance(obj, Mapping):
2059
- return _wrong_type_message(obj, name, self.__name__)
2241
+ return _wrong_type_message(
2242
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a Mapping"
2243
+ )
2060
2244
  try:
2061
2245
  if sum([a in obj for a in self.args]) == 1:
2062
2246
  return ""
@@ -2066,6 +2250,7 @@ class one_of(compiled_schema):
2066
2250
  return _wrong_type_message(obj, name, self.__name__, str(e))
2067
2251
 
2068
2252
 
2253
+ @_set__name__
2069
2254
  class keys(compiled_schema):
2070
2255
  """
2071
2256
  This represents a dictionary containing all the keys in a collection of
@@ -2073,6 +2258,7 @@ class keys(compiled_schema):
2073
2258
  """
2074
2259
 
2075
2260
  args: tuple[object, ...]
2261
+ __name__: str
2076
2262
 
2077
2263
  def __init__(self, *args: object) -> None:
2078
2264
  """
@@ -2088,7 +2274,9 @@ class keys(compiled_schema):
2088
2274
  subs: Mapping[str, object] = {},
2089
2275
  ) -> str:
2090
2276
  if not isinstance(obj, Mapping):
2091
- return _wrong_type_message(obj, name, "Mapping") # TODO: __name__
2277
+ return _wrong_type_message(
2278
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a Mapping"
2279
+ )
2092
2280
  for k in self.args:
2093
2281
  if k not in obj:
2094
2282
  return f"{name}[{repr(k)}] is missing"
@@ -2268,6 +2456,7 @@ class _fields(compiled_schema):
2268
2456
  return ""
2269
2457
 
2270
2458
 
2459
+ @_set__name__
2271
2460
  class fields(wrapper, Generic[StringKeyType]):
2272
2461
  """
2273
2462
  `d` is a dictionary `{"field1": schema1, ...}`.
@@ -2277,6 +2466,7 @@ class fields(wrapper, Generic[StringKeyType]):
2277
2466
  """
2278
2467
 
2279
2468
  d: Mapping[StringKeyType, object]
2469
+ __name__: str
2280
2470
 
2281
2471
  def __init__(self, d: Mapping[StringKeyType, object]) -> None:
2282
2472
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vtjson
3
- Version: 2.2.6
3
+ Version: 2.2.8
4
4
  Summary: An easy to use validation library compatible with Python type annotations
5
5
  Author-email: Michel Van den Bergh <michel.vandenbergh@uhasselt.be>
6
6
  Project-URL: Homepage, https://github.com/vdbergh/vtjson
@@ -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=Fj74tRDCniPjuaCUdwRbTmBJEeS9yaXiD2M7d03Q-wE,91767
4
+ vtjson-2.2.8.dist-info/licenses/AUTHORS,sha256=qmxaXxaIO-YPNHJAZ0dcCrnPCs1x9ocbtMksiy4i80M,21
5
+ vtjson-2.2.8.dist-info/licenses/LICENSE,sha256=n7xW-zX8xBLHzCdqWIMRuMzBD_ACLcNCwio0LEkKt1o,1077
6
+ vtjson-2.2.8.dist-info/METADATA,sha256=GyByXqMU-lqhEeolMZt4LlN3KIizRRrGfbP4AiP3AN8,3980
7
+ vtjson-2.2.8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
8
+ vtjson-2.2.8.dist-info/top_level.txt,sha256=9DlSF3l63igcvnYPcj117F2hzOW4Nx0N-JBoW3jjBZM,7
9
+ vtjson-2.2.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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=yUD2ojGUUlDZ-KVF5Tzhle6VRoMZx8HVODhWMFFJrZc,87751
4
- vtjson-2.2.6.dist-info/licenses/AUTHORS,sha256=qmxaXxaIO-YPNHJAZ0dcCrnPCs1x9ocbtMksiy4i80M,21
5
- vtjson-2.2.6.dist-info/licenses/LICENSE,sha256=n7xW-zX8xBLHzCdqWIMRuMzBD_ACLcNCwio0LEkKt1o,1077
6
- vtjson-2.2.6.dist-info/METADATA,sha256=yHpR0TUruUh51sZEtYuCveijFPlTtB-ju2WfYYRXR-g,3980
7
- vtjson-2.2.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- vtjson-2.2.6.dist-info/top_level.txt,sha256=9DlSF3l63igcvnYPcj117F2hzOW4Nx0N-JBoW3jjBZM,7
9
- vtjson-2.2.6.dist-info/RECORD,,