vtjson 2.2.6__py3-none-any.whl → 2.2.7__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.7"
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
 
@@ -823,6 +899,7 @@ class set_name(wrapper):
823
899
  )
824
900
 
825
901
 
902
+ @_set__name__
826
903
  class regex(compiled_schema):
827
904
  """
828
905
  This matches the strings which match the given pattern.
@@ -857,10 +934,6 @@ class regex(compiled_schema):
857
934
  if not isinstance(name, str):
858
935
  raise SchemaError(f"The regex name {_c(name)} is not a string")
859
936
  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
937
 
865
938
  try:
866
939
  self.pattern = re.compile(regex, flags)
@@ -878,7 +951,9 @@ class regex(compiled_schema):
878
951
  subs: Mapping[str, object] = {},
879
952
  ) -> str:
880
953
  if not isinstance(obj, str):
881
- return _wrong_type_message(obj, name, self.__name__)
954
+ return _wrong_type_message(
955
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
956
+ )
882
957
  try:
883
958
  if self.fullmatch and self.pattern.fullmatch(obj):
884
959
  return ""
@@ -889,6 +964,7 @@ class regex(compiled_schema):
889
964
  return _wrong_type_message(obj, name, self.__name__)
890
965
 
891
966
 
967
+ @_set__name__
892
968
  class glob(compiled_schema):
893
969
  """
894
970
  Unix style filename matching. This is implemented using
@@ -910,9 +986,7 @@ class glob(compiled_schema):
910
986
 
911
987
  self.pattern = pattern
912
988
 
913
- if name is None:
914
- self.__name__ = f"glob({repr(pattern)})"
915
- else:
989
+ if name is not None:
916
990
  self.__name__ = name
917
991
 
918
992
  try:
@@ -931,7 +1005,9 @@ class glob(compiled_schema):
931
1005
  subs: Mapping[str, object] = {},
932
1006
  ) -> str:
933
1007
  if not isinstance(obj, str):
934
- return _wrong_type_message(obj, name, self.__name__)
1008
+ return _wrong_type_message(
1009
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
1010
+ )
935
1011
  try:
936
1012
  if pathlib.PurePath(obj).match(self.pattern):
937
1013
  return ""
@@ -941,6 +1017,7 @@ class glob(compiled_schema):
941
1017
  return _wrong_type_message(obj, name, self.__name__, str(e))
942
1018
 
943
1019
 
1020
+ @_set__name__
944
1021
  class magic(compiled_schema):
945
1022
  """
946
1023
  Checks if a buffer (for example a string or a byte array) has the given
@@ -966,9 +1043,7 @@ class magic(compiled_schema):
966
1043
 
967
1044
  self.mime_type = mime_type
968
1045
 
969
- if name is None:
970
- self.__name__ = f"magic({repr(mime_type)})"
971
- else:
1046
+ if name is not None:
972
1047
  self.__name__ = name
973
1048
 
974
1049
  def __validate__(
@@ -979,7 +1054,12 @@ class magic(compiled_schema):
979
1054
  subs: Mapping[str, object] = {},
980
1055
  ) -> str:
981
1056
  if not isinstance(obj, (str, bytes)):
982
- return _wrong_type_message(obj, name, self.__name__)
1057
+ return _wrong_type_message(
1058
+ obj,
1059
+ name,
1060
+ self.__name__,
1061
+ explanation=f"{_c(obj)} is not a string nor bytes",
1062
+ )
983
1063
  try:
984
1064
  objmime_type = magic_.from_buffer(obj, mime=True)
985
1065
  except Exception as e:
@@ -994,6 +1074,7 @@ class magic(compiled_schema):
994
1074
  return ""
995
1075
 
996
1076
 
1077
+ @_set__name__
997
1078
  class div(compiled_schema):
998
1079
  """
999
1080
  This matches the integers `x` such that `(x - remainder) % divisor` == 0.
@@ -1024,13 +1105,7 @@ class div(compiled_schema):
1024
1105
  self.divisor = divisor
1025
1106
  self.remainder = remainder
1026
1107
 
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:
1108
+ if name is not None:
1034
1109
  self.__name__ = name
1035
1110
 
