pyglove 0.4.5.dev202501050808__py3-none-any.whl → 0.4.5.dev202501060809__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.
Files changed (91) hide show
  1. pyglove/core/__init__.py +24 -21
  2. pyglove/core/geno/base.py +53 -38
  3. pyglove/core/geno/base_test.py +2 -4
  4. pyglove/core/geno/categorical.py +36 -27
  5. pyglove/core/geno/custom.py +18 -15
  6. pyglove/core/geno/numerical.py +19 -16
  7. pyglove/core/geno/space.py +3 -4
  8. pyglove/core/hyper/base.py +6 -6
  9. pyglove/core/hyper/categorical.py +91 -52
  10. pyglove/core/hyper/custom.py +7 -7
  11. pyglove/core/hyper/custom_test.py +9 -10
  12. pyglove/core/hyper/derived.py +30 -22
  13. pyglove/core/hyper/derived_test.py +2 -4
  14. pyglove/core/hyper/dynamic_evaluation.py +3 -4
  15. pyglove/core/hyper/evolvable.py +57 -46
  16. pyglove/core/hyper/numerical.py +48 -24
  17. pyglove/core/hyper/numerical_test.py +9 -9
  18. pyglove/core/hyper/object_template.py +58 -46
  19. pyglove/core/logging_test.py +0 -2
  20. pyglove/core/patching/object_factory.py +4 -4
  21. pyglove/core/patching/pattern_based.py +4 -4
  22. pyglove/core/patching/rule_based.py +4 -3
  23. pyglove/core/symbolic/base.py +167 -131
  24. pyglove/core/symbolic/base_test.py +17 -19
  25. pyglove/core/symbolic/boilerplate.py +4 -5
  26. pyglove/core/symbolic/class_wrapper.py +9 -9
  27. pyglove/core/symbolic/compounding.py +2 -2
  28. pyglove/core/symbolic/compounding_test.py +2 -4
  29. pyglove/core/symbolic/dict.py +70 -54
  30. pyglove/core/symbolic/dict_test.py +117 -100
  31. pyglove/core/symbolic/diff.py +12 -12
  32. pyglove/core/symbolic/flags.py +1 -1
  33. pyglove/core/symbolic/functor.py +16 -15
  34. pyglove/core/symbolic/functor_test.py +2 -4
  35. pyglove/core/symbolic/inferred.py +2 -2
  36. pyglove/core/symbolic/list.py +70 -47
  37. pyglove/core/symbolic/list_test.py +117 -98
  38. pyglove/core/symbolic/object.py +42 -40
  39. pyglove/core/symbolic/object_test.py +95 -88
  40. pyglove/core/symbolic/origin.py +5 -7
  41. pyglove/core/symbolic/pure_symbolic.py +4 -3
  42. pyglove/core/symbolic/ref.py +12 -8
  43. pyglove/core/tuning/local_backend.py +2 -2
  44. pyglove/core/tuning/protocols.py +3 -3
  45. pyglove/core/typing/annotation_conversion.py +3 -3
  46. pyglove/core/typing/callable_ext.py +11 -13
  47. pyglove/core/typing/callable_signature.py +19 -18
  48. pyglove/core/typing/callable_signature_test.py +3 -5
  49. pyglove/core/typing/class_schema.py +48 -44
  50. pyglove/core/typing/class_schema_test.py +3 -5
  51. pyglove/core/typing/custom_typing.py +5 -4
  52. pyglove/core/typing/key_specs.py +5 -7
  53. pyglove/core/typing/key_specs_test.py +4 -4
  54. pyglove/core/typing/type_conversion.py +4 -5
  55. pyglove/core/typing/type_conversion_test.py +12 -12
  56. pyglove/core/typing/typed_missing.py +6 -7
  57. pyglove/core/typing/typed_missing_test.py +7 -8
  58. pyglove/core/typing/value_specs.py +210 -141
  59. pyglove/core/typing/value_specs_test.py +12 -13
  60. pyglove/core/utils/__init__.py +159 -0
  61. pyglove/core/{object_utils → utils}/common_traits_test.py +1 -3
  62. pyglove/core/{object_utils → utils}/docstr_utils_test.py +1 -3
  63. pyglove/core/{object_utils → utils}/error_utils.py +3 -3
  64. pyglove/core/{object_utils → utils}/error_utils_test.py +1 -1
  65. pyglove/core/{object_utils → utils}/formatting.py +1 -1
  66. pyglove/core/{object_utils → utils}/formatting_test.py +1 -2
  67. pyglove/core/{object_utils → utils}/hierarchical.py +23 -25
  68. pyglove/core/{object_utils → utils}/hierarchical_test.py +3 -5
  69. pyglove/core/{object_utils → utils}/json_conversion_test.py +1 -3
  70. pyglove/core/{object_utils → utils}/missing.py +2 -2
  71. pyglove/core/{object_utils → utils}/missing_test.py +2 -4
  72. pyglove/core/{object_utils → utils}/thread_local_test.py +1 -3
  73. pyglove/core/{object_utils → utils}/timing.py +3 -3
  74. pyglove/core/{object_utils → utils}/timing_test.py +2 -3
  75. pyglove/core/{object_utils → utils}/value_location.py +2 -2
  76. pyglove/core/{object_utils → utils}/value_location_test.py +2 -4
  77. pyglove/core/views/base.py +25 -29
  78. pyglove/core/views/html/base.py +14 -15
  79. pyglove/core/views/html/controls/base.py +5 -5
  80. pyglove/core/views/html/controls/progress_bar.py +3 -5
  81. pyglove/core/views/html/tree_view.py +37 -35
  82. {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/METADATA +1 -1
  83. {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/RECORD +90 -90
  84. {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/WHEEL +1 -1
  85. pyglove/core/object_utils/__init__.py +0 -161
  86. /pyglove/core/{object_utils → utils}/common_traits.py +0 -0
  87. /pyglove/core/{object_utils → utils}/docstr_utils.py +0 -0
  88. /pyglove/core/{object_utils → utils}/json_conversion.py +0 -0
  89. /pyglove/core/{object_utils → utils}/thread_local.py +0 -0
  90. {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/LICENSE +0 -0
  91. {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/top_level.txt +0 -0
@@ -22,7 +22,7 @@ import re
22
22
  import sys
23
23
  import typing
24
24
  import __main__
25
- from pyglove.core import object_utils
25
+ from pyglove.core import utils
26
26
  from pyglove.core.typing import callable_signature
27
27
  from pyglove.core.typing import class_schema
28
28
  from pyglove.core.typing import inspect as pg_inspect
@@ -35,7 +35,7 @@ from pyglove.core.typing.class_schema import ValueSpec
35
35
  from pyglove.core.typing.custom_typing import CustomTyping
36
36
 
37
37
 
38
- MISSING_VALUE = object_utils.MISSING_VALUE
38
+ MISSING_VALUE = utils.MISSING_VALUE
39
39
 
40
40
 
41
41
  class _FrozenValuePlaceholder(CustomTyping):
@@ -169,7 +169,7 @@ class ValueSpecBase(ValueSpec):
169
169
  self,
170
170
  default: typing.Any,
171
171
  use_default_apply: bool = True,
172
- root_path: typing.Optional[object_utils.KeyPath] = None
172
+ root_path: typing.Optional[utils.KeyPath] = None,
173
173
  ) -> ValueSpec:
174
174
  """Set default value and returns `self`."""
175
175
  # NOTE(daiyip): Default can be schema.MissingValue types, all are
@@ -246,13 +246,13 @@ class ValueSpecBase(ValueSpec):
246
246
  self,
247
247
  value: typing.Any,
248
248
  allow_partial: bool = False,
249
- child_transform: typing.Optional[typing.Callable[
250
- [object_utils.KeyPath, Field, typing.Any],
251
- typing.Any
252
- ]] = None,
253
- root_path: typing.Optional[object_utils.KeyPath] = None) -> typing.Any: # pyformat: disable pylint: disable=line-too-long
249
+ child_transform: typing.Optional[
250
+ typing.Callable[[utils.KeyPath, Field, typing.Any], typing.Any]
251
+ ] = None,
252
+ root_path: typing.Optional[utils.KeyPath] = None,
253
+ ) -> typing.Any: # pyformat: disable pylint: disable=line-too-long
254
254
  """Apply spec to validate and complete value."""
255
- root_path = root_path or object_utils.KeyPath()
255
+ root_path = root_path or utils.KeyPath()
256
256
  if self.frozen and self.default is not _FROZEN_VALUE_PLACEHOLDER:
257
257
  # Always return the default value if a field is frozen.
258
258
  if MISSING_VALUE != value and self.default != value:
@@ -291,9 +291,8 @@ class ValueSpecBase(ValueSpec):
291
291
  value = self._transform(value)
292
292
  except Exception as e: # pylint: disable=broad-except
293
293
  raise e.__class__(
294
- object_utils.message_on_path(
295
- str(e), root_path)
296
- ).with_traceback(sys.exc_info()[2])
294
+ utils.message_on_path(str(e), root_path)
295
+ ).with_traceback(sys.exc_info()[2])
297
296
 
298
297
  return self.skip_user_transform.apply(
299
298
  value,
@@ -309,9 +308,12 @@ class ValueSpecBase(ValueSpec):
309
308
  converter = type_conversion.get_converter(type(value), self.value_type)
310
309
  if converter is None:
311
310
  raise TypeError(
312
- object_utils.message_on_path(
311
+ utils.message_on_path(
313
312
  f'Expect {self.value_type} '
314
- f'but encountered {type(value)!r}: {value}.', root_path))
313
+ f'but encountered {type(value)!r}: {value}.',
314
+ root_path,
315
+ )
316
+ )
315
317
  value = converter(value)
316
318
 
317
319
  # NOTE(daiyip): child nodes validation and transformation is done before
@@ -325,15 +327,18 @@ class ValueSpecBase(ValueSpec):
325
327
  self._validate(root_path, value)
326
328
  return value
327
329
 
328
- def _validate(self, path: object_utils.KeyPath, value: typing.Any):
330
+ def _validate(self, path: utils.KeyPath, value: typing.Any):
329
331
  """Validation on applied value. Child class can override."""
330
332
 
331
- def _apply(self,
332
- value: typing.Any,
333
- allow_partial: bool,
334
- child_transform: typing.Callable[
335
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
336
- root_path: object_utils.KeyPath) -> typing.Any:
333
+ def _apply(
334
+ self,
335
+ value: typing.Any,
336
+ allow_partial: bool,
337
+ child_transform: typing.Callable[
338
+ [utils.KeyPath, Field, typing.Any], typing.Any
339
+ ],
340
+ root_path: utils.KeyPath,
341
+ ) -> typing.Any:
337
342
  """Customized apply so each subclass can override."""
338
343
  del allow_partial
339
344
  del child_transform
@@ -401,17 +406,17 @@ class ValueSpecBase(ValueSpec):
401
406
  **kwargs
402
407
  ) -> str:
403
408
  """Format this object."""
404
- return object_utils.kvlist_str(
409
+ return utils.kvlist_str(
405
410
  [
406
411
  ('default', self._default, MISSING_VALUE),
407
412
  ('noneable', self._is_noneable, False),
408
- ('frozen', self._frozen, False)
413
+ ('frozen', self._frozen, False),
409
414
  ],
410
415
  label=self.__class__.__name__,
411
416
  compact=compact,
412
417
  verbose=verbose,
413
418
  root_indent=root_indent,
414
- **kwargs
419
+ **kwargs,
415
420
  )
416
421
 
417
422
 
@@ -552,15 +557,18 @@ class Str(Generic, PrimitiveType):
552
557
  **kwargs,
553
558
  )
554
559
 
555
- def _validate(self, path: object_utils.KeyPath, value: str) -> None:
560
+ def _validate(self, path: utils.KeyPath, value: str) -> None:
556
561
  """Validates applied value."""
557
562
  if not self._regex:
558
563
  return
559
564
  if not self._regex.match(value):
560
565
  raise ValueError(
561
- object_utils.message_on_path(
566
+ utils.message_on_path(
562
567
  f'String {value!r} does not match '
563
- f'regular expression {self._regex.pattern!r}.', path))
568
+ f'regular expression {self._regex.pattern!r}.',
569
+ path,
570
+ )
571
+ )
564
572
 
