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
@@ -11,16 +11,14 @@
|
|
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.Dict."""
|
15
|
-
|
16
14
|
import copy
|
17
15
|
import inspect
|
18
16
|
import io
|
19
17
|
import pickle
|
20
18
|
import unittest
|
21
19
|
|
22
|
-
from pyglove.core import object_utils
|
23
20
|
from pyglove.core import typing as pg_typing
|
21
|
+
from pyglove.core import utils
|
24
22
|
from pyglove.core.symbolic import base
|
25
23
|
from pyglove.core.symbolic import flags
|
26
24
|
from pyglove.core.symbolic import inferred
|
@@ -31,7 +29,7 @@ from pyglove.core.symbolic.pure_symbolic import NonDeterministic
|
|
31
29
|
from pyglove.core.symbolic.pure_symbolic import PureSymbolic
|
32
30
|
|
33
31
|
|
34
|
-
MISSING_VALUE =
|
32
|
+
MISSING_VALUE = utils.MISSING_VALUE
|
35
33
|
|
36
34
|
|
37
35
|
class DictTest(unittest.TestCase):
|
@@ -44,14 +42,14 @@ class DictTest(unittest.TestCase):
|
|
44
42
|
self.assertEqual(len(sd), 0)
|
45
43
|
|
46
44
|
# Schemaless dict created from a regular dict.
|
47
|
-
sd = Dict({'a': 1})
|
45
|
+
sd = Dict({'a': 1, 1: 1})
|
48
46
|
self.assertIsNone(sd.value_spec)
|
49
|
-
self.assertEqual(sd,
|
47
|
+
self.assertEqual(sd, {'a': 1, 1: 1})
|
50
48
|
|
51
49
|
# Schemaless dict created from key value pairs.
|
52
|
-
sd = Dict((('a', 1),))
|
50
|
+
sd = Dict((('a', 1), (1, 1)))
|
53
51
|
self.assertIsNone(sd.value_spec)
|
54
|
-
self.assertEqual(sd,
|
52
|
+
self.assertEqual(sd, {'a': 1, 1: 1})
|
55
53
|
|
56
54
|
# Schemaless dict created from keyword args.
|
57
55
|
sd = Dict(a=1)
|
@@ -59,9 +57,9 @@ class DictTest(unittest.TestCase):
|
|
59
57
|
self.assertEqual(sd, dict(a=1))
|
60
58
|
|
61
59
|
# Schemaless dict created from both a regular dict and keyword args.
|
62
|
-
sd = Dict({'a': 1}, a=2)
|
60
|
+
sd = Dict({'a': 1, 1: 1}, a=2)
|
63
61
|
self.assertIsNone(sd.value_spec)
|
64
|
-
self.assertEqual(sd,
|
62
|
+
self.assertEqual(sd, {'a': 2, 1: 1})
|
65
63
|
|
66
64
|
# Schematized dict.
|
67
65
|
vs = pg_typing.Dict([('a', pg_typing.Int())])
|
@@ -305,8 +303,8 @@ class DictTest(unittest.TestCase):
|
|
305
303
|
with self.assertRaisesRegex(
|
306
304
|
base.WritePermissionError, 'Cannot modify field of a sealed Dict.'):
|
307
305
|
sd['b'] = 1
|
308
|
-
with self.assertRaisesRegex(KeyError, 'Key must be string type'):
|
309
|
-
sd[0] = 1
|
306
|
+
with self.assertRaisesRegex(KeyError, 'Key must be string or int type'):
|
307
|
+
sd[0.5] = 1
|
310
308
|
|
311
309
|
# Set item in a schematized dict.
|
312
310
|
sd = Dict(value_spec=pg_typing.Dict([('a', pg_typing.Int(default=0))]))
|
@@ -786,35 +784,45 @@ class DictTest(unittest.TestCase):
|
|
786
784
|
sd.missing_values(flatten=False), {'a': MISSING_VALUE})
|
787
785
|
|
788
786
|
# A non-schematized dict has a schematized child.
|
789
|
-
sd = Dict(x
|
787
|
+
sd = Dict({'x': sd, 1: sd})
|
790
788
|
self.assertIsNone(sd.value_spec)
|
791
|
-
self.assertEqual(
|
789
|
+
self.assertEqual(
|
790
|
+
sd.missing_values(), {'x.a': MISSING_VALUE, '[1].a': MISSING_VALUE}
|
791
|
+
)
|
792
792
|
|
793
793
|
def test_sym_has(self):
|
794
|
-
sd = Dict(x
|
794
|
+
sd = Dict({'x': 1, 1: dict(a=3), 'y': Dict({'z': 2, 2: 3})})
|
795
795
|
self.assertTrue(sd.sym_has('x'))
|
796
|
+
self.assertTrue(sd.sym_has(1))
|
796
797
|
self.assertTrue(sd.sym_has('y.z'))
|
797
|
-
self.assertTrue(sd.sym_has(
|
798
|
+
self.assertTrue(sd.sym_has('[1].a'))
|
799
|
+
self.assertTrue(sd.sym_has('y[2]'))
|
800
|
+
self.assertTrue(sd.sym_has(utils.KeyPath.parse('y.z')))
|
798
801
|
self.assertFalse(sd.sym_has('x.z'))
|
799
802
|
|
800
803
|
def test_sym_get(self):
|
801
|
-
sd = Dict(x
|
804
|
+
sd = Dict({'x': 1, 1: dict(a=3), 'y': Dict({'z': 2, 2: 3})})
|
802
805
|
self.assertEqual(sd.sym_get('x'), 1)
|
806
|
+
self.assertEqual(sd.sym_get(1), dict(a=3))
|
803
807
|
self.assertEqual(sd.sym_get('y.z'), 2)
|
808
|
+
self.assertEqual(sd.sym_get('[1].a'), 3)
|
809
|
+
self.assertEqual(sd.sym_get('y[2]'), 3)
|
804
810
|
self.assertIsNone(sd.sym_get('x.z', None))
|
805
811
|
with self.assertRaisesRegex(
|
806
812
|
KeyError, 'Cannot query sub-key \'z\' of object.'):
|
807
813
|
sd.sym_get('x.z')
|
808
814
|
|
809
815
|
def test_sym_hasattr(self):
|
810
|
-
sd = Dict(x
|
816
|
+
sd = Dict({'x': 1, 1: dict(a=3), 'y': Dict({'z': 2, 2: 3})})
|
811
817
|
self.assertTrue(sd.sym_hasattr('x'))
|
818
|
+
self.assertTrue(sd.sym_hasattr(1))
|
812
819
|
self.assertFalse(sd.sym_hasattr('y.z'))
|
813
820
|
self.assertFalse(sd.sym_hasattr('a'))
|
814
821
|
|
815
822
|
def test_sym_getattr(self):
|
816
|
-
sd = Dict(x
|
823
|
+
sd = Dict({'x': 1, 1: dict(a=3), 'y': Dict({'z': 2, 2: 3})})
|
817
824
|
self.assertEqual(sd.sym_getattr('x'), 1)
|
825
|
+
self.assertEqual(sd.sym_getattr(1), dict(a=3))
|
818
826
|
self.assertIsNone(sd.sym_getattr('a', None))
|
819
827
|
with self.assertRaisesRegex(
|
820
828
|
AttributeError,
|
@@ -832,8 +840,9 @@ class DictTest(unittest.TestCase):
|
|
832
840
|
with self.assertRaisesRegex(AttributeError, 'z'):
|
833
841
|
_ = sd.sym_inferred('z')
|
834
842
|
|
835
|
-
sd = Dict(y=1, x=
|
843
|
+
sd = Dict(y=1, x={'x': Dict(y=inferred.ValueFromParentChain()), 1: 2})
|
836
844
|
self.assertEqual(sd.x.x.y, 1)
|
845
|
+
self.assertEqual(sd.x[1], 2)
|
837
846
|
|
838
847
|
def test_sym_field(self):
|
839
848
|
sd = Dict(x=1, y=Dict(z=2))
|
@@ -859,9 +868,9 @@ class DictTest(unittest.TestCase):
|
|
859
868
|
self.assertIs(sd.sym_attr_field('x'), spec.schema.get_field('x'))
|
860
869
|
|
861
870
|
def test_sym_keys(self):
|
862
|
-
sd = Dict(x
|
871
|
+
sd = Dict({'x': 1, 'y': 2, 1: 3})
|
863
872
|
self.assertEqual(next(sd.sym_keys()), 'x')
|
864
|
-
self.assertEqual(list(sd.sym_keys()), ['x', 'y'])
|
873
|
+
self.assertEqual(list(sd.sym_keys()), ['x', 'y', 1])
|
865
874
|
|
866
875
|
sd = Dict(x=1, z=3, y=2, value_spec=pg_typing.Dict([
|
867
876
|
(pg_typing.StrKey(), pg_typing.Int())
|
@@ -874,9 +883,9 @@ class DictTest(unittest.TestCase):
|
|
874
883
|
self.assertEqual(list(sd.sym_keys()), ['x', 'y'])
|
875
884
|
|
876
885
|
def test_sym_values(self):
|
877
|
-
sd = Dict(x
|
886
|
+
sd = Dict({'x': 1, 'y': 2, 1: 3})
|
878
887
|
self.assertEqual(next(sd.sym_values()), 1)
|
879
|
-
self.assertEqual(list(sd.sym_values()), [1, 2])
|
888
|
+
self.assertEqual(list(sd.sym_values()), [1, 2, 3])
|
880
889
|
|
881
890
|
sd = Dict(x=1, z=3, y=2, value_spec=pg_typing.Dict([
|
882
891
|
(pg_typing.StrKey(), pg_typing.Int())
|
@@ -891,9 +900,9 @@ class DictTest(unittest.TestCase):
|
|
891
900
|
)
|
892
901
|
|
893
902
|
def test_sym_items(self):
|
894
|
-
sd = Dict(x
|
903
|
+
sd = Dict({'x': 1, 'y': 2, 1: 3})
|
895
904
|
self.assertEqual(next(sd.sym_items()), ('x', 1))
|
896
|
-
self.assertEqual(list(sd.sym_items()), [('x', 1), ('y', 2)])
|
905
|
+
self.assertEqual(list(sd.sym_items()), [('x', 1), ('y', 2), (1, 3)])
|
897
906
|
|
898
907
|
sd = Dict(x=1, z=3, y=2, value_spec=pg_typing.Dict([
|
899
908
|
(pg_typing.StrKey(), pg_typing.Int())
|
@@ -917,9 +926,9 @@ class DictTest(unittest.TestCase):
|
|
917
926
|
|
918
927
|
def test_sym_rebind(self):
|
919
928
|
# Refer to RebindTest for more detailed tests.
|
920
|
-
sd = Dict(x
|
921
|
-
sd.sym_rebind(x=2)
|
922
|
-
self.assertEqual(sd,
|
929
|
+
sd = Dict({'x': 1, 'y': 2, 1: 3})
|
930
|
+
sd.sym_rebind({1: 4}, x=2)
|
931
|
+
self.assertEqual(sd, {'x': 2, 'y': 2, 1: 4})
|
923
932
|
|
924
933
|
def test_sym_clone(self):
|
925
934
|
class A:
|
@@ -997,6 +1006,12 @@ class DictTest(unittest.TestCase):
|
|
997
1006
|
y: int = 1
|
998
1007
|
use_symbolic_comparison = True
|
999
1008
|
|
1009
|
+
sd = Dict({'x': A(2), 1: B(2)})
|
1010
|
+
self.assertEqual(sd.sym_nondefault(), {'x.x': 2, '[1].y': 2})
|
1011
|
+
|
1012
|
+
sd = Dict({'x': A(1), 1: B(1)})
|
1013
|
+
self.assertEqual(sd.sym_nondefault(), {'x.x': 1})
|
1014
|
+
|
1000
1015
|
sd = Dict(x=1, y=dict(a1=A(1)), value_spec=pg_typing.Dict([
|
1001
1016
|
('x', pg_typing.Int(default=0)),
|
1002
1017
|
('y', pg_typing.Dict([
|
@@ -1080,7 +1095,7 @@ class DictTest(unittest.TestCase):
|
|
1080
1095
|
self.assertTrue(Dict().sym_eq(Dict()))
|
1081
1096
|
self.assertTrue(base.eq(Dict(), Dict()))
|
1082
1097
|
|
1083
|
-
self.assertEqual(Dict(a
|
1098
|
+
self.assertEqual(Dict({'a': 1, 1: 2}), Dict({'a': 1, 1: 2}))
|
1084
1099
|
self.assertTrue(Dict(a=1).sym_eq(Dict(a=1)))
|
1085
1100
|
self.assertTrue(base.eq(Dict(a=1), Dict(a=1)))
|
1086
1101
|
self.assertTrue(
|
@@ -1130,6 +1145,8 @@ class DictTest(unittest.TestCase):
|
|
1130
1145
|
self.assertTrue(base.ne(Dict(), 1))
|
1131
1146
|
self.assertNotEqual(Dict(), Dict(a=1))
|
1132
1147
|
self.assertTrue(base.ne(Dict(), Dict(a=1)))
|
1148
|
+
self.assertNotEqual(Dict({1: 1}), Dict({'1': 1}))
|
1149
|
+
self.assertTrue(base.ne(Dict({1: 1}), Dict({'1': 1})))
|
1133
1150
|
self.assertNotEqual(Dict(a=0), Dict(a=1))
|
1134
1151
|
self.assertTrue(base.ne(Dict(a=0), Dict(a=1)))
|
1135
1152
|
|
@@ -1192,6 +1209,7 @@ class DictTest(unittest.TestCase):
|
|
1192
1209
|
self.assertEqual(hash(Dict(a=1)), hash(Dict(a=1)))
|
1193
1210
|
self.assertEqual(hash(Dict(a=dict(x=1))), hash(Dict(a=dict(x=1))))
|
1194
1211
|
self.assertNotEqual(hash(Dict()), hash(Dict(a=1)))
|
1212
|
+
self.assertNotEqual(hash(Dict({'1': 1})), hash(Dict({1: 1})))
|
1195
1213
|
self.assertNotEqual(hash(Dict(a=1)), hash(Dict(a=2)))
|
1196
1214
|
|
1197
1215
|
class A:
|
@@ -1247,7 +1265,7 @@ class DictTest(unittest.TestCase):
|
|
1247
1265
|
self.assertEqual(sd.x.a.sym_path, 'x.a')
|
1248
1266
|
self.assertEqual(sd.y[0].b.sym_path, 'y[0].b')
|
1249
1267
|
|
1250
|
-
sd.sym_setpath(
|
1268
|
+
sd.sym_setpath(utils.KeyPath('a'))
|
1251
1269
|
self.assertEqual(sd.sym_path, 'a')
|
1252
1270
|
self.assertEqual(sd.x.sym_path, 'a.x')
|
1253
1271
|
self.assertEqual(sd.x.a.sym_path, 'a.x.a')
|
@@ -1704,96 +1722,112 @@ class RebindTest(unittest.TestCase):
|
|
1704
1722
|
'd': 'foo', # Unchanged.
|
1705
1723
|
'e': 'bar'
|
1706
1724
|
})
|
1707
|
-
self.assertEqual(
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
1735
|
-
|
1736
|
-
|
1737
|
-
|
1738
|
-
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1725
|
+
self.assertEqual(
|
1726
|
+
updates,
|
1727
|
+
[
|
1728
|
+
{ # Notification to `sd.c[0]`.
|
1729
|
+
'p': base.FieldUpdate(
|
1730
|
+
utils.KeyPath.parse('c[0].p'),
|
1731
|
+
target=sd.c[0],
|
1732
|
+
field=None,
|
1733
|
+
old_value=1,
|
1734
|
+
new_value=MISSING_VALUE,
|
1735
|
+
),
|
1736
|
+
'q': base.FieldUpdate(
|
1737
|
+
utils.KeyPath.parse('c[0].q'),
|
1738
|
+
target=sd.c[0],
|
1739
|
+
field=None,
|
1740
|
+
old_value=MISSING_VALUE,
|
1741
|
+
new_value=2,
|
1742
|
+
),
|
1743
|
+
},
|
1744
|
+
{ # Notification to `sd.c`.
|
1745
|
+
'[0].p': base.FieldUpdate(
|
1746
|
+
utils.KeyPath.parse('c[0].p'),
|
1747
|
+
target=sd.c[0],
|
1748
|
+
field=None,
|
1749
|
+
old_value=1,
|
1750
|
+
new_value=MISSING_VALUE,
|
1751
|
+
),
|
1752
|
+
'[0].q': base.FieldUpdate(
|
1753
|
+
utils.KeyPath.parse('c[0].q'),
|
1754
|
+
target=sd.c[0],
|
1755
|
+
field=None,
|
1756
|
+
old_value=MISSING_VALUE,
|
1757
|
+
new_value=2,
|
1758
|
+
),
|
1759
|
+
},
|
1760
|
+
{ # Notification to `sd.b.y`.
|
1761
|
+
'z': base.FieldUpdate(
|
1762
|
+
utils.KeyPath.parse('b.y.z'),
|
1763
|
+
target=sd.b.y,
|
1764
|
+
field=None,
|
1765
|
+
old_value=MISSING_VALUE,
|
1766
|
+
new_value=1,
|
1767
|
+
),
|
1768
|
+
},
|
1769
|
+
{ # Notification to `sd.b`.
|
1770
|
+
'x': base.FieldUpdate(
|
1771
|
+
utils.KeyPath.parse('b.x'),
|
1772
|
+
target=sd.b,
|
1773
|
+
field=None,
|
1774
|
+
old_value=1,
|
1775
|
+
new_value=2,
|
1776
|
+
),
|
1777
|
+
'y.z': base.FieldUpdate(
|
1778
|
+
utils.KeyPath.parse('b.y.z'),
|
1779
|
+
target=sd.b.y,
|
1780
|
+
field=None,
|
1781
|
+
old_value=MISSING_VALUE,
|
1782
|
+
new_value=1,
|
1783
|
+
),
|
1784
|
+
},
|
1785
|
+
{ # Notification to `sd`.
|
1786
|
+
'a': base.FieldUpdate(
|
1787
|
+
utils.KeyPath.parse('a'),
|
1788
|
+
target=sd,
|
1789
|
+
field=None,
|
1790
|
+
old_value=1,
|
1791
|
+
new_value=2,
|
1792
|
+
),
|
1793
|
+
'b.x': base.FieldUpdate(
|
1794
|
+
utils.KeyPath.parse('b.x'),
|
1795
|
+
target=sd.b,
|
1796
|
+
field=None,
|
1797
|
+
old_value=1,
|
1798
|
+
new_value=2,
|
1799
|
+
),
|
1800
|
+
'b.y.z': base.FieldUpdate(
|
1801
|
+
utils.KeyPath.parse('b.y.z'),
|
1802
|
+
target=sd.b.y,
|
1803
|
+
field=None,
|
1804
|
+
old_value=MISSING_VALUE,
|
1805
|
+
new_value=1,
|
1806
|
+
),
|
1807
|
+
'c[0].p': base.FieldUpdate(
|
1808
|
+
utils.KeyPath.parse('c[0].p'),
|
1809
|
+
target=sd.c[0],
|
1810
|
+
field=None,
|
1811
|
+
old_value=1,
|
1812
|
+
new_value=MISSING_VALUE,
|
1813
|
+
),
|
1814
|
+
'c[0].q': base.FieldUpdate(
|
1815
|
+
utils.KeyPath.parse('c[0].q'),
|
1816
|
+
target=sd.c[0],
|
1817
|
+
field=None,
|
1818
|
+
old_value=MISSING_VALUE,
|
1819
|
+
new_value=2,
|
1820
|
+
),
|
1821
|
+
'e': base.FieldUpdate(
|
1822
|
+
utils.KeyPath.parse('e'),
|
1823
|
+
target=sd,
|
1824
|
+
field=None,
|
1825
|
+
old_value=MISSING_VALUE,
|
1826
|
+
new_value='bar',
|
1827
|
+
),
|
1828
|
+
},
|
1829
|
+
],
|
1830
|
+
)
|
1797
1831
|
|
1798
1832
|
def test_rebind_with_fn(self):
|
1799
1833
|
sd = Dict(a=1, b=dict(x=2, y='foo', z=[0, 1, 2]))
|
@@ -1845,10 +1879,6 @@ class RebindTest(unittest.TestCase):
|
|
1845
1879
|
ValueError, 'There are no values to rebind.'):
|
1846
1880
|
Dict().rebind({})
|
1847
1881
|
|
1848
|
-
with self.assertRaisesRegex(
|
1849
|
-
KeyError, 'Key must be string type. Encountered 1'):
|
1850
|
-
Dict().rebind({1: 1})
|
1851
|
-
|
1852
1882
|
with self.assertRaisesRegex(
|
1853
1883
|
ValueError, 'Required value is not specified.'):
|
1854
1884
|
Dict(a=1, value_spec=pg_typing.Dict([('a', pg_typing.Int())])).rebind({
|
@@ -1859,13 +1889,17 @@ class SerializationTest(unittest.TestCase):
|
|
1859
1889
|
"""Dedicated tests for `pg.Dict` serialization."""
|
1860
1890
|
|
1861
1891
|
def test_schemaless(self):
|
1862
|
-
sd = Dict()
|
1892
|
+
sd = Dict({1: 2})
|
1863
1893
|
sd.b = 0
|
1864
1894
|
sd.c = None
|
1865
1895
|
sd.a = 'foo'
|
1866
1896
|
|
1867
1897
|
# Key order is preserved.
|
1868
|
-
self.assertEqual(
|
1898
|
+
self.assertEqual(
|
1899
|
+
sd.to_json_str(),
|
1900
|
+
'{"n_:1": 2, "b": 0, "c": null, "a": "foo"}'
|
1901
|
+
)
|
1902
|
+
self.assertEqual(base.from_json_str(sd.to_json_str()), sd)
|
1869
1903
|
|
1870
1904
|
def test_schematized(self):
|
1871
1905
|
sd = Dict.partial(
|
@@ -1907,6 +1941,36 @@ class SerializationTest(unittest.TestCase):
|
|
1907
1941
|
self.assertEqual(sd.to_json_str(), '{"x": 1, "y": 2.0}')
|
1908
1942
|
self.assertEqual(base.from_json_str(sd.to_json_str(), value_spec=spec), sd)
|
1909
1943
|
|
1944
|
+
def test_hide_frozen(self):
|
1945
|
+
|
1946
|
+
class A(pg_object.Object):
|
1947
|
+
x: pg_typing.Int().freeze(1)
|
1948
|
+
|
1949
|
+
sd = Dict.partial(
|
1950
|
+
a=A(),
|
1951
|
+
value_spec=pg_typing.Dict([
|
1952
|
+
('a', pg_typing.Object(A)),
|
1953
|
+
('b', pg_typing.Bool(True).freeze()),
|
1954
|
+
]))
|
1955
|
+
self.assertEqual(
|
1956
|
+
sd.to_json(),
|
1957
|
+
{
|
1958
|
+
'a': {
|
1959
|
+
'_type': A.__type_name__
|
1960
|
+
},
|
1961
|
+
}
|
1962
|
+
)
|
1963
|
+
self.assertEqual(
|
1964
|
+
sd.to_json(hide_frozen=False),
|
1965
|
+
{
|
1966
|
+
'a': {
|
1967
|
+
'_type': A.__type_name__,
|
1968
|
+
'x': 1,
|
1969
|
+
},
|
1970
|
+
'b': True
|
1971
|
+
}
|
1972
|
+
)
|
1973
|
+
|
1910
1974
|
def test_hide_default_values(self):
|
1911
1975
|
|
1912
1976
|
class A(pg_object.Object):
|
@@ -2046,7 +2110,9 @@ class FormatTest(unittest.TestCase):
|
|
2046
2110
|
|
2047
2111
|
def test_compact_python_format(self):
|
2048
2112
|
self.assertEqual(
|
2049
|
-
|
2113
|
+
utils.format(
|
2114
|
+
self._dict, compact=True, python_format=True, markdown=True
|
2115
|
+
),
|
2050
2116
|
"`{'a1': 1, 'a2': {'b1': {'c1': [{'d1': MISSING_VALUE, "
|
2051
2117
|
"'d2': True, 'd3': A(x=2, y=MISSING_VALUE, z={'p': [None, True], "
|
2052
2118
|
"'q': 'foo', 't': 'foo'})}]}}}`",
|
@@ -2054,8 +2120,12 @@ class FormatTest(unittest.TestCase):
|
|
2054
2120
|
|
2055
2121
|
def test_noncompact_python_format(self):
|
2056
2122
|
self.assertEqual(
|
2057
|
-
|
2058
|
-
|
2123
|
+
utils.format(
|
2124
|
+
self._dict,
|
2125
|
+
compact=False,
|
2126
|
+
verbose=False,
|
2127
|
+
python_format=True,
|
2128
|
+
markdown=True,
|
2059
2129
|
),
|
2060
2130
|
inspect.cleandoc("""
|
2061
2131
|
```
|
@@ -2155,6 +2225,7 @@ class FormatTest(unittest.TestCase):
|
|
2155
2225
|
}"""))
|
2156
2226
|
|
2157
2227
|
def test_noncompact_verbose_with_extra_blankline_for_field_docstr(self):
|
2228
|
+
self.maxDiff = None
|
2158
2229
|
self.assertEqual(
|
2159
2230
|
self._dict.format(
|
2160
2231
|
compact=False, verbose=True, extra_blankline_for_field_docstr=True),
|
@@ -2255,6 +2326,43 @@ class FormatTest(unittest.TestCase):
|
|
2255
2326
|
"""),
|
2256
2327
|
)
|
2257
2328
|
|
2329
|
+
def test_hide_frozen(self):
|
2330
|
+
d = Dict(x=1, value_spec=pg_typing.Dict([
|
2331
|
+
('x', pg_typing.Int()),
|
2332
|
+
('y', pg_typing.Bool(True).freeze()),
|
2333
|
+
('z', pg_typing.Dict([
|
2334
|
+
('v', pg_typing.Int(1)),
|
2335
|
+
('w', pg_typing.Bool().freeze(True)),
|
2336
|
+
]))
|
2337
|
+
]))
|
2338
|
+
self.assertEqual(
|
2339
|
+
d.format(compact=True),
|
2340
|
+
'{x=1, z={v=1}}'
|
2341
|
+
)
|
2342
|
+
self.assertEqual(
|
2343
|
+
d.format(compact=False, hide_frozen=False),
|
2344
|
+
'{\n x = 1,\n y = True,\n z = {\n v = 1,\n w = True\n }\n}'
|
2345
|
+
)
|
2346
|
+
|
2347
|
+
def test_compact_int_key(self):
|
2348
|
+
d = Dict({1: 1, '1': 2})
|
2349
|
+
self.assertEqual(d.format(compact=True), '{[1]=1, 1=2}')
|
2350
|
+
self.assertEqual(
|
2351
|
+
d.format(compact=True, python_format=True),
|
2352
|
+
'{1: 1, \'1\': 2}'
|
2353
|
+
)
|
2354
|
+
|
2355
|
+
def test_non_compact_int_key(self):
|
2356
|
+
d = Dict({1: 1, '1': 2})
|
2357
|
+
self.assertEqual(
|
2358
|
+
d.format(compact=False, verbose=False),
|
2359
|
+
'{\n [1] = 1,\n 1 = 2\n}'
|
2360
|
+
)
|
2361
|
+
self.assertEqual(
|
2362
|
+
d.format(compact=False, python_format=True),
|
2363
|
+
'{\n 1: 1,\n \'1\': 2\n}'
|
2364
|
+
)
|
2365
|
+
|
2258
2366
|
|
2259
2367
|
def _on_change_callback(updates):
|
2260
2368
|
del updates
|