1036
1111
  def __validate__(
@@ -1041,13 +1116,16 @@ class div(compiled_schema):
1041
1116
  subs: Mapping[str, object] = {},
1042
1117
  ) -> str:
1043
1118
  if not isinstance(obj, int):
1044
- return _wrong_type_message(obj, name, "int")
1119
+ return _wrong_type_message(
1120
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not an integer"
1121
+ )
1045
1122
  elif (obj - self.remainder) % self.divisor == 0:
1046
1123
  return ""
1047
1124
  else:
1048
1125
  return _wrong_type_message(obj, name, self.__name__)
1049
1126
 
1050
1127
 
1128
+ @_set__name__
1051
1129
  class close_to(compiled_schema):
1052
1130
  """
1053
1131
  This matches the real numbers that are close to `x` in the sense of
@@ -1087,9 +1165,6 @@ class close_to(compiled_schema):
1087
1165
  )
1088
1166
  self.kw["abs_tol"] = abs_tol
1089
1167
 
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
1168
  self.x = x
1094
1169
 
1095
1170
  def __validate__(
@@ -1100,19 +1175,23 @@ class close_to(compiled_schema):
1100
1175
  subs: Mapping[str, object] = {},
1101
1176
  ) -> str:
1102
1177
  if not isinstance(obj, (float, int)):
1103
- return _wrong_type_message(obj, name, "number")
1178
+ return _wrong_type_message(
1179
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not an integer"
1180
+ )
1104
1181
  elif math.isclose(obj, self.x, **self.kw):
1105
1182
  return ""
1106
1183
  else:
1107
1184
  return _wrong_type_message(obj, name, self.__name__)
1108
1185
 
1109
1186
 
1187
+ @_set__name__
1110
1188
  class gt(compiled_schema):
1111
1189
  """
1112
1190
  This checks if `object > lb`.
1113
1191
  """
1114
1192
 
1115
1193
  lb: comparable
1194
+ __name__: str
1116
1195
 
1117
1196
  def __init__(self, lb: comparable) -> None:
1118
1197
  """
@@ -1148,12 +1227,14 @@ class gt(compiled_schema):
1148
1227
  return f"{self.message(name, obj)}: {str(e)}"
1149
1228
 
1150
1229
 
1230
+ @_set__name__
1151
1231
  class ge(compiled_schema):
1152
1232
  """
1153
1233
  This checks if `object >= lb`.
1154
1234
  """
1155
1235
 
1156
1236
  lb: comparable
1237
+ __name__: str
1157
1238
 
1158
1239
  def __init__(self, lb: comparable) -> None:
1159
1240
  """
@@ -1189,12 +1270,14 @@ class ge(compiled_schema):
1189
1270
  return f"{self.message(name, obj)}: {str(e)}"
1190
1271
 
1191
1272
 
1273
+ @_set__name__
1192
1274
  class lt(compiled_schema):
1193
1275
  """
1194
1276
  This checks if `object < ub`.
1195
1277
  """
1196
1278
 
1197
1279
  ub: comparable
1280
+ __name__: str
1198
1281
 
1199
1282
  def __init__(self, ub: comparable) -> None:
1200
1283
  """
@@ -1230,12 +1313,14 @@ class lt(compiled_schema):
1230
1313
  return f"{self.message(name, obj)}: {str(e)}"
1231
1314
 
1232
1315
 
1316
+ @_set__name__
1233
1317
  class le(compiled_schema):
1234
1318
  """
1235
1319
  This checks if `object <= ub`.
1236
1320
  """
1237
1321
 
1238
1322
  ub: comparable
1323
+ __name__: str
1239
1324
 
1240
1325
  def __init__(self, ub: comparable) -> None:
1241
1326
  """
@@ -1271,6 +1356,7 @@ class le(compiled_schema):
1271
1356
  return f"{self.message(name, obj)}: {str(e)}"
1272
1357
 
1273
1358
 
1359
+ @_set__name__
1274
1360
  class interval(compiled_schema):
1275
1361
  """
1276
1362
  This checks if `lb <= object <= ub`, provided the comparisons make sense.
@@ -1278,6 +1364,7 @@ class interval(compiled_schema):
1278
1364
 
1279
1365
  lb_s: str
1280
1366
  ub_s: str