565
573
  @property
566
574
  def regex(self):
@@ -595,7 +603,7 @@ class Str(Generic, PrimitiveType):
595
603
  ) -> str:
596
604
  """Format this object."""
597
605
  regex_pattern = self._regex.pattern if self._regex else None
598
- return object_utils.kvlist_str(
606
+ return utils.kvlist_str(
599
607
  [
600
608
  ('default', self._default, MISSING_VALUE),
601
609
  ('regex', regex_pattern, None),
@@ -606,7 +614,7 @@ class Str(Generic, PrimitiveType):
606
614
  compact=compact,
607
615
  verbose=verbose,
608
616
  root_indent=root_indent,
609
- **kwargs
617
+ **kwargs,
610
618
  )
611
619
 
612
620
  def _eq(self, other: 'Str') -> bool:
@@ -665,15 +673,17 @@ class Number(Generic, PrimitiveType):
665
673
  """Returns maximum value of acceptable values."""
666
674
  return self._max_value
667
675
 
668
- def _validate(self, path: object_utils.KeyPath,
669
- value: numbers.Number) -> None:
676
+ def _validate(self, path: utils.KeyPath, value: numbers.Number) -> None:
670
677
  """Validates applied value."""
671
678
  if ((self._min_value is not None and value < self._min_value) or
672
679
  (self._max_value is not None and value > self._max_value)):
673
680
  raise ValueError(
674
- object_utils.message_on_path(
681
+ utils.message_on_path(
675
682
  f'Value {value} is out of range '
676
- f'(min={self._min_value}, max={self._max_value}).', path))
683
+ f'(min={self._min_value}, max={self._max_value}).',
684
+ path,
685
+ )
686
+ )
677
687
 
678
688
  def _extend(self, base: 'Number') -> None:
679
689
  """Number specific extend."""
@@ -726,19 +736,19 @@ class Number(Generic, PrimitiveType):
726
736
  **kwargs
727
737
  ) -> str:
