pyglove 0.4.5.dev202411132359__py3-none-any.whl → 0.4.5.dev202501250807__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 (118) hide show
  1. pyglove/core/__init__.py +40 -21
  2. pyglove/core/coding/__init__.py +42 -0
  3. pyglove/core/coding/errors.py +111 -0
  4. pyglove/core/coding/errors_test.py +98 -0
  5. pyglove/core/coding/execution.py +312 -0
  6. pyglove/core/coding/execution_test.py +333 -0
  7. pyglove/core/{object_utils/codegen.py → coding/function_generation.py} +10 -4
  8. pyglove/core/{object_utils/codegen_test.py → coding/function_generation_test.py} +5 -7
  9. pyglove/core/coding/parsing.py +153 -0
  10. pyglove/core/coding/parsing_test.py +150 -0
  11. pyglove/core/coding/permissions.py +100 -0
  12. pyglove/core/coding/permissions_test.py +93 -0
  13. pyglove/core/geno/base.py +53 -38
  14. pyglove/core/geno/base_test.py +2 -4
  15. pyglove/core/geno/categorical.py +36 -27
  16. pyglove/core/geno/custom.py +18 -15
  17. pyglove/core/geno/numerical.py +19 -16
  18. pyglove/core/geno/space.py +3 -4
  19. pyglove/core/hyper/base.py +6 -6
  20. pyglove/core/hyper/categorical.py +91 -52
  21. pyglove/core/hyper/custom.py +7 -7
  22. pyglove/core/hyper/custom_test.py +9 -10
  23. pyglove/core/hyper/derived.py +30 -22
  24. pyglove/core/hyper/derived_test.py +3 -5
  25. pyglove/core/hyper/dynamic_evaluation.py +3 -4
  26. pyglove/core/hyper/evolvable.py +57 -46
  27. pyglove/core/hyper/numerical.py +48 -24
  28. pyglove/core/hyper/numerical_test.py +9 -9
  29. pyglove/core/hyper/object_template.py +58 -46
  30. pyglove/core/logging_test.py +0 -2
  31. pyglove/core/patching/object_factory.py +4 -4
  32. pyglove/core/patching/pattern_based.py +4 -4
  33. pyglove/core/patching/rule_based.py +4 -3
  34. pyglove/core/symbolic/__init__.py +4 -0
  35. pyglove/core/symbolic/base.py +200 -136
  36. pyglove/core/symbolic/base_test.py +17 -19
  37. pyglove/core/symbolic/boilerplate.py +4 -5
  38. pyglove/core/symbolic/class_wrapper.py +10 -14
  39. pyglove/core/symbolic/class_wrapper_test.py +2 -2
  40. pyglove/core/symbolic/compounding.py +2 -2
  41. pyglove/core/symbolic/compounding_test.py +2 -4
  42. pyglove/core/symbolic/contextual_object.py +288 -0
  43. pyglove/core/symbolic/contextual_object_test.py +327 -0
  44. pyglove/core/symbolic/dict.py +115 -87
  45. pyglove/core/symbolic/dict_test.py +188 -131
  46. pyglove/core/symbolic/diff.py +12 -12
  47. pyglove/core/symbolic/flags.py +1 -1
  48. pyglove/core/symbolic/functor.py +16 -15
  49. pyglove/core/symbolic/functor_test.py +2 -4
  50. pyglove/core/symbolic/inferred.py +2 -2
  51. pyglove/core/symbolic/list.py +70 -47
  52. pyglove/core/symbolic/list_test.py +117 -98
  53. pyglove/core/symbolic/object.py +59 -58
  54. pyglove/core/symbolic/object_test.py +143 -90
  55. pyglove/core/symbolic/origin.py +5 -7
  56. pyglove/core/symbolic/pure_symbolic.py +4 -3
  57. pyglove/core/symbolic/ref.py +33 -16
  58. pyglove/core/symbolic/ref_test.py +17 -0
  59. pyglove/core/tuning/local_backend.py +2 -2
  60. pyglove/core/tuning/protocols.py +3 -3
  61. pyglove/core/typing/annotation_conversion.py +8 -3
  62. pyglove/core/typing/annotation_conversion_test.py +8 -0
  63. pyglove/core/typing/callable_ext.py +11 -13
  64. pyglove/core/typing/callable_signature.py +22 -19
  65. pyglove/core/typing/callable_signature_test.py +3 -5
  66. pyglove/core/typing/class_schema.py +93 -54
  67. pyglove/core/typing/class_schema_test.py +4 -5
  68. pyglove/core/typing/custom_typing.py +5 -4
  69. pyglove/core/typing/key_specs.py +5 -7
  70. pyglove/core/typing/key_specs_test.py +4 -4
  71. pyglove/core/typing/type_conversion.py +4 -5
  72. pyglove/core/typing/type_conversion_test.py +12 -12
  73. pyglove/core/typing/typed_missing.py +6 -7
  74. pyglove/core/typing/typed_missing_test.py +7 -8
  75. pyglove/core/typing/value_specs.py +287 -144
  76. pyglove/core/typing/value_specs_test.py +148 -25
  77. pyglove/core/utils/__init__.py +172 -0
  78. pyglove/core/{object_utils → utils}/common_traits.py +2 -2
  79. pyglove/core/{object_utils → utils}/common_traits_test.py +1 -3
  80. pyglove/core/utils/contextual.py +147 -0
  81. pyglove/core/utils/contextual_test.py +88 -0
  82. pyglove/core/{object_utils → utils}/docstr_utils_test.py +1 -3
  83. pyglove/core/{object_utils → utils}/error_utils.py +3 -3
  84. pyglove/core/{object_utils → utils}/error_utils_test.py +1 -1
  85. pyglove/core/{object_utils → utils}/formatting.py +1 -1
  86. pyglove/core/{object_utils → utils}/formatting_test.py +1 -2
  87. pyglove/core/{object_utils → utils}/hierarchical.py +23 -25
  88. pyglove/core/{object_utils → utils}/hierarchical_test.py +3 -5
  89. pyglove/core/{object_utils → utils}/json_conversion.py +1 -1
  90. pyglove/core/{object_utils → utils}/json_conversion_test.py +1 -3
  91. pyglove/core/{object_utils → utils}/missing.py +2 -2
  92. pyglove/core/{object_utils → utils}/missing_test.py +2 -4
  93. pyglove/core/utils/text_color.py +128 -0
  94. pyglove/core/utils/text_color_test.py +94 -0
  95. pyglove/core/{object_utils → utils}/thread_local_test.py +1 -3
  96. pyglove/core/{object_utils → utils}/timing.py +21 -10
  97. pyglove/core/{object_utils → utils}/timing_test.py +14 -12
  98. pyglove/core/{object_utils → utils}/value_location.py +2 -2
  99. pyglove/core/{object_utils → utils}/value_location_test.py +2 -4
  100. pyglove/core/views/base.py +25 -29
  101. pyglove/core/views/html/base.py +15 -16
  102. pyglove/core/views/html/controls/base.py +46 -9
  103. pyglove/core/views/html/controls/label.py +13 -2
  104. pyglove/core/views/html/controls/label_test.py +27 -8
  105. pyglove/core/views/html/controls/progress_bar.py +3 -5
  106. pyglove/core/views/html/controls/progress_bar_test.py +2 -2
  107. pyglove/core/views/html/controls/tab.py +217 -66
  108. pyglove/core/views/html/controls/tab_test.py +46 -15
  109. pyglove/core/views/html/tree_view.py +39 -37
  110. {pyglove-0.4.5.dev202411132359.dist-info → pyglove-0.4.5.dev202501250807.dist-info}/METADATA +17 -3
  111. pyglove-0.4.5.dev202501250807.dist-info/RECORD +218 -0
  112. {pyglove-0.4.5.dev202411132359.dist-info → pyglove-0.4.5.dev202501250807.dist-info}/WHEEL +1 -1
  113. pyglove/core/object_utils/__init__.py +0 -164
  114. pyglove-0.4.5.dev202411132359.dist-info/RECORD +0 -203
  115. /pyglove/core/{object_utils → utils}/docstr_utils.py +0 -0
  116. /pyglove/core/{object_utils → utils}/thread_local.py +0 -0
  117. {pyglove-0.4.5.dev202411132359.dist-info → pyglove-0.4.5.dev202501250807.dist-info}/LICENSE +0 -0
  118. {pyglove-0.4.5.dev202411132359.dist-info → pyglove-0.4.5.dev202501250807.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,18 @@ 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
+
40
+
41
+ class _FrozenValuePlaceholder(CustomTyping):
42
+ """Placeholder for to-be-assigned frozen value."""
43
+
44
+ def custom_apply(self, *args, **kwargs) -> typing.Tuple[bool, typing.Any]:
45
+ return (False, self)
46
+
47
+
48
+ _FROZEN_VALUE_PLACEHOLDER = _FrozenValuePlaceholder()
49
+
39
50
 
40
51
  # Type alias for ValueSpec object or Python annotation that could be converted
41
52
  # to ValueSpec via `pg.typing.ValueSpec.from_annotation()`. This type alias is
@@ -158,7 +169,7 @@ class ValueSpecBase(ValueSpec):
158
169
  self,
159
170
  default: typing.Any,
160
171
  use_default_apply: bool = True,
161
- root_path: typing.Optional[object_utils.KeyPath] = None
172
+ root_path: typing.Optional[utils.KeyPath] = None,
162
173
  ) -> ValueSpec:
163
174
  """Set default value and returns `self`."""
164
175
  # NOTE(daiyip): Default can be schema.MissingValue types, all are
@@ -194,8 +205,18 @@ class ValueSpecBase(ValueSpec):
194
205
 
195
206
  def extend(self, base: ValueSpec) -> ValueSpec:
196
207
  """Extend current value spec on top of a base spec."""
197
- if base.frozen:
198
- raise TypeError(f'Cannot extend a frozen value spec: {base!r}')
208
+ if base.frozen and (not self.frozen or self.default != base.default):
209
+ raise TypeError(f'{self!r} cannot extend a frozen value spec: {base!r}')
210
+
211
+ # Special handling for extending enum.
212
+ if self.frozen and isinstance(base, Enum):
213
+ if self.default in base.values:
214
+ return Enum(MISSING_VALUE, base.values).freeze(self.default)
215
+ else:
216
+ raise TypeError(
217
+ f'{self!r} cannot extend {base!r} with incompatible '
218
+ f'frozen value: {self.default!r} '
219
+ )
199
220
 
200
221
  if self._transform is None:
201
222
  self._transform = base.transform
@@ -225,14 +246,14 @@ class ValueSpecBase(ValueSpec):
225
246
  self,
226
247
  value: typing.Any,
227
248
  allow_partial: bool = False,
228
- child_transform: typing.Optional[typing.Callable[
229
- [object_utils.KeyPath, Field, typing.Any],
230
- typing.Any
231
- ]] = None,
232
- 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
233
254
  """Apply spec to validate and complete value."""
234
- root_path = root_path or object_utils.KeyPath()
235
- if self.frozen:
255
+ root_path = root_path or utils.KeyPath()
256
+ if self.frozen and self.default is not _FROZEN_VALUE_PLACEHOLDER:
236
257
  # Always return the default value if a field is frozen.
237
258
  if MISSING_VALUE != value and self.default != value:
238
259
  raise ValueError(
@@ -270,8 +291,8 @@ class ValueSpecBase(ValueSpec):
270
291
  value = self._transform(value)
271
292
  except Exception as e: # pylint: disable=broad-except
272
293
  raise e.__class__(
273
- object_utils.message_on_path(str(e), root_path)
274
- ).with_traceback(sys.exc_info()[2])
294
+ utils.message_on_path(str(e), root_path)
295
+ ).with_traceback(sys.exc_info()[2])
275
296
 
