pyglove 0.4.5.dev202410301815__py3-none-any.whl → 0.4.5.dev202411020808__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.

Potentially problematic release.


This version of pyglove might be problematic. Click here for more details.

@@ -116,7 +116,7 @@ class FileSystem(metaclass=abc.ABCMeta):
116
116
  """Removes a directory chain based on a path."""
117
117
 
118
118
 
119
- def _resolve_path(path: Union[str, os.PathLike[str]]) -> str:
119
+ def resolve_path(path: Union[str, os.PathLike[str]]) -> str:
120
120
  if isinstance(path, str):
121
121
  return path
122
122
  elif hasattr(path, '__fspath__'):
@@ -243,7 +243,7 @@ class MemoryFileSystem(FileSystem):
243
243
  self._prefix = prefix
244
244
 
245
245
  def _internal_path(self, path: Union[str, os.PathLike[str]]) -> str:
246
- return '/' + _resolve_path(path).lstrip(self._prefix)
246
+ return '/' + resolve_path(path).lstrip(self._prefix)
247
247
 
248
248
  def _locate(self, path: Union[str, os.PathLike[str]]) -> Any:
249
249
  current = self._root
@@ -287,7 +287,7 @@ class MemoryFileSystem(FileSystem):
287
287
  def _parent_and_name(
288
288
  self, path: Union[str, os.PathLike[str]]
289
289
  ) -> tuple[dict[str, Any], str]:
290
- path = _resolve_path(path)
290
+ path = resolve_path(path)
291
291
  rpos = path.rfind('/')
292
292
  assert rpos >= 0, path
293
293
  name = path[rpos + 1:]
@@ -382,7 +382,7 @@ class _FileSystemRegistry:
382
382
 
383
383
  def get(self, path: Union[str, os.PathLike[str]]) -> FileSystem:
384
384
  """Gets the file system for a path."""
385
- path = _resolve_path(path)
385
+ path = resolve_path(path)
386
386
  for prefix, fs in self._filesystems:
387
387
  if path.startswith(prefix):
388
388
  return fs
@@ -107,7 +107,7 @@ class _SequenceIORegistry(object):
107
107
 
108
108
  def get(self, path: Union[str, os.PathLike[str]]) -> SequenceIO:
109
109
  """Gets the record IO system for a path."""
110
- path = _resolve_path(path)
110
+ path = file_system.resolve_path(path)
111
111
  parts = path.split('.')
112
112
  if parts:
113
113
  extension = parts[-1].lower()
@@ -126,15 +126,6 @@ def add_sequence_io(extension: str, sequence_io: SequenceIO) -> None:
126
126
  _registry.add(extension, sequence_io)
127
127
 
128
128
 