728
738
  """Format this object."""
729
- return object_utils.kvlist_str(
739
+ return utils.kvlist_str(
730
740
  [
731
741
  ('default', self._default, MISSING_VALUE),
732
742
  ('min', self._min_value, None),
733
743
  ('max', self._max_value, None),
734
744
  ('noneable', self._is_noneable, False),
735
- ('frozen', self._frozen, False)
745
+ ('frozen', self._frozen, False),
736
746
  ],
737
747
  label=self.__class__.__name__,
738
748
  compact=compact,
739
749
  verbose=verbose,
740
750
  root_indent=root_indent,
741
- **kwargs
751
+ **kwargs,
742
752
  )
743
753
 
744
754
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -944,13 +954,14 @@ class Enum(Generic, PrimitiveType):
944
954
  """Returns all acceptable values of this spec."""
945
955
  return self._values
946
956
 
947
- def _validate(self, path: object_utils.KeyPath, value: typing.Any) -> None:
957
+ def _validate(self, path: utils.KeyPath, value: typing.Any) -> None:
948
958
  """Validates applied value."""
949
959
  if value not in self._values:
950
960
  raise ValueError(
951
- object_utils.message_on_path(
952
- f'Value {value!r} is not in candidate list {self._values}.',
953
- path))
961
+ utils.message_on_path(
962
+ f'Value {value!r} is not in candidate list {self._values}.', path
963
+ )
964
+ )
954
965
 