276
297
  return self.skip_user_transform.apply(
277
298
  value,
@@ -287,9 +308,12 @@ class ValueSpecBase(ValueSpec):
287
308
  converter = type_conversion.get_converter(type(value), self.value_type)
288
309
  if converter is None:
289
310
  raise TypeError(
290
- object_utils.message_on_path(
311
+ utils.message_on_path(
291
312
  f'Expect {self.value_type} '
292
- f'but encountered {type(value)!r}: {value}.', root_path))
313
+ f'but encountered {type(value)!r}: {value}.',
314
+ root_path,
315
+ )
316
+ )
293
317
  value = converter(value)
294
318
 
295
319
  # NOTE(daiyip): child nodes validation and transformation is done before
@@ -303,15 +327,18 @@ class ValueSpecBase(ValueSpec):
303
327
  self._validate(root_path, value)
304
328
  return value
305
329
 
306
- def _validate(self, path: object_utils.KeyPath, value: typing.Any):
330
+ def _validate(self, path: utils.KeyPath, value: typing.Any):
307
331
  """Validation on applied value. Child class can override."""
308
332
 
309
- def _apply(self,
310
- value: typing.Any,
311
- allow_partial: bool,
312
- child_transform: typing.Callable[
313
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
314
- 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:
315
342
  """Customized apply so each subclass can override."""
316
343
  del allow_partial
317
344
  del child_transform
@@ -319,7 +346,7 @@ class ValueSpecBase(ValueSpec):
319
346
  return value
320
347
 
321
348
  def is_compatible(self, other: ValueSpec) -> bool:
322
- """Returns if current spec is compatible with the other value spec."""
349
+ """Returns if current spec can receive all values from the other spec."""
323
350
  if self is other:
324
351
  return True
325
352
  if not isinstance(other, self.__class__):
@@ -379,17 +406,17 @@ class ValueSpecBase(ValueSpec):
379
406
  **kwargs
380
407
  ) -> str:
381
408
  """Format this object."""
382
- return object_utils.kvlist_str(
409
+ return utils.kvlist_str(
383
410
  [
384
411
  ('default', self._default, MISSING_VALUE),
385
412
  ('noneable', self._is_noneable, False),
386
- ('frozen', self._frozen, False)
413
+ ('frozen', self._frozen, False),
387
414
  ],
388
415
  label=self.__class__.__name__,
389
416
  compact=compact,
390
417
  verbose=verbose,
391
418
  root_indent=root_indent,
392
- **kwargs
419
+ **kwargs,
393
420
  )
394
421
 
395
422
 
@@ -417,6 +444,12 @@ class PrimitiveType(ValueSpecBase):
417
444
  value_type, default, is_noneable=is_noneable, frozen=frozen
418
445
  )
419
446
 
447
+ def __call__(self, *args, **kwargs) -> typing.Any:
448
+ del kwargs
449
+ if (not args and self.has_default) or self.frozen:
450
+ return self.default
451
+ return self.apply(self.value_type(*args))
452
+
420
453
 
421
454
  class Bool(PrimitiveType):
422
455
  """Value spec for boolean type.
@@ -524,15 +557,18 @@ class Str(Generic, PrimitiveType):
524
557
  **kwargs,
525
558
  )
526
559
 
527
- def _validate(self, path: object_utils.KeyPath, value: str) -> None:
560
+ def _validate(self, path: utils.KeyPath, value: str) -> None:
528
561
  """Validates applied value."""
529
562
  if not self._regex:
530
563
  return
531
564
  if not self._regex.match(value):
532
565
  raise ValueError(
533
- object_utils.message_on_path(
566
+ utils.message_on_path(
534
567
  f'String {value!r} does not match '
535
- f'regular expression {self._regex.pattern!r}.', path))
568
+ f'regular expression {self._regex.pattern!r}.',
569
+ path,
570
+ )
571
+ )
536
572
 
537
573
  @property
538
574
  def regex(self):
@@ -567,7 +603,7 @@ class Str(Generic, PrimitiveType):
567
603
  ) -> str:
568
604
  """Format this object."""
569
605
  regex_pattern = self._regex.pattern if self._regex else None
570
- return object_utils.kvlist_str(
606
+ return utils.kvlist_str(
571
607
  [
572
608
  ('default', self._default, MISSING_VALUE),
573
609
  ('regex', regex_pattern, None),
@@ -578,7 +614,7 @@ class Str(Generic, PrimitiveType):
578
614
  compact=compact,
579
615
  verbose=verbose,
580
616
  root_indent=root_indent,
581
- **kwargs
617
+ **kwargs,
582
618
  )
583
619
 
584
620
  def _eq(self, other: 'Str') -> bool:
@@ -637,15 +673,17 @@ class Number(Generic, PrimitiveType):
637
673
  """Returns maximum value of acceptable values."""
638
674
  return self._max_value
639
675
 
640
- def _validate(self, path: object_utils.KeyPath,
641
- value: numbers.Number) -> None:
676
+ def _validate(self, path: utils.KeyPath, value: numbers.Number) -> None:
642
677
  """Validates applied value."""
643
678
  if ((self._min_value is not None and value < self._min_value) or
644
679
  (self._max_value is not None and value > self._max_value)):
645
680
  raise ValueError(
646
- object_utils.message_on_path(
681
+ utils.message_on_path(
647
682
  f'Value {value} is out of range '
648
- f'(min={self._min_value}, max={self._max_value}).', path))
683
+ f'(min={self._min_value}, max={self._max_value}).',
684
+ path,
685
+ )
686
+ )
649
687
 
650
688
  def _extend(self, base: 'Number') -> None:
651
689
  """Number specific extend."""
@@ -698,19 +736,19 @@ class Number(Generic, PrimitiveType):
698
736
  **kwargs
699
737
  ) -> str:
700
738
  """Format this object."""
701
- return object_utils.kvlist_str(
739
+ return utils.kvlist_str(
702
740
  [
703
741
  ('default', self._default, MISSING_VALUE),
704
742
  ('min', self._min_value, None),
705
743
  ('max', self._max_value, None),
706
744
  ('noneable', self._is_noneable, False),
707
- ('frozen', self._frozen, False)
745
+ ('frozen', self._frozen, False),
708
746
  ],
709
747
  label=self.__class__.__name__,
710
748
  compact=compact,
711
749
  verbose=verbose,
712
750
  root_indent=root_indent,
713
- **kwargs
751
+ **kwargs,
714
752
  )
715
753
 
716
754
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -898,6 +936,12 @@ class Enum(Generic, PrimitiveType):
898
936
  value_type, default, is_noneable=is_noneable, frozen=frozen
899
937
  )
900
938
 
939
+ def __call__(self, *args, **kwargs) -> typing.Any:
940
+ del kwargs
941
+ if (not args and self.has_default) or self.frozen:
942
+ return self.default
943
+ return self.apply(*args)
944
+
901
945
  def noneable(self) -> 'Enum':
902
946
  """Noneable is specially treated for Enum."""
903
947
  if None not in self._values:
@@ -910,13 +954,14 @@ class Enum(Generic, PrimitiveType):
910
954
  """Returns all acceptable values of this spec."""
911
955
  return self._values
912
956
 
913
- def _validate(self, path: object_utils.KeyPath, value: typing.Any) -> None:
957
+ def _validate(self, path: utils.KeyPath, value: typing.Any) -> None:
914
958
  """Validates applied value."""
915
959
  if value not in self._values:
916
960
  raise ValueError(
917
- object_utils.message_on_path(
918
- f'Value {value!r} is not in candidate list {self._values}.',
919
- path))
961
+ utils.message_on_path(
962
+ f'Value {value!r} is not in candidate list {self._values}.', path
963
+ )
964
+ )
920
965
 
921
966
  def _extend(self, base: 'Enum') -> None:
922
967
  """Enum specific extend."""
@@ -929,6 +974,12 @@ class Enum(Generic, PrimitiveType):
929
974
  f'{repr(v)} is not an acceptable value.'
930
975
  ) from e
931
976
 
977
+ def is_compatible(self, other: ValueSpec) -> bool:
978
+ """Enum specific compatibility check."""
979
+ if other.frozen and other.default in self.values:
980
+ return True
981
+ return super().is_compatible(other)
982
+
932
983
  def _is_compatible(self, other: 'Enum') -> bool:
933
984
  """Enum specific compatibility check."""
934
985
  for v in other.values:
@@ -955,7 +1006,7 @@ class Enum(Generic, PrimitiveType):
955
1006
  **kwargs
956
1007
  ) -> str:
957
1008
  """Format this object."""
958
- return object_utils.kvlist_str(
1009
+ return utils.kvlist_str(
959
1010
  [
960
1011
  ('default', self._default, MISSING_VALUE),
961
1012
  ('values', self._values, None),
@@ -965,7 +1016,7 @@ class Enum(Generic, PrimitiveType):
965
1016
  compact=compact,
966
1017
  verbose=verbose,
967
1018
  root_indent=root_indent,
968
- **kwargs
1019
+ **kwargs,
969
1020
  )
970
1021
 
971
1022
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -1067,6 +1118,12 @@ class List(Generic, ValueSpecBase):
1067
1118
  list, default, transform, is_noneable=is_noneable, frozen=frozen
1068
1119
  )
1069
1120
 
1121
+ def __call__(self, *args, **kwargs) -> typing.Any:
1122
+ del kwargs
1123
+ if (not args and self.has_default) or self.frozen:
1124
+ return self.default
1125
+ return self.apply(list(*args))
1126
+
1070
1127
  @property
1071
1128
  def element(self) -> Field:
1072
1129
  """Returns Field specification of list element."""
@@ -1087,12 +1144,15 @@ class List(Generic, ValueSpecBase):
1087
1144
  """Returns max size of the list."""
1088
1145
  return self._element.key.max_value # pytype: disable=attribute-error # bind-properties
1089
1146
 
1090
- def _apply(self,
1091
- value: typing.List[typing.Any],
1092
- allow_partial: bool,
1093
- child_transform: typing.Callable[
1094
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
1095
- 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:
1096
1156
  """List specific apply."""
1097
1157
  # NOTE(daiyip): for symbolic List, write access using `__setitem__` will
1098
1158
  # trigger permission error when `accessor_writable` is set to False.
@@ -1109,27 +1169,35 @@ class List(Generic, ValueSpecBase):
1109
1169
  getitem = getattr(value, 'sym_getattr', value.__getitem__)
1110
1170
  for i in range(len(value)):
1111
1171
  v = self._element.apply(
1112
- getitem(i), allow_partial=allow_partial, transform_fn=child_transform,
1113
- 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
+ )
1114
1177
  if getitem(i) is not v:
1115
1178
  set_item(i, v)
1116
1179
  return value
1117
1180
 
1118
- def _validate(
1119
- self, path: object_utils.KeyPath, value: typing.List[typing.Any]):
1181
+ def _validate(self, path: utils.KeyPath, value: typing.List[typing.Any]):
1120
1182
  """Validates applied value."""
1121
1183
  if len(value) < self.min_size:
1122
1184
  raise ValueError(
1123
- object_utils.message_on_path(
1185
+ utils.message_on_path(
1124
1186
  f'Length of list {value!r} is less than '
1125
- f'min size ({self.min_size}).', path))
1187
+ f'min size ({self.min_size}).',
1188
+ path,
1189
+ )
1190
+ )
1126
1191
 
1127
1192
  if self.max_size is not None:
1128
1193
  if len(value) > self.max_size:
1129
1194
  raise ValueError(
1130
- object_utils.message_on_path(
1195
+ utils.message_on_path(
1131
1196
  f'Length of list {value!r} is greater than '
1132
- f'max size ({self.max_size}).', path))
1197
+ f'max size ({self.max_size}).',
1198
+ path,
1199
+ )
1200
+ )
1133
1201
 
1134
1202
  def _extend(self, base: 'List') -> None:
1135
1203
  """List specific extend."""
@@ -1157,7 +1225,7 @@ class List(Generic, ValueSpecBase):
1157
1225
  **kwargs,
1158
1226
  ) -> str:
1159
1227
  """Format this object."""
1160
- return object_utils.kvlist_str(
1228
+ return utils.kvlist_str(
1161
1229
  [
1162
1230
  ('', self._element.value, None),
1163
1231
  ('min_size', self.min_size, 0),
@@ -1170,7 +1238,7 @@ class List(Generic, ValueSpecBase):
1170
1238
  compact=compact,
1171
1239
  verbose=verbose,
1172
1240
  root_indent=root_indent,
1173
- **kwargs
1241
+ **kwargs,
1174
1242
  )
1175
1243
 
1176
1244
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -1316,6 +1384,12 @@ class Tuple(Generic, ValueSpecBase):
1316
1384
  tuple, default, transform, is_noneable=is_noneable, frozen=frozen
1317
1385
  )
1318
1386
 
1387
+ def __call__(self, *args, **kwargs) -> typing.Any:
1388
+ del kwargs
1389
+ if (not args and self.has_default) or self.frozen:
1390
+ return self.default
1391
+ return self.apply(tuple(*args))
1392
+
1319
1393
  @property
1320
1394
  def fixed_length(self) -> bool:
1321
1395
  """Returns True if current Tuple spec is fixed length."""
@@ -1357,35 +1431,50 @@ class Tuple(Generic, ValueSpecBase):
1357
1431
  """Returns length of this tuple."""
1358
1432
  return len(self._elements) if self.fixed_length else 0
1359
1433
 
1360
- def _apply(self,
1361
- value: typing.Tuple[typing.Any, ...],
1362
- allow_partial: bool,
1363
- child_transform: typing.Callable[
1364
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
1365
- 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:
1366
1443
  """Tuple specific apply."""
1367
1444
  if self.fixed_length:
1368
1445
  if len(value) != len(self.elements):
1369
1446
  raise ValueError(
1370
- object_utils.message_on_path(
1447
+ utils.message_on_path(
1371
1448
  f'Length of input tuple ({len(value)}) does not match the '
1372
1449
  f'length of spec ({len(self.elements)}). '
1373
- f'Input: {value}, Spec: {self!r}', root_path))
1450
+ f'Input: {value}, Spec: {self!r}',
1451
+ root_path,
1452
+ )
1453
+ )
1374
1454
  else:
1375
1455
  if len(value) < self.min_size:
1376
1456
  raise ValueError(
1377
- object_utils.message_on_path(
1457
+ utils.message_on_path(
1378
1458
  f'Length of tuple {value} is less than '
1379
- f'min size ({self.min_size}).', root_path))
1459
+ f'min size ({self.min_size}).',
1460
+ root_path,
1461
+ )
1462
+ )
1380
1463
  if self.max_size is not None and len(value) > self.max_size:
1381
1464
  raise ValueError(
1382
- object_utils.message_on_path(
1465
+ utils.message_on_path(
1383
1466
  f'Length of tuple {value} is greater than '
1384
- f'max size ({self.max_size}).', root_path))
1467
+ f'max size ({self.max_size}).',
1468
+ root_path,
1469
+ )
1470
+ )
1385
1471
  return tuple([
1386
1472
  self._elements[i if self.fixed_length else 0].apply( # pylint: disable=g-complex-comprehension
1387
- v, allow_partial=allow_partial, transform_fn=child_transform,
1388
- 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
+ )
1389
1478
  for i, v in enumerate(value)
1390
1479
  ])
1391
1480
 
@@ -1475,7 +1564,7 @@ class Tuple(Generic, ValueSpecBase):
1475
1564
  else:
1476
1565
  value = self._elements[0].value
1477
1566
  default_min, default_max = 0, None
1478
- return object_utils.kvlist_str(
1567
+ return utils.kvlist_str(
1479
1568
  [
1480
1569
  ('', value, None),
1481
1570
  ('default', self._default, MISSING_VALUE),
@@ -1488,7 +1577,7 @@ class Tuple(Generic, ValueSpecBase):
1488
1577
  compact=compact,
1489
1578
  verbose=verbose,
1490
1579
  root_indent=root_indent,
1491
- **kwargs
1580
+ **kwargs,
1492
1581
  )
1493
1582
 
1494
1583
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -1617,6 +1706,9 @@ class Dict(Generic, ValueSpecBase):
1617
1706
  if MISSING_VALUE == default:
1618
1707
  self.set_default(default)
1619
1708
 
1709
+ def __call__(self, *args, **kwargs) -> typing.Any:
1710
+ return self.apply(dict(*args, **kwargs))
1711
+
1620
1712
  @property
1621
1713
  def schema(self) -> typing.Optional[Schema]:
1622
1714
  """Returns the schema of this dict spec."""
@@ -1632,7 +1724,7 @@ class Dict(Generic, ValueSpecBase):
1632
1724
  self,
1633
1725
  default: typing.Any,
1634
1726
  use_default_apply: bool = True,
1635
- root_path: typing.Optional[object_utils.KeyPath] = None,
1727
+ root_path: typing.Optional[utils.KeyPath] = None,
1636
1728
  ) -> ValueSpec:
1637
1729
  if MISSING_VALUE == default and self._schema:
1638
1730
  self._use_generated_default = True
@@ -1652,12 +1744,15 @@ class Dict(Generic, ValueSpecBase):
1652
1744
  forward_refs.update(field.value.forward_refs)
1653
1745
  return forward_refs
1654
1746
 
1655
- def _apply(self,
1656
- value: typing.Dict[typing.Any, typing.Any],
1657
- allow_partial: bool,
1658
- child_transform: typing.Callable[
1659
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
1660
- 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:
1661
1756
  """Dict specific apply."""
1662
1757
  if not self._schema:
1663
1758
  return value
@@ -1701,11 +1796,13 @@ class Dict(Generic, ValueSpecBase):
1701
1796
  **kwargs,
1702
1797
  ) -> str:
1703
1798
  """Format this object."""
1704
- return object_utils.kvlist_str(
1799
+ return utils.kvlist_str(
1705
1800
  [
1706
- ('fields',
1707
- list(self._schema.values()) if self._schema else None,
1708
- None),
1801
+ (
1802
+ 'fields',
1803
+ list(self._schema.values()) if self._schema else None,
1804
+ None,
1805
+ ),
1709
1806
  ('noneable', self._is_noneable, False),
1710
1807
  ('frozen', self._frozen, False),
1711
1808
  ],
@@ -1816,6 +1913,9 @@ class Object(Generic, ValueSpecBase):
1816
1913
  t, default, transform, is_noneable=is_noneable, frozen=frozen
1817
1914
  )
1818
1915
 
1916
+ def __call__(self, *args, **kwargs) -> typing.Any:
1917
+ return self.apply(self.cls(*args, **kwargs))
1918
+
1819
1919
  @property
1820
1920
  def forward_refs(self) -> typing.Set[class_schema.ForwardRef]:
1821
1921
  """Returns forward references used in this spec."""
@@ -1834,19 +1934,24 @@ class Object(Generic, ValueSpecBase):
1834
1934
  def value_type(self) -> typing.Type[typing.Any]:
1835
1935
  return self.cls
1836
1936
 
1837
- def _apply(self,
1838
- value: typing.Any,
1839
- allow_partial: bool,
1840
- child_transform: typing.Callable[
1841
- [object_utils.KeyPath, Field, typing.Any], typing.Any],
1842
- 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:
1843
1946
  """Object specific apply."""
1844
1947
  del child_transform
1845
- if isinstance(value, object_utils.MaybePartial):
1948
+ if isinstance(value, utils.MaybePartial):
1846
1949
  if not allow_partial and value.is_partial:
1847
1950
  raise ValueError(
1848
- object_utils.message_on_path(
1849
- 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
+ )
1850
1955
  return value
1851
1956
 
1852
1957
  def extend(self, base: ValueSpec) -> ValueSpec:
@@ -1897,9 +2002,9 @@ class Object(Generic, ValueSpecBase):
1897
2002
  name = self._forward_ref.name
1898
2003
  else:
1899
2004
  name = self._value_type.__name__
1900
- return object_utils.kvlist_str(
2005
+ return utils.kvlist_str(
1901
2006
  [
1902
- ('', object_utils.RawText(name), None),
2007
+ ('', utils.RawText(name), None),
1903
2008
  ('default', self._default, MISSING_VALUE),
1904
2009
  ('noneable', self._is_noneable, False),
1905
2010
  ('frozen', self._frozen, False),
@@ -1908,7 +2013,7 @@ class Object(Generic, ValueSpecBase):
1908
2013
  compact=compact,
1909
2014
  verbose=verbose,
1910
2015
  root_indent=root_indent,
1911
- **kwargs
2016
+ **kwargs,
1912
2017
  )
1913
2018
 
1914
2019
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -2014,6 +2119,10 @@ class Callable(Generic, ValueSpecBase):
2014
2119
  frozen=frozen,
2015
2120
  )
2016
2121
 
2122
+ def __call__(self, *args, **kwargs) -> typing.Any:
2123
+ del args, kwargs
2124
+ raise TypeError(f'{self!r} cannot be instantiated.')
2125
+
2017
2126
  @functools.cached_property
2018
2127
  def forward_refs(self) -> typing.Set[class_schema.ForwardRef]:
2019
2128
  """Returns forward references used in this spec."""
@@ -2041,12 +2150,12 @@ class Callable(Generic, ValueSpecBase):
2041
2150
  """Value spec for return value."""
2042
2151
  return self._return_value
2043
2152
 
2044
- def _validate(self, path: object_utils.KeyPath, value: typing.Any) -> None:
2153
+ def _validate(self, path: utils.KeyPath, value: typing.Any) -> None:
2045
2154
  """Validate applied value."""
2046
2155
  if not callable(value):
2047
2156
  raise TypeError(
2048
- object_utils.message_on_path(
2049
- f'Value is not callable: {value!r}.', path))
2157
+ utils.message_on_path(f'Value is not callable: {value!r}.', path)
2158
+ )
2050
2159
 
2051
2160
  # Shortcircuit if there is no signature to check.
2052
2161
  if not (self._args or self._kw or self._return_value):
@@ -2058,10 +2167,12 @@ class Callable(Generic, ValueSpecBase):
2058
2167
 
2059
2168
  if len(self._args) > len(signature.args) and not signature.has_varargs:
2060
2169
  raise TypeError(
2061
- object_utils.message_on_path(
2170
+ utils.message_on_path(
2062
2171
  f'{signature.id} only take {len(signature.args)} positional '
2063
2172
  f'arguments, while {len(self._args)} is required by {self!r}.',
2064
- path))
2173
+ path,
2174
+ )
2175
+ )
2065
2176
 
2066
2177
  # Check positional arguments.
2067
2178
  for i in range(min(len(self._args), len(signature.args))):
@@ -2069,10 +2180,12 @@ class Callable(Generic, ValueSpecBase):
2069
2180
  dest_spec = signature.args[i].value_spec
2070
2181
  if not dest_spec.is_compatible(src_spec):
2071
2182
  raise TypeError(
2072
- object_utils.message_on_path(
2183
+ utils.message_on_path(
2073
2184
  f'Value spec of positional argument {i} is not compatible. '
2074
2185
  f'Expected: {dest_spec!r}, Actual: {src_spec!r}.',
2075
- path))
2186
+ path,
2187
+ )
2188
+ )
2076
2189
  if len(self._args) > len(signature.args):
2077
2190
  assert signature.varargs
2078
2191
  assert isinstance(signature.varargs.value_spec, List), signature.varargs
@@ -2081,10 +2194,13 @@ class Callable(Generic, ValueSpecBase):
2081
2194
  src_spec = self._args[i]
2082
2195
  if not dest_spec.is_compatible(src_spec):
2083
2196
  raise TypeError(
2084
- object_utils.message_on_path(
2197
+ utils.message_on_path(
2085
2198
  f'Value spec of positional argument {i} is not compatible '
2086
2199
  f'with the value spec of *{signature.varargs.name}. '
2087
- f'Expected: {dest_spec!r}, Actual: {src_spec!r}.', path))
2200
+ f'Expected: {dest_spec!r}, Actual: {src_spec!r}.',
2201
+ path,
2202
+ )
2203
+ )
2088
2204
 
2089
2205
  # Check keyword arguments.
2090
2206
  dest_args = signature.args + signature.kwonlyargs
@@ -2097,37 +2213,46 @@ class Callable(Generic, ValueSpecBase):
2097
2213
  if dest_spec is not None:
2098
2214
  if not dest_spec.is_compatible(src_spec):
2099
2215
  raise TypeError(
2100
- object_utils.message_on_path(
2216
+ utils.message_on_path(
2101
2217
  f'Value spec of keyword argument {arg_name!r} is not '
2102
2218
  f'compatible. Expected: {src_spec!r}, Actual: {dest_spec!r}.',
2103
- path))
2219
+ path,
2220
+ )
2221
+ )
2104
2222
  elif signature.varkw:
2105
2223
  assert isinstance(signature.varkw.value_spec, Dict), signature.varkw
2106
2224
  varkw_value_spec = signature.varkw.value_spec.schema.dynamic_field.value # pytype: disable=attribute-error
2107
2225
  if not varkw_value_spec.is_compatible(src_spec):
2108
2226
  raise TypeError(
2109
- object_utils.message_on_path(
2227
+ utils.message_on_path(
2110
2228
  f'Value spec of keyword argument {arg_name!r} is not '
2111
- f'compatible with the value spec of '
2229
+ 'compatible with the value spec of '
2112
2230
  f'**{signature.varkw.name}. '
2113
2231
  f'Expected: {varkw_value_spec!r}, '
2114
- f'Actual: {src_spec!r}.', path))
2232
+ f'Actual: {src_spec!r}.',
2233
+ path,
2234
+ )
2235
+ )
2115
2236
  else:
2116
2237
  raise TypeError(
2117
- object_utils.message_on_path(
2238
+ utils.message_on_path(
2118
2239
  f'Keyword argument {arg_name!r} does not exist in {value!r}.',
2119
- path))
2240
+ path,
2241
+ )
2242
+ )
2120
2243
 
2121
2244
  # Check return value
2122
2245
  if (self._return_value and signature.return_value
2123
2246
  and not isinstance(signature.return_value, Any)
2124
2247
  and not self._return_value.is_compatible(signature.return_value)):
2125
2248
  raise TypeError(
2126
- object_utils.message_on_path(
2127
- f'Value spec for return value is not compatible. '
2249
+ utils.message_on_path(
2250
+ 'Value spec for return value is not compatible. '
2128
2251
  f'Expected: {self._return_value!r}, '
2129
2252
  f'Actual: {signature.return_value!r} ({value!r}).',
2130
- path))
2253
+ path,
2254
+ )
2255
+ )
2131
2256
 
2132
2257
  def _extend(self, base: 'Callable') -> None:
2133
2258
  """Callable specific extension."""
@@ -2198,14 +2323,14 @@ class Callable(Generic, ValueSpecBase):
2198
2323
  **kwargs,
2199
2324
  ) -> str:
2200
2325
  """Format this spec."""
2201
- return object_utils.kvlist_str(
2326
+ return utils.kvlist_str(
2202
2327
  [
2203
2328
  ('args', self._args, []),
2204
2329
  ('kw', self._kw, []),
2205
2330
  ('returns', self._return_value, None),
2206
2331
  ('default', self._default, MISSING_VALUE),
2207
2332
  ('noneable', self._is_noneable, False),
2208
- ('frozen', self._frozen, False)
2333
+ ('frozen', self._frozen, False),
2209
2334
  ],
2210
2335
  label=self.__class__.__name__,
2211
2336
  compact=compact,
@@ -2297,14 +2422,14 @@ class Functor(Callable):
2297
2422
  returns=returns,
2298
2423
  default=default,
2299
2424
  transform=transform,
2300
- callable_type=object_utils.Functor,
2425
+ callable_type=utils.Functor,
2301
2426
  is_noneable=is_noneable,
2302
2427
  frozen=frozen,
2303
2428
  )
2304
2429
 
2305
2430
  def _annotate(self) -> typing.Any:
2306
2431
  """Annotate with PyType annotation."""
2307
- return object_utils.Functor
2432
+ return utils.Functor
2308
2433
 
2309
2434
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
2310
2435
  exclude_keys = kwargs.pop('exclude_keys', set())
@@ -2351,6 +2476,10 @@ class Type(Generic, ValueSpecBase):
2351
2476
  self._forward_ref = forward_ref
2352
2477
  super().__init__(type, default, is_noneable=is_noneable, frozen=frozen)
2353
2478
 
2479
+ def __call__(self, *args, **kwargs) -> typing.Any:
2480
+ del args, kwargs
2481
+ return self.type
2482
+
2354
2483
  @property
2355
2484
  def type(self) -> typing.Type[typing.Any]:
2356
2485
  """Returns desired type."""
@@ -2365,12 +2494,14 @@ class Type(Generic, ValueSpecBase):
2365
2494
  return set()
2366
2495
  return set([self._forward_ref])
2367
2496
 
2368
- 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
2369
2498
  """Validate applied value."""
2370
2499
  if self.type_resolved and not pg_inspect.is_subclass(value, self.type):
2371
2500
  raise ValueError(
2372
- object_utils.message_on_path(
2373
- 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
+ )
2374
2505
 
2375
2506
  def _is_compatible(self, other: 'Type') -> bool:
2376
2507
  """Type specific compatiblity check."""
@@ -2406,7 +2537,7 @@ class Type(Generic, ValueSpecBase):
2406
2537
  **kwargs,
2407
2538
  ) -> str:
2408
2539
  """Format this object."""
2409
- return object_utils.kvlist_str(
2540
+ return utils.kvlist_str(
2410
2541
  [
2411
2542
  ('', self._expected_type, None),
2412
2543
  ('default', self._default, MISSING_VALUE),
@@ -2417,7 +2548,7 @@ class Type(Generic, ValueSpecBase):
2417
2548
  compact=compact,
2418
2549
  verbose=verbose,
2419
2550
  root_indent=root_indent,
2420
- **kwargs
2551
+ **kwargs,
2421
2552
  )
2422
2553
 
2423
2554
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -2539,6 +2670,10 @@ class Union(Generic, ValueSpecBase):
2539
2670
  frozen=frozen,
2540
2671
  )
2541
2672
 
2673
+ def __call__(self, *args, **kwargs) -> typing.Any:
2674
+ del args, kwargs
2675
+ raise TypeError(f'{self!r} cannot be instantiated.')
2676
+
2542
2677
  @functools.cached_property
2543
2678
  def forward_refs(self) -> typing.Set[class_schema.ForwardRef]:
2544
2679
  """Returns forward references used in this spec."""
@@ -2603,14 +2738,15 @@ class Union(Generic, ValueSpecBase):
2603
2738
  return c
2604
2739
  return None
2605
2740
 
2606
- def _apply(self,
2607
- value: typing.Any,
2608
- allow_partial: bool,
2609
- child_transform: typing.Callable[
2610
- [object_utils.KeyPath, Field, typing.Any],
2611
- typing.Any
2612
- ],
2613
- 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:
2614
2750
  """Union specific apply."""
2615
2751
  # Match strong-typed candidates first.
2616
2752
  if not self.type_resolved:
@@ -2712,7 +2848,7 @@ class Union(Generic, ValueSpecBase):
2712
2848
  **kwargs,
2713
2849
  ) -> str:
2714
2850
  """Format this object."""
2715
- return object_utils.kvlist_str(
2851
+ return utils.kvlist_str(
2716
2852
  [
2717
2853
  ('', self._candidates, None),
2718
2854
  ('default', self._default, MISSING_VALUE),
@@ -2724,7 +2860,7 @@ class Union(Generic, ValueSpecBase):
2724
2860
  verbose=verbose,
2725
2861
  root_indent=root_indent,
2726
2862
  list_wrap_threshold=kwargs.pop('list_wrap_threshold', 20),
2727
- **kwargs
2863
+ **kwargs,
2728
2864
  )
2729
2865
 
2730
2866
  def to_json(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
@@ -2856,6 +2992,10 @@ class Any(ValueSpecBase):
2856
2992
  )
2857
2993
  self._annotation = annotation
2858
2994
 
2995
+ def __call__(self, *args, **kwargs) -> typing.Any:
2996
+ del args, kwargs
2997
+ raise TypeError(f'{self!r} cannot be instantiated.')
2998
+
2859
2999
  def is_compatible(self, other: ValueSpec) -> bool:
2860
3000
  """Any is compatible with any ValueSpec."""
2861
3001
  return True
@@ -2868,17 +3008,17 @@ class Any(ValueSpecBase):
2868
3008
  **kwargs,
2869
3009
  ) -> str:
2870
3010
  """Format this object."""
2871
- return object_utils.kvlist_str(
3011
+ return utils.kvlist_str(
2872
3012
  [
2873
3013
  ('default', self._default, MISSING_VALUE),
2874
3014
  ('frozen', self._frozen, False),
2875
- ('annotation', self._annotation, MISSING_VALUE)
3015
+ ('annotation', self._annotation, MISSING_VALUE),
2876
3016
  ],
2877
3017
  label=self.__class__.__name__,
2878
3018
  compact=compact,
2879
3019
  verbose=verbose,
2880
3020
  root_indent=root_indent,
2881
- **kwargs
3021
+ **kwargs,
2882
3022
  )
2883
3023
 
2884
3024
  def annotate(self, annotation: typing.Any) -> 'Any':
@@ -2948,7 +3088,7 @@ ValueSpec.ObjectType = Object
2948
3088
  def ensure_value_spec(
2949
3089
  value_spec: class_schema.ValueSpec,
2950
3090
  src_spec: class_schema.ValueSpec,
2951
- root_path: typing.Optional[object_utils.KeyPath] = None
3091
+ root_path: typing.Optional[utils.KeyPath] = None,
2952
3092
  ) -> typing.Optional[class_schema.ValueSpec]:
2953
3093
  """Extract counter part from value spec that matches dest spec type.
2954
3094
 
@@ -2969,7 +3109,10 @@ def ensure_value_spec(
2969
3109
  return None
2970
3110
  if not src_spec.is_compatible(value_spec):
2971
3111
  raise TypeError(
2972
- object_utils.message_on_path(
3112
+ utils.message_on_path(
2973
3113
  f'Source spec {src_spec} is not compatible with destination '
2974
- f'spec {value_spec}.', root_path))
3114
+ f'spec {value_spec}.',
3115
+ root_path,
3116
+ )
3117
+ )
2975
3118
  return value_spec