1367
+ __name__: str
1281
1368
 
1282
1369
  def __init__(
1283
1370
  self,
@@ -1346,6 +1433,7 @@ class interval(compiled_schema):
1346
1433
  setattr(self, "__validate__", anything().__validate__)
1347
1434
 
1348
1435
 
1436
+ @_set__name__
1349
1437
  class size(compiled_schema):
1350
1438
  """
1351
1439
  Matches the objects (which support `len()` such as strings or lists) whose
@@ -1353,6 +1441,7 @@ class size(compiled_schema):
1353
1441
  """
1354
1442
 
1355
1443
  interval_: interval
1444
+ __name__: str
1356
1445
 
1357
1446
  def __init__(self, lb: int, ub: int | types.EllipsisType | None = None) -> None:
1358
1447
  """
@@ -1625,11 +1714,14 @@ def validate(
1625
1714
  # Some predefined schemas
1626
1715
 
1627
1716
 
1717
+ @_set__name__
1628
1718
  class number(compiled_schema):
1629
1719
  """
1630
1720
  A deprecated alias for `float`.
1631
1721
  """
1632
1722
 
1723
+ __name__: str
1724
+
1633
1725
  def __init__(self) -> None:
1634
1726
  warnings.warn(
1635
1727
  "The schema 'number' is deprecated. Use 'float' instead.",
@@ -1646,14 +1738,20 @@ class number(compiled_schema):
1646
1738
  if isinstance(obj, (int, float)):
1647
1739
  return ""
1648
1740
  else:
1649
- return _wrong_type_message(obj, name, "number")
1741
+ return _wrong_type_message(obj, name, self.__name__)
1650
1742
 
1651
1743
 
1744
+ @_set__name__
1652
1745
  class float_(compiled_schema):
1653
1746
  """
1654
1747
  Schema that only matches floats. Not ints.
1655
1748
  """
1656
1749
 
1750
+ __name__: str
1751
+
1752
+ def __init__(self) -> None:
1753
+ pass
1754
+
1657
1755
  def __validate__(
1658
1756
  self,
1659
1757
  obj: object,
@@ -1664,9 +1762,10 @@ class float_(compiled_schema):
1664
1762
  if isinstance(obj, float):
1665
1763
  return ""
1666
1764
  else:
1667
- return _wrong_type_message(obj, name, "float_")
1765
+ return _wrong_type_message(obj, name, self.__name__)
1668
1766
 
1669
1767
 
1768
+ @_set__name__
1670
1769
  class email(compiled_schema):
1671
1770
  """
1672
1771
  Checks if the object is a valid email address. This uses the package
@@ -1675,6 +1774,7 @@ class email(compiled_schema):
1675
1774
  """
1676
1775
 
1677
1776
  kw: dict[str, Any]
1777
+ __name__: str
1678
1778
 
1679
1779
  def __init__(self, **kw: Any) -> None:
1680
1780
  """
@@ -1695,14 +1795,17 @@ class email(compiled_schema):
1695
1795
  subs: Mapping[str, object] = {},
1696
1796
  ) -> str:
1697
1797
  if not isinstance(obj, str):
1698
- return _wrong_type_message(obj, name, "email", f"{_c(obj)} is not a string")
1798
+ return _wrong_type_message(
1799
+ obj, name, self.__name__, f"{_c(obj)} is not a string"
1800
+ )
1699
1801
  try:
1700
1802
  email_validator.validate_email(obj, **self.kw)
1701
1803
  return ""
1702
1804
  except Exception as e:
1703
- return _wrong_type_message(obj, name, "email", str(e))
1805
+ return _wrong_type_message(obj, name, self.__name__, str(e))
1704
1806
 
1705
1807
 
1808
+ @_set__name__
1706
1809
  class ip_address(compiled_schema):
1707
1810
  """
1708
1811
  Matches ip addresses of the specified version which can be 4, 6 or None.
@@ -1719,10 +1822,7 @@ class ip_address(compiled_schema):
1719
1822
  """
1720
1823
  if version is not None and version not in (4, 6):
1721
1824
  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})"
1825
+
1726
1826
  if version == 4:
1727
1827
  self.method = ipaddress.IPv4Address
1728
1828
  elif version == 6:
@@ -1738,7 +1838,12 @@ class ip_address(compiled_schema):
1738
1838
  subs: Mapping[str, object] = {},
1739
1839
  ) -> str:
1740
1840
  if not isinstance(obj, (int, str, bytes)):
1741
- return _wrong_type_message(obj, name, self.__name__)
1841
+ return _wrong_type_message(
1842
+ obj,
1843
+ name,
1844
+ self.__name__,
1845
+ explanation=f"{_c(obj)} is not a string, an int or bytes",
1846
+ )
1742
1847
  try:
1743
1848
  self.method(obj)
1744
1849
  except ValueError as e:
@@ -1746,6 +1851,7 @@ class ip_address(compiled_schema):
1746
1851
  return ""
1747
1852
 
1748
1853
 
1854
+ @_set__name__
1749
1855
  class regex_pattern(compiled_schema):
1750
1856
  """
1751
1857
  Matches valid regular expression patterns
@@ -1754,7 +1860,7 @@ class regex_pattern(compiled_schema):
1754
1860
  __name__: str
1755
1861
 
1756
1862
  def __init__(self) -> None:
1757
- self.__name__ = "regex_pattern"
1863
+ pass
1758
1864
 
1759
1865
  def __validate__(
1760
1866
  self,
@@ -1764,7 +1870,9 @@ class regex_pattern(compiled_schema):
1764
1870
  subs: Mapping[str, object] = {},
1765
1871
  ) -> str:
1766
1872
  if not isinstance(obj, str):
1767
- return _wrong_type_message(obj, name, self.__name__)
1873
+ return _wrong_type_message(
1874
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
1875
+ )
1768
1876
  try:
1769
1877
  re.compile(obj)
1770
1878
  except re.error as e:
@@ -1772,11 +1880,60 @@ class regex_pattern(compiled_schema):
1772
1880
  return ""
1773
1881
 
1774
1882
 
1883
+ @_set__name__
1884
+ class unique(compiled_schema):
1885
+ """
1886
+ Matches containers whose entries do not repeat. We first attempt to convert the
1887
+ object to a set and check its size. If this does not work then we check the
1888
+ entries of the object one by one (this is a quadratic algorithm).
1889
+ """
1890
+
1891
+ __name__: str
1892
+
1893
+ def __init__(self) -> None:
1894
+ pass
1895
+
1896
+ def __validate__(
1897
+ self,
1898
+ obj: object,
1899
+ name: str = "object",
1900
+ strict: bool = True,
1901
+ subs: Mapping[str, object] = {},
1902
+ ) -> str:
1903
+ if not isinstance(obj, Iterable):
1904
+ return _wrong_type_message(
1905
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not iterable"
1906
+ )
1907
+ try:
1908
+ if isinstance(obj, Sized):
1909
+ if len(set(obj)) == len(obj):
1910
+ return ""
1911
+ except Exception:
1912
+ pass
1913
+ try:
1914
+ object_list = []
1915
+ for o in obj:
1916
+ if o in object_list:
1917
+ return _wrong_type_message(
1918
+ obj, name, self.__name__, explanation=f"{_c(o)} is repeated"
1919
+ )
1920
+ object_list.append(o)
1921
+ except Exception as e:
1922
+ return _wrong_type_message(obj, name, self.__name__, explanation=str(e))
1923
+ return ""
1924
+
1925
+
1926
+ @_set__name__
1775
1927
  class url(compiled_schema):
1776
1928
  """
1777
1929
  Matches valid urls.
1778
1930
  """
1779
1931
 
1932
+ __name__: str
1933
+
1934
+ def __init__(self) -> None:
1935
+ pass
1936
+
1780
1937
  def __validate__(
1781
1938
  self,
1782
1939
  obj: object,
@@ -1785,13 +1942,16 @@ class url(compiled_schema):
1785
1942
  subs: Mapping[str, object] = {},
1786
1943
  ) -> str:
1787
1944
  if not isinstance(obj, str):
1788
- return _wrong_type_message(obj, name, "url")
1945
+ return _wrong_type_message(
1946
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
1947
+ )
1789
1948
  result = urllib.parse.urlparse(obj)
1790
1949
  if all([result.scheme, result.netloc]):
1791
1950
  return ""
1792
- return _wrong_type_message(obj, name, "url")
1951
+ return _wrong_type_message(obj, name, self.__name__)
1793
1952
 
1794
1953
 
1954
+ @_set__name__
1795
1955
  class date_time(compiled_schema):
1796
1956
  """