955
966
  def _extend(self, base: 'Enum') -> None:
956
967
  """Enum specific extend."""
@@ -995,7 +1006,7 @@ class Enum(Generic, PrimitiveType):
995
1006
  **kwargs
996
1007
  ) -> str:
997
1008
  """Format this object."""
998
- return object_utils.kvlist_str(
1009
+ return utils.kvlist_str(
999
1010
  [
1000
1011
  ('default', self._default, MISSING_VALUE),
1001
1012
  ('values', self._values, None),
@@ -1005,7 +1016,7 @@ class Enum(Generic, PrimitiveType):
1005
1016
  compact=compact,
1006
1017
  verbose=verbose,
1007
1018
  root_indent=root_indent,
1008
- **kwargs
1019
+ **kwargs,
1009
1020
  )
1010
1021
 
1011
1022
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -1133,12 +1144,15 @@ class List(Generic, ValueSpecBase):
1133
1144
  """Returns max size of the list."""
1134
1145
  return self._element.key.max_value # pytype: disable=attribute-error # bind-properties
1135
1146
 
1136
- def _apply(self,
1137
- value: typing.List[typing.Any],
1138
- allow_partial: bool,
1139
- child_transform: typing.Callable[
1140
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
1141
- root_path: object_utils.KeyPath) -> typing.Any:
1147
+ def _apply(
1148
+ self,
1149
+ value: typing.List[typing.Any],
1150
+ allow_partial: bool,
1151
+ child_transform: typing.Callable[
1152
+ [utils.KeyPath, Field, typing.Any], typing.Any
1153
+ ],
1154
+ root_path: utils.KeyPath,
1155
+ ) -> typing.Any:
1142
1156
  """List specific apply."""
1143
1157
  # NOTE(daiyip): for symbolic List, write access using `__setitem__` will
1144
1158
  # trigger permission error when `accessor_writable` is set to False.
@@ -1155,27 +1169,35 @@ class List(Generic, ValueSpecBase):
1155
1169
  getitem = getattr(value, 'sym_getattr', value.__getitem__)
1156
1170
  for i in range(len(value)):
1157
1171
  v = self._element.apply(
1158
- getitem(i), allow_partial=allow_partial, transform_fn=child_transform,
1159
- root_path=object_utils.KeyPath(i, root_path))
1172
+ getitem(i),
1173
+ allow_partial=allow_partial,
1174
+ transform_fn=child_transform,
1175
+ root_path=utils.KeyPath(i, root_path),
1176
+ )
1160
1177
  if getitem(i) is not v:
1161
1178
  set_item(i, v)
1162
1179
  return value
1163
1180
 
1164
- def _validate(
1165
- self, path: object_utils.KeyPath, value: typing.List[typing.Any]):
1181
+ def _validate(self, path: utils.KeyPath, value: typing.List[typing.Any]):
1166
1182
  """Validates applied value."""
1167
1183
  if len(value) < self.min_size:
1168
1184
  raise ValueError(
1169
- object_utils.message_on_path(
1185
+ utils.message_on_path(
1170
1186
  f'Length of list {value!r} is less than '
1171
- f'min size ({self.min_size}).', path))
1187
+ f'min size ({self.min_size}).',
1188
+ path,
1189
+ )
1190
+ )
1172
1191
 
1173
1192
  if self.max_size is not None:
1174
1193
  if len(value) > self.max_size:
1175
1194
  raise ValueError(
1176
- object_utils.message_on_path(
1195
+ utils.message_on_path(
1177
1196
  f'Length of list {value!r} is greater than '
1178
- f'max size ({self.max_size}).', path))
1197
+ f'max size ({self.max_size}).',
1198
+ path,
1199
+ )
1200
+ )
1179
1201
 
1180
1202
  def _extend(self, base: 'List') -> None:
1181
1203
  """List specific extend."""
@@ -1203,7 +1225,7 @@ class List(Generic, ValueSpecBase):
1203
1225
  **kwargs,
1204
1226
  ) -> str:
1205
1227
  """Format this object."""
