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.
- pyglove/core/__init__.py +24 -21
- pyglove/core/geno/base.py +53 -38
- pyglove/core/geno/base_test.py +2 -4
- pyglove/core/geno/categorical.py +36 -27
- pyglove/core/geno/custom.py +18 -15
- pyglove/core/geno/numerical.py +19 -16
- pyglove/core/geno/space.py +3 -4
- pyglove/core/hyper/base.py +6 -6
- pyglove/core/hyper/categorical.py +91 -52
- 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 +3 -4
- 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/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 +4 -3
- pyglove/core/symbolic/base.py +167 -131
- pyglove/core/symbolic/base_test.py +17 -19
- pyglove/core/symbolic/boilerplate.py +4 -5
- pyglove/core/symbolic/class_wrapper.py +9 -9
- pyglove/core/symbolic/compounding.py +2 -2
- pyglove/core/symbolic/compounding_test.py +2 -4
- pyglove/core/symbolic/dict.py +70 -54
- pyglove/core/symbolic/dict_test.py +117 -100
- pyglove/core/symbolic/diff.py +12 -12
- pyglove/core/symbolic/flags.py +1 -1
- pyglove/core/symbolic/functor.py +16 -15
- pyglove/core/symbolic/functor_test.py +2 -4
- pyglove/core/symbolic/inferred.py +2 -2
- pyglove/core/symbolic/list.py +70 -47
- pyglove/core/symbolic/list_test.py +117 -98
- pyglove/core/symbolic/object.py +42 -40
- pyglove/core/symbolic/object_test.py +95 -88
- pyglove/core/symbolic/origin.py +5 -7
- pyglove/core/symbolic/pure_symbolic.py +4 -3
- pyglove/core/symbolic/ref.py +12 -8
- pyglove/core/tuning/local_backend.py +2 -2
- pyglove/core/tuning/protocols.py +3 -3
- pyglove/core/typing/annotation_conversion.py +3 -3
- pyglove/core/typing/callable_ext.py +11 -13
- pyglove/core/typing/callable_signature.py +19 -18
- pyglove/core/typing/callable_signature_test.py +3 -5
- pyglove/core/typing/class_schema.py +48 -44
- pyglove/core/typing/class_schema_test.py +3 -5
- pyglove/core/typing/custom_typing.py +5 -4
- pyglove/core/typing/key_specs.py +5 -7
- pyglove/core/typing/key_specs_test.py +4 -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 +210 -141
- pyglove/core/typing/value_specs_test.py +12 -13
- pyglove/core/utils/__init__.py +159 -0
- pyglove/core/{object_utils → utils}/common_traits_test.py +1 -3
- pyglove/core/{object_utils → utils}/docstr_utils_test.py +1 -3
- pyglove/core/{object_utils → utils}/error_utils.py +3 -3
- pyglove/core/{object_utils → utils}/error_utils_test.py +1 -1
- pyglove/core/{object_utils → utils}/formatting.py +1 -1
- pyglove/core/{object_utils → utils}/formatting_test.py +1 -2
- 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_test.py +1 -3
- pyglove/core/{object_utils → utils}/missing.py +2 -2
- pyglove/core/{object_utils → utils}/missing_test.py +2 -4
- pyglove/core/{object_utils → utils}/thread_local_test.py +1 -3
- pyglove/core/{object_utils → utils}/timing.py +3 -3
- pyglove/core/{object_utils → utils}/timing_test.py +2 -3
- pyglove/core/{object_utils → utils}/value_location.py +2 -2
- pyglove/core/{object_utils → utils}/value_location_test.py +2 -4
- pyglove/core/views/base.py +25 -29
- pyglove/core/views/html/base.py +14 -15
- pyglove/core/views/html/controls/base.py +5 -5
- pyglove/core/views/html/controls/progress_bar.py +3 -5
- pyglove/core/views/html/tree_view.py +37 -35
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/METADATA +1 -1
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/RECORD +90 -90
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/WHEEL +1 -1
- pyglove/core/object_utils/__init__.py +0 -161
- /pyglove/core/{object_utils → utils}/common_traits.py +0 -0
- /pyglove/core/{object_utils → utils}/docstr_utils.py +0 -0
- /pyglove/core/{object_utils → utils}/json_conversion.py +0 -0
- /pyglove/core/{object_utils → utils}/thread_local.py +0 -0
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/LICENSE +0 -0
- {pyglove-0.4.5.dev202501050808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/top_level.txt +0 -0
@@ -11,15 +11,13 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
-
"""Tests for pyglove.symbolic.base."""
|
15
|
-
|
16
14
|
import copy
|
17
15
|
import inspect
|
18
16
|
from typing import Any
|
19
17
|
import unittest
|
20
18
|
|
21
|
-
from pyglove.core import object_utils
|
22
19
|
from pyglove.core import typing as pg_typing
|
20
|
+
from pyglove.core import utils
|
23
21
|
from pyglove.core import views
|
24
22
|
from pyglove.core.symbolic import base
|
25
23
|
from pyglove.core.symbolic.dict import Dict
|
@@ -33,7 +31,7 @@ class FieldUpdateTest(unittest.TestCase):
|
|
33
31
|
def test_basics(self):
|
34
32
|
x = Dict(x=1)
|
35
33
|
f = pg_typing.Field('x', pg_typing.Int())
|
36
|
-
update = base.FieldUpdate(
|
34
|
+
update = base.FieldUpdate(utils.KeyPath('x'), x, f, 1, 2)
|
37
35
|
self.assertEqual(update.path, 'x')
|
38
36
|
self.assertIs(update.target, x)
|
39
37
|
self.assertIs(update.field, f)
|
@@ -42,15 +40,15 @@ class FieldUpdateTest(unittest.TestCase):
|
|
42
40
|
|
43
41
|
def test_format(self):
|
44
42
|
self.assertEqual(
|
45
|
-
base.FieldUpdate(
|
46
|
-
|
47
|
-
)
|
43
|
+
base.FieldUpdate(utils.KeyPath('x'), Dict(x=1), None, 1, 2).format(
|
44
|
+
compact=True
|
45
|
+
),
|
48
46
|
'FieldUpdate(parent_path=, path=x, old_value=1, new_value=2)',
|
49
47
|
)
|
50
48
|
|
51
49
|
self.assertEqual(
|
52
50
|
base.FieldUpdate(
|
53
|
-
|
51
|
+
utils.KeyPath('a'), Dict(x=Dict(a=1)).x, None, 1, 2
|
54
52
|
).format(compact=True),
|
55
53
|
'FieldUpdate(parent_path=x, path=a, old_value=1, new_value=2)',
|
56
54
|
)
|
@@ -59,34 +57,34 @@ class FieldUpdateTest(unittest.TestCase):
|
|
59
57
|
x = Dict()
|
60
58
|
f = pg_typing.Field('x', pg_typing.Int())
|
61
59
|
self.assertEqual(
|
62
|
-
base.FieldUpdate(
|
63
|
-
base.FieldUpdate(
|
60
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 1, 2),
|
61
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 1, 2),
|
64
62
|
)
|
65
63
|
|
66
64
|
# Targets are not the same instance.
|
67
65
|
self.assertNotEqual(
|
68
|
-
base.FieldUpdate(
|
69
|
-
base.FieldUpdate(
|
66
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 1, 2),
|
67
|
+
base.FieldUpdate(utils.KeyPath('a'), Dict(), f, 1, 2),
|
70
68
|
)
|
71
69
|
|
72
70
|
# Fields are not the same instance.
|
73
71
|
self.assertNotEqual(
|
74
|
-
base.FieldUpdate(
|
75
|
-
base.FieldUpdate(
|
72
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 1, 2),
|
73
|
+
base.FieldUpdate(utils.KeyPath('b'), x, copy.copy(f), 1, 2),
|
76
74
|
)
|
77
75
|
|
78
76
|
self.assertNotEqual(
|
79
|
-
base.FieldUpdate(
|
80
|
-
base.FieldUpdate(
|
77
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 1, 2),
|
78
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 0, 2),
|
81
79
|
)
|
82
80
|
|
83
81
|
self.assertNotEqual(
|
84
|
-
base.FieldUpdate(
|
85
|
-
base.FieldUpdate(
|
82
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 1, 2),
|
83
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 1, 1),
|
86
84
|
)
|
87
85
|
|
88
86
|
self.assertNotEqual(
|
89
|
-
base.FieldUpdate(
|
87
|
+
base.FieldUpdate(utils.KeyPath('a'), x, f, 1, 2), Dict()
|
90
88
|
)
|
91
89
|
|
92
90
|
|
@@ -15,11 +15,10 @@
|
|
15
15
|
|
16
16
|
import copy
|
17
17
|
import inspect
|
18
|
-
|
19
18
|
from typing import Any, List, Optional, Type
|
20
19
|
|
21
|
-
from pyglove.core import object_utils
|
22
20
|
from pyglove.core import typing as pg_typing
|
21
|
+
from pyglove.core import utils
|
23
22
|
from pyglove.core.symbolic import flags
|
24
23
|
from pyglove.core.symbolic import object as pg_object
|
25
24
|
|
@@ -129,9 +128,9 @@ def boilerplate_class(
|
|
129
128
|
cls.auto_register = True
|
130
129
|
|
131
130
|
allow_partial = value.allow_partial
|
132
|
-
def _freeze_field(
|
133
|
-
|
134
|
-
|
131
|
+
def _freeze_field(
|
132
|
+
path: utils.KeyPath, field: pg_typing.Field, value: Any
|
133
|
+
) -> Any:
|
135
134
|
# We do not do validation since Object is already in valid form.
|
136
135
|
del path
|
137
136
|
if not isinstance(field.key, pg_typing.ListKey):
|
@@ -26,8 +26,8 @@ import types
|
|
26
26
|
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, Union
|
27
27
|
|
28
28
|
from pyglove.core import detouring
|
29
|
-
from pyglove.core import object_utils
|
30
29
|
from pyglove.core import typing as pg_typing
|
30
|
+
from pyglove.core import utils
|
31
31
|
|
32
32
|
from pyglove.core.symbolic import dict as pg_dict # pylint: disable=unused-import
|
33
33
|
from pyglove.core.symbolic import list as pg_list # pylint: disable=unused-import
|
@@ -71,7 +71,7 @@ class _SubclassedWrapperBase(ClassWrapper):
|
|
71
71
|
# the `__init__` method.
|
72
72
|
auto_typing = False
|
73
73
|
|
74
|
-
@
|
74
|
+
@utils.explicit_method_override
|
75
75
|
def __init__(self, *args, **kwargs):
|
76
76
|
"""Overridden __init__ to construct symbolic wrapper only."""
|
77
77
|
# NOTE(daiyip): We avoid `__init__` to be called multiple times.
|
@@ -100,7 +100,7 @@ class _SubclassedWrapperBase(ClassWrapper):
|
|
100
100
|
def __init_subclass__(cls):
|
101
101
|
# Class wrappers inherit `__init__` from the user class. Therefore, we mark
|
102
102
|
# all of them as explicitly overridden.
|
103
|
-
|
103
|
+
utils.explicit_method_override(cls.__init__)
|
104
104
|
|
105
105
|
super().__init_subclass__()
|
106
106
|
if cls.__init__ is _SubclassedWrapperBase.__init__:
|
@@ -129,7 +129,7 @@ class _SubclassedWrapperBase(ClassWrapper):
|
|
129
129
|
init_arg_list, arg_fields = _extract_init_signature(
|
130
130
|
cls, auto_doc=cls.auto_doc, auto_typing=cls.auto_typing)
|
131
131
|
|
132
|
-
@
|
132
|
+
@utils.explicit_method_override
|
133
133
|
@functools.wraps(cls.__init__)
|
134
134
|
def _sym_init(self, *args, **kwargs):
|
135
135
|
_SubclassedWrapperBase.__init__(self, *args, **kwargs)
|
@@ -522,7 +522,7 @@ def apply_wrappers(
|
|
522
522
|
"""
|
523
523
|
if not wrapper_classes:
|
524
524
|
wrapper_classes = []
|
525
|
-
for _, c in
|
525
|
+
for _, c in utils.JSONConvertible.registered_types():
|
526
526
|
if (issubclass(c, ClassWrapper)
|
527
527
|
and c not in (ClassWrapper, _SubclassedWrapperBase)
|
528
528
|
and (not where or where(c))
|
@@ -544,13 +544,13 @@ def _extract_init_signature(
|
|
544
544
|
# Read args docstr from both class doc string and __init__ doc string.
|
545
545
|
args_docstr = dict()
|
546
546
|
if cls.__doc__:
|
547
|
-
cls_docstr =
|
547
|
+
cls_docstr = utils.DocStr.parse(cls.__doc__)
|
548
548
|
args_docstr = cls_docstr.args
|
549
549
|
if init_method.__doc__:
|
550
|
-
init_docstr =
|
550
|
+
init_docstr = utils.DocStr.parse(init_method.__doc__)
|
551
551
|
args_docstr.update(init_docstr.args)
|
552
|
-
docstr =
|
553
|
-
|
552
|
+
docstr = utils.DocStr(
|
553
|
+
utils.DocStrStyle.GOOGLE,
|
554
554
|
short_description=None,
|
555
555
|
long_description=None,
|
556
556
|
examples=[],
|
@@ -19,7 +19,7 @@ import sys
|
|
19
19
|
import types
|
20
20
|
from typing import Any, Dict, List, Optional, Tuple, Type, Union
|
21
21
|
|
22
|
-
from pyglove.core import
|
22
|
+
from pyglove.core import utils
|
23
23
|
from pyglove.core.symbolic.base import Symbolic
|
24
24
|
from pyglove.core.symbolic.object import Object
|
25
25
|
import pyglove.core.typing as pg_typing
|
@@ -39,7 +39,7 @@ class Compound(Object):
|
|
39
39
|
# from the user class to compound with.
|
40
40
|
Object.__init_subclass__(cls)
|
41
41
|
|
42
|
-
@
|
42
|
+
@utils.explicit_method_override
|
43
43
|
def __init__(self, *args, **kwargs):
|
44
44
|
# `explicit_init` allows the `__init__` of the other classes that sit after
|
45
45
|
# `Compound` to be bypassed.
|
@@ -11,15 +11,13 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
-
"""Tests for pyglove.compounding."""
|
15
|
-
|
16
14
|
import abc
|
17
15
|
import dataclasses
|
18
16
|
import sys
|
19
17
|
import unittest
|
20
18
|
|
21
|
-
from pyglove.core import object_utils
|
22
19
|
from pyglove.core import typing as pg_typing
|
20
|
+
from pyglove.core import utils
|
23
21
|
from pyglove.core.symbolic.compounding import compound as pg_compound
|
24
22
|
from pyglove.core.symbolic.compounding import compound_class as pg_compound_class
|
25
23
|
from pyglove.core.symbolic.dict import Dict
|
@@ -145,7 +143,7 @@ class UserClassTest(unittest.TestCase):
|
|
145
143
|
class A(Object):
|
146
144
|
x: int
|
147
145
|
|
148
|
-
@
|
146
|
+
@utils.explicit_method_override
|
149
147
|
def __init__(self, x):
|
150
148
|
super().__init__(x=x)
|
151
149
|
assert type(self) is A # pylint: disable=unidiomatic-typecheck
|
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:
|
@@ -156,27 +160,31 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
156
160
|
{
|
157
161
|
k: base.from_json(
|
158
162
|
v,
|
159
|
-
root_path=
|
163
|
+
root_path=utils.KeyPath(k, root_path),
|
160
164
|
allow_partial=allow_partial,
|
161
|
-
**kwargs
|
162
|
-
)
|
165
|
+
**kwargs,
|
166
|
+
)
|
167
|
+
for k, v in json_value.items()
|
163
168
|
},
|
164
169
|
value_spec=value_spec,
|
165
170
|
root_path=root_path,
|
166
171
|
allow_partial=allow_partial,
|
167
172
|
)
|
168
173
|
|
169
|
-
def __init__(
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
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
|
+
):
|
180
188
|
"""Constructor.
|
181
189
|
|
182
190
|
Args:
|
@@ -335,8 +343,8 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
335
343
|
return self
|
336
344
|
|
337
345
|
def _sym_rebind(
|
338
|
-
self, path_value_pairs: typing.Dict[
|
339
|
-
|
346
|
+
self, path_value_pairs: typing.Dict[utils.KeyPath, Any]
|
347
|
+
) -> List[base.FieldUpdate]:
|
340
348
|
"""Subclass specific rebind implementation."""
|
341
349
|
updates = []
|
342
350
|
for k, v in path_value_pairs.items():
|
@@ -360,7 +368,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
360
368
|
if keys:
|
361
369
|
for key in keys:
|
362
370
|
v = self.sym_getattr(key)
|
363
|
-
if
|
371
|
+
if utils.MISSING_VALUE == v:
|
364
372
|
missing[key] = field.value.default
|
365
373
|
else:
|
366
374
|
if isinstance(v, base.Symbolic):
|
@@ -514,14 +522,13 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
514
522
|
pass_through=True)
|
515
523
|
|
516
524
|
def _update_children_paths(
|
517
|
-
self,
|
518
|
-
|
519
|
-
new_path: object_utils.KeyPath) -> None:
|
525
|
+
self, old_path: utils.KeyPath, new_path: utils.KeyPath
|
526
|
+
) -> None:
|
520
527
|
"""Update children paths according to root_path of current node."""
|
521
528
|
del old_path
|
522
529
|
for k, v in self.sym_items():
|
523
530
|
if isinstance(v, base.TopologyAware):
|
524
|
-
v.sym_setpath(
|
531
|
+
v.sym_setpath(utils.KeyPath(k, new_path))
|
525
532
|
|
526
533
|
def _set_item_without_permission_check( # pytype: disable=signature-mismatch # overriding-parameter-type-checks
|
527
534
|
self, key: Union[str, int], value: Any) -> Optional[base.FieldUpdate]:
|
@@ -550,7 +557,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
550
557
|
# Detach old value from object tree.
|
551
558
|
if isinstance(old_value, base.TopologyAware):
|
552
559
|
old_value.sym_setparent(None)
|
553
|
-
old_value.sym_setpath(
|
560
|
+
old_value.sym_setpath(utils.KeyPath())
|
554
561
|
|
555
562
|
if (pg_typing.MISSING_VALUE == value and
|
556
563
|
(not field or isinstance(field.key, pg_typing.NonConstKey))):
|
@@ -589,13 +596,15 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
589
596
|
value = base.from_json(
|
590
597
|
value,
|
591
598
|
allow_partial=allow_partial,
|
592
|
-
root_path=
|
599
|
+
root_path=utils.KeyPath(name, self.sym_path),
|
600
|
+
)
|
593
601
|
if field and flags.is_type_check_enabled():
|
594
602
|
value = field.apply(
|
595
603
|
value,
|
596
604
|
allow_partial=allow_partial,
|
597
605
|
transform_fn=base.symbolic_transform_fn(self._allow_partial),
|
598
|
-
root_path=
|
606
|
+
root_path=utils.KeyPath(name, self.sym_path),
|
607
|
+
)
|
599
608
|
return self._relocate_if_symbolic(name, value)
|
600
609
|
|
601
610
|
@property
|
@@ -603,8 +612,9 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
603
612
|
"""Returns True if current dict subscribes field updates."""
|
604
613
|
return self._onchange_callback is not None
|
605
614
|
|
606
|
-
def _on_change(
|
607
|
-
|
615
|
+
def _on_change(
|
616
|
+
self, field_updates: typing.Dict[utils.KeyPath, base.FieldUpdate]
|
617
|
+
):
|
608
618
|
"""On change event of Dict."""
|
609
619
|
if self._onchange_callback:
|
610
620
|
self._onchange_callback(field_updates)
|
@@ -814,8 +824,8 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
814
824
|
hide_default_values: bool = False,
|
815
825
|
exclude_keys: Optional[Sequence[Union[str, int]]] = None,
|
816
826
|
use_inferred: bool = False,
|
817
|
-
**kwargs
|
818
|
-
) ->
|
827
|
+
**kwargs,
|
828
|
+
) -> utils.JSONValueType:
|
819
829
|
"""Converts current object to a dict with plain Python objects."""
|
820
830
|
exclude_keys = set(exclude_keys or [])
|
821
831
|
if self._value_spec and self._value_spec.schema:
|
@@ -858,11 +868,12 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
858
868
|
|
859
869
|
def custom_apply(
|
860
870
|
self,
|
861
|
-
path:
|
871
|
+
path: utils.KeyPath,
|
862
872
|
value_spec: pg_typing.ValueSpec,
|
863
873
|
allow_partial: bool,
|
864
874
|
child_transform: Optional[
|
865
|
-
Callable[[
|
875
|
+
Callable[[utils.KeyPath, pg_typing.Field, Any], Any]
|
876
|
+
] = None,
|
866
877
|
) -> Tuple[bool, 'Dict']:
|
867
878
|
"""Implement pg.typing.CustomTyping interface.
|
868
879
|
|
@@ -881,9 +892,12 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
881
892
|
if self._value_spec:
|
882
893
|
if value_spec and not value_spec.is_compatible(self._value_spec):
|
883
894
|
raise ValueError(
|
884
|
-
|
895
|
+
utils.message_on_path(
|
885
896
|
f'Dict (spec={self._value_spec!r}) cannot be assigned to an '
|
886
|
-
f'incompatible field (spec={value_spec!r}).',
|
897
|
+
f'incompatible field (spec={value_spec!r}).',
|
898
|
+
path,
|
899
|
+
)
|
900
|
+
)
|
887
901
|
if self._allow_partial == allow_partial:
|
888
902
|
proceed_with_standard_apply = False
|
889
903
|
else:
|
@@ -906,7 +920,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
906
920
|
exclude_keys: Optional[Set[Union[str, int]]] = None,
|
907
921
|
use_inferred: bool = False,
|
908
922
|
cls_name: Optional[str] = None,
|
909
|
-
bracket_type:
|
923
|
+
bracket_type: utils.BracketType = utils.BracketType.CURLY,
|
910
924
|
key_as_attribute: bool = False,
|
911
925
|
extra_blankline_for_field_docstr: bool = False,
|
912
926
|
**kwargs,
|
@@ -948,7 +962,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
948
962
|
v = self.sym_inferred(k, default=v)
|
949
963
|
field_list.append((None, k, v))
|
950
964
|
|
951
|
-
open_bracket, close_bracket =
|
965
|
+
open_bracket, close_bracket = utils.bracket_chars(bracket_type)
|
952
966
|
if not field_list:
|
953
967
|
return f'{cls_name}{open_bracket}{close_bracket}'
|
954
968
|
|
@@ -956,7 +970,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
956
970
|
s = [f'{cls_name}{open_bracket}']
|
957
971
|
kv_strs = []
|
958
972
|
for _, k, v in field_list:
|
959
|
-
v_str =
|
973
|
+
v_str = utils.format(
|
960
974
|
v,
|
961
975
|
compact,
|
962
976
|
verbose,
|
@@ -967,7 +981,8 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
967
981
|
python_format=python_format,
|
968
982
|
use_inferred=use_inferred,
|
969
983
|
extra_blankline_for_field_docstr=extra_blankline_for_field_docstr,
|
970
|
-
**kwargs
|
984
|
+
**kwargs,
|
985
|
+
)
|
971
986
|
if not python_format or key_as_attribute:
|
972
987
|
if isinstance(k, int):
|
973
988
|
k = f'[{k}]'
|
@@ -989,7 +1004,7 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
989
1004
|
description = typing.cast(pg_typing.Field, f).description
|
990
1005
|
for line in description.split('\n'):
|
991
1006
|
s.append(_indent(f'# {line}\n', root_indent + 1))
|
992
|
-
v_str =
|
1007
|
+
v_str = utils.format(
|
993
1008
|
v,
|
994
1009
|
compact,
|
995
1010
|
verbose,
|
@@ -1000,7 +1015,8 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
|
|
1000
1015
|
python_format=python_format,
|
1001
1016
|
use_inferred=use_inferred,
|
1002
1017
|
extra_blankline_for_field_docstr=extra_blankline_for_field_docstr,
|
1003
|
-
**kwargs
|
1018
|
+
**kwargs,
|
1019
|
+
)
|
1004
1020
|
|
1005
1021
|
if not python_format:
|
1006
1022
|
# Format in PyGlove's format (default).
|