1797
1957
  Without argument this represents an ISO 8601 date-time. The `format`
@@ -1806,10 +1966,6 @@ class date_time(compiled_schema):
1806
1966
  :param format: format string for `strftime`
1807
1967
  """
1808
1968
  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
1969
 
1814
1970
  def __validate__(
1815
1971
  self,
@@ -1819,7 +1975,9 @@ class date_time(compiled_schema):
1819
1975
  subs: Mapping[str, object] = {},
1820
1976
  ) -> str:
1821
1977
  if not isinstance(obj, str):
1822
- return _wrong_type_message(obj, name, self.__name__)
1978
+ return _wrong_type_message(
1979
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
1980
+ )
1823
1981
  if self.format is not None:
1824
1982
  try:
1825
1983
  datetime.datetime.strptime(obj, self.format)
@@ -1833,11 +1991,17 @@ class date_time(compiled_schema):
1833
1991
  return ""
1834
1992
 
1835
1993
 
1994
+ @_set__name__
1836
1995
  class date(compiled_schema):
1837
1996
  """
1838
1997
  Matches an ISO 8601 date.
1839
1998
  """
1840
1999
 
2000
+ __name__: str
2001
+
2002
+ def __init__(self) -> None:
2003
+ pass
2004
+
1841
2005
  def __validate__(
1842
2006
  self,
1843
2007
  obj: object,
@@ -1846,19 +2010,27 @@ class date(compiled_schema):
1846
2010
  subs: Mapping[str, object] = {},
1847
2011
  ) -> str:
1848
2012
  if not isinstance(obj, str):
1849
- return _wrong_type_message(obj, name, "date")
2013
+ return _wrong_type_message(
2014
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
2015
+ )
1850
2016
  try:
1851
2017
  datetime.date.fromisoformat(obj)
1852
2018
  except Exception as e:
1853
- return _wrong_type_message(obj, name, "date", str(e))
2019
+ return _wrong_type_message(obj, name, self.__name__, str(e))
1854
2020
  return ""
1855
2021
 
1856
2022
 
2023
+ @_set__name__
1857
2024
  class time(compiled_schema):
1858
2025
  """
1859
2026
  Matches an ISO 8601 time.
1860
2027
  """
1861
2028
 
2029
+ __name__: str
2030
+
2031
+ def __init__(self) -> None:
2032
+ pass
2033
+
1862
2034
  def __validate__(
1863
2035
  self,
1864
2036
  obj: object,
@@ -1867,19 +2039,27 @@ class time(compiled_schema):
1867
2039
  subs: Mapping[str, object] = {},
1868
2040
  ) -> str:
1869
2041
  if not isinstance(obj, str):
1870
- return _wrong_type_message(obj, name, "date")
2042
+ return _wrong_type_message(
2043
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
2044
+ )
1871
2045
  try:
1872
2046
  datetime.time.fromisoformat(obj)
1873
2047
  except Exception as e:
1874
- return _wrong_type_message(obj, name, "time", str(e))
2048
+ return _wrong_type_message(obj, name, self.__name__, str(e))
1875
2049
  return ""
1876
2050
 
1877
2051
 
2052
+ @_set__name__
1878
2053
  class nothing(compiled_schema):
1879
2054
  """
1880
2055
  Matches nothing.
1881
2056
  """
1882
2057
 
2058
+ __name__: str
2059
+
2060
+ def __init__(self) -> None:
2061
+ pass
2062
+
1883
2063
  def __validate__(
1884
2064
  self,
1885
2065
  obj: object,
@@ -1887,14 +2067,20 @@ class nothing(compiled_schema):
1887
2067
  strict: bool = True,
1888
2068
  subs: Mapping[str, object] = {},
1889
2069
  ) -> str:
1890
- return _wrong_type_message(obj, name, "nothing")
2070
+ return _wrong_type_message(obj, name, self.__name__)
1891
2071
 
1892
2072
 
2073
+ @_set__name__
1893
2074
  class anything(compiled_schema):
1894
2075
  """