1206
- return object_utils.kvlist_str(
1228
+ return utils.kvlist_str(
1207
1229
  [
1208
1230
  ('', self._element.value, None),
1209
1231
  ('min_size', self.min_size, 0),
@@ -1216,7 +1238,7 @@ class List(Generic, ValueSpecBase):
1216
1238
  compact=compact,
1217
1239
  verbose=verbose,
1218
1240
  root_indent=root_indent,
1219
- **kwargs
1241
+ **kwargs,
1220
1242
  )
1221
1243
 
1222
1244
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -1409,35 +1431,50 @@ class Tuple(Generic, ValueSpecBase):
1409
1431
  """Returns length of this tuple."""
1410
1432
  return len(self._elements) if self.fixed_length else 0
1411
1433
 
1412
- def _apply(self,
1413
- value: typing.Tuple[typing.Any, ...],
1414
- allow_partial: bool,
1415
- child_transform: typing.Callable[
1416
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
1417
- root_path: object_utils.KeyPath) -> typing.Any:
1434
+ def _apply(
1435
+ self,
1436
+ value: typing.Tuple[typing.Any, ...],
1437
+ allow_partial: bool,
1438
+ child_transform: typing.Callable[
1439
+ [utils.KeyPath, Field, typing.Any], typing.Any
1440
+ ],
1441
+ root_path: utils.KeyPath,
1442
+ ) -> typing.Any:
1418
1443
  """Tuple specific apply."""
1419
1444
  if self.fixed_length:
1420
1445
  if len(value) != len(self.elements):
1421
1446
  raise ValueError(
1422
- object_utils.message_on_path(
1447
+ utils.message_on_path(
1423
1448
  f'Length of input tuple ({len(value)}) does not match the '
1424
1449
  f'length of spec ({len(self.elements)}). '
1425
- f'Input: {value}, Spec: {self!r}', root_path))
1450
+ f'Input: {value}, Spec: {self!r}',
1451
+ root_path,
1452
+ )
1453
+ )
1426
1454
  else:
1427
1455
  if len(value) < self.min_size:
1428
1456
  raise ValueError(
1429
- object_utils.message_on_path(
1457
+ utils.message_on_path(
1430
1458
  f'Length of tuple {value} is less than '
1431
- f'min size ({self.min_size}).', root_path))
1459
+ f'min size ({self.min_size}).',
1460
+ root_path,
1461
+ )
1462
+ )
1432
1463
  if self.max_size is not None and len(value) > self.max_size:
1433
1464
  raise ValueError(
1434
- object_utils.message_on_path(
1465
+ utils.message_on_path(
1435
1466
  f'Length of tuple {value} is greater than '
1436
- f'max size ({self.max_size}).', root_path))
1467
+ f'max size ({self.max_size}).',
1468
+ root_path,
1469
+ )
1470
+ )
1437
1471
  return tuple([
1438
1472
  self._elements[i if self.fixed_length else 0].apply( # pylint: disable=g-complex-comprehension
1439
- v, allow_partial=allow_partial, transform_fn=child_transform,
1440
- root_path=object_utils.KeyPath(i, root_path))
1473
+ v,
1474
+ allow_partial=allow_partial,
1475
+ transform_fn=child_transform,
1476
+ root_path=utils.KeyPath(i, root_path),
1477
+ )
1441
1478
  for i, v in enumerate(value)
1442
1479
  ])
1443
1480
 
@@ -1527,7 +1564,7 @@ class Tuple(Generic, ValueSpecBase):
1527
1564
  else:
1528
1565
  value = self._elements[0].value
1529
1566
  default_min, default_max = 0, None
