pyglove 0.5.0.dev202510230131__py3-none-any.whl → 0.5.0.dev202511300809__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.
@@ -685,7 +685,7 @@ def from_json(
685
685
  *,
686
686
  context: Optional[JSONConversionContext] = None,
687
687
  auto_import: bool = True,
688
- auto_dict: bool = False,
688
+ convert_unknown: bool = False,
689
689
  **kwargs
690
690
  ) -> Any:
691
691
  """Deserializes a (maybe) JSONConvertible value from JSON value.
@@ -697,8 +697,13 @@ def from_json(
697
697
  identify its parent module and automatically import it. For example,
698
698
  if the type is 'foo.bar.A', PyGlove will try to import 'foo.bar' and
699
699
  find the class 'A' within the imported module.
700
- auto_dict: If True, dict with '_type' that cannot be loaded will remain
701
- as dict, with '_type' renamed to 'type_name'.
700
+ convert_unknown: If True, when a '_type' is not registered and cannot
701
+ be imported, PyGlove will create objects of:
702
+ - `pg.symbolic.UnknownType` for unknown types;
703
+ - `pg.symbolic.UnknownTypedObject` for objects of unknown types;
704
+ - `pg.symbolic.UnknownFunction` for unknown functions;
705
+ - `pg.symbolic.UnknownMethod` for unknown methods.
706
+ If False, TypeError will be raised.
702
707
  **kwargs: Keyword arguments that will be passed to JSONConvertible.__init__.
703
708
 
704
709
  Returns:
@@ -707,14 +712,21 @@ def from_json(
707
712
  if context is None:
708
713
  if (isinstance(json_value, dict)
709
714
  and (context_node := json_value.get(JSONConvertible.CONTEXT_KEY))):
710
- context = JSONConversionContext.from_json(context_node, **kwargs)
715
+ context = JSONConversionContext.from_json(
716
+ context_node,
717
+ auto_import=auto_import,
718
+ convert_unknown=convert_unknown,
719
+ **kwargs
720
+ )
711
721
  json_value = json_value[JSONConvertible.ROOT_VALUE_KEY]
712
722
  else:
713
723
  context = JSONConversionContext()
714
724
 
715
725
  typename_resolved = kwargs.pop('_typename_resolved', False)
716
726
  if not typename_resolved:
717
- json_value = resolve_typenames(json_value, auto_import, auto_dict)
727
+ json_value = resolve_typenames(
728
+ json_value, auto_import=auto_import, convert_unknown=convert_unknown
729
+ )
718
730
 
719
731
  def child_from(v):
720
732
  return from_json(v, context=context, _typename_resolved=True, **kwargs)
@@ -743,7 +755,7 @@ def from_json(
743
755
  def resolve_typenames(
744
756
  json_value: JSONValueType,
745
757
  auto_import: bool = True,
746
- auto_dict: bool = False,
758
+ convert_unknown: bool = False,
747
759
  ) -> JSONValueType:
748
760
  """Inplace resolves the "_type" keys with their factories in a JSON tree."""
749
761
 
@@ -755,11 +767,11 @@ def resolve_typenames(
755
767
  return False
756
768
  type_name = v[JSONConvertible.TYPE_NAME_KEY]
757
769
  if type_name == 'type':
758
- factory_fn = _type_from_json
770
+ factory_fn = _type_from_json(convert_unknown)
759
771
  elif type_name == 'function':
760
- factory_fn = _function_from_json
772
+ factory_fn = _function_from_json(convert_unknown)
761
773
  elif type_name == 'method':
762
- factory_fn = _method_from_json
774
+ factory_fn = _method_from_json(convert_unknown)
763
775
  else:
764
776
  cls = JSONConvertible.class_from_typename(type_name)
765
777
  if cls is None:
@@ -768,32 +780,38 @@ def resolve_typenames(
768
780
  cls = _load_symbol(type_name)
769
781
  assert inspect.isclass(cls), cls
770
782
  except (ModuleNotFoundError, AttributeError) as e:
771
- if not auto_dict:
783
+ if not convert_unknown:
772
784
  raise TypeError(
773
785
  f'Cannot load class {type_name!r}.\n'
774
- 'Try pass `auto_dict=True` to load the object into a dict '
775
- 'without depending on the type.'
786
+ 'Try pass `convert_unknown=True` to load the object into '
787
+ '`pg.symbolic.UnknownObject` without depending on the type.'
776
788
  ) from e
777
- elif not auto_dict:
789
+ elif not convert_unknown:
778
790
  raise TypeError(
779
791
  f'Type name \'{type_name}\' is not registered '
780
792
  'with a `pg.JSONConvertible` subclass.\n'
781
- 'Try pass `auto_import=True` to load the type from its module, '
782
- 'or pass `auto_dict=True` to load the object into a dict '
783
- 'without depending on the type.'
793
+ 'Try pass `auto_import=True` to load the type from its module.'
784
794
  )
785
795
 
786
796
  factory_fn = getattr(cls, 'from_json', None)
787
- if cls is not None and factory_fn is None and not auto_dict:
797
+ if cls is not None and factory_fn is None and not convert_unknown:
788
798
  raise TypeError(
789
799
  f'{cls} is not a `pg.JSONConvertible` subclass.'
790
- 'Try pass `auto_dict=True` to load the object into a dict '
791
- 'without depending on the type.'
800
+ 'Try pass `convert_unknown=True` to load the object into a '
801
+ '`pg.symbolic.UnknownObject` without depending on the type.'
792
802
  )
793
803
 
794
- if factory_fn is None and auto_dict:
795
- v['type_name'] = type_name
796
- v.pop(JSONConvertible.TYPE_NAME_KEY)
804
+ if factory_fn is None and convert_unknown:
805
+ type_name = v[JSONConvertible.TYPE_NAME_KEY]
806
+ def _factory_fn(json_value: Dict[str, Any], **kwargs):
807
+ del kwargs
808
+ # See `pg.symbolic.UnknownObject` for details.
809
+ unknown_object_cls = JSONConvertible.class_from_typename(
810
+ 'unknown_object'
811
+ )
812
+ return unknown_object_cls(type_name=type_name, **json_value) # pytype: disable=wrong-keyword-args
813
+
814
+ v[JSONConvertible.TYPE_NAME_KEY] = _factory_fn
797
815
  return True
798
816
  assert factory_fn is not None
799
817
 
@@ -992,39 +1010,79 @@ def _load_symbol(type_name: str) -> Any:
992
1010
  return symbol
993
1011
 
994
1012
 
995
- def _type_from_json(json_value: Dict[str, str], **kwargs) -> Type[Any]:
1013
+ def _type_from_json(convert_unknown: bool) -> Callable[..., Any]:
996
1014
  """Loads a type from a JSON dict."""
997
- del kwargs
998
- t = _load_symbol(json_value['name'])
999
- if 'args' in json_value:
1000
- return _bind_type_args(
1001
- t, from_json(json_value['args'], _typename_resolved=True)
1002
- )
1003
- return t
1015
+ def _fn(json_value: Dict[str, str], **kwargs) -> Type[Any]:
1016
+ del kwargs
1017
+ try:
1018
+ t = _load_symbol(json_value['name'])
1019
+ if 'args' in json_value:
1020
+ return _bind_type_args(
1021
+ t, from_json(json_value['args'], _typename_resolved=True)
1022
+ )
1023
+ return t
1024
+ except (ModuleNotFoundError, AttributeError) as e:
1025
+ if not convert_unknown:
1026
+ raise TypeError(
1027
+ f'Cannot load type {json_value["name"]!r}.\n'
1028
+ 'Try pass `convert_unknown=True` to load the object '
1029
+ 'into `pg.UnknownType` without depending on the type.'
1030
+ ) from e
1031
+ # See `pg.symbolic.UnknownType` for details.
1032
+ json_value[JSONConvertible.TYPE_NAME_KEY] = 'unknown_type'
1033
+ return from_json(json_value)
1034
+ return _fn
1004
1035
 
1005
1036
 
1006
1037
  def _function_from_json(
1007
- json_value: Dict[str, str], **kwargs) -> types.FunctionType:
1038
+ convert_unknown: bool
1039
+ ) -> Callable[..., types.FunctionType]:
1008
1040
  """Loads a function from a JSON dict."""
1009
- del kwargs
1010
- function_name = json_value['name']
1011
- if 'code' in json_value:
1012
- code = marshal.loads(
1013
- base64.decodebytes(json_value['code'].encode('utf-8')))
1014
- defaults = from_json(json_value['defaults'], _typename_resolved=True)
1015
- return types.FunctionType(
1016
- code=code,
1017
- globals=globals(),
1018
- argdefs=defaults,
1019
- )
1020
- else:
1021
- return _load_symbol(function_name)
1022
-
1023
-
1024
- def _method_from_json(json_value: Dict[str, str], **kwargs) -> types.MethodType:
1041
+ def _fn(json_value: Dict[str, str], **kwargs) -> types.FunctionType:
1042
+ del kwargs
1043
+ function_name = json_value['name']
1044
+ if 'code' in json_value:
1045
+ code = marshal.loads(
1046
+ base64.decodebytes(json_value['code'].encode('utf-8')))
1047
+ defaults = from_json(json_value['defaults'], _typename_resolved=True)
1048
+ return types.FunctionType(
1049
+ code=code,
1050
+ globals=globals(),
1051
+ argdefs=defaults,
1052
+ )
1053
+ else:
1054
+ try:
1055
+ return _load_symbol(function_name)
1056
+ except (ModuleNotFoundError, AttributeError) as e:
1057
+ if not convert_unknown:
1058
+ raise TypeError(
1059
+ f'Cannot load function {function_name!r}.\n'
1060
+ 'Try pass `convert_unknown=True` to load the object into '
1061
+ '`pg.UnknownFunction` without depending on the type.'
1062
+ ) from e
1063
+ json_value[JSONConvertible.TYPE_NAME_KEY] = 'unknown_function'
1064
+ return from_json(json_value)
1065
+ return _fn
1066
+
1067
+
1068
+ def _method_from_json(
1069
+ convert_unknown: bool
1070
+ ) -> Callable[..., types.MethodType]:
1025
1071
  """Loads a class method from a JSON dict."""
1026
- del kwargs
1027
- return _load_symbol(json_value['name'])
1072
+ def _fn(json_value: Dict[str, str], **kwargs) -> types.MethodType:
1073
+ del kwargs
1074
+ try:
1075
+ return _load_symbol(json_value['name'])
1076
+ except (ModuleNotFoundError, AttributeError) as e:
1077
+ if not convert_unknown:
1078
+ raise TypeError(
1079
+ f'Cannot load method {json_value["name"]!r}.\n'
1080
+ 'Try pass `convert_unknown=True` to load the object '
1081
+ 'into `pg.UnknownMethod` without depending on the type.'
1082
+ ) from e
1083
+ json_value[JSONConvertible.TYPE_NAME_KEY] = 'unknown_method'
1084
+ return from_json(json_value)
1085
+ return _fn
1028
1086
 
1029
1087
 
1030
1088
  def _bind_type_args(t, args):
@@ -14,6 +14,7 @@
14
14
  import abc
15
15
  import typing
16
16
  import unittest
17
+ from pyglove.core.symbolic import unknown_symbols
17
18
  from pyglove.core.typing import inspect as pg_inspect
18
19
  from pyglove.core.utils import json_conversion
19
20
 
@@ -271,7 +272,8 @@ class JSONConvertibleTest(unittest.TestCase):
271
272
  self.assert_conversion_is(typing.List[typing.List[int]])
272
273
  self.assert_conversion_is(typing.Annotated[int, 'abc'])
273
274
  self.assert_conversion_is(typing.Dict[str, typing.Any])
274
- self.assert_conversion_is(typing.Union[int, str])
275
+ # From Python 3.14, union no longer preserves `is` identity.
276
+ self.assert_conversion_equal(typing.Union[int, str])
275
277
  self.assert_conversion_is(typing.Sequence[int])
276
278
  self.assert_conversion_is(typing.Set[int])
277
279
  self.assert_conversion_is(typing.FrozenSet[int])
@@ -307,6 +309,19 @@ class JSONConvertibleTest(unittest.TestCase):
307
309
  self.assertEqual(baz1(1), 2)
308
310
  self.assertEqual(baz1(1, 2), 3)
309
311
 
312
+ with self.assertRaisesRegex(
313
+ TypeError, 'Cannot load function .*'):
314
+ json_conversion.from_json(
315
+ {'_type': 'function', 'name': 'non_existent_function'}
316
+ )
317
+ self.assertEqual(
318
+ json_conversion.from_json(
319
+ {'_type': 'function', 'name': 'non_existent_function'},
320
+ convert_unknown=True
321
+ ),
322
+ unknown_symbols.UnknownFunction('non_existent_function')
323
+ )
324
+
310
325
  def test_json_conversion_for_methods(self):
311
326
  # Test class-level method.
312
327
  f = json_conversion.from_json(json_conversion.to_json(X.Y.Z.class_method))
@@ -319,6 +334,19 @@ class JSONConvertibleTest(unittest.TestCase):
319
334
  ValueError, 'Cannot convert instance method .* to JSON.'):
320
335
  json_conversion.to_json(X.Y.Z().instance_method)
321
336
 
337
+ with self.assertRaisesRegex(
338
+ TypeError, 'Cannot load method .*'):
339
+ json_conversion.from_json(
340
+ {'_type': 'method', 'name': 'non_existent_method'}
341
+ )
342
+ self.assertEqual(
343
+ json_conversion.from_json(
344
+ {'_type': 'method', 'name': 'non_existent_method'},
345
+ convert_unknown=True
346
+ ),
347
+ unknown_symbols.UnknownMethod('non_existent_method')
348
+ )
349
+
322
350
  def test_json_conversion_for_opaque_objects(self):
323
351
  self.assert_conversion_equal(X(1))
324
352
 
@@ -335,12 +363,15 @@ class JSONConvertibleTest(unittest.TestCase):
335
363
  ValueError, 'Cannot decode opaque object with pickle.'):
336
364
  json_conversion.from_json(json_dict)
337
365
 
338
- def test_json_conversion_auto_dict(self):
339
- # Does not exist.
366
+ def test_json_conversion_convert_unknown(self):
340
367
  self.assertEqual(
341
368
  json_conversion.from_json([
342
369
  '__tuple__',
343
370
  1,
371
+ {
372
+ '_type': 'type',
373
+ 'name': 'Unknown type',
374
+ },
344
375
  {
345
376
  '_type': 'Unknown type',
346
377
  'x': [{
@@ -350,13 +381,18 @@ class JSONConvertibleTest(unittest.TestCase):
350
381
  'name': 'builtins.print'
351
382
  }]
352
383
  }
353
- ], auto_dict=True),
354
- (1, {
355
- 'type_name': 'Unknown type',
356
- 'x': [{
357
- 'type_name': 'Unknown type',
358
- }, print]
359
- })
384
+ ], convert_unknown=True),
385
+ (
386
+ 1,
387
+ unknown_symbols.UnknownType('Unknown type'),
388
+ unknown_symbols.UnknownTypedObject(
389
+ type_name='Unknown type',
390
+ x=[
391
+ unknown_symbols.UnknownTypedObject('Unknown type'),
392
+ print
393
+ ]
394
+ )
395
+ )
360
396
  )
361
397
 
362
398
  def test_json_conversion_with_bad_types(self):
@@ -383,6 +419,10 @@ class JSONConvertibleTest(unittest.TestCase):
383
419
  TypeError, 'Cannot load class .*'):
384
420
  json_conversion.from_json({'_type': '__main__.ABC'})
385
421
 
422
+ with self.assertRaisesRegex(
423
+ TypeError, 'Cannot load type .*'):
424
+ json_conversion.from_json({'_type': 'type', 'name': '__main__.ABC'})
425
+
386
426
  # Type exist but not a JSONConvertible subclass.
387
427
  class A:
388
428
  pass
@@ -451,6 +491,41 @@ class JSONConvertibleTest(unittest.TestCase):
451
491
  self.assertIs(y_prime['t'], y_prime['v'][1])
452
492
  self.assertIs(y_prime['u'], y_prime['v'][0])
453
493
 
494
+ def test_json_conversion_with_sharing_convert_unknown(self):
495
+ self.assertEqual(
496
+ json_conversion.from_json(
497
+ {
498
+ '__context__': {
499
+ 'shared_objects': [
500
+ {
501
+ '_type': 'type',
502
+ 'name': '__main__.ABC',
503
+ },
504
+ {
505
+ '_type': '__main__.ABC',
506
+ 'x': 1
507
+ }
508
+ ]
509
+ },
510
+ '__root__': [
511
+ {
512
+ '__ref__': 0
513
+ },
514
+ {
515
+ '__ref__': 1
516
+ },
517
+ ]
518
+ },
519
+ convert_unknown=True
520
+ ),
521
+ [
522
+ unknown_symbols.UnknownType('__main__.ABC'),
523
+ unknown_symbols.UnknownTypedObject(
524
+ type_name='__main__.ABC',
525
+ x=1
526
+ )
527
+ ]
528
+ )
454
529
 
455
530
  if __name__ == '__main__':
456
531
  unittest.main()
@@ -158,6 +158,39 @@ class TabControl(HtmlControl):
158
158
  position='beforebegin',
159
159
  )
160
160
 
161
+ def remove(self, index_or_name: Union[int, str]) -> Tab:
162
+ """Removes a tab identified by index or name."""
163
+ index = self.indexof(index_or_name)
164
+ if index == -1:
165
+ raise ValueError(f'Tab not found: {index_or_name!r}')
166
+
167
+ with pg_flags.notify_on_change(False):
168
+ tab = self.tabs.pop(index)
169
+
170
+ self._run_javascript(
171
+ f"""
172
+ const button = document.querySelectorAll('#{self.element_id()}-button-group > .tab-button')[{index}];
173
+ if (button) {{
174
+ button.remove();
175
+ }}
176
+ const content = document.querySelectorAll('#{self.element_id()}-content-group > .tab-content')[{index}];
177
+ if (content) {{
178
+ content.remove();
179
+ }}
180
+ """
181
+ )
182
+
183
+ if not self.tabs:
184
+ self._sync_members(selected=0)
185
+ return tab
186
+
187
+ if self.selected == index:
188
+ new_selected = index - 1 if index == len(self.tabs) else index
189
+ self.select(max(0, new_selected))
190
+ elif self.selected > index:
191
+ self._sync_members(selected=self.selected - 1)
192
+ return tab
193
+
161
194
  def indexof(self, index_or_name: Union[int, str]) -> int:
162
195
  if isinstance(index_or_name, int):
163
196
  index = index_or_name
@@ -154,6 +154,43 @@ class TabControlTest(unittest.TestCase):
154
154
  self.assertEqual(len(scripts), 1)
155
155
  self.assertEqual(tab.selected, 1)
156
156
 
157
+ def test_remove(self):
158
+ tabs = [tab_lib.Tab(l, l, name=l) for l in ['a', 'b', 'c', 'd']]
159
+ tc = tab_lib.TabControl(tabs, selected='c')
160
+ self.assertEqual([t.name for t in tc.tabs], ['a', 'b', 'c', 'd'])
161
+ self.assertEqual(tc.selected, 2)
162
+
163
+ # Trigger rendering so scripts are tracked.
164
+ _ = tc.to_html()
165
+ with tc.track_scripts() as scripts:
166
+ tc.remove('b')
167
+ self.assertEqual(len(scripts), 1)
168
+ self.assertEqual([t.name for t in tc.tabs], ['a', 'c', 'd'])
169
+ self.assertEqual(tc.selected, 1)
170
+
171
+ with tc.track_scripts() as scripts:
172
+ # Remove currently selected tab 'c'
173
+ tc.remove('c')
174
+ # 1 script for remove, 1 for select.
175
+ self.assertEqual(len(scripts), 2)
176
+ self.assertEqual([t.name for t in tc.tabs], ['a', 'd'])
177
+ self.assertEqual(tc.selected, 1)
178
+
179
+ with tc.track_scripts() as scripts:
180
+ tc.remove(1)
181
+ self.assertEqual(len(scripts), 2)
182
+ self.assertEqual([t.name for t in tc.tabs], ['a'])
183
+ self.assertEqual(tc.selected, 0)
184
+
185
+ with tc.track_scripts() as scripts:
186
+ tc.remove('a')
187
+ self.assertEqual(len(scripts), 1)
188
+ self.assertEqual(tc.tabs, [])
189
+ self.assertEqual(tc.selected, 0)
190
+
191
+ with self.assertRaisesRegex(ValueError, 'Tab not found'):
192
+ tc.remove('x')
193
+
157
194
 
158
195
  if __name__ == '__main__':
159
196
  unittest.main()
@@ -57,7 +57,7 @@ class NextValue(base.Mutator):
57
57
  """A mutator to increase current DNA by 1."""
58
58
 
59
59
  def mutate(self, dna, step):
60
- return dna.next_dna()
60
+ return dna.next_dna() or dna
61
61
 
62
62
 
63
63
  def search_space():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyglove
3
- Version: 0.5.0.dev202510230131
3
+ Version: 0.5.0.dev202511300809
4
4
  Summary: PyGlove: A library for manipulating Python objects.
5
5
  Home-page: https://github.com/google/pyglove
6
6
  Author: PyGlove Authors
@@ -23,6 +23,12 @@ Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
24
  Requires-Dist: docstring-parser>=0.12
25
25
  Requires-Dist: termcolor>=1.1.0
26
+ Provides-Extra: all
27
+ Requires-Dist: docstring-parser>=0.12; extra == "all"
28
+ Requires-Dist: termcolor>=1.1.0; extra == "all"
29
+ Requires-Dist: fsspec>=2023.3.0; extra == "all"
30
+ Provides-Extra: io
31
+ Requires-Dist: fsspec>=2023.3.0; extra == "io"
26
32
  Dynamic: author
27
33
  Dynamic: author-email
28
34
  Dynamic: classifier
@@ -32,6 +38,7 @@ Dynamic: home-page
32
38
  Dynamic: keywords
33
39
  Dynamic: license
34
40
  Dynamic: license-file
41
+ Dynamic: provides-extra
35
42
  Dynamic: requires-dist
36
43
  Dynamic: summary
37
44
 
@@ -56,8 +56,8 @@ pyglove/core/hyper/numerical_test.py,sha256=UWdH55Bok7bghYDLJOGsgOwV_2LNkhj1AmFw
56
56
  pyglove/core/hyper/object_template.py,sha256=YPALTV0mMULa7iuqnryTpA2wMsdyFZ_6g-R525asAr8,22222
57
57
  pyglove/core/hyper/object_template_test.py,sha256=TEFX7LIqUvdCdJILnK_gP5xIgNJKzRnioUF0CGVBzcY,9105
58
58
  pyglove/core/io/__init__.py,sha256=4ZT1a595DqQuLTNYc2JP_eCp_KesXvHmKRkr777bzpg,785
59
- pyglove/core/io/file_system.py,sha256=E_kSi1Lqo31al4GJYywCzJT97X3ByW8Te4xVfAM93D4,13990
60
- pyglove/core/io/file_system_test.py,sha256=mQdg4p8_D66sxRp_Hu2ILPvJa6PcR_y8q3NB0UCYjW8,8719
59
+ pyglove/core/io/file_system.py,sha256=r7x_kDWDynKbAcO8tEkkRHShOPiYXyB9wmCXv2c-Oes,23149
60
+ pyglove/core/io/file_system_test.py,sha256=QvcPEQj3hAk7xc8VkFda1ZzgsV0etBimc1V9CJXr_Rk,19145
61
61
  pyglove/core/io/sequence.py,sha256=XdVpPBuvhUnrTIWMUrak_qdcNdUJBpjgH5c1b5I3E2A,8873
62
62
  pyglove/core/io/sequence_test.py,sha256=mnONyNG1M1sCae2tyI-tF8qns96htfZPKycthETPthU,4062
63
63
  pyglove/core/patching/__init__.py,sha256=C1Q1cWPV74YL3eXbzGvc-8aPw1DR8EK6lRhQYDCwHek,2059
@@ -67,8 +67,8 @@ pyglove/core/patching/pattern_based.py,sha256=UtSNB-ARNqVjXwZovjVi84QEoXUGLLBTgL
67
67
  pyglove/core/patching/pattern_based_test.py,sha256=PW1EcVfsFPB6wtgwg3s4dzvigWn3b5S8eMNGo0SJiZ0,2771
68
68
  pyglove/core/patching/rule_based.py,sha256=JAQp8mWeIOxwIdqusA3GmXia-fxQhQsxbUTmE329wF8,17038
69
69
  pyglove/core/patching/rule_based_test.py,sha256=qfy0ILmczV_LMHWEnwo2y079OrJsGYO0nKxSZdmIUcI,18782
70
- pyglove/core/symbolic/__init__.py,sha256=VMQj8oW2hGaJwqgchBJbu5qXoJKaNizxv__vsYL4b7U,6057
71
- pyglove/core/symbolic/base.py,sha256=aRo-v1w1kGHPhJNddaGA-SZMeLSQs4dNyRPEjHH4Phg,79102
70
+ pyglove/core/symbolic/__init__.py,sha256=ifUnJyF_hNFyrNAqlN7ClKWUvZouIA38GrYctnMc-F4,6402
71
+ pyglove/core/symbolic/base.py,sha256=QMAMFuqH_FjwJUSlUZKTBnxDpiVkM9Z8j611u6FWAcg,79816
72
72
  pyglove/core/symbolic/base_test.py,sha256=OHEexXI7uE2bixT-trfR3j-dfiAJsbY7pFyAA6XEPqA,7338
73
73
  pyglove/core/symbolic/boilerplate.py,sha256=sQ3G25r5bo_UmIdjreL4jkAuQCXIHVlvUfGjjkNod6Y,5955
74
74
  pyglove/core/symbolic/boilerplate_test.py,sha256=1CZ1W6kq3l-3tpaknhGFa04V18bO7vPzis5qzWnxHEs,5252
@@ -91,9 +91,9 @@ pyglove/core/symbolic/functor_test.py,sha256=9c5_7OBKNVNbYC7IaVQB6c5ks2v00qQ36oi
91
91
  pyglove/core/symbolic/inferred.py,sha256=E4zgphg6NNZad9Fl3jdHQOMZeqEp9XHq5OUYqXEmwZQ,3178
92
92
  pyglove/core/symbolic/inferred_test.py,sha256=G6uPykONcChvs6vZujXHSWaYfjewLTVBscMqzzKNty0,1270
93
93
  pyglove/core/symbolic/list.py,sha256=CRDoBxYJsmNly1MxhY5vO0wp6EUTnxze6-2O9vXHna4,30717
94
- pyglove/core/symbolic/list_test.py,sha256=Q3kqQ6aaQ40Nw6osSxrGk4N_E1lGZyvwdvxZgLRwMS0,61954
95
- pyglove/core/symbolic/object.py,sha256=UgDgKdcYDYX3J51EMQamdwaXHkG4SHPunAGkSuHuTa0,42768
96
- pyglove/core/symbolic/object_test.py,sha256=rDP7lcQZTFdQCqeaNYs7ZfwvGanzHz7CHM33NCmRIFk,94391
94
+ pyglove/core/symbolic/list_test.py,sha256=sH3wuJB6SqXVefJEPmzGVfoXc-ZiJ1ZTV4-O88LFuaM,61943
95
+ pyglove/core/symbolic/object.py,sha256=g6omG6r6B5TQaHSgoOWCEL_2OY_DcutxOTe1R1M1uFo,42822
96
+ pyglove/core/symbolic/object_test.py,sha256=mB8Aw1foE3XWdRX1LVn9C9U5XJeR7iqZYHrv4y94STE,94514
97
97
  pyglove/core/symbolic/origin.py,sha256=OSWMKjvPcISOXrzuX3lCQC8m_qaGl-9INsIB81erUnU,6124
98
98
  pyglove/core/symbolic/origin_test.py,sha256=dU_ZGrGDetM_lYVMn3wQO0d367_t_t8eESe3NrKPBNE,3159
99
99
  pyglove/core/symbolic/pure_symbolic.py,sha256=pvo15gn35_KLiGW_XrTjlx5ddmHbwpLr93VgbQ59uQ8,3231
@@ -101,6 +101,8 @@ pyglove/core/symbolic/ref.py,sha256=gIu02b8BfKspH1XejXhEFh_Iil3jvfGHdpaCRq6qor0,
101
101
  pyglove/core/symbolic/ref_test.py,sha256=-rCA1AaLZnyuKOh0cJzS5UaQ_9Kp4p7xexZ_e3IwpOg,8974
102
102
  pyglove/core/symbolic/symbolize.py,sha256=ohID9-V8QiFe7OMpPlRomiqUnKBVMpypd8ZuMuHaa4s,6582
103
103
  pyglove/core/symbolic/symbolize_test.py,sha256=o7bRfMhGc6uw2FIH8arE99-bPb3i0YixcHYyiP-QqeQ,6487
104
+ pyglove/core/symbolic/unknown_symbols.py,sha256=-BuT1izzGZDjuz_OSPDz9UAd1ialpxK8ceTZtIdni1Y,4323
105
+ pyglove/core/symbolic/unknown_symbols_test.py,sha256=0bjZ4cYjDdTCHwQ5GHe-D7VVDfJez7iG0v6Z0ksEDTU,3069
104
106
  pyglove/core/tuning/__init__.py,sha256=JtXpjsBto01fLf55hZ1dSx-CEZUyVQeyRP9AMH_hw8c,2229
105
107
  pyglove/core/tuning/backend.py,sha256=GwbBI9nHYYe5h6iDuhqRtD-Msjmmc7wFtagxW0rTypU,5597
106
108
  pyglove/core/tuning/backend_test.py,sha256=vyfUi509-hbF5uYk-I0FsoniPFBXmobQVl-4d0YPIWY,1999
@@ -113,8 +115,8 @@ pyglove/core/tuning/sample_test.py,sha256=JqwDPy3EPC_VjU9dipk90jj1kovZB3Zb9hAjAl
113
115
  pyglove/core/typing/__init__.py,sha256=u2YSrSi8diTkQn8_1J2hEpk5o7zDhx2tU_oRuS-k1XU,14580
114
116
  pyglove/core/typing/annotated.py,sha256=llaajIDj9GK-4kUGJoO4JsHU6ESPOra2SZ-jG6xmsOQ,3203
115
117
  pyglove/core/typing/annotated_test.py,sha256=p1qid3R-jeiOTTxOVq6hXW8XFvn-h1cUzJWISPst2l8,2484
116
- pyglove/core/typing/annotation_conversion.py,sha256=hi4LcRXwYzspHAKZ0rtXlq2dQyAmo9GXrm_HCJAGl34,15657
117
- pyglove/core/typing/annotation_conversion_test.py,sha256=g66iyt3ti_pskIXndk4DiKgO8j8aMYOe2nPKXszlXmw,17675
118
+ pyglove/core/typing/annotation_conversion.py,sha256=pnm6dZbn_nsTCreyarspkwpsdteMb8uFT2TLtblq_0M,15780
119
+ pyglove/core/typing/annotation_conversion_test.py,sha256=N49ZuzsmaqVi23wszDpfwcJApr2-Pk2E_ELrjssSQb0,17598
118
120
  pyglove/core/typing/annotation_future_test.py,sha256=tAVuzWNfW8R4e4l7fx88Q4nJDM2LPUogNKNAIIPAEWQ,3959
119
121
  pyglove/core/typing/callable_ext.py,sha256=PiBQWPeUAH7Lgmf2xKCZqgK7N0OSrTdbnEkV8Ph31OA,9127
120
122
  pyglove/core/typing/callable_ext_test.py,sha256=TnWKU4_ZjvpbHZFtFHgFvCMDiCos8VmLlODcM_7Xg8M,10156
@@ -130,12 +132,12 @@ pyglove/core/typing/json_schema_test.py,sha256=ZxMO2xgKiELNDzoQ84cmXsyCtFA0Ltn1I
130
132
  pyglove/core/typing/key_specs.py,sha256=-7xjCuUGoQgD0sMafsRFNlw3S4f1r-7t5OO4ev5bbeI,9225
131
133
  pyglove/core/typing/key_specs_test.py,sha256=5zornpyHMAYoRaG8KDXHiQ3obu9UfRp3399lBeUNTPk,6499
132
134
  pyglove/core/typing/pytype_support.py,sha256=lyX11WVbCwoOi5tTQ90pEOS-yvo_6iEi7Lxbp-nXu2A,2069
133
- pyglove/core/typing/type_conversion.py,sha256=0L4Cbsw_QiM-gpsn-4y-XLEIvwiUB16Clj9gCtoC_Xc,5224
134
- pyglove/core/typing/type_conversion_test.py,sha256=BhASOGvtKXmYLWKCELU1RVB_Nmt1V-saSkGogvsNL7E,5342
135
+ pyglove/core/typing/type_conversion.py,sha256=S_57FU-9DOk-MTE-1Mh31FMshaA3IoKiSDsoKxGxGv4,5432
136
+ pyglove/core/typing/type_conversion_test.py,sha256=rK0lAjLi1azKY4ZltquIsCpKh20EtYSIekArnqI6ThQ,5475
135
137
  pyglove/core/typing/typed_missing.py,sha256=-l1omAu0jBZv5BnsFYXBqfvQwVBnmPh_X1wcIKD9bOk,2734
136
138
  pyglove/core/typing/typed_missing_test.py,sha256=TCNsb1SRpFaVdxYn2mB_yaLuja8w5Qn5NP7uGiZVBWs,2301
137
- pyglove/core/typing/value_specs.py,sha256=8E83QDZMb3lMXhgzfVNt9u6Bg3NPkvpjLXetjkps8UU,103263
138
- pyglove/core/typing/value_specs_test.py,sha256=eGXVxdduIM-oEaapJS9Kh7WSQHRUFegLIJ1GEzQkKHA,131017
139
+ pyglove/core/typing/value_specs.py,sha256=oaLjvJ61Gv7myn93krzG3kfdw0n9va3sxmyDjy0xRFY,103368
140
+ pyglove/core/typing/value_specs_test.py,sha256=Mi0Esw-0E_1JSjoEQcjkefkcaS0-omIBzlWVTRYv1F8,131170
139
141
  pyglove/core/utils/__init__.py,sha256=6P2VcGkjDsOFG640Jqu-jd1K3pfAK5NkcK3NBPLI6RY,8726
140
142
  pyglove/core/utils/common_traits.py,sha256=PWxOgPhG5H60ZwfO8xNAEGRjFUqqDZQBWQYomOfvdy8,3640
141
143
  pyglove/core/utils/common_traits_test.py,sha256=DIuZB_1xfmeTVfWnGOguDQcDAM_iGgBOe8C-5CsIqBc,1122
@@ -149,8 +151,8 @@ pyglove/core/utils/formatting.py,sha256=Wn4d933LQLhuMIfjdRJgpxOThCxBxQrkRBa6Z1-h
149
151
  pyglove/core/utils/formatting_test.py,sha256=hhg-nL6DyE5A2QA92ALHK5QtfAYKfPpTbBARF-IT1j0,14241
150
152
  pyglove/core/utils/hierarchical.py,sha256=jwB-0FhqOspAymAkvJphRhPTQEsoShmKupCZpU3Vip4,19690
151
153
  pyglove/core/utils/hierarchical_test.py,sha256=f382DMJPa_bavJGGQDjuw-hWcafUg5bkQCPX-nbzeiI,21077
152
- pyglove/core/utils/json_conversion.py,sha256=V7wUviGKhEPWi1gtCGSDXXvBzV6cO7CvmEiGDZ2jWFY,34643
153
- pyglove/core/utils/json_conversion_test.py,sha256=6afuPJxBXIO-OxFzJBkv1MZqNX-44HIBD6YJjwxXSbs,13412
154
+ pyglove/core/utils/json_conversion.py,sha256=PWV51Dm7J-ovakhqXJux_zBAFqvjHKb9RObER8phDvw,37165
155
+ pyglove/core/utils/json_conversion_test.py,sha256=w4k6qgXGEnNXrfryTQppxtF3GJ9rdEHjvjznXSIOMcg,15809
154
156
  pyglove/core/utils/missing.py,sha256=9gslt1lXd1qSEIuAFxUWu30oD-YdYcnm13eau1S9uqY,1445
155
157
  pyglove/core/utils/missing_test.py,sha256=D6-FuVEwCyJemUiPLcwLmwyptqI5Bx0Pfipc2juhKSE,1335
156
158
  pyglove/core/utils/text_color.py,sha256=xcCTCxY2qFNZs_jismMGus8scEXKBpYGAhpAgnz-MHk,4112
@@ -175,8 +177,8 @@ pyglove/core/views/html/controls/label.py,sha256=2u7z_6o-ANf6EbxufFl_fZ1VFSUrjNw
175
177
  pyglove/core/views/html/controls/label_test.py,sha256=_Fi6vMITup8iFYTiU_1w7FZCXaYp1eMmVBxub8JMYbs,5170
176
178
  pyglove/core/views/html/controls/progress_bar.py,sha256=0an0eCbPCDjwrR58C16NwLZ-cf3Oy0wQerLsiNgGHmk,5235
177
179
  pyglove/core/views/html/controls/progress_bar_test.py,sha256=kKOJDZQtBPkmNcgIBrRQkNNzcTm51ojuFBTRUEDSsp0,3506
178
- pyglove/core/views/html/controls/tab.py,sha256=dn2rs6IBqvjtKvk0BC8ypVYqjjHsqJvP_Bh9y94QjMc,10818
179
- pyglove/core/views/html/controls/tab_test.py,sha256=deRXg4LM4dzVgods5HVTXznrOWdddF6wrcl1RuhmRCA,5656
180
+ pyglove/core/views/html/controls/tab.py,sha256=f3ZfYyXfMmERGOXY4a4bxmOhomL3MQONMossaxw8hQw,11851
181
+ pyglove/core/views/html/controls/tab_test.py,sha256=V0HrY0YaGyVlOykMCFg85QSxOq8eBPa3Fqcv2q1c12s,6912
180
182
  pyglove/core/views/html/controls/tooltip.py,sha256=01BbpuM1twf3FYMUT09_Ck5JSSONe8QE9RmyA9nhCnU,3092
181
183
  pyglove/core/views/html/controls/tooltip_test.py,sha256=17BY-WmZKpz9tCbySPcwG6KJyfeE_MeMyKxtfxorBQ0,3194
182
184
  pyglove/ext/__init__.py,sha256=3jp8cJvKW6PENOZlmVAbT0w-GBRn_kjhc0wDX3XjpOE,755
@@ -187,7 +189,7 @@ pyglove/ext/early_stopping/step_wise.py,sha256=P99Z2hODmCNBnR3iVOOj2NCCwveSH6h5V
187
189
  pyglove/ext/early_stopping/step_wise_test.py,sha256=I9DDMrCpDwIWC6mV9w2pDypnrwYnWjg6QXTFNT13cts,9032
188
190
  pyglove/ext/evolution/__init__.py,sha256=lAf4NyxUZRt39kMFFoW_i8-ExigJXakG1-sUREW7jkQ,3214
189
191
  pyglove/ext/evolution/base.py,sha256=I27qJja6MErMs3SyrlBYvmDQ4eTq9dY9RVpscKlwReQ,50090
190
- pyglove/ext/evolution/base_test.py,sha256=yIw4YS60c_MvDj71QkoxX5Y2NLZgGc_KzT_NuHMCXMk,29936
192
+ pyglove/ext/evolution/base_test.py,sha256=HgWSGGHh7nd03IFLln3dKV4TsI1kK4idJd4azAGaxHw,29943
191
193
  pyglove/ext/evolution/hill_climb.py,sha256=Bysi2u4KEM7d9CIPcnvKKgEQHttkaKFkI8xlrNOkBB8,1688
192
194
  pyglove/ext/evolution/hill_climb_test.py,sha256=7snzopGFRgkryNXiDVcHMhtVz6LXLZCOH_tz_t15b4I,3110
193
195
  pyglove/ext/evolution/mutators.py,sha256=ZkNmIf9B2KRP3H7UfML7nkjUYPPgOkm5Fe1kaJQ8W5I,10062
@@ -218,8 +220,8 @@ pyglove/ext/scalars/randoms.py,sha256=LkMIIx7lOq_lvJvVS3BrgWGuWl7Pi91-lA-O8x_gZs
218
220
  pyglove/ext/scalars/randoms_test.py,sha256=nEhiqarg8l_5EOucp59CYrpO2uKxS1pe0hmBdZUzRNM,2000
219
221
  pyglove/ext/scalars/step_wise.py,sha256=IDw3tuTpv0KVh7AN44W43zqm1-E0HWPUlytWOQC9w3Y,3789
220
222
  pyglove/ext/scalars/step_wise_test.py,sha256=TL1vJ19xVx2t5HKuyIzGoogF7N3Rm8YhLE6JF7i0iy8,2540
221
- pyglove-0.5.0.dev202510230131.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
222
- pyglove-0.5.0.dev202510230131.dist-info/METADATA,sha256=ym-feRv6WNcWJcHwyu0hlpledVeQZznTxZpGyI62kog,7089
223
- pyglove-0.5.0.dev202510230131.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
224
- pyglove-0.5.0.dev202510230131.dist-info/top_level.txt,sha256=wITzJSKcj8GZUkbq-MvUQnFadkiuAv_qv5qQMw0fIow,8
225
- pyglove-0.5.0.dev202510230131.dist-info/RECORD,,
223
+ pyglove-0.5.0.dev202511300809.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
224
+ pyglove-0.5.0.dev202511300809.dist-info/METADATA,sha256=UenEruuR6yfx1_hUKjd-L5lbN15GMZnpOhKYeA7hwPc,7349
225
+ pyglove-0.5.0.dev202511300809.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
226
+ pyglove-0.5.0.dev202511300809.dist-info/top_level.txt,sha256=wITzJSKcj8GZUkbq-MvUQnFadkiuAv_qv5qQMw0fIow,8
227
+ pyglove-0.5.0.dev202511300809.dist-info/RECORD,,