129
- def _resolve_path(path: Union[str, os.PathLike[str]]) -> str:
130
- if isinstance(path, str):
131
- return path
132
- elif hasattr(path, '__fspath__'):
133
- return path.__fspath__()
134
- else:
135
- raise ValueError(f'Unsupported path: {path!r}.')
136
-
137
-
138
129
  def open_sequence(
139
130
  path: Union[str, os.PathLike[str]],
140
131
  mode: str = 'r',
@@ -145,6 +136,7 @@ def open_sequence(
145
136
  deserializer: Optional[
146
137
  Callable[[Union[bytes, str]], Any]
147
138
  ] = None,
139
+ make_dirs_if_not_exist: bool = True,
148
140
  ) -> Sequence:
149
141
  """Open sequence for reading or writing.
150
142
 
@@ -155,10 +147,16 @@ def open_sequence(
155
147
  object to a string or bytes.
156
148
  deserializer: (Optional) A deserializer function for converting a string or
157
149
  bytes to a structured object.
150
+ make_dirs_if_not_exist: (Optional) Whether to create the directories
151
+ if they do not exist. Applicable when opening in write or append mode.
158
152
 
159
153
  Returns:
160
154
  A sequence for reading or writing.
161
155
  """
156
+ if 'w' in mode or 'a' in mode:
157
+ parent_dir = os.path.dirname(path)
158
+ if make_dirs_if_not_exist:
159
+ file_system.mkdirs(parent_dir, exist_ok=True)
162
160
  return _registry.get(path).open(
163
161
  path, mode, serializer=serializer, deserializer=deserializer
164
162
  )
@@ -13,7 +13,6 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import os
16
- import pathlib
17
16
  import tempfile
18
17
  import unittest
19
18
  from pyglove.core.io import sequence as sequence_io
@@ -25,7 +24,7 @@ class LineSequenceIOTest(unittest.TestCase):
25
24
 
26
25
  def test_read_write(self):
27
26
  tmp_dir = tempfile.gettempdir()
28
- file1 = os.path.join(tmp_dir, 'file1')
27
+ file1 = os.path.join(tmp_dir, 'abc', 'file1')
29
28
  with pg_symbolic.open_jsonl(file1, 'w') as f:
30
29
  self.assertIsInstance(f, sequence_io.LineSequence)
31
30
  f.add(1)
@@ -73,19 +72,7 @@ class LineSequenceIOTest(unittest.TestCase):
73
72
  self.assertEqual(list(iter(f)), ['foo', 'bar'])
74
73
 
75
74
 
76
- class MemoryRecordIOIOTest(unittest.TestCase):
77
-
78
- def test_resolve_path(self):
79
- self.assertEqual(
80
- sequence_io._resolve_path('/file1.mem@123'),
81
- '/file1.mem@123'
82
- )
83
- self.assertEqual(
84
- sequence_io._resolve_path(pathlib.Path('/file1.mem@123.txt')),
85
- '/file1.mem@123.txt'
86
- )
87
- with self.assertRaisesRegex(ValueError, 'Unsupported path'):
88
- sequence_io._resolve_path(1)
75
+ class MemorySequenceIOTest(unittest.TestCase):
89
76
 
90
77
  def test_read_write(self):
91
78
  with sequence_io.open_sequence('/file1.mem@123', 'w') as f:
@@ -30,19 +30,19 @@ class ErrorInfo(json_conversion.JSONConvertible, formatting.Formattable):
30
30
  """Serializable error information.
31
31
 
32
32
  Attributes:
33
- type: The type path of the error. For example,
33
+ tag: A path of the error types in the exception chain. For example,
34
34
  `ValueError.ZeroDivisionError` means the error is a `ZeroDivisionError`
35
35
  raised at the first place and then reraised as a `ValueError`.
36
36
  description: The description of the error.
37
37
  stacktrace: The stacktrace of the error.
38
38
  """
39
39
 
40
- type: str
40
+ tag: str
41
41
  description: str
42
42
  stacktrace: str
43
43
 
44
44
  @classmethod
45
- def _get_type(cls, error: BaseException):
45
+ def _compute_tag(cls, error: BaseException):
46
46
  error_types = []
47
47
  while error is not None:
48
48
  error_types.append(error.__class__.__name__)
@@ -53,7 +53,7 @@ class ErrorInfo(json_conversion.JSONConvertible, formatting.Formattable):
53
53
  def from_exception(cls, error: BaseException) -> 'ErrorInfo':
54
54
  """Creates an error info from an exception."""
55
55
  return cls(
56
- type=cls._get_type(error),
56
+ tag=cls._compute_tag(error),
57
57
  description=str(error),
58
58
  stacktrace=''.join(
59
59
  traceback.format_exception(*sys.exc_info())
@@ -63,7 +63,7 @@ class ErrorInfo(json_conversion.JSONConvertible, formatting.Formattable):
63
63
  def to_json(self, **kwargs) -> Dict[str, Any]:
64
64
  return self.to_json_dict(
65
65
  fields=dict(
66
- type=(self.type, None),
66
+ tag=(self.tag, None),
67
67
  description=(self.description, None),
68
68
  stacktrace=(self.stacktrace, None),
69
69
  ),
@@ -74,7 +74,7 @@ class ErrorInfo(json_conversion.JSONConvertible, formatting.Formattable):
74
74
  def format(self, *args, **kwargs) -> str:
75
75
  return formatting.kvlist_str(
76
76
  [
77
- ('type', self.type, None),
77
+ ('tag', self.tag, None),
78
78
  ('description', self.description, None),
79
79
  ('stacktrace', self.stacktrace, None),
80
80
  ],
@@ -36,13 +36,13 @@ class ErrorInfoTest(unittest.TestCase):
36
36
  except ValueError as e:
37
37
  error_info = error_utils.ErrorInfo.from_exception(e)
38
38
  self.assertIsNotNone(error_info)
39
- self.assertEqual(error_info.type, 'ValueError.ZeroDivisionError')
39
+ self.assertEqual(error_info.tag, 'ValueError.ZeroDivisionError')
40
40
  self.assertEqual(error_info.description, 'Bad call to `foo`')
41
41
  self.assertIn('Traceback (most recent call last)', error_info.stacktrace)
42
42
 
43
43
  def test_to_json(self):
44
44
  error_info = error_utils.ErrorInfo(
45
- type='ValueError.ZeroDivisionError',
45
+ tag='ValueError.ZeroDivisionError',
46
46
  description='Bad call to `foo`',
47
47
  stacktrace='Traceback (most recent call last)',
48
48
  )
@@ -53,7 +53,7 @@ class ErrorInfoTest(unittest.TestCase):
53
53
 
54
54
  def test_format(self):
55
55
  error_info = error_utils.ErrorInfo(
56
- type='ValueError.ZeroDivisionError',
56
+ tag='ValueError.ZeroDivisionError',
57
57
  description='Bad call to `foo`',
58
58
  stacktrace='Traceback (most recent call last)',
59
59
  )
@@ -62,7 +62,7 @@ class ErrorInfoTest(unittest.TestCase):
62
62
  inspect.cleandoc(
63
63
  """
64
64
  ErrorInfo(
65
- type='ValueError.ZeroDivisionError',
65
+ tag='ValueError.ZeroDivisionError',
66
66
  description='Bad call to `foo`',
67
67
  stacktrace='Traceback (most recent call last)'
68
68
  )
@@ -202,9 +202,8 @@ class JSONConvertible(metaclass=abc.ABCMeta):
202
202
  Returns:
203
203
  An instance of cls.
204
204
  """
205
- del kwargs
206
205
  assert isinstance(json_value, dict)
207
- init_args = {k: from_json(v) for k, v in json_value.items()
206
+ init_args = {k: from_json(v, **kwargs) for k, v in json_value.items()
208
207
  if k != JSONConvertible.TYPE_NAME_KEY}
209
208
  return cls(**init_args)
210
209
 
@@ -13,10 +13,12 @@
13
13
  # limitations under the License.
14
14
  """Utilities for timing."""
15
15
 
16
+ import collections
16
17
  import dataclasses
17
18
  import time
18
19
  from typing import Any, Dict, List, Optional
19
20
 
21
+ from pyglove.core.object_utils import error_utils
20
22
  from pyglove.core.object_utils import json_conversion
21
23
  from pyglove.core.object_utils import thread_local
22
24
 
@@ -30,7 +32,7 @@ class TimeIt:
30
32
  name: str
31
33
  elapse: float = 0.0
32
34
  has_ended: bool = True
33
- error: Optional[Exception] = None
35
+ error: Optional[error_utils.ErrorInfo] = None
34
36
 
35
37
  @property
36
38
  def has_started(self) -> bool:
@@ -66,6 +68,9 @@ class TimeIt:
66
68
  num_ended: int = 0
67
69
  num_failed: int = 0
68
70
  avg_duration: float = 0.0
71
+ error_tags: Dict[str, int] = dataclasses.field(
72
+ default_factory=lambda: collections.defaultdict(int)
73
+ )
69
74
 
70
75
  def update(self, status: 'TimeIt.Status'):
71
76
  self.avg_duration = (
@@ -77,6 +82,8 @@ class TimeIt:
77
82
  self.num_ended += 1
78
83
  if status.has_error:
79
84
  self.num_failed += 1
85
+ assert status.error is not None
86
+ self.error_tags[status.error.tag] += 1
80
87
 
81
88
  def to_json(self, **kwargs) -> Dict[str, Any]:
82
89
  return self.to_json_dict(
@@ -85,6 +92,7 @@ class TimeIt:
85
92
  num_ended=(self.num_ended, 0),
86
93
  num_failed=(self.num_failed, 0),
87
94
  avg_duration=(self.avg_duration, 0.0),
95
+ error_tags=(self.error_tags, {}),
88
96
  ),
89
97
  exclude_default=True,
90
98
  **kwargs,
@@ -113,13 +121,13 @@ class TimeIt:
113
121
  **kwargs,
114
122
  )
115
123
 
116
- def __init__(self, name: str):
117
- self._name = name
118
- self._start_time = None
119
- self._end_time = None
120
- self._child_contexts = {}
121
- self._error = None
122
- self._parent = None
124
+ def __init__(self, name: str = ''):
125
+ self._name: str = name
126
+ self._start_time: Optional[float] = None
127
+ self._end_time: Optional[float] = None
128
+ self._child_contexts: Dict[str, TimeIt] = {}
129
+ self._error: Optional[error_utils.ErrorInfo] = None
130
+ self._parent: Optional[TimeIt] = None
123
131
 
124
132
  @property
125
133
  def name(self) -> str:
@@ -145,7 +153,9 @@ class TimeIt:
145
153
  """Ends timing."""
146
154
  if not self.has_ended:
147
155
  self._end_time = time.time()
148
- self._error = error
156
+ self._error = (
157
+ None if error is None else error_utils.ErrorInfo.from_exception(error)
158
+ )
149
159
  return True
150
160
  return False
151
161
 
@@ -170,7 +180,7 @@ class TimeIt:
170
180
  return self._end_time
171
181
 
172
182
  @property
173
- def error(self) -> Optional[BaseException]:
183
+ def error(self) -> Optional[error_utils.ErrorInfo]:
174
184
  """Returns error."""
175
185
  return self._error
176
186
 
@@ -199,7 +209,8 @@ class TimeIt:
199
209
  for child in self._child_contexts.values():
200
210
  child_result = child.status()
201
211
  for k, v in child_result.items():
202
- result[f'{self.name}.{k}'] = v
212
+ key = f'{self.name}.{k}' if self.name else k
213
+ result[key] = v
203
214
  return result
204
215
 
205
216
  def __enter__(self):
@@ -220,6 +231,6 @@ class TimeIt:
220
231
  thread_local.thread_local_set('__timing_context__', self._parent)
221
232
 
222
233
 
223
- def timeit(name: str) -> TimeIt:
234
+ def timeit(name: str = '') -> TimeIt:
224
235
  """Context manager to time a block of code."""
225
236
  return TimeIt(name)
@@ -100,8 +100,8 @@ class TimeItTest(unittest.TestCase):
100
100
  r = t.status()
101
101
  self.assertTrue(r['node'].has_error)
102
102
  self.assertTrue(t.has_error)
103
- self.assertIsInstance(t.error, ValueError)
104
- self.assertIsInstance(r['node'].error, ValueError)
103
+ self.assertTrue(t.error.tag.startswith('ValueError'))
104
+ self.assertTrue(r['node'].error.tag.startswith('ValueError'))
105
105
  self.assertTrue(r['node.child'].has_error)
106
106
  self.assertTrue(t1.has_error)
107
107
  self.assertTrue(r['node.child.grandchild'].has_error)
@@ -111,7 +111,7 @@ class TimeItTest(unittest.TestCase):
111
111
  summary = timing.TimeIt.StatusSummary()
112
112
  self.assertFalse(summary)
113
113
  for i in range(10):
114
- with timing.timeit('node') as t:
114
+ with timing.timeit() as t:
115
115
  time.sleep(0.1)
116
116
  with timing.timeit('child'):
117
117
  time.sleep(0.1)
@@ -126,7 +126,7 @@ class TimeItTest(unittest.TestCase):
126
126
  self.assertTrue(summary)
127
127
  self.assertEqual(
128
128
  list(summary.breakdown.keys()),
129
- ['node', 'node.child', 'node.child.grandchild']
129
+ ['', 'child', 'child.grandchild']
130
130
  )
131
131
  self.assertEqual(
132
132
  [x.num_started for x in summary.breakdown.values()],
@@ -140,6 +140,10 @@ class TimeItTest(unittest.TestCase):
140
140
  [x.num_failed for x in summary.breakdown.values()],
141
141
  [0, 0, 2]
142
142
  )
143
+ self.assertEqual(
144
+ summary.breakdown['child.grandchild'].error_tags,
145
+ {'ValueError': 2},
146
+ )
143
147
  # Test serialization.
144
148
  json_dict = summary.to_json()
145
149
  summary2 = timing.TimeIt.StatusSummary.from_json(json_dict)
@@ -2041,13 +2041,16 @@ def contains(
2041
2041
  return not traverse(x, _contains)
2042
2042
 
2043
2043
 
2044
- def from_json(json_value: Any,
2045
- *,
2046
- allow_partial: bool = False,
2047
- root_path: Optional[object_utils.KeyPath] = None,
2048
- auto_import: bool = True,
2049
- auto_dict: bool = False,
2050
- **kwargs) -> Any:
2044
+ def from_json(
2045
+ json_value: Any,
2046
+ *,
2047
+ allow_partial: bool = False,
2048
+ root_path: Optional[object_utils.KeyPath] = None,
2049
+ auto_import: bool = True,
2050
+ auto_dict: bool = False,
2051
+ value_spec: Optional[pg_typing.ValueSpec] = None,
2052
+ **kwargs
2053
+ ) -> Any:
2051
2054
  """Deserializes a (maybe) symbolic value from JSON value.
2052
2055
 
2053
2056
  Example::
@@ -2073,6 +2076,7 @@ def from_json(json_value: Any,
2073
2076
  find the class 'A' within the imported module.
2074
2077
  auto_dict: If True, dict with '_type' that cannot be loaded will remain
2075
2078
  as dict, with '_type' renamed to 'type_name'.
2079
+ value_spec: The value spec for the symbolic list or dict.
2076
2080
  **kwargs: Allow passing through keyword arguments to from_json of specific
2077
2081
  types.
2078
2082
 
@@ -2093,10 +2097,15 @@ def from_json(json_value: Any,
2093
2097
  json_value, auto_import=auto_import, auto_dict=auto_dict
2094
2098
  )
2095
2099
 
2096
- kwargs.update({
2097
- 'allow_partial': allow_partial,
2098
- 'root_path': root_path,
2099
- })
2100
+ def _load_child(k, v):
2101
+ return from_json(
2102
+ v,
2103
+ root_path=object_utils.KeyPath(k, root_path),
2104
+ _typename_resolved=True,
2105
+ allow_partial=allow_partial,
2106
+ **kwargs
2107
+ )
2108
+
2100
2109
  if isinstance(json_value, list):
2101
2110
  if (json_value
2102
2111
  and json_value[0] == object_utils.JSONConvertible.TUPLE_MARKER):
@@ -2106,21 +2115,27 @@ def from_json(json_value: Any,
2106
2115
  f'Tuple should have at least one element '
2107
2116
  f'besides \'{object_utils.JSONConvertible.TUPLE_MARKER}\'. '
2108
2117
  f'Encountered: {json_value}', root_path))
2109
- kwargs.pop('root_path')
2110
- return tuple([
2111
- from_json(
2112
- v,
2113
- root_path=object_utils.KeyPath(i, root_path),
2114
- _typename_resolved=True,
2115
- **kwargs
2116
- )
2117
- for i, v in enumerate(json_value[1:])
2118
- ])
2119
- return Symbolic.ListType(json_value, **kwargs) # pytype: disable=not-callable # pylint: disable=not-callable
2118
+ return tuple(_load_child(i, v) for i, v in enumerate(json_value[1:]))
2119
+ return Symbolic.ListType.from_json( # pytype: disable=attribute-error
2120
+ json_value,
2121
+ value_spec=value_spec,
2122
+ root_path=root_path,
2123
+ allow_partial=allow_partial,
2124
+ **kwargs,
2125
+ )
2120
2126
  elif isinstance(json_value, dict):
2121
2127
  if object_utils.JSONConvertible.TYPE_NAME_KEY not in json_value:
2122
- return Symbolic.DictType.from_json(json_value, **kwargs)
2123
- return object_utils.from_json(json_value, _typename_resolved=True, **kwargs)
2128
+ return Symbolic.DictType.from_json( # pytype: disable=attribute-error
2129
+ json_value,
2130
+ value_spec=value_spec,
2131
+ root_path=root_path,
2132
+ allow_partial=allow_partial,
2133
+ **kwargs,
2134
+ )
2135
+ return object_utils.from_json(
2136
+ json_value, _typename_resolved=True,
2137
+ root_path=root_path, allow_partial=allow_partial, **kwargs
2138
+ )
2124
2139
  return json_value
2125
2140
 
2126
2141
 
@@ -152,10 +152,19 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
152
152
  # Not okay:
153
153
  d.a.f2.abc = 1
154
154
  """
155
- return cls(json_value,
156
- value_spec=value_spec,
157
- allow_partial=allow_partial,
158
- root_path=root_path)
155
+ return cls(
156
+ {
157
+ k: base.from_json(
158
+ v,
159
+ root_path=object_utils.KeyPath(k, root_path),
160
+ allow_partial=allow_partial,
161
+ **kwargs
162
+ ) for k, v in json_value.items()
163
+ },
164
+ value_spec=value_spec,
165
+ root_path=root_path,
166
+ allow_partial=allow_partial,
167
+ )
159
168
 
160
169
  def __init__(self,
161
170
  dict_obj: Union[
@@ -132,10 +132,19 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
132
132
  Returns:
133
133
  A schema-less symbolic list, but its items maybe symbolic.
134
134
  """
135
- return cls(json_value,
136
- value_spec=value_spec,
137
- allow_partial=allow_partial,
138
- root_path=root_path)
135
+ return cls(
136
+ [
137
+ base.from_json(
138
+ v,
139
+ root_path=object_utils.KeyPath(i, root_path),
140
+ allow_partial=allow_partial,
141
+ **kwargs
142
+ ) for i, v in enumerate(json_value)
143
+ ],
144
+ value_spec=value_spec,
145
+ root_path=root_path,
146
+ allow_partial=allow_partial,
147
+ )
139
148
 
140
149
  def __init__(
141
150
  self,
@@ -543,7 +543,9 @@ class Object(base.Symbolic, metaclass=ObjectMeta):
543
543
  json_value: Any,
544
544
  *,
545
545
  allow_partial: bool = False,
546
- root_path: Optional[object_utils.KeyPath] = None) -> 'Object':
546
+ root_path: Optional[object_utils.KeyPath] = None,
547
+ **kwargs
548
+ ) -> 'Object':
547
549
  """Class method that load an symbolic Object from a JSON value.
548
550
 
549
551
  Example::
@@ -580,12 +582,13 @@ class Object(base.Symbolic, metaclass=ObjectMeta):
580
582
  json_value: Input JSON value, only JSON dict is acceptable.
581
583
  allow_partial: Whether to allow elements of the list to be partial.
582
584
  root_path: KeyPath of loaded object in its object tree.
585
+ **kwargs: Additional keyword arguments to pass through.
583
586
 
584
587
  Returns:
585
588
  A symbolic Object instance.
586
589
  """
587
590
  return cls(allow_partial=allow_partial, root_path=root_path, **{
588
- k: base.from_json(v, allow_partial=allow_partial)
591
+ k: base.from_json(v, allow_partial=allow_partial, **kwargs)
589
592
  for k, v in json_value.items()
590
593
  })
591
594
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyglove
3
- Version: 0.4.5.dev202410301815
3
+ Version: 0.4.5.dev202411020808
4
4
  Summary: PyGlove: A library for manipulating Python objects.
5
5
  Home-page: https://github.com/google/pyglove
6
6
  Author: PyGlove Authors
@@ -43,10 +43,10 @@ pyglove/core/hyper/numerical_test.py,sha256=_xZe0qe3wJdrQL4F8pgt0zf04zpbc_9c_5va
43
43
  pyglove/core/hyper/object_template.py,sha256=x6aBe-6ueo3CsFJ2yhbXbcdJKfId6wm_KsgkHHbpSoY,22325
44
44
  pyglove/core/hyper/object_template_test.py,sha256=TEFX7LIqUvdCdJILnK_gP5xIgNJKzRnioUF0CGVBzcY,9105
45
45
  pyglove/core/io/__init__.py,sha256=4ZT1a595DqQuLTNYc2JP_eCp_KesXvHmKRkr777bzpg,785
46
- pyglove/core/io/file_system.py,sha256=KR1riWNBVZpkgIcqPUhR5xqjCN5Lhp937x7Ubjpv-jE,13283
46
+ pyglove/core/io/file_system.py,sha256=ZfeQeZ1HF1WjV1REC9wCaut5Wkdu_FjxPzulUju7Z_E,13279
47
47
  pyglove/core/io/file_system_test.py,sha256=FX0ySuh_Xcg1RO68do7ikD4pvslKUzfSpwZ6P4wIP7c,8691
48
- pyglove/core/io/sequence.py,sha256=Kir8JM8lxjrlKr1gs3hvhCB8F08PPz4K8-aDI_US9Vo,8042
49
- pyglove/core/io/sequence_test.py,sha256=iqDR-MPm64VbUPKFYocVKH91Y6Z6tP1TZB0PzCn92tE,4265
48
+ pyglove/core/io/sequence.py,sha256=7QWMGXPtJzHyGPgqkT3yJ01FxKJ4mP4lF5HRDiIHNbQ,8165
49
+ pyglove/core/io/sequence_test.py,sha256=6tmnS7frBuDR8ussT5jugeh23TDsPDrDnbfxHh81Gy4,3891
50
50
  pyglove/core/object_utils/__init__.py,sha256=bFyt-_uNzpOjJGDfYFTRP1kV6rL4du9xGx_OaFMcIxI,8758
51
51
  pyglove/core/object_utils/codegen.py,sha256=HQlpjz42oh_2lrGSflwuAcEneE9Bv8pgPahQzvJm1KI,1568
52
52
  pyglove/core/object_utils/codegen_test.py,sha256=ThPVyE805plNvM8vwlDxMrcjV-GGdDgbBLSqSOpCvJ0,2166
@@ -54,20 +54,20 @@ pyglove/core/object_utils/common_traits.py,sha256=9wfWvcq3uuVgL8mQexgJmWdF2aaQ-w
54
54
  pyglove/core/object_utils/common_traits_test.py,sha256=wIeVsF3kon9K0Kbblcaib9hBJeZ76LyGZDD-5A1BD9w,1182
55
55
  pyglove/core/object_utils/docstr_utils.py,sha256=5BY40kXozPKVGOB0eN8jy1P5_GHIzqFJ9FXAu_kzxaw,5119
56
56
  pyglove/core/object_utils/docstr_utils_test.py,sha256=1NIsXXpp87HGC8LB7vx1KEMVVrmeGi733Xpuf6yTUq0,4287
57
- pyglove/core/object_utils/error_utils.py,sha256=wnGX_aR4TdbCylvUOh-x6PPYzGSJBnfyX9MANpk03u8,5780
58
- pyglove/core/object_utils/error_utils_test.py,sha256=vlFkR41jNLzUnwqF6IXy7HmXhpLlwOvUvlVMoMSOitk,4175
57
+ pyglove/core/object_utils/error_utils.py,sha256=5mcD61La1tTYmmKodsWfnt8R-yV3yfBfbW4o5rZzCTg,5801
58
+ pyglove/core/object_utils/error_utils_test.py,sha256=rnX4HYsZaMphWPm4ppgzCQ49LAXfJJ9KDTiDz4f9Ahc,4171
59
59
  pyglove/core/object_utils/formatting.py,sha256=cXGWJd6zleS9QiEfY3w4fqWfFYgi_QF8S2IapTOzAj8,14994
60
60
  pyglove/core/object_utils/formatting_test.py,sha256=QGbpUS8u70NoF8-3v5IYmPWEsML3ZbIwkQpUMwQdTkQ,13589
61
61
  pyglove/core/object_utils/hierarchical.py,sha256=za9sA6XnlUOKUHMKNwQPNSOK9E3wDqXFQB0AND2Yghw,19754
62
62
  pyglove/core/object_utils/hierarchical_test.py,sha256=H7AMpUmL8g9AeKsb4T8JrP1eXOleyLSsrw6TGUvEDB4,21150
63
- pyglove/core/object_utils/json_conversion.py,sha256=1XEwz4LzEh8wHsTIC7jL7lD7L5tK-sOJoUuNe76Omv0,26583
63
+ pyglove/core/object_utils/json_conversion.py,sha256=bR46Z3IfSRYFV-QUsxZgetA09PyfDZ6gkAj1-q-WxvQ,26578
64
64
  pyglove/core/object_utils/json_conversion_test.py,sha256=KGt0r628KHi4fTfeCgrhirfINpYXIR45l5ER4z09jjI,11907
65
65
  pyglove/core/object_utils/missing.py,sha256=0liMs9iEyQxxu6UohdJ5hEM246e9Nu05qp0hqriHsl0,1459
66
66
  pyglove/core/object_utils/missing_test.py,sha256=B36p-vqUvAnXWMszAj9GOPBN0_8cq7vVF61AkcsZ9qU,1396
67
67
  pyglove/core/object_utils/thread_local.py,sha256=i-CnyY3VREtLfAj4_JndBnsKuQLIgwG29ma8dAyRxbI,4839
68
68
  pyglove/core/object_utils/thread_local_test.py,sha256=EvU1-TF7KqpLQxxBvHd7dxtuY22YUQSIwQ0UcR-NORA,6816
69
- pyglove/core/object_utils/timing.py,sha256=PeSN59g8vQDpenPgsWf4oYP45c0UDSpnFYDKhrtcSBc,6665
70
- pyglove/core/object_utils/timing_test.py,sha256=Ye4qBrNl5ix2C_K-qT5TxKHui4Kvwmea3uUTx8t26qk,4828
69
+ pyglove/core/object_utils/timing.py,sha256=ihOdcZaJo96wpe4U-bXEu-H1PZMWeWOaU-nSW9DFStY,7262
70
+ pyglove/core/object_utils/timing_test.py,sha256=jym-jV55kRujhgoxmDUUIXuqRLDnBGYiNKN3lUMbnfg,4943
71
71
  pyglove/core/object_utils/value_location.py,sha256=lSFQNTazY2M6_nRLmMbouqZAcZSiOLZQnmQPMD2FDMs,26770
72
72
  pyglove/core/object_utils/value_location_test.py,sha256=wCZYqWf_tq3l4ZM6dnkAs1obmq8LfYawkns2NKos9kk,21406
73
73
  pyglove/core/patching/__init__.py,sha256=C1Q1cWPV74YL3eXbzGvc-8aPw1DR8EK6lRhQYDCwHek,2059
@@ -78,7 +78,7 @@ pyglove/core/patching/pattern_based_test.py,sha256=PW1EcVfsFPB6wtgwg3s4dzvigWn3b
78
78
  pyglove/core/patching/rule_based.py,sha256=QJsDsYVpyfUoaTZeXZtAdFuxpvB1eniY0qYdZvVqzk0,17056
79
79
  pyglove/core/patching/rule_based_test.py,sha256=qfy0ILmczV_LMHWEnwo2y079OrJsGYO0nKxSZdmIUcI,18782
80
80
  pyglove/core/symbolic/__init__.py,sha256=jYq-LwR1Ql3iMChjz9lN-0heDKiocmxR0ZJFEJ8RHHQ,5787
81
- pyglove/core/symbolic/base.py,sha256=JNgh6eU_d5DRKQKlw4QP0FSJJg1RaVTrgGBjumg3ELs,78292
81
+ pyglove/core/symbolic/base.py,sha256=y84C1c5x1va_HOFaPg4Htpud78B_UqoDKJ4HxiWSOJQ,78607
82
82
  pyglove/core/symbolic/base_test.py,sha256=YLMlQGF4TbxAB2PcN1-ckI70gRIVDxabv-goh43CV7A,7333
83
83
  pyglove/core/symbolic/boilerplate.py,sha256=YO8ZTZJ3VfAqeHqJpIY_ORVDxc1XIzxdplNlpexWEyc,6000
84
84
  pyglove/core/symbolic/boilerplate_test.py,sha256=1CZ1W6kq3l-3tpaknhGFa04V18bO7vPzis5qzWnxHEs,5252
@@ -86,7 +86,7 @@ pyglove/core/symbolic/class_wrapper.py,sha256=s8TL7LLim4xRcC5fxlYMuS1zdaEDIZomSF
86
86
  pyglove/core/symbolic/class_wrapper_test.py,sha256=bPK-qZ7tVKanzXb1mZ4StkLB5kHtecBjKBesg2NQfL0,21636
87
87
  pyglove/core/symbolic/compounding.py,sha256=zg6x09rtaSEb5v5pYJWWWpI5Cezy2Oy1iuWw4LUj2HY,11717
88
88
  pyglove/core/symbolic/compounding_test.py,sha256=PSnk_ds0q6pRJrpN9teMwZtMrbUp5_P-D7ea7wRTK6k,8372
89
- pyglove/core/symbolic/dict.py,sha256=fXEaWok9hgCmMjZjvzIIbP-KBnImbfTMDOp1m40XfjI,36617
89
+ pyglove/core/symbolic/dict.py,sha256=gp2sn9nf7movorKWDQsbCQmj0PBdqFul0FYJLm5_kac,36839
90
90
  pyglove/core/symbolic/dict_test.py,sha256=09kAEy_Kiwr8O59CIKK9a9KG-xxJJEIKbfEcZhs5KfU,70809
91
91
  pyglove/core/symbolic/diff.py,sha256=g_KGL50R--LaMcqMQfC2jq7EuRxd8gaYY9X_KYGsdSk,16186
92
92
  pyglove/core/symbolic/diff_test.py,sha256=EDiGHqqKhi-NeMxr-bgjBEqlquee_4l_0IM6hgAb9Mg,29400
@@ -96,9 +96,9 @@ pyglove/core/symbolic/functor.py,sha256=YGhSgsll2dKIc8JeVMVRzzhIliEO025XaGPzHzv0
96
96
  pyglove/core/symbolic/functor_test.py,sha256=7ZKPmJkDj-zvlDJyp1EKLJ8HDmvlhsiVFky0sbeCqpA,31846
97
97
  pyglove/core/symbolic/inferred.py,sha256=jGCKXLkYGDs-iUflR57UWrCrOQIpkpv5kHVyj-Jbhy4,3192
98
98
  pyglove/core/symbolic/inferred_test.py,sha256=G6uPykONcChvs6vZujXHSWaYfjewLTVBscMqzzKNty0,1270
99
- pyglove/core/symbolic/list.py,sha256=6N0O3nwU9lCoLX-9nhe2VQbM6fk5kVP4QioRktiNHKw,30123
99
+ pyglove/core/symbolic/list.py,sha256=63v4Ph0FdkoCDj1FjwcmjUHGZSJLBLxaTKcGg7PdghE,30345
100
100
  pyglove/core/symbolic/list_test.py,sha256=yHYAJhe_EYwtU9p8eDztSXNBjnAGKe0UDN5U6S-xDr8,60627
101
- pyglove/core/symbolic/object.py,sha256=Bj8zV1oxBIXynEhDS7bYOf7JmtuKralm2Yz72K6UJBQ,42258
101
+ pyglove/core/symbolic/object.py,sha256=1NdVMGoZiyuuxXIbQiW-n4NhUdHSuiedB-chx1n0BrQ,42349
102
102
  pyglove/core/symbolic/object_test.py,sha256=9-iwW3WVXfQnN4Jj2nlWFXAMJz3PEAYVlINgb7m9_LA,93013
103
103
  pyglove/core/symbolic/origin.py,sha256=5bH1jZvFHY5jwku32vDm8Bj2i-buv-YNuzOOsA5GlSA,6177
104
104
  pyglove/core/symbolic/origin_test.py,sha256=dU_ZGrGDetM_lYVMn3wQO0d367_t_t8eESe3NrKPBNE,3159
@@ -186,8 +186,8 @@ pyglove/ext/scalars/randoms.py,sha256=LkMIIx7lOq_lvJvVS3BrgWGuWl7Pi91-lA-O8x_gZs
186
186
  pyglove/ext/scalars/randoms_test.py,sha256=nEhiqarg8l_5EOucp59CYrpO2uKxS1pe0hmBdZUzRNM,2000
187
187
  pyglove/ext/scalars/step_wise.py,sha256=IDw3tuTpv0KVh7AN44W43zqm1-E0HWPUlytWOQC9w3Y,3789
188
188
  pyglove/ext/scalars/step_wise_test.py,sha256=TL1vJ19xVx2t5HKuyIzGoogF7N3Rm8YhLE6JF7i0iy8,2540
189
- pyglove-0.4.5.dev202410301815.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
190
- pyglove-0.4.5.dev202410301815.dist-info/METADATA,sha256=jIeDOiGyeIig84equ3ZG2EjO4s1his-CfD1PjMETKpU,6666
191
- pyglove-0.4.5.dev202410301815.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
192
- pyglove-0.4.5.dev202410301815.dist-info/top_level.txt,sha256=wITzJSKcj8GZUkbq-MvUQnFadkiuAv_qv5qQMw0fIow,8
193
- pyglove-0.4.5.dev202410301815.dist-info/RECORD,,
189
+ pyglove-0.4.5.dev202411020808.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
190
+ pyglove-0.4.5.dev202411020808.dist-info/METADATA,sha256=OFXogc-n-WTnIvBpoY6reTyUuXwvVN0ZyWGPWxkRBSY,6666
191
+ pyglove-0.4.5.dev202411020808.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
192
+ pyglove-0.4.5.dev202411020808.dist-info/top_level.txt,sha256=wITzJSKcj8GZUkbq-MvUQnFadkiuAv_qv5qQMw0fIow,8
193
+ pyglove-0.4.5.dev202411020808.dist-info/RECORD,,