1530
- return object_utils.kvlist_str(
1567
+ return utils.kvlist_str(
1531
1568
  [
1532
1569
  ('', value, None),
1533
1570
  ('default', self._default, MISSING_VALUE),
@@ -1540,7 +1577,7 @@ class Tuple(Generic, ValueSpecBase):
1540
1577
  compact=compact,
1541
1578
  verbose=verbose,
1542
1579
  root_indent=root_indent,
1543
- **kwargs
1580
+ **kwargs,
1544
1581
  )
1545
1582
 
1546
1583
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -1687,7 +1724,7 @@ class Dict(Generic, ValueSpecBase):
1687
1724
  self,
1688
1725
  default: typing.Any,
1689
1726
  use_default_apply: bool = True,
1690
- root_path: typing.Optional[object_utils.KeyPath] = None,
1727
+ root_path: typing.Optional[utils.KeyPath] = None,
1691
1728
  ) -> ValueSpec:
1692
1729
  if MISSING_VALUE == default and self._schema:
1693
1730
  self._use_generated_default = True
@@ -1707,12 +1744,15 @@ class Dict(Generic, ValueSpecBase):
1707
1744
  forward_refs.update(field.value.forward_refs)
1708
1745
  return forward_refs
1709
1746
 
1710
- def _apply(self,
1711
- value: typing.Dict[typing.Any, typing.Any],
1712
- allow_partial: bool,
1713
- child_transform: typing.Callable[
1714
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
1715
- root_path: object_utils.KeyPath) -> typing.Any:
1747
+ def _apply(
1748
+ self,
1749
+ value: typing.Dict[typing.Any, typing.Any],
1750
+ allow_partial: bool,
1751
+ child_transform: typing.Callable[
1752
+ [utils.KeyPath, Field, typing.Any], typing.Any
1753
+ ],
1754
+ root_path: utils.KeyPath,
1755
+ ) -> typing.Any:
1716
1756
  """Dict specific apply."""
1717
1757
  if not self._schema:
1718
1758
  return value
@@ -1756,11 +1796,13 @@ class Dict(Generic, ValueSpecBase):
1756
1796
  **kwargs,
1757
1797
  ) -> str:
1758
1798
  """Format this object."""
1759
- return object_utils.kvlist_str(
1799
+ return utils.kvlist_str(
1760
1800
  [
1761
- ('fields',
1762
- list(self._schema.values()) if self._schema else None,
1763
- None),
1801
+ (
1802
+ 'fields',
1803
+ list(self._schema.values()) if self._schema else None,
1804
+ None,
1805
+ ),
1764
1806
  ('noneable', self._is_noneable, False),
1765
1807
  ('frozen', self._frozen, False),
1766
1808
  ],
@@ -1892,19 +1934,24 @@ class Object(Generic, ValueSpecBase):
1892
1934
  def value_type(self) -> typing.Type[typing.Any]:
1893
1935
  return self.cls
1894
1936
 
1895
- def _apply(self,
1896
- value: typing.Any,
1897
- allow_partial: bool,
1898
- child_transform: typing.Callable[
1899
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
1900
- root_path: object_utils.KeyPath) -> typing.Any:
1937
+ def _apply(
1938
+ self,
1939
+ value: typing.Any,
1940
+ allow_partial: bool,
1941
+ child_transform: typing.Callable[
1942
+ [utils.KeyPath, Field, typing.Any], typing.Any
1943
+ ],
1944
+ root_path: utils.KeyPath,
1945
+ ) -> typing.Any:
1901
1946
  """Object specific apply."""
1902
1947
  del child_transform
1903
- if isinstance(value, object_utils.MaybePartial):
1948
+ if isinstance(value, utils.MaybePartial):
1904
1949
  if not allow_partial and value.is_partial:
1905
1950
  raise ValueError(
1906
- object_utils.message_on_path(
1907
- f'Object {value} is not fully bound.', root_path))
1951
+ utils.message_on_path(
1952
+ f'Object {value} is not fully bound.', root_path
1953
+ )
1954
+ )
1908
1955
  return value
1909
1956
 
1910
1957
  def extend(self, base: ValueSpec) -> ValueSpec:
@@ -1955,9 +2002,9 @@ class Object(Generic, ValueSpecBase):
1955
2002
  name = self._forward_ref.name
1956
2003
  else:
1957
2004
  name = self._value_type.__name__
1958
- return object_utils.kvlist_str(
2005
+ return utils.kvlist_str(
1959
2006
  [
1960
- ('', object_utils.RawText(name), None),
2007
+ ('', utils.RawText(name), None),
1961
2008
  ('default', self._default, MISSING_VALUE),
1962
2009
  ('noneable', self._is_noneable, False),
1963
2010
  ('frozen', self._frozen, False),
@@ -1966,7 +2013,7 @@ class Object(Generic, ValueSpecBase):
1966
2013
  compact=compact,
1967
2014
  verbose=verbose,
1968
2015
  root_indent=root_indent,
1969
- **kwargs
2016
+ **kwargs,
1970
2017
  )
1971
2018
 
1972
2019
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -2103,12 +2150,12 @@ class Callable(Generic, ValueSpecBase):
2103
2150
  """Value spec for return value."""
2104
2151
  return self._return_value
2105
2152
 
2106
- def _validate(self, path: object_utils.KeyPath, value: typing.Any) -> None:
2153
+ def _validate(self, path: utils.KeyPath, value: typing.Any) -> None:
2107
2154
  """Validate applied value."""
2108
2155
  if not callable(value):
2109
2156
  raise TypeError(
2110
- object_utils.message_on_path(
2111
- f'Value is not callable: {value!r}.', path))
2157
+ utils.message_on_path(f'Value is not callable: {value!r}.', path)
2158
+ )
2112
2159
 
2113
2160
  # Shortcircuit if there is no signature to check.
2114
2161
  if not (self._args or self._kw or self._return_value):
@@ -2120,10 +2167,12 @@ class Callable(Generic, ValueSpecBase):
2120
2167
 
2121
2168
  if len(self._args) > len(signature.args) and not signature.has_varargs:
2122
2169
  raise TypeError(
2123
- object_utils.message_on_path(
2170
+ utils.message_on_path(
2124
2171
  f'{signature.id} only take {len(signature.args)} positional '
2125
2172
  f'arguments, while {len(self._args)} is required by {self!r}.',
2126
- path))
2173
+ path,
2174
+ )
2175
+ )
2127
2176
 
2128
2177
  # Check positional arguments.
2129
2178
  for i in range(min(len(self._args), len(signature.args))):
@@ -2131,10 +2180,12 @@ class Callable(Generic, ValueSpecBase):
2131
2180
  dest_spec = signature.args[i].value_spec
2132
2181
  if not dest_spec.is_compatible(src_spec):
2133
2182
  raise TypeError(
2134
- object_utils.message_on_path(
2183
+ utils.message_on_path(
2135
2184
  f'Value spec of positional argument {i} is not compatible. '
2136
2185
  f'Expected: {dest_spec!r}, Actual: {src_spec!r}.',
2137
- path))
2186
+ path,
2187
+ )
2188
+ )
2138
2189
  if len(self._args) > len(signature.args):
2139
2190
  assert signature.varargs
2140
2191
  assert isinstance(signature.varargs.value_spec, List), signature.varargs
@@ -2143,10 +2194,13 @@ class Callable(Generic, ValueSpecBase):
2143
2194
  src_spec = self._args[i]
2144
2195
  if not dest_spec.is_compatible(src_spec):
2145
2196
  raise TypeError(
2146
- object_utils.message_on_path(
2197
+ utils.message_on_path(
2147
2198
  f'Value spec of positional argument {i} is not compatible '
2148
2199
  f'with the value spec of *{signature.varargs.name}. '
2149
- f'Expected: {dest_spec!r}, Actual: {src_spec!r}.', path))
2200
+ f'Expected: {dest_spec!r}, Actual: {src_spec!r}.',
2201
+ path,
2202
+ )
2203
+ )
2150
2204
 
2151
2205
  # Check keyword arguments.
2152
2206
  dest_args = signature.args + signature.kwonlyargs
@@ -2159,37 +2213,46 @@ class Callable(Generic, ValueSpecBase):
2159
2213
  if dest_spec is not None:
2160
2214
  if not dest_spec.is_compatible(src_spec):
2161
2215
  raise TypeError(
2162
- object_utils.message_on_path(
2216
+ utils.message_on_path(
2163
2217
  f'Value spec of keyword argument {arg_name!r} is not '
2164
2218
  f'compatible. Expected: {src_spec!r}, Actual: {dest_spec!r}.',
2165
- path))
2219
+ path,
2220
+ )
2221
+ )
2166
2222
  elif signature.varkw:
2167
2223
  assert isinstance(signature.varkw.value_spec, Dict), signature.varkw
2168
2224
  varkw_value_spec = signature.varkw.value_spec.schema.dynamic_field.value # pytype: disable=attribute-error
2169
2225
  if not varkw_value_spec.is_compatible(src_spec):
2170
2226
  raise TypeError(
2171
- object_utils.message_on_path(
2227
+ utils.message_on_path(
2172
2228
  f'Value spec of keyword argument {arg_name!r} is not '
2173
- f'compatible with the value spec of '
2229
+ 'compatible with the value spec of '
2174
2230
  f'**{signature.varkw.name}. '
2175
2231
  f'Expected: {varkw_value_spec!r}, '
2176
- f'Actual: {src_spec!r}.', path))
2232
+ f'Actual: {src_spec!r}.',
2233
+ path,
2234
+ )
2235
+ )
2177
2236
  else:
2178
2237
  raise TypeError(
2179
- object_utils.message_on_path(
2238
+ utils.message_on_path(
2180
2239
  f'Keyword argument {arg_name!r} does not exist in {value!r}.',
2181
- path))
2240
+ path,
2241
+ )
2242
+ )
2182
2243
 
2183
2244
  # Check return value
2184
2245
  if (self._return_value and signature.return_value
2185
2246
  and not isinstance(signature.return_value, Any)
2186
2247
  and not self._return_value.is_compatible(signature.return_value)):
2187
2248
  raise TypeError(
2188
- object_utils.message_on_path(
2189
- f'Value spec for return value is not compatible. '
2249
+ utils.message_on_path(
2250
+ 'Value spec for return value is not compatible. '
2190
2251
  f'Expected: {self._return_value!r}, '
2191
2252
  f'Actual: {signature.return_value!r} ({value!r}).',
2192
- path))
2253
+ path,
2254
+ )
2255
+ )
2193
2256
 
2194
2257
  def _extend(self, base: 'Callable') -> None:
2195
2258
  """Callable specific extension."""
@@ -2260,14 +2323,14 @@ class Callable(Generic, ValueSpecBase):
2260
2323
  **kwargs,
2261
2324
  ) -> str:
2262
2325
  """Format this spec."""
2263
- return object_utils.kvlist_str(
2326
+ return utils.kvlist_str(
2264
2327
  [
2265
2328
  ('args', self._args, []),
2266
2329
  ('kw', self._kw, []),
2267
2330
  ('returns', self._return_value, None),
2268
2331
  ('default', self._default, MISSING_VALUE),
2269
2332
  ('noneable', self._is_noneable, False),
2270
- ('frozen', self._frozen, False)
2333
+ ('frozen', self._frozen, False),
2271
2334
  ],
2272
2335
  label=self.__class__.__name__,
2273
2336
  compact=compact,
@@ -2359,14 +2422,14 @@ class Functor(Callable):
2359
2422
  returns=returns,
2360
2423
  default=default,
2361
2424
  transform=transform,
2362
- callable_type=object_utils.Functor,
2425
+ callable_type=utils.Functor,
2363
2426
  is_noneable=is_noneable,
2364
2427
  frozen=frozen,
2365
2428
  )
2366
2429
 
2367
2430
  def _annotate(self) -> typing.Any:
2368
2431
  """Annotate with PyType annotation."""
2369
- return object_utils.Functor
2432
+ return utils.Functor
2370
2433
 
2371
2434
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
2372
2435
  exclude_keys = kwargs.pop('exclude_keys', set())
@@ -2431,12 +2494,14 @@ class Type(Generic, ValueSpecBase):
2431
2494
  return set()
2432
2495
  return set([self._forward_ref])
2433
2496
 
2434
- def _validate(self, path: object_utils.KeyPath, value: typing.Type) -> None: # pylint: disable=g-bare-generic
2497
+ def _validate(self, path: utils.KeyPath, value: typing.Type) -> None: # pylint: disable=g-bare-generic
2435
2498
  """Validate applied value."""
2436
2499
  if self.type_resolved and not pg_inspect.is_subclass(value, self.type):
2437
2500
  raise ValueError(
2438
- object_utils.message_on_path(
2439
- f'{value!r} is not a subclass of {self.type!r}', path))
2501
+ utils.message_on_path(
2502
+ f'{value!r} is not a subclass of {self.type!r}', path
2503
+ )
2504
+ )
2440
2505
 