1895
2076
  Matchess anything.
1896
2077
  """
1897
2078
 
2079
+ __name__: str
2080
+
2081
+ def __init__(self) -> None:
2082
+ pass
2083
+
1898
2084
  def __validate__(
1899
2085
  self,
1900
2086
  obj: object,
@@ -1905,6 +2091,7 @@ class anything(compiled_schema):
1905
2091
  return ""
1906
2092
 
1907
2093
 
2094
+ @_set__name__
1908
2095
  class domain_name(compiled_schema):
1909
2096
  """
1910
2097
  Checks if the object is a valid domain name.
@@ -1923,16 +2110,6 @@ class domain_name(compiled_schema):
1923
2110
  self.re_ascii = re.compile(r"[\x00-\x7F]*")
1924
2111
  self.ascii_only = ascii_only
1925
2112
  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
2113
 
1937
2114
  def __validate__(
1938
2115
  self,
@@ -1942,7 +2119,9 @@ class domain_name(compiled_schema):
1942
2119
  subs: Mapping[str, object] = {},
1943
2120
  ) -> str:
1944
2121
  if not isinstance(obj, str):
1945
- return _wrong_type_message(obj, name, self.__name__)
2122
+ return _wrong_type_message(
2123
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a string"
2124
+ )
1946
2125
  if self.ascii_only:
1947
2126
  if not self.re_ascii.fullmatch(obj):
