pyglove 0.4.5.dev20240319__py3-none-any.whl → 0.4.5.dev202501132210__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.
- pyglove/core/__init__.py +54 -20
- pyglove/core/coding/__init__.py +42 -0
- pyglove/core/coding/errors.py +111 -0
- pyglove/core/coding/errors_test.py +98 -0
- pyglove/core/coding/execution.py +309 -0
- pyglove/core/coding/execution_test.py +333 -0
- pyglove/core/{object_utils/codegen.py → coding/function_generation.py} +10 -4
- pyglove/core/{object_utils/codegen_test.py → coding/function_generation_test.py} +5 -7
- pyglove/core/coding/parsing.py +153 -0
- pyglove/core/coding/parsing_test.py +150 -0
- pyglove/core/coding/permissions.py +100 -0
- pyglove/core/coding/permissions_test.py +93 -0
- pyglove/core/geno/base.py +54 -41
- pyglove/core/geno/base_test.py +2 -4
- pyglove/core/geno/categorical.py +37 -28
- pyglove/core/geno/custom.py +19 -16
- pyglove/core/geno/numerical.py +20 -17
- pyglove/core/geno/space.py +4 -5
- pyglove/core/hyper/base.py +6 -6
- pyglove/core/hyper/categorical.py +94 -55
- pyglove/core/hyper/custom.py +7 -7
- pyglove/core/hyper/custom_test.py +9 -10
- pyglove/core/hyper/derived.py +30 -22
- pyglove/core/hyper/derived_test.py +2 -4
- pyglove/core/hyper/dynamic_evaluation.py +5 -6
- pyglove/core/hyper/evolvable.py +57 -46
- pyglove/core/hyper/numerical.py +48 -24
- pyglove/core/hyper/numerical_test.py +9 -9
- pyglove/core/hyper/object_template.py +58 -46
- pyglove/core/io/__init__.py +1 -0
- pyglove/core/io/file_system.py +17 -7
- pyglove/core/io/file_system_test.py +2 -0
- pyglove/core/io/sequence.py +299 -0
- pyglove/core/io/sequence_test.py +124 -0
- pyglove/core/logging_test.py +0 -2
- pyglove/core/patching/object_factory.py +4 -4
- pyglove/core/patching/pattern_based.py +4 -4
- pyglove/core/patching/rule_based.py +17 -5
- pyglove/core/patching/rule_based_test.py +27 -4
- pyglove/core/symbolic/__init__.py +2 -7
- pyglove/core/symbolic/base.py +320 -183
- pyglove/core/symbolic/base_test.py +123 -19
- pyglove/core/symbolic/boilerplate.py +7 -13
- pyglove/core/symbolic/boilerplate_test.py +25 -23
- pyglove/core/symbolic/class_wrapper.py +48 -45
- pyglove/core/symbolic/class_wrapper_test.py +2 -2
- pyglove/core/symbolic/compounding.py +9 -15
- pyglove/core/symbolic/compounding_test.py +2 -4
- pyglove/core/symbolic/dict.py +154 -110
- pyglove/core/symbolic/dict_test.py +238 -130
- pyglove/core/symbolic/diff.py +199 -10
- pyglove/core/symbolic/diff_test.py +226 -0
- pyglove/core/symbolic/flags.py +1 -1
- pyglove/core/symbolic/functor.py +29 -26
- pyglove/core/symbolic/functor_test.py +102 -50
- pyglove/core/symbolic/inferred.py +2 -2
- pyglove/core/symbolic/list.py +81 -50
- pyglove/core/symbolic/list_test.py +119 -97
- pyglove/core/symbolic/object.py +225 -113
- pyglove/core/symbolic/object_test.py +320 -108
- pyglove/core/symbolic/origin.py +17 -14
- pyglove/core/symbolic/origin_test.py +4 -2
- pyglove/core/symbolic/pure_symbolic.py +4 -3
- pyglove/core/symbolic/ref.py +108 -21
- pyglove/core/symbolic/ref_test.py +93 -0
- pyglove/core/symbolic/symbolize_test.py +10 -2
- pyglove/core/tuning/local_backend.py +2 -2
- pyglove/core/tuning/protocols.py +3 -3
- pyglove/core/tuning/sample_test.py +3 -3
- pyglove/core/typing/__init__.py +14 -5
- pyglove/core/typing/annotation_conversion.py +43 -27
- pyglove/core/typing/annotation_conversion_test.py +23 -0
- pyglove/core/typing/callable_ext.py +241 -3
- pyglove/core/typing/callable_ext_test.py +255 -0
- pyglove/core/typing/callable_signature.py +510 -66
- pyglove/core/typing/callable_signature_test.py +619 -99
- pyglove/core/typing/class_schema.py +229 -154
- pyglove/core/typing/class_schema_test.py +149 -95
- pyglove/core/typing/custom_typing.py +5 -4
- pyglove/core/typing/inspect.py +63 -0
- pyglove/core/typing/inspect_test.py +39 -0
- pyglove/core/typing/key_specs.py +10 -11
- pyglove/core/typing/key_specs_test.py +7 -4
- pyglove/core/typing/type_conversion.py +4 -5
- pyglove/core/typing/type_conversion_test.py +12 -12
- pyglove/core/typing/typed_missing.py +6 -7
- pyglove/core/typing/typed_missing_test.py +7 -8
- pyglove/core/typing/value_specs.py +604 -362
- pyglove/core/typing/value_specs_test.py +328 -90
- pyglove/core/utils/__init__.py +164 -0
- pyglove/core/{object_utils → utils}/common_traits.py +3 -67
- pyglove/core/utils/common_traits_test.py +36 -0
- pyglove/core/{object_utils → utils}/docstr_utils.py +23 -0
- pyglove/core/{object_utils → utils}/docstr_utils_test.py +36 -4
- pyglove/core/{object_utils → utils}/error_utils.py +78 -9
- pyglove/core/{object_utils → utils}/error_utils_test.py +61 -5
- pyglove/core/utils/formatting.py +464 -0
- pyglove/core/utils/formatting_test.py +453 -0
- pyglove/core/{object_utils → utils}/hierarchical.py +23 -25
- pyglove/core/{object_utils → utils}/hierarchical_test.py +3 -5
- pyglove/core/{object_utils → utils}/json_conversion.py +177 -52
- pyglove/core/{object_utils → utils}/json_conversion_test.py +97 -16
- pyglove/core/{object_utils → utils}/missing.py +3 -3
- pyglove/core/{object_utils → utils}/missing_test.py +2 -4
- pyglove/core/utils/text_color.py +128 -0
- pyglove/core/utils/text_color_test.py +94 -0
- pyglove/core/{object_utils → utils}/thread_local_test.py +1 -3
- pyglove/core/utils/timing.py +236 -0
- pyglove/core/utils/timing_test.py +154 -0
- pyglove/core/{object_utils → utils}/value_location.py +275 -6
- pyglove/core/utils/value_location_test.py +707 -0
- pyglove/core/views/__init__.py +32 -0
- pyglove/core/views/base.py +804 -0
- pyglove/core/views/base_test.py +580 -0
- pyglove/core/views/html/__init__.py +27 -0
- pyglove/core/views/html/base.py +547 -0
- pyglove/core/views/html/base_test.py +830 -0
- pyglove/core/views/html/controls/__init__.py +35 -0
- pyglove/core/views/html/controls/base.py +275 -0
- pyglove/core/views/html/controls/label.py +207 -0
- pyglove/core/views/html/controls/label_test.py +157 -0
- pyglove/core/views/html/controls/progress_bar.py +183 -0
- pyglove/core/views/html/controls/progress_bar_test.py +97 -0
- pyglove/core/views/html/controls/tab.py +320 -0
- pyglove/core/views/html/controls/tab_test.py +87 -0
- pyglove/core/views/html/controls/tooltip.py +99 -0
- pyglove/core/views/html/controls/tooltip_test.py +99 -0
- pyglove/core/views/html/tree_view.py +1517 -0
- pyglove/core/views/html/tree_view_test.py +1461 -0
- {pyglove-0.4.5.dev20240319.dist-info → pyglove-0.4.5.dev202501132210.dist-info}/METADATA +18 -4
- pyglove-0.4.5.dev202501132210.dist-info/RECORD +214 -0
- {pyglove-0.4.5.dev20240319.dist-info → pyglove-0.4.5.dev202501132210.dist-info}/WHEEL +1 -1
- pyglove/core/object_utils/__init__.py +0 -154
- pyglove/core/object_utils/common_traits_test.py +0 -82
- pyglove/core/object_utils/formatting.py +0 -234
- pyglove/core/object_utils/formatting_test.py +0 -223
- pyglove/core/object_utils/value_location_test.py +0 -385
- pyglove/core/symbolic/schema_utils.py +0 -327
- pyglove/core/symbolic/schema_utils_test.py +0 -57
- pyglove/core/typing/class_schema_utils.py +0 -202
- pyglove/core/typing/class_schema_utils_test.py +0 -194
- pyglove-0.4.5.dev20240319.dist-info/RECORD +0 -185
- /pyglove/core/{object_utils → utils}/thread_local.py +0 -0
- {pyglove-0.4.5.dev20240319.dist-info → pyglove-0.4.5.dev202501132210.dist-info}/LICENSE +0 -0
- {pyglove-0.4.5.dev20240319.dist-info → pyglove-0.4.5.dev202501132210.dist-info}/top_level.txt +0 -0
pyglove/core/symbolic/dict.py
CHANGED
@@ -16,8 +16,8 @@
|
|
16
16
|
import typing
|
17
17
|
from typing import Any, Callable, Iterable, Iterator, List, Optional, Sequence, Set, Tuple, Union
|
18
18
|
|
19
|
-
from pyglove.core import object_utils
|
20
19
|
from pyglove.core import typing as pg_typing
|
20
|
+
from pyglove.core import utils
|
21
21
|
from pyglove.core.symbolic import base
|
22
22
|
from pyglove.core.symbolic import flags
|
23
23
|
|
@@ -96,14 +96,16 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
96
96
|
"""
|
97
97
|
|
98
98
|
@classmethod
|
99
|
-
def partial(
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
99
|
+
def partial(
|
100
|
+
cls,
|
101
|
+
dict_obj: Optional[typing.Dict[Union[str, int], Any]] = None,
|
102
|
+
value_spec: Optional[pg_typing.Dict] = None,
|
103
|
+
*,
|
104
|
+
onchange_callback: Optional[
|
105
|
+
Callable[[typing.Dict[utils.KeyPath, base.FieldUpdate]], None]
|
106
|
+
] = None, # pylint: disable=bad-continuation
|
107
|
+
**kwargs,
|
108
|
+
) -> 'Dict':
|
107
109
|
"""Class method that creates a partial Dict object."""
|
108
110
|
return cls(dict_obj,
|
109
111
|
value_spec=value_spec,
|
@@ -112,13 +114,15 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
112
114
|
**kwargs)
|
113
115
|
|
114
116
|
@classmethod
|
115
|
-
def from_json(
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
def from_json(
|
118
|
+
cls,
|
119
|
+
json_value: Any,
|
120
|
+
*,
|
121
|
+
value_spec: Optional[pg_typing.Dict] = None,
|
122
|
+
allow_partial: bool = False,
|
123
|
+
root_path: Optional[utils.KeyPath] = None,
|
124
|
+
**kwargs,
|
125
|
+
) -> 'Dict':
|
122
126
|
"""Class method that load an symbolic Dict from a JSON value.
|
123
127
|
|
124
128
|
Args:
|
@@ -152,22 +156,35 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
152
156
|
# Not okay:
|
153
157
|
d.a.f2.abc = 1
|
154
158
|
"""
|
155
|
-
return cls(
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
159
|
+
return cls(
|
160
|
+
{
|
161
|
+
k: base.from_json(
|
162
|
+
v,
|
163
|
+
root_path=utils.KeyPath(k, root_path),
|
164
|
+
allow_partial=allow_partial,
|
165
|
+
**kwargs,
|
166
|
+
)
|
167
|
+
for k, v in json_value.items()
|
168
|
+
},
|
169
|
+
value_spec=value_spec,
|
170
|
+
root_path=root_path,
|
171
|
+
allow_partial=allow_partial,
|
172
|
+
)
|
173
|
+
|
174
|
+
def __init__(
|
175
|
+
self,
|
176
|
+
dict_obj: Union[
|
177
|
+
None,
|
178
|
+
Iterable[Tuple[Union[str, int], Any]],
|
179
|
+
typing.Dict[Union[str, int], Any],
|
180
|
+
] = None,
|
181
|
+
*,
|
182
|
+
value_spec: Optional[pg_typing.Dict] = None,
|
183
|
+
onchange_callback: Optional[
|
184
|
+
Callable[[typing.Dict[utils.KeyPath, base.FieldUpdate]], None]
|
185
|
+
] = None, # pylint: disable=bad-continuation
|
186
|
+
**kwargs,
|
187
|
+
):
|
171
188
|
"""Constructor.
|
172
189
|
|
173
190
|
Args:
|
@@ -326,8 +343,8 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
326
343
|
return self
|
327
344
|
|
328
345
|
def _sym_rebind(
|
329
|
-
self, path_value_pairs: typing.Dict[
|
330
|
-
|
346
|
+
self, path_value_pairs: typing.Dict[utils.KeyPath, Any]
|
347
|
+
) -> List[base.FieldUpdate]:
|
331
348
|
"""Subclass specific rebind implementation."""
|
332
349
|
updates = []
|
333
350
|
for k, v in path_value_pairs.items():
|
@@ -336,7 +353,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
336
353
|
updates.append(update)
|
337
354
|
return updates
|
338
355
|
|
339
|
-
def _sym_missing(self) -> typing.Dict[str, Any]:
|
356
|
+
def _sym_missing(self) -> typing.Dict[Union[str, int], Any]:
|
340
357
|
"""Returns missing values.
|
341
358
|
|
342
359
|
Returns:
|
@@ -351,7 +368,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
351
368
|
if keys:
|
352
369
|
for key in keys:
|
353
370
|
v = self.sym_getattr(key)
|
354
|
-
if
|
371
|
+
if utils.MISSING_VALUE == v:
|
355
372
|
missing[key] = field.value.default
|
356
373
|
else:
|
357
374
|
if isinstance(v, base.Symbolic):
|
@@ -366,7 +383,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
366
383
|
missing[k] = missing_child
|
367
384
|
return missing
|
368
385
|
|
369
|
-
def _sym_nondefault(self) -> typing.Dict[str, Any]:
|
386
|
+
def _sym_nondefault(self) -> typing.Dict[Union[str, int], Any]:
|
370
387
|
"""Returns non-default values as key/value pairs in a dict."""
|
371
388
|
non_defaults = dict()
|
372
389
|
if self._value_spec is not None and self._value_spec.schema:
|
@@ -399,9 +416,9 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
399
416
|
return value
|
400
417
|
|
401
418
|
if value.__class__ is base_value.__class__:
|
402
|
-
getter = lambda x, k: x.sym_getattr(k)
|
419
|
+
getter = lambda x, k: x.sym_getattr(k, pg_typing.MISSING_VALUE)
|
403
420
|
elif isinstance(value, dict) and isinstance(base_value, dict):
|
404
|
-
getter = lambda x, k: x
|
421
|
+
getter = lambda x, k: x.get(k, pg_typing.MISSING_VALUE)
|
405
422
|
else:
|
406
423
|
return value
|
407
424
|
|
@@ -435,7 +452,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
435
452
|
"""Tests if a symbolic attribute exists."""
|
436
453
|
return key in self
|
437
454
|
|
438
|
-
def sym_keys(self) -> Iterator[str]:
|
455
|
+
def sym_keys(self) -> Iterator[Union[str, int]]:
|
439
456
|
"""Iterates the keys of symbolic attributes."""
|
440
457
|
if self._value_spec is None or self._value_spec.schema is None:
|
441
458
|
for key in super().__iter__():
|
@@ -458,7 +475,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
458
475
|
yield self._sym_getattr(k)
|
459
476
|
|
460
477
|
def sym_items(self) -> Iterator[
|
461
|
-
Tuple[str, Any]]:
|
478
|
+
Tuple[Union[str, int], Any]]:
|
462
479
|
"""Iterates the (key, value) pairs of symbolic attributes."""
|
463
480
|
for k in self.sym_keys():
|
464
481
|
yield k, self._sym_getattr(k)
|
@@ -481,7 +498,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
481
498
|
if v != pg_typing.MISSING_VALUE])))
|
482
499
|
|
483
500
|
def _sym_getattr( # pytype: disable=signature-mismatch # overriding-parameter-type-checks
|
484
|
-
self, key: str) -> Any:
|
501
|
+
self, key: Union[str, int]) -> Any:
|
485
502
|
"""Gets symbolic attribute by key."""
|
486
503
|
return super().__getitem__(key)
|
487
504
|
|
@@ -505,21 +522,20 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
505
522
|
pass_through=True)
|
506
523
|
|
507
524
|
def _update_children_paths(
|
508
|
-
self,
|
509
|
-
|
510
|
-
new_path: object_utils.KeyPath) -> None:
|
525
|
+
self, old_path: utils.KeyPath, new_path: utils.KeyPath
|
526
|
+
) -> None:
|
511
527
|
"""Update children paths according to root_path of current node."""
|
512
528
|
del old_path
|
513
529
|
for k, v in self.sym_items():
|
514
530
|
if isinstance(v, base.TopologyAware):
|
515
|
-
v.sym_setpath(
|
531
|
+
v.sym_setpath(utils.KeyPath(k, new_path))
|
516
532
|
|
517
533
|
def _set_item_without_permission_check( # pytype: disable=signature-mismatch # overriding-parameter-type-checks
|
518
|
-
self, key: str, value: Any) -> Optional[base.FieldUpdate]:
|
534
|
+
self, key: Union[str, int], value: Any) -> Optional[base.FieldUpdate]:
|
519
535
|
"""Set item without permission check."""
|
520
|
-
if not isinstance(key, str):
|
536
|
+
if not isinstance(key, (str, int)):
|
521
537
|
raise KeyError(self._error_message(
|
522
|
-
f'Key must be string type. Encountered {key!r}.'))
|
538
|
+
f'Key must be string or int type. Encountered {key!r}.'))
|
523
539
|
|
524
540
|
old_value = self.get(key, pg_typing.MISSING_VALUE)
|
525
541
|
if old_value is value:
|
@@ -536,12 +552,12 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
536
552
|
container_cls = self.__class__
|
537
553
|
raise KeyError(
|
538
554
|
self._error_message(
|
539
|
-
f'Key
|
555
|
+
f'Key {key!r} is not allowed for {container_cls}.'))
|
540
556
|
|
541
557
|
# Detach old value from object tree.
|
542
558
|
if isinstance(old_value, base.TopologyAware):
|
543
559
|
old_value.sym_setparent(None)
|
544
|
-
old_value.sym_setpath(
|
560
|
+
old_value.sym_setpath(utils.KeyPath())
|
545
561
|
|
546
562
|
if (pg_typing.MISSING_VALUE == value and
|
547
563
|
(not field or isinstance(field.key, pg_typing.NonConstKey))):
|
@@ -566,9 +582,11 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
566
582
|
return base.FieldUpdate(
|
567
583
|
self.sym_path + key, target, field, old_value, new_value)
|
568
584
|
|
569
|
-
def _formalized_value(
|
570
|
-
|
571
|
-
|
585
|
+
def _formalized_value(
|
586
|
+
self, name: Union[str, int],
|
587
|
+
field: Optional[pg_typing.Field],
|
588
|
+
value: Any
|
589
|
+
) -> Any:
|
572
590
|
"""Get transformed (formal) value from user input."""
|
573
591
|
allow_partial = base.accepts_partial(self)
|
574
592
|
if field and pg_typing.MISSING_VALUE == value:
|
@@ -578,13 +596,15 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
578
596
|
value = base.from_json(
|
579
597
|
value,
|
580
598
|
allow_partial=allow_partial,
|
581
|
-
root_path=
|
599
|
+
root_path=utils.KeyPath(name, self.sym_path),
|
600
|
+
)
|
582
601
|
if field and flags.is_type_check_enabled():
|
583
602
|
value = field.apply(
|
584
603
|
value,
|
585
604
|
allow_partial=allow_partial,
|
586
605
|
transform_fn=base.symbolic_transform_fn(self._allow_partial),
|
587
|
-
root_path=
|
606
|
+
root_path=utils.KeyPath(name, self.sym_path),
|
607
|
+
)
|
588
608
|
return self._relocate_if_symbolic(name, value)
|
589
609
|
|
590
610
|
@property
|
@@ -592,8 +612,9 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
592
612
|
"""Returns True if current dict subscribes field updates."""
|
593
613
|
return self._onchange_callback is not None
|
594
614
|
|
595
|
-
def _on_change(
|
596
|
-
|
615
|
+
def _on_change(
|
616
|
+
self, field_updates: typing.Dict[utils.KeyPath, base.FieldUpdate]
|
617
|
+
):
|
597
618
|
"""On change event of Dict."""
|
598
619
|
if self._onchange_callback:
|
599
620
|
self._onchange_callback(field_updates)
|
@@ -616,14 +637,14 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
616
637
|
"""Customizes pickle.load."""
|
617
638
|
self.__init__(state['value'], **state['kwargs'])
|
618
639
|
|
619
|
-
def __getitem__(self, key: str) -> Any:
|
640
|
+
def __getitem__(self, key: Union[str, int]) -> Any:
|
620
641
|
"""Get item in this Dict."""
|
621
642
|
try:
|
622
643
|
return self.sym_inferred(key)
|
623
644
|
except AttributeError as e:
|
624
645
|
raise KeyError(key) from e
|
625
646
|
|
626
|
-
def __setitem__(self, key: str, value: Any) -> None:
|
647
|
+
def __setitem__(self, key: Union[str, int], value: Any) -> None:
|
627
648
|
"""Set item in this Dict.
|
628
649
|
|
629
650
|
Args:
|
@@ -724,11 +745,11 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
724
745
|
"""Iterate keys in field declaration order."""
|
725
746
|
return self.sym_keys()
|
726
747
|
|
727
|
-
def keys(self) -> Iterator[str]: # pytype: disable=signature-mismatch
|
748
|
+
def keys(self) -> Iterator[Union[str, int]]: # pytype: disable=signature-mismatch
|
728
749
|
"""Returns an iterator of keys in current dict."""
|
729
750
|
return self.sym_keys()
|
730
751
|
|
731
|
-
def items(self) -> Iterator[Tuple[str, Any]]: # pytype: disable=signature-mismatch
|
752
|
+
def items(self) -> Iterator[Tuple[Union[str, int], Any]]: # pytype: disable=signature-mismatch
|
732
753
|
"""Returns an iterator of (key, value) items in current dict."""
|
733
754
|
return self.sym_items()
|
734
755
|
|
@@ -741,7 +762,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
741
762
|
return self.sym_clone(deep=False)
|
742
763
|
|
743
764
|
def pop(
|
744
|
-
self, key:
|
765
|
+
self, key: Union[str, int], default: Any = base.RAISE_IF_NOT_FOUND # pylint: disable=protected-access
|
745
766
|
) -> Any:
|
746
767
|
"""Pops a key from current dict."""
|
747
768
|
if key in self:
|
@@ -753,7 +774,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
753
774
|
raise KeyError(key)
|
754
775
|
return default
|
755
776
|
|
756
|
-
def popitem(self) -> Tuple[str, Any]:
|
777
|
+
def popitem(self) -> Tuple[Union[str, int], Any]:
|
757
778
|
if self._value_spec is not None:
|
758
779
|
raise ValueError(
|
759
780
|
'\'popitem\' cannot be performed on a Dict with value spec.')
|
@@ -772,7 +793,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
772
793
|
if value_spec:
|
773
794
|
self.use_value_spec(value_spec, self._allow_partial)
|
774
795
|
|
775
|
-
def setdefault(self, key: str, default: Any = None) -> Any:
|
796
|
+
def setdefault(self, key: Union[str, int], default: Any = None) -> Any:
|
776
797
|
"""Sets default as the value to key if not present."""
|
777
798
|
value = pg_typing.MISSING_VALUE
|
778
799
|
if key in self:
|
@@ -782,12 +803,15 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
782
803
|
value = default
|
783
804
|
return value
|
784
805
|
|
785
|
-
def update(
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
806
|
+
def update(
|
807
|
+
self,
|
808
|
+
other: Union[
|
809
|
+
None,
|
810
|
+
typing.Dict[Union[str, int], Any],
|
811
|
+
Iterable[Tuple[Union[str, int], Any]]
|
812
|
+
] = None,
|
813
|
+
**kwargs
|
814
|
+
) -> None: # pytype: disable=signature-mismatch
|
791
815
|
"""Update Dict with the same semantic as update on standard dict."""
|
792
816
|
updates = dict(other) if other else {}
|
793
817
|
updates.update(kwargs)
|
@@ -796,10 +820,12 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
796
820
|
|
797
821
|
def sym_jsonify(
|
798
822
|
self,
|
823
|
+
hide_frozen: bool = True,
|
799
824
|
hide_default_values: bool = False,
|
800
|
-
exclude_keys: Optional[Sequence[str]] = None,
|
825
|
+
exclude_keys: Optional[Sequence[Union[str, int]]] = None,
|
801
826
|
use_inferred: bool = False,
|
802
|
-
**kwargs
|
827
|
+
**kwargs,
|
828
|
+
) -> utils.JSONValueType:
|
803
829
|
"""Converts current object to a dict with plain Python objects."""
|
804
830
|
exclude_keys = set(exclude_keys or [])
|
805
831
|
if self._value_spec and self._value_spec.schema:
|
@@ -809,26 +835,30 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
809
835
|
# NOTE(daiyip): The key values of frozen field can safely be excluded
|
810
836
|
# since they will be the same for a class.
|
811
837
|
field = self._value_spec.schema[key_spec]
|
812
|
-
if
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
838
|
+
if hide_frozen and field.frozen:
|
839
|
+
continue
|
840
|
+
for key in keys:
|
841
|
+
if key not in exclude_keys:
|
842
|
+
value = self.sym_getattr(key)
|
843
|
+
if use_inferred and isinstance(value, base.Inferential):
|
844
|
+
value = self.sym_inferred(key, default=value)
|
845
|
+
if pg_typing.MISSING_VALUE == value:
|
846
|
+
continue
|
847
|
+
if hide_default_values and base.eq(value, field.default_value):
|
848
|
+
continue
|
849
|
+
json_repr[key] = base.to_json(
|
850
|
+
value,
|
851
|
+
hide_frozen=hide_frozen,
|
852
|
+
hide_default_values=hide_default_values,
|
853
|
+
use_inferred=use_inferred,
|
854
|
+
**kwargs)
|
826
855
|
return json_repr
|
827
856
|
else:
|
828
857
|
return {
|
829
858
|
k: base.to_json(
|
830
859
|
self.sym_inferred(k, default=v) if (
|
831
860
|
use_inferred and isinstance(v, base.Inferential)) else v,
|
861
|
+
hide_frozen=hide_frozen,
|
832
862
|
hide_default_values=hide_default_values,
|
833
863
|
use_inferred=use_inferred,
|
834
864
|
**kwargs)
|
@@ -838,11 +868,12 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
838
868
|
|
839
869
|
def custom_apply(
|
840
870
|
self,
|
841
|
-
path:
|
871
|
+
path: utils.KeyPath,
|
842
872
|
value_spec: pg_typing.ValueSpec,
|
843
873
|
allow_partial: bool,
|
844
874
|
child_transform: Optional[
|
845
|
-
Callable[[
|
875
|
+
Callable[[utils.KeyPath, pg_typing.Field, Any], Any]
|
876
|
+
] = None,
|
846
877
|
) -> Tuple[bool, 'Dict']:
|
847
878
|
"""Implement pg.typing.CustomTyping interface.
|
848
879
|
|
@@ -861,9 +892,12 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
861
892
|
if self._value_spec:
|
862
893
|
if value_spec and not value_spec.is_compatible(self._value_spec):
|
863
894
|
raise ValueError(
|
864
|
-
|
895
|
+
utils.message_on_path(
|
865
896
|
f'Dict (spec={self._value_spec!r}) cannot be assigned to an '
|
866
|
-
f'incompatible field (spec={value_spec!r}).',
|
897
|
+
f'incompatible field (spec={value_spec!r}).',
|
898
|
+
path,
|
899
|
+
)
|
900
|
+
)
|
867
901
|
if self._allow_partial == allow_partial:
|
868
902
|
proceed_with_standard_apply = False
|
869
903
|
else:
|
@@ -879,14 +913,14 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
879
913
|
root_indent: int = 0,
|
880
914
|
*,
|
881
915
|
python_format: bool = False,
|
882
|
-
|
916
|
+
hide_frozen: bool = True,
|
883
917
|
hide_default_values: bool = False,
|
884
918
|
hide_missing_values: bool = False,
|
885
|
-
include_keys: Optional[Set[str]] = None,
|
886
|
-
exclude_keys: Optional[Set[str]] = None,
|
919
|
+
include_keys: Optional[Set[Union[str, int]]] = None,
|
920
|
+
exclude_keys: Optional[Set[Union[str, int]]] = None,
|
887
921
|
use_inferred: bool = False,
|
888
922
|
cls_name: Optional[str] = None,
|
889
|
-
bracket_type:
|
923
|
+
bracket_type: utils.BracketType = utils.BracketType.CURLY,
|
890
924
|
key_as_attribute: bool = False,
|
891
925
|
extra_blankline_for_field_docstr: bool = False,
|
892
926
|
**kwargs,
|
@@ -910,6 +944,8 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
910
944
|
for key in keys:
|
911
945
|
if _should_include_key(key):
|
912
946
|
field = self._value_spec.schema[key_spec]
|
947
|
+
if hide_frozen and field.frozen:
|
948
|
+
continue
|
913
949
|
v = self.sym_getattr(key)
|
914
950
|
if use_inferred and isinstance(v, base.Inferential):
|
915
951
|
v = self.sym_inferred(key, default=v)
|
@@ -926,32 +962,34 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
926
962
|
v = self.sym_inferred(k, default=v)
|
927
963
|
field_list.append((None, k, v))
|
928
964
|
|
929
|
-
open_bracket, close_bracket =
|
965
|
+
open_bracket, close_bracket = utils.bracket_chars(bracket_type)
|
930
966
|
if not field_list:
|
931
|
-
return
|
932
|
-
f'{cls_name}{open_bracket}{close_bracket}', markdown
|
933
|
-
)
|
967
|
+
return f'{cls_name}{open_bracket}{close_bracket}'
|
934
968
|
|
935
969
|
if compact:
|
936
970
|
s = [f'{cls_name}{open_bracket}']
|
937
971
|
kv_strs = []
|
938
972
|
for _, k, v in field_list:
|
939
|
-
v_str =
|
973
|
+
v_str = utils.format(
|
940
974
|
v,
|
941
975
|
compact,
|
942
976
|
verbose,
|
943
977
|
root_indent + 1,
|
978
|
+
hide_frozen=hide_frozen,
|
944
979
|
hide_default_values=hide_default_values,
|
945
980
|
hide_missing_values=hide_missing_values,
|
946
981
|
python_format=python_format,
|
947
982
|
use_inferred=use_inferred,
|
948
983
|
extra_blankline_for_field_docstr=extra_blankline_for_field_docstr,
|
949
|
-
**kwargs
|
984
|
+
**kwargs,
|
985
|
+
)
|
950
986
|
if not python_format or key_as_attribute:
|
951
|
-
|
987
|
+
if isinstance(k, int):
|
988
|
+
k = f'[{k}]'
|
989
|
+
item = f'{k}={v_str}'
|
952
990
|
else:
|
953
|
-
|
954
|
-
|
991
|
+
item = f'{k!r}: {v_str}'
|
992
|
+
kv_strs.append(item)
|
955
993
|
s.append(', '.join(kv_strs))
|
956
994
|
s.append(close_bracket)
|
957
995
|
else:
|
@@ -966,29 +1004,35 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
966
1004
|
description = typing.cast(pg_typing.Field, f).description
|
967
1005
|
for line in description.split('\n'):
|
968
1006
|
s.append(_indent(f'# {line}\n', root_indent + 1))
|
969
|
-
v_str =
|
1007
|
+
v_str = utils.format(
|
970
1008
|
v,
|
971
1009
|
compact,
|
972
1010
|
verbose,
|
973
1011
|
root_indent + 1,
|
1012
|
+
hide_frozen=hide_frozen,
|
974
1013
|
hide_default_values=hide_default_values,
|
975
1014
|
hide_missing_values=hide_missing_values,
|
976
1015
|
python_format=python_format,
|
977
1016
|
use_inferred=use_inferred,
|
978
1017
|
extra_blankline_for_field_docstr=extra_blankline_for_field_docstr,
|
979
|
-
**kwargs
|
1018
|
+
**kwargs,
|
1019
|
+
)
|
1020
|
+
|
980
1021
|
if not python_format:
|
981
1022
|
# Format in PyGlove's format (default).
|
982
|
-
|
1023
|
+
if isinstance(k, int):
|
1024
|
+
k = f'[{k}]'
|
1025
|
+
item = f'{k} = {v_str}'
|
983
1026
|
elif key_as_attribute:
|
984
1027
|
# Format `pg.Objects` under Python format.
|
985
|
-
|
1028
|
+
item = f'{k}={v_str}'
|
986
1029
|
else:
|
987
1030
|
# Format regular `pg.Dict` under Python format.
|
988
|
-
|
1031
|
+
item = f'{k!r}: {v_str}'
|
1032
|
+
s.append(_indent(item, root_indent + 1))
|
989
1033
|
s.append('\n')
|
990
1034
|
s.append(_indent(close_bracket, root_indent))
|
991
|
-
return
|
1035
|
+
return ''.join(s)
|
992
1036
|
|
993
1037
|
def __repr__(self) -> str:
|
994
1038
|
"""Operator repr()."""
|