2441
2506
  def _is_compatible(self, other: 'Type') -> bool:
2442
2507
  """Type specific compatiblity check."""
@@ -2472,7 +2537,7 @@ class Type(Generic, ValueSpecBase):
2472
2537
  **kwargs,
2473
2538
  ) -> str:
2474
2539
  """Format this object."""
2475
- return object_utils.kvlist_str(
2540
+ return utils.kvlist_str(
2476
2541
  [
2477
2542
  ('', self._expected_type, None),
2478
2543
  ('default', self._default, MISSING_VALUE),
@@ -2483,7 +2548,7 @@ class Type(Generic, ValueSpecBase):
2483
2548
  compact=compact,
2484
2549
  verbose=verbose,
2485
2550
  root_indent=root_indent,
2486
- **kwargs
2551
+ **kwargs,
2487
2552
  )
2488
2553
 
2489
2554
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -2673,14 +2738,15 @@ class Union(Generic, ValueSpecBase):
2673
2738
  return c
2674
2739
  return None
2675
2740
 
2676
- def _apply(self,
2677
- value: typing.Any,
2678
- allow_partial: bool,
2679
- child_transform: typing.Callable[
2680
- [object_utils.KeyPath, Field, typing.Any],
2681
- typing.Any
2682
- ],
2683
- root_path: object_utils.KeyPath) -> typing.Any:
2741
+ def _apply(
2742
+ self,
2743
+ value: typing.Any,
2744
+ allow_partial: bool,
2745
+ child_transform: typing.Callable[
2746
+ [utils.KeyPath, Field, typing.Any], typing.Any
2747
+ ],
2748
+ root_path: utils.KeyPath,
2749
+ ) -> typing.Any:
2684
2750
  """Union specific apply."""
2685
2751
  # Match strong-typed candidates first.
2686
2752
  if not self.type_resolved:
@@ -2782,7 +2848,7 @@ class Union(Generic, ValueSpecBase):
2782
2848
  **kwargs,
2783
2849
  ) -> str:
2784
2850
  """Format this object."""
2785
- return object_utils.kvlist_str(
2851
+ return utils.kvlist_str(
2786
2852
  [
2787
2853
  ('', self._candidates, None),
2788
2854
  ('default', self._default, MISSING_VALUE),
@@ -2794,7 +2860,7 @@ class Union(Generic, ValueSpecBase):
2794
2860
  verbose=verbose,
2795
2861
  root_indent=root_indent,
2796
2862
  list_wrap_threshold=kwargs.pop('list_wrap_threshold', 20),
2797
- **kwargs
2863
+ **kwargs,
2798
2864
  )
2799
2865
 
2800
2866
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -2942,17 +3008,17 @@ class Any(ValueSpecBase):
2942
3008
  **kwargs,
2943
3009
  ) -> str:
2944
3010
  """Format this object."""
2945
- return object_utils.kvlist_str(
3011
+ return utils.kvlist_str(
2946
3012
  [
2947
3013
  ('default', self._default, MISSING_VALUE),
2948
3014
  ('frozen', self._frozen, False),
2949
- ('annotation', self._annotation, MISSING_VALUE)
3015
+ ('annotation', self._annotation, MISSING_VALUE),
2950
3016
  ],
2951
3017
  label=self.__class__.__name__,
2952
3018
  compact=compact,
2953
3019
  verbose=verbose,
2954
3020
  root_indent=root_indent,
2955
- **kwargs
3021
+ **kwargs,
2956
3022
  )
2957
3023
 
2958
3024
  def annotate(self, annotation: typing.Any) -> 'Any':
@@ -3022,7 +3088,7 @@ ValueSpec.ObjectType = Object
3022
3088
  def ensure_value_spec(
3023
3089
  value_spec: class_schema.ValueSpec,
3024
3090
  src_spec: class_schema.ValueSpec,
3025
- root_path: typing.Optional[object_utils.KeyPath] = None
3091
+ root_path: typing.Optional[utils.KeyPath] = None,
3026
3092
  ) -> typing.Optional[class_schema.ValueSpec]:
3027
3093
  """Extract counter part from value spec that matches dest spec type.
3028
3094
 
@@ -3043,7 +3109,10 @@ def ensure_value_spec(
3043
3109
  return None
3044
3110
  if not src_spec.is_compatible(value_spec):
3045
3111
  raise TypeError(
3046
- object_utils.message_on_path(
3112
+ utils.message_on_path(
3047
3113
  f'Source spec {src_spec} is not compatible with destination '
3048
- f'spec {value_spec}.', root_path))
3114
+ f'spec {value_spec}.',
3115
+ root_path,
3116
+ )
3117
+ )
3049
3118
  return value_spec