1948
2127
  return _wrong_type_message(
@@ -1961,6 +2140,7 @@ class domain_name(compiled_schema):
1961
2140
  return ""
1962
2141
 
1963
2142
 
2143
+ @_set__name__
1964
2144
  class at_least_one_of(compiled_schema):
1965
2145
  """
1966
2146
  This represents a dictionary with a least one key among a collection of
@@ -1975,8 +2155,6 @@ class at_least_one_of(compiled_schema):
1975
2155
  :param args: a collection of keys
1976
2156
  """
1977
2157
  self.args = args
1978
- args_s = [repr(a) for a in args]
1979
- self.__name__ = f"{self.__class__.__name__}({','.join(args_s)})"
1980
2158
 
1981
2159
  def __validate__(
1982
2160
  self,
@@ -1986,7 +2164,9 @@ class at_least_one_of(compiled_schema):
1986
2164
  subs: Mapping[str, object] = {},
1987
2165
  ) -> str:
1988
2166
  if not isinstance(obj, Mapping):
1989
- return _wrong_type_message(obj, name, self.__name__)
2167
+ return _wrong_type_message(
2168
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a Mapping"
2169
+ )
1990
2170
  try:
1991
2171
  if any([a in obj for a in self.args]):
1992
2172
  return ""
@@ -1996,6 +2176,7 @@ class at_least_one_of(compiled_schema):
1996
2176
  return _wrong_type_message(obj, name, self.__name__, str(e))
1997
2177
 
1998
2178
 
2179
+ @_set__name__
1999
2180
  class at_most_one_of(compiled_schema):
2000
2181
  """
2001
2182
  This represents an dictionary with at most one key among a collection of
@@ -2010,8 +2191,6 @@ class at_most_one_of(compiled_schema):
2010
2191
  :param args: a collection of keys
2011
2192
  """
2012
2193
  self.args = args
2013
- args_s = [repr(a) for a in args]
2014
- self.__name__ = f"{self.__class__.__name__}({','.join(args_s)})"
2015
2194
 
2016
2195
  def __validate__(
2017
2196
  self,
@@ -2021,7 +2200,9 @@ class at_most_one_of(compiled_schema):
2021
2200
  subs: Mapping[str, object] = {},
2022
2201
  ) -> str:
2023
2202
  if not isinstance(obj, Mapping):
2024
- return _wrong_type_message(obj, name, self.__name__)
2203
+ return _wrong_type_message(
2204
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a Mapping"
2205
+ )
2025
2206
  try:
2026
2207
  if sum([a in obj for a in self.args]) <= 1:
2027
2208
  return ""
@@ -2031,6 +2212,7 @@ class at_most_one_of(compiled_schema):
2031
2212
  return _wrong_type_message(obj, name, self.__name__, str(e))
2032
2213
 
2033
2214
 
2215
+ @_set__name__
2034
2216
  class one_of(compiled_schema):
2035
2217
  """
2036
2218
  This represents a dictionary with exactly one key among a collection of
@@ -2045,8 +2227,6 @@ class one_of(compiled_schema):
2045
2227
  :param args: a collection of keys
2046
2228
  """
2047
2229
  self.args = args
2048
- args_s = [repr(a) for a in args]
2049
- self.__name__ = f"{self.__class__.__name__}({','.join(args_s)})"
2050
2230
 
2051
2231
  def __validate__(
2052
2232
  self,
@@ -2056,7 +2236,9 @@ class one_of(compiled_schema):
2056
2236
  subs: Mapping[str, object] = {},
2057
2237
  ) -> str:
2058
2238
  if not isinstance(obj, Mapping):
2059
- return _wrong_type_message(obj, name, self.__name__)
2239
+ return _wrong_type_message(
2240
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a Mapping"
2241
+ )
2060
2242
  try:
2061
2243
  if sum([a in obj for a in self.args]) == 1:
2062
2244
  return ""
@@ -2066,6 +2248,7 @@ class one_of(compiled_schema):
2066
2248
  return _wrong_type_message(obj, name, self.__name__, str(e))
2067
2249
 
2068
2250
 
2251
+ @_set__name__
2069
2252
  class keys(compiled_schema):
2070
2253
  """
2071
2254
  This represents a dictionary containing all the keys in a collection of
@@ -2073,6 +2256,7 @@ class keys(compiled_schema):
2073
2256
  """
2074
2257
 
2075
2258
  args: tuple[object, ...]
2259
+ __name__: str
2076
2260
 
2077
2261
  def __init__(self, *args: object) -> None:
2078
2262
  """
@@ -2088,7 +2272,9 @@ class keys(compiled_schema):
2088
2272
  subs: Mapping[str, object] = {},
2089
2273
  ) -> str:
2090
2274
  if not isinstance(obj, Mapping):
2091
- return _wrong_type_message(obj, name, "Mapping") # TODO: __name__
2275
+ return _wrong_type_message(
2276
+ obj, name, self.__name__, explanation=f"{_c(obj)} is not a Mapping"
2277
+ )
2092
2278
  for k in self.args:
2093
2279
  if k not in obj:
2094
2280
  return f"{name}[{repr(k)}] is missing"
@@ -2268,6 +2454,7 @@ class _fields(compiled_schema):
2268
2454
  return ""
2269
2455
 
2270
2456
 
2457
+ @_set__name__
2271
2458
  class fields(wrapper, Generic[StringKeyType]):
2272
2459
  """
2273
2460
  `d` is a dictionary `{"field1": schema1, ...}`.
@@ -2277,6 +2464,7 @@ class fields(wrapper, Generic[StringKeyType]):
2277
2464
  """
2278
2465
 
2279
2466
  d: Mapping[StringKeyType, object]
2467
+ __name__: str
2280
2468
 
2281
2469
  def __init__(self, d: Mapping[StringKeyType, object]) -> None:
2282
2470
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vtjson
3
- Version: 2.2.6
3
+ Version: 2.2.7
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=AZOYnkjYeefa6agUiU7FUl7_fk8tUAxGBsqc6a1Hee0,91671
4
+ vtjson-2.2.7.dist-info/licenses/AUTHORS,sha256=qmxaXxaIO-YPNHJAZ0dcCrnPCs1x9ocbtMksiy4i80M,21
5
+ vtjson-2.2.7.dist-info/licenses/LICENSE,sha256=n7xW-zX8xBLHzCdqWIMRuMzBD_ACLcNCwio0LEkKt1o,1077
6
+ vtjson-2.2.7.dist-info/METADATA,sha256=Rvm5_Z2otxfFfcf8StFHpZAIOuNmqXu-GQNFflf7MRs,3980
7
+ vtjson-2.2.7.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
8
+ vtjson-2.2.7.dist-info/top_level.txt,sha256=9DlSF3l63igcvnYPcj117F2hzOW4Nx0N-JBoW3jjBZM,7
9
+ vtjson-2.2.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
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,,