pyglove 0.4.5.dev202501030808__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.dev202501030808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/METADATA +1 -1
- {pyglove-0.4.5.dev202501030808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/RECORD +90 -90
- {pyglove-0.4.5.dev202501030808.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.dev202501030808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/LICENSE +0 -0
- {pyglove-0.4.5.dev202501030808.dist-info → pyglove-0.4.5.dev202501060809.dist-info}/top_level.txt +0 -0
pyglove/core/symbolic/list.py
CHANGED
@@ -18,8 +18,8 @@ import math
|
|
18
18
|
import numbers
|
19
19
|
import typing
|
20
20
|
from typing import Any, Callable, Dict, Iterable, Iterator, Optional, Tuple, Union
|
21
|
-
from pyglove.core import object_utils
|
22
21
|
from pyglove.core import typing as pg_typing
|
22
|
+
from pyglove.core import utils
|
23
23
|
from pyglove.core.symbolic import base
|
24
24
|
from pyglove.core.symbolic import flags
|
25
25
|
|
@@ -74,13 +74,16 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
74
74
|
"""
|
75
75
|
|
76
76
|
@classmethod
|
77
|
-
def partial(
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
77
|
+
def partial(
|
78
|
+
cls,
|
79
|
+
items: Optional[Iterable[Any]] = None,
|
80
|
+
*,
|
81
|
+
value_spec: Optional[pg_typing.List] = None,
|
82
|
+
onchange_callback: Optional[
|
83
|
+
Callable[[Dict[utils.KeyPath, base.FieldUpdate]], None]
|
84
|
+
] = None,
|
85
|
+
**kwargs,
|
86
|
+
) -> 'List':
|
84
87
|
"""Class method that creates a partial List object."""
|
85
88
|
return cls(items,
|
86
89
|
value_spec=value_spec,
|
@@ -89,13 +92,15 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
89
92
|
**kwargs)
|
90
93
|
|
91
94
|
@classmethod
|
92
|
-
def from_json(
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
95
|
+
def from_json(
|
96
|
+
cls,
|
97
|
+
json_value: Any,
|
98
|
+
*,
|
99
|
+
value_spec: Optional[pg_typing.List] = None,
|
100
|
+
allow_partial: bool = False,
|
101
|
+
root_path: Optional[utils.KeyPath] = None,
|
102
|
+
**kwargs,
|
103
|
+
) -> 'List':
|
99
104
|
"""Class method that load an symbolic List from a JSON value.
|
100
105
|
|
101
106
|
Example::
|
@@ -136,10 +141,11 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
136
141
|
[
|
137
142
|
base.from_json(
|
138
143
|
v,
|
139
|
-
root_path=
|
144
|
+
root_path=utils.KeyPath(i, root_path),
|
140
145
|
allow_partial=allow_partial,
|
141
|
-
**kwargs
|
142
|
-
)
|
146
|
+
**kwargs,
|
147
|
+
)
|
148
|
+
for i, v in enumerate(json_value)
|
143
149
|
],
|
144
150
|
value_spec=value_spec,
|
145
151
|
root_path=root_path,
|
@@ -151,12 +157,14 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
151
157
|
items: Optional[Iterable[Any]] = None,
|
152
158
|
*,
|
153
159
|
value_spec: Optional[pg_typing.List] = None,
|
154
|
-
onchange_callback: Optional[
|
155
|
-
[Dict[
|
160
|
+
onchange_callback: Optional[
|
161
|
+
Callable[[Dict[utils.KeyPath, base.FieldUpdate]], None]
|
162
|
+
] = None,
|
156
163
|
allow_partial: bool = False,
|
157
164
|
accessor_writable: bool = True,
|
158
165
|
sealed: bool = False,
|
159
|
-
root_path: Optional[
|
166
|
+
root_path: Optional[utils.KeyPath] = None,
|
167
|
+
):
|
160
168
|
"""Constructor.
|
161
169
|
|
162
170
|
Args:
|
@@ -337,8 +345,8 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
337
345
|
return missing
|
338
346
|
|
339
347
|
def _sym_rebind(
|
340
|
-
self, path_value_pairs: typing.Dict[
|
341
|
-
|
348
|
+
self, path_value_pairs: typing.Dict[utils.KeyPath, Any]
|
349
|
+
) -> typing.List[base.FieldUpdate]:
|
342
350
|
"""Subclass specific rebind implementation."""
|
343
351
|
updates = []
|
344
352
|
|
@@ -378,14 +386,13 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
378
386
|
return self
|
379
387
|
|
380
388
|
def _update_children_paths(
|
381
|
-
self,
|
382
|
-
|
383
|
-
new_path: object_utils.KeyPath) -> None:
|
389
|
+
self, old_path: utils.KeyPath, new_path: utils.KeyPath
|
390
|
+
) -> None:
|
384
391
|
"""Update children paths according to root_path of current node."""
|
385
392
|
del old_path
|
386
393
|
for idx, item in self.sym_items():
|
387
394
|
if isinstance(item, base.TopologyAware):
|
388
|
-
item.sym_setpath(
|
395
|
+
item.sym_setpath(utils.KeyPath(idx, new_path))
|
389
396
|
|
390
397
|
def _set_item_without_permission_check( # pytype: disable=signature-mismatch # overriding-parameter-type-checks
|
391
398
|
self, key: int, value: Any) -> Optional[base.FieldUpdate]:
|
@@ -432,13 +439,15 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
432
439
|
value = base.from_json(
|
433
440
|
value,
|
434
441
|
allow_partial=allow_partial,
|
435
|
-
root_path=
|
442
|
+
root_path=utils.KeyPath(idx, self.sym_path),
|
443
|
+
)
|
436
444
|
if self._value_spec and flags.is_type_check_enabled():
|
437
445
|
value = self._value_spec.element.apply(
|
438
446
|
value,
|
439
447
|
allow_partial=allow_partial,
|
440
448
|
transform_fn=base.symbolic_transform_fn(self._allow_partial),
|
441
|
-
root_path=
|
449
|
+
root_path=utils.KeyPath(idx, self.sym_path),
|
450
|
+
)
|
442
451
|
return self._relocate_if_symbolic(idx, value)
|
443
452
|
|
444
453
|
@property
|
@@ -446,8 +455,7 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
446
455
|
"""Returns True if current list subscribes field updates."""
|
447
456
|
return self._onchange_callback is not None
|
448
457
|
|
449
|
-
def _on_change(self,
|
450
|
-
field_updates: Dict[object_utils.KeyPath, base.FieldUpdate]):
|
458
|
+
def _on_change(self, field_updates: Dict[utils.KeyPath, base.FieldUpdate]):
|
451
459
|
"""On change event of List."""
|
452
460
|
# Do nothing for now to handle changes of List.
|
453
461
|
|
@@ -463,7 +471,7 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
463
471
|
# Update paths for children.
|
464
472
|
for idx, item in self.sym_items():
|
465
473
|
if isinstance(item, base.TopologyAware) and item.sym_path.key != idx:
|
466
|
-
item.sym_setpath(
|
474
|
+
item.sym_setpath(utils.KeyPath(idx, self.sym_path))
|
467
475
|
|
468
476
|
if self._onchange_callback is not None:
|
469
477
|
self._onchange_callback(field_updates)
|
@@ -723,11 +731,12 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
723
731
|
|
724
732
|
def custom_apply(
|
725
733
|
self,
|
726
|
-
path:
|
734
|
+
path: utils.KeyPath,
|
727
735
|
value_spec: pg_typing.ValueSpec,
|
728
736
|
allow_partial: bool,
|
729
737
|
child_transform: Optional[
|
730
|
-
Callable[[
|
738
|
+
Callable[[utils.KeyPath, pg_typing.Field, Any], Any]
|
739
|
+
] = None,
|
731
740
|
) -> Tuple[bool, 'List']:
|
732
741
|
"""Implement pg.typing.CustomTyping interface.
|
733
742
|
|
@@ -746,9 +755,12 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
746
755
|
if self._value_spec:
|
747
756
|
if value_spec and not value_spec.is_compatible(self._value_spec):
|
748
757
|
raise ValueError(
|
749
|
-
|
758
|
+
utils.message_on_path(
|
750
759
|
f'List (spec={self._value_spec!r}) cannot be assigned to an '
|
751
|
-
f'incompatible field (spec={value_spec!r}).',
|
760
|
+
f'incompatible field (spec={value_spec!r}).',
|
761
|
+
path,
|
762
|
+
)
|
763
|
+
)
|
752
764
|
if self._allow_partial == allow_partial:
|
753
765
|
proceed_with_standard_apply = False
|
754
766
|
else:
|
@@ -758,9 +770,8 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
758
770
|
return (proceed_with_standard_apply, self)
|
759
771
|
|
760
772
|
def sym_jsonify(
|
761
|
-
self,
|
762
|
-
|
763
|
-
**kwargs) -> object_utils.JSONValueType:
|
773
|
+
self, use_inferred: bool = False, **kwargs
|
774
|
+
) -> utils.JSONValueType:
|
764
775
|
"""Converts current list to a list of plain Python objects."""
|
765
776
|
def json_item(idx):
|
766
777
|
v = self.sym_getattr(idx)
|
@@ -778,7 +789,7 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
778
789
|
python_format: bool = False,
|
779
790
|
use_inferred: bool = False,
|
780
791
|
cls_name: Optional[str] = None,
|
781
|
-
bracket_type:
|
792
|
+
bracket_type: utils.BracketType = utils.BracketType.SQUARE,
|
782
793
|
**kwargs,
|
783
794
|
) -> str:
|
784
795
|
"""Formats this List."""
|
@@ -787,16 +798,22 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
787
798
|
return ' ' * 2 * indent + text
|
788
799
|
|
789
800
|
cls_name = cls_name or ''
|
790
|
-
open_bracket, close_bracket =
|
801
|
+
open_bracket, close_bracket = utils.bracket_chars(bracket_type)
|
791
802
|
s = [f'{cls_name}{open_bracket}']
|
792
803
|
if compact:
|
793
804
|
kv_strs = []
|
794
805
|
for idx, elem in self.sym_items():
|
795
806
|
if use_inferred and isinstance(elem, base.Inferential):
|
796
807
|
elem = self.sym_inferred(idx, default=elem)
|
797
|
-
v_str =
|
798
|
-
elem,
|
799
|
-
|
808
|
+
v_str = utils.format(
|
809
|
+
elem,
|
810
|
+
compact,
|
811
|
+
verbose,
|
812
|
+
root_indent + 1,
|
813
|
+
python_format=python_format,
|
814
|
+
use_inferred=use_inferred,
|
815
|
+
**kwargs,
|
816
|
+
)
|
800
817
|
if python_format:
|
801
818
|
kv_strs.append(v_str)
|
802
819
|
else:
|
@@ -812,9 +829,15 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
|
|
812
829
|
s.append('\n')
|
813
830
|
else:
|
814
831
|
s.append(',\n')
|
815
|
-
v_str =
|
816
|
-
elem,
|
817
|
-
|
832
|
+
v_str = utils.format(
|
833
|
+
elem,
|
834
|
+
compact,
|
835
|
+
verbose,
|
836
|
+
root_indent + 1,
|
837
|
+
python_format=python_format,
|
838
|
+
use_inferred=use_inferred,
|
839
|
+
**kwargs,
|
840
|
+
)
|
818
841
|
if python_format:
|
819
842
|
s.append(_indent(v_str, root_indent + 1))
|
820
843
|
else:
|
@@ -20,8 +20,8 @@ import pickle
|
|
20
20
|
from typing import Any
|
21
21
|
import unittest
|
22
22
|
|
23
|
-
from pyglove.core import object_utils
|
24
23
|
from pyglove.core import typing as pg_typing
|
24
|
+
from pyglove.core import utils
|
25
25
|
from pyglove.core.symbolic import base
|
26
26
|
from pyglove.core.symbolic import flags
|
27
27
|
from pyglove.core.symbolic import inferred
|
@@ -34,7 +34,7 @@ from pyglove.core.symbolic.pure_symbolic import NonDeterministic
|
|
34
34
|
from pyglove.core.symbolic.pure_symbolic import PureSymbolic
|
35
35
|
|
36
36
|
|
37
|
-
MISSING_VALUE =
|
37
|
+
MISSING_VALUE = utils.MISSING_VALUE
|
38
38
|
|
39
39
|
|
40
40
|
class ListTest(unittest.TestCase):
|
@@ -685,7 +685,7 @@ class ListTest(unittest.TestCase):
|
|
685
685
|
self.assertTrue(sl.sym_has('[0].x'))
|
686
686
|
self.assertTrue(sl.sym_has('[0].x[0]'))
|
687
687
|
self.assertTrue(sl.sym_has('[0].x[0].y'))
|
688
|
-
self.assertTrue(sl.sym_has(
|
688
|
+
self.assertTrue(sl.sym_has(utils.KeyPath.parse('[0].x[0].y')))
|
689
689
|
|
690
690
|
def test_sym_get(self):
|
691
691
|
sl = List([dict(x=[dict(y=1)])])
|
@@ -1100,7 +1100,7 @@ class ListTest(unittest.TestCase):
|
|
1100
1100
|
self.assertEqual(sl[1].sym_path, '[1]')
|
1101
1101
|
self.assertEqual(sl[1][0].b.sym_path, '[1][0].b')
|
1102
1102
|
|
1103
|
-
sl.sym_setpath(
|
1103
|
+
sl.sym_setpath(utils.KeyPath('a'))
|
1104
1104
|
self.assertEqual(sl.sym_path, 'a')
|
1105
1105
|
self.assertEqual(sl[0].sym_path, 'a[0]')
|
1106
1106
|
self.assertEqual(sl[0].a.sym_path, 'a[0].a')
|
@@ -1412,96 +1412,112 @@ class RebindTest(unittest.TestCase):
|
|
1412
1412
|
'[3]': 'foo', # Unchanged.
|
1413
1413
|
'[4]': Insertion('bar')
|
1414
1414
|
})
|
1415
|
-
self.assertEqual(
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1504
|
-
|
1415
|
+
self.assertEqual(
|
1416
|
+
updates,
|
1417
|
+
[
|
1418
|
+
{ # Notification to `sl[2][0]`.
|
1419
|
+
'p': base.FieldUpdate(
|
1420
|
+
utils.KeyPath.parse('[2][0].p'),
|
1421
|
+
target=sl[2][0],
|
1422
|
+
field=None,
|
1423
|
+
old_value=1,
|
1424
|
+
new_value=MISSING_VALUE,
|
1425
|
+
),
|
1426
|
+
'q': base.FieldUpdate(
|
1427
|
+
utils.KeyPath.parse('[2][0].q'),
|
1428
|
+
target=sl[2][0],
|
1429
|
+
field=None,
|
1430
|
+
old_value=MISSING_VALUE,
|
1431
|
+
new_value=2,
|
1432
|
+
),
|
1433
|
+
},
|
1434
|
+
{ # Notification to `sl.c`.
|
1435
|
+
'[0].p': base.FieldUpdate(
|
1436
|
+
utils.KeyPath.parse('[2][0].p'),
|
1437
|
+
target=sl[2][0],
|
1438
|
+
field=None,
|
1439
|
+
old_value=1,
|
1440
|
+
new_value=MISSING_VALUE,
|
1441
|
+
),
|
1442
|
+
'[0].q': base.FieldUpdate(
|
1443
|
+
utils.KeyPath.parse('[2][0].q'),
|
1444
|
+
target=sl[2][0],
|
1445
|
+
field=None,
|
1446
|
+
old_value=MISSING_VALUE,
|
1447
|
+
new_value=2,
|
1448
|
+
),
|
1449
|
+
},
|
1450
|
+
{ # Notification to `sl[1].y`.
|
1451
|
+
'z': base.FieldUpdate(
|
1452
|
+
utils.KeyPath.parse('[1].y.z'),
|
1453
|
+
target=sl[1].y,
|
1454
|
+
field=None,
|
1455
|
+
old_value=MISSING_VALUE,
|
1456
|
+
new_value=1,
|
1457
|
+
),
|
1458
|
+
},
|
1459
|
+
{ # Notification to `sl.b`.
|
1460
|
+
'x': base.FieldUpdate(
|
1461
|
+
utils.KeyPath.parse('[1].x'),
|
1462
|
+
target=sl[1],
|
1463
|
+
field=None,
|
1464
|
+
old_value=1,
|
1465
|
+
new_value=2,
|
1466
|
+
),
|
1467
|
+
'y.z': base.FieldUpdate(
|
1468
|
+
utils.KeyPath.parse('[1].y.z'),
|
1469
|
+
target=sl[1].y,
|
1470
|
+
field=None,
|
1471
|
+
old_value=MISSING_VALUE,
|
1472
|
+
new_value=1,
|
1473
|
+
),
|
1474
|
+
},
|
1475
|
+
{ # Notification to `sl`.
|
1476
|
+
'[0]': base.FieldUpdate(
|
1477
|
+
utils.KeyPath.parse('[0]'),
|
1478
|
+
target=sl,
|
1479
|
+
field=None,
|
1480
|
+
old_value=1,
|
1481
|
+
new_value=2,
|
1482
|
+
),
|
1483
|
+
'[1].x': base.FieldUpdate(
|
1484
|
+
utils.KeyPath.parse('[1].x'),
|
1485
|
+
target=sl[1],
|
1486
|
+
field=None,
|
1487
|
+
old_value=1,
|
1488
|
+
new_value=2,
|
1489
|
+
),
|
1490
|
+
'[1].y.z': base.FieldUpdate(
|
1491
|
+
utils.KeyPath.parse('[1].y.z'),
|
1492
|
+
target=sl[1].y,
|
1493
|
+
field=None,
|
1494
|
+
old_value=MISSING_VALUE,
|
1495
|
+
new_value=1,
|
1496
|
+
),
|
1497
|
+
'[2][0].p': base.FieldUpdate(
|
1498
|
+
utils.KeyPath.parse('[2][0].p'),
|
1499
|
+
target=sl[2][0],
|
1500
|
+
field=None,
|
1501
|
+
old_value=1,
|
1502
|
+
new_value=MISSING_VALUE,
|
1503
|
+
),
|
1504
|
+
'[2][0].q': base.FieldUpdate(
|
1505
|
+
utils.KeyPath.parse('[2][0].q'),
|
1506
|
+
target=sl[2][0],
|
1507
|
+
field=None,
|
1508
|
+
old_value=MISSING_VALUE,
|
1509
|
+
new_value=2,
|
1510
|
+
),
|
1511
|
+
'[4]': base.FieldUpdate(
|
1512
|
+
utils.KeyPath.parse('[4]'),
|
1513
|
+
target=sl,
|
1514
|
+
field=None,
|
1515
|
+
old_value=MISSING_VALUE,
|
1516
|
+
new_value='bar',
|
1517
|
+
),
|
1518
|
+
},
|
1519
|
+
],
|
1520
|
+
)
|
1505
1521
|
|
1506
1522
|
def test_rebind_with_fn(self):
|
1507
1523
|
sl = List([0, dict(x=1, y='foo', z=[2, 3, 4])])
|
@@ -1716,7 +1732,7 @@ class FormatTest(unittest.TestCase):
|
|
1716
1732
|
|
1717
1733
|
def test_compact_python_format(self):
|
1718
1734
|
self.assertEqual(
|
1719
|
-
|
1735
|
+
utils.format(
|
1720
1736
|
self._list, compact=True, python_format=True, markdown=True
|
1721
1737
|
),
|
1722
1738
|
"`[{'a1': 1, 'a2': {'b1': {'c1': [{'d1': MISSING_VALUE, "
|
@@ -1726,9 +1742,12 @@ class FormatTest(unittest.TestCase):
|
|
1726
1742
|
|
1727
1743
|
def test_noncompact_python_format(self):
|
1728
1744
|
self.assertEqual(
|
1729
|
-
|
1730
|
-
self._list,
|
1731
|
-
|
1745
|
+
utils.format(
|
1746
|
+
self._list,
|
1747
|
+
compact=False,
|
1748
|
+
verbose=False,
|
1749
|
+
python_format=True,
|
1750
|
+
markdown=True,
|
1732
1751
|
),
|
1733
1752
|
inspect.cleandoc("""
|
1734
1753
|
```
|