pyglove 0.4.5.dev202504210810__py3-none-any.whl → 0.4.5.dev202504230810__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/coding/errors.py +2 -2
- pyglove/core/coding/execution.py +3 -3
- pyglove/core/coding/execution_test.py +4 -0
- pyglove/core/utils/formatting.py +20 -2
- pyglove/core/utils/formatting_test.py +26 -0
- {pyglove-0.4.5.dev202504210810.dist-info → pyglove-0.4.5.dev202504230810.dist-info}/METADATA +1 -1
- {pyglove-0.4.5.dev202504210810.dist-info → pyglove-0.4.5.dev202504230810.dist-info}/RECORD +10 -10
- {pyglove-0.4.5.dev202504210810.dist-info → pyglove-0.4.5.dev202504230810.dist-info}/WHEEL +0 -0
- {pyglove-0.4.5.dev202504210810.dist-info → pyglove-0.4.5.dev202504230810.dist-info}/licenses/LICENSE +0 -0
- {pyglove-0.4.5.dev202504210810.dist-info → pyglove-0.4.5.dev202504230810.dist-info}/top_level.txt +0 -0
pyglove/core/coding/errors.py
CHANGED
@@ -28,7 +28,7 @@ class CodeError(RuntimeError):
|
|
28
28
|
def __init__(
|
29
29
|
self,
|
30
30
|
code: str,
|
31
|
-
cause:
|
31
|
+
cause: BaseException,
|
32
32
|
):
|
33
33
|
self.code = code
|
34
34
|
self.cause = cause
|
@@ -93,7 +93,7 @@ class CodeError(RuntimeError):
|
|
93
93
|
class SerializationError(RuntimeError):
|
94
94
|
"""Object serialization error."""
|
95
95
|
|
96
|
-
def __init__(self, message: Optional[str], cause:
|
96
|
+
def __init__(self, message: Optional[str], cause: BaseException):
|
97
97
|
self.message = message
|
98
98
|
self.cause = cause
|
99
99
|
|
pyglove/core/coding/execution.py
CHANGED
@@ -131,7 +131,7 @@ def evaluate(
|
|
131
131
|
result = eval( # pylint: disable=eval-used
|
132
132
|
compile(last_expr, '', mode='eval'), global_vars
|
133
133
|
)
|
134
|
-
except
|
134
|
+
except BaseException as e:
|
135
135
|
raise errors.CodeError(code, e) from e
|
136
136
|
|
137
137
|
for result_var in result_vars:
|
@@ -139,7 +139,7 @@ def evaluate(
|
|
139
139
|
else:
|
140
140
|
try:
|
141
141
|
exec(compile(code_block, '', mode='exec'), global_vars) # pylint: disable=exec-used
|
142
|
-
except
|
142
|
+
except BaseException as e:
|
143
143
|
raise errors.CodeError(code, e) from e
|
144
144
|
global_vars[RESULT_KEY] = list(global_vars.values())[-1]
|
145
145
|
|
@@ -188,7 +188,7 @@ def sandbox_call(
|
|
188
188
|
r = func(*args, **kwargs)
|
189
189
|
try:
|
190
190
|
return pickle.dumps(r)
|
191
|
-
except
|
191
|
+
except BaseException as e:
|
192
192
|
raise errors.SerializationError(
|
193
193
|
f'Cannot serialize sandbox result: {r}', e
|
194
194
|
) from e
|
@@ -217,6 +217,10 @@ class EvaluateTest(unittest.TestCase):
|
|
217
217
|
execution.evaluate(
|
218
218
|
'raise ValueError()', permission=permissions.CodePermission.ALL
|
219
219
|
)
|
220
|
+
with self.assertRaisesRegex(errors.CodeError, 'SystemExit'):
|
221
|
+
execution.evaluate(
|
222
|
+
'raise SystemExit()', permission=permissions.CodePermission.ALL
|
223
|
+
)
|
220
224
|
|
221
225
|
|
222
226
|
@dataclasses.dataclass
|
pyglove/core/utils/formatting.py
CHANGED
@@ -161,6 +161,7 @@ def kvlist_str(
|
|
161
161
|
label: Optional[str] = None,
|
162
162
|
bracket_type: BracketType = BracketType.ROUND,
|
163
163
|
custom_format: Optional[CustomFormatFn] = None,
|
164
|
+
memo: Optional[Set[int]] = None,
|
164
165
|
**kwargs,
|
165
166
|
) -> str:
|
166
167
|
"""Formats a list key/value pairs into a comma delimited string.
|
@@ -178,6 +179,8 @@ def kvlist_str(
|
|
178
179
|
custom_format: An optional custom format function, which will be applied to
|
179
180
|
each value (and child values) in kvlist. If the function returns None, it
|
180
181
|
will fall back to the default `pg.format`.
|
182
|
+
memo: A set of object ids that have been formatted. Used to avoid
|
183
|
+
infinite recursion in the formatting process.
|
181
184
|
**kwargs: Keyword arguments that will be passed through unto child
|
182
185
|
``Formattable`` objects.
|
183
186
|
Returns:
|
@@ -208,6 +211,7 @@ def kvlist_str(
|
|
208
211
|
verbose=verbose,
|
209
212
|
root_indent=child_indent,
|
210
213
|
custom_format=custom_format,
|
214
|
+
memo=memo,
|
211
215
|
**kwargs
|
212
216
|
)
|
213
217
|
if not compact:
|
@@ -271,6 +275,7 @@ def format( # pylint: disable=redefined-builtin
|
|
271
275
|
max_bytes_len: Optional[int] = None,
|
272
276
|
*,
|
273
277
|
custom_format: Optional[CustomFormatFn] = None,
|
278
|
+
memo: Optional[Set[int]] = None,
|
274
279
|
**kwargs,
|
275
280
|
) -> str:
|
276
281
|
"""Formats a (maybe) hierarchical value with flags.
|
@@ -297,6 +302,8 @@ def format( # pylint: disable=redefined-builtin
|
|
297
302
|
custom_format: An optional custom format function, which will be applied to
|
298
303
|
each value (and child values) in kvlist. If the function returns None, it
|
299
304
|
will fall back to the default `pg.format`.
|
305
|
+
memo: A set of object ids that have been formatted. Used to avoid
|
306
|
+
infinite recursion in the formatting process.
|
300
307
|
**kwargs: Keyword arguments that will be passed through unto child
|
301
308
|
``Formattable`` objects.
|
302
309
|
|
@@ -309,6 +316,14 @@ def format( # pylint: disable=redefined-builtin
|
|
309
316
|
if result is not None:
|
310
317
|
return maybe_markdown_quote(result, markdown)
|
311
318
|
|
319
|
+
if memo is None:
|
320
|
+
memo = set()
|
321
|
+
|
322
|
+
id_ = id(value)
|
323
|
+
if id_ in memo:
|
324
|
+
return f'<recursive {value.__class__.__name__} at 0x{id_:x}>' # pylint: disable=bad-whitespace
|
325
|
+
memo.add(id_)
|
326
|
+
|
312
327
|
exclude_keys = exclude_keys or set()
|
313
328
|
|
314
329
|
def _should_include_key(key: str) -> bool:
|
@@ -327,6 +342,7 @@ def format( # pylint: disable=redefined-builtin
|
|
327
342
|
max_str_len=max_str_len,
|
328
343
|
max_bytes_len=max_bytes_len,
|
329
344
|
custom_format=custom_format,
|
345
|
+
memo=memo,
|
330
346
|
**kwargs
|
331
347
|
)
|
332
348
|
|
@@ -345,6 +361,7 @@ def format( # pylint: disable=redefined-builtin
|
|
345
361
|
max_str_len=max_str_len,
|
346
362
|
max_bytes_len=max_bytes_len,
|
347
363
|
custom_format=custom_format,
|
364
|
+
memo=memo,
|
348
365
|
**kwargs
|
349
366
|
)
|
350
367
|
elif isinstance(value, (list, tuple)):
|
@@ -393,6 +410,7 @@ def format( # pylint: disable=redefined-builtin
|
|
393
410
|
if compact else str_ext(value, custom_format, root_indent)]
|
394
411
|
if strip_object_id and 'object at 0x' in s[-1]:
|
395
412
|
s = [f'{value.__class__.__name__}(...)']
|
413
|
+
memo.remove(id_)
|
396
414
|
return maybe_markdown_quote(''.join(s), markdown)
|
397
415
|
|
398
416
|
|
@@ -454,10 +472,10 @@ def camel_to_snake(text: str, separator: str = '_') -> str:
|
|
454
472
|
return (separator.join(c for c in chunks if c)).lower()
|
455
473
|
|
456
474
|
|
457
|
-
def printv(
|
475
|
+
def printv(*args, **kwargs):
|
458
476
|
"""Prints formatted value."""
|
459
477
|
fs = kwargs.pop('file', sys.stdout)
|
460
|
-
print(format(v, **kwargs), file=fs)
|
478
|
+
print(*[format(v, **kwargs) for v in args], file=fs)
|
461
479
|
|
462
480
|
|
463
481
|
def _indent(text: str, indent: int) -> str:
|
@@ -12,6 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
import inspect
|
15
|
+
import io
|
15
16
|
import unittest
|
16
17
|
|
17
18
|
from pyglove.core.utils import formatting
|
@@ -408,6 +409,26 @@ class FormatTest(unittest.TestCase):
|
|
408
409
|
'{\'x\': <a/>}'
|
409
410
|
)
|
410
411
|
|
412
|
+
def test_recursion(self):
|
413
|
+
# Recursive dict.
|
414
|
+
x = dict(x=1)
|
415
|
+
x['y'] = x
|
416
|
+
self.assertEqual(
|
417
|
+
formatting.format(x, compact=True),
|
418
|
+
f'{{\'x\': 1, \'y\': <recursive dict at 0x{id(x):x}>}}'
|
419
|
+
)
|
420
|
+
self.assertEqual(
|
421
|
+
formatting.format(x, compact=False),
|
422
|
+
f'{{\n \'x\': 1,\n \'y\': <recursive dict at 0x{id(x):x}>\n}}'
|
423
|
+
)
|
424
|
+
# Non-recursive dict.
|
425
|
+
y = dict(x=1)
|
426
|
+
a = dict(x=y, y=y)
|
427
|
+
self.assertEqual(
|
428
|
+
formatting.format(a, compact=True),
|
429
|
+
'{\'x\': {\'x\': 1}, \'y\': {\'x\': 1}}'
|
430
|
+
)
|
431
|
+
|
411
432
|
def test_markdown(self):
|
412
433
|
|
413
434
|
class A(formatting.Formattable):
|
@@ -448,6 +469,11 @@ class FormatTest(unittest.TestCase):
|
|
448
469
|
formatting.format(b'bar', max_bytes_len=2), 'b\'ba...\''
|
449
470
|
)
|
450
471
|
|
472
|
+
def test_printv(self):
|
473
|
+
with io.StringIO() as f:
|
474
|
+
formatting.printv(1, 2, 3, file=f)
|
475
|
+
self.assertEqual(f.getvalue(), '1 2 3\n')
|
476
|
+
|
451
477
|
|
452
478
|
if __name__ == '__main__':
|
453
479
|
unittest.main()
|
@@ -3,10 +3,10 @@ pyglove/core/__init__.py,sha256=BF-8v1D5lTBAo4vlpDt0qyOG9NQ71oh_UfthBVrPaN4,9614
|
|
3
3
|
pyglove/core/logging.py,sha256=Sr5nLyUQmc4CAEYAq8qbP3ghpjmpz2sOuhq2A0tgQ6I,2456
|
4
4
|
pyglove/core/logging_test.py,sha256=3z_c6wnxbqDbwUmSOAZzeDPXvzoweYL5QHUQVMJ5Xgo,1917
|
5
5
|
pyglove/core/coding/__init__.py,sha256=tuHIg19ZchtkOQbdFVTVLkUpBa5f1eo66XtnKw3lcIU,1645
|
6
|
-
pyglove/core/coding/errors.py,sha256=
|
6
|
+
pyglove/core/coding/errors.py,sha256=aP3Y4amBzOKdlb5JnESJ3kdoijQXbiBiPDMeA88LNrk,3310
|
7
7
|
pyglove/core/coding/errors_test.py,sha256=fwOR8vLiRvLadubsccyE19hLHj-kThlCQt88qmUYk9M,2311
|
8
|
-
pyglove/core/coding/execution.py,sha256=
|
9
|
-
pyglove/core/coding/execution_test.py,sha256=
|
8
|
+
pyglove/core/coding/execution.py,sha256=KGKl4ovtAPYJI-eQTLBTMwqE4FXSLbTDCj5NI4kVmy4,10943
|
9
|
+
pyglove/core/coding/execution_test.py,sha256=7V6hwShKiqpLR8jZl1tFvV3qV8QW5ZcEtBZ1rSOFPrc,9111
|
10
10
|
pyglove/core/coding/function_generation.py,sha256=2fCqcdcizVYtGYE6QGpw5m1kuH9Fp0OF4BjyJ4en6tw,1636
|
11
11
|
pyglove/core/coding/function_generation_test.py,sha256=kbSwmZF8Vog0R0OTSpuzPblEbMLoRJ1TigeIrwDhHS8,2161
|
12
12
|
pyglove/core/coding/parsing.py,sha256=JXTdzFS9iB5-JVi9_-rDFORj_EZEtr7In8HBGHp09no,4084
|
@@ -139,8 +139,8 @@ pyglove/core/utils/docstr_utils.py,sha256=5BY40kXozPKVGOB0eN8jy1P5_GHIzqFJ9FXAu_
|
|
139
139
|
pyglove/core/utils/docstr_utils_test.py,sha256=i33VT6zHXEuIIJ4PPg1bVSfaYSnUsC8yST_NfpT-Uds,4228
|
140
140
|
pyglove/core/utils/error_utils.py,sha256=ACIqtq4hsWrV00Gxd1OyeHCI-obGBR6J3H9VI1Y9clM,5780
|
141
141
|
pyglove/core/utils/error_utils_test.py,sha256=zwTzmyJupIW8GeF3Z-gnpVNdhdTYwzmO0ClODqbR4bU,4164
|
142
|
-
pyglove/core/utils/formatting.py,sha256=
|
143
|
-
pyglove/core/utils/formatting_test.py,sha256=
|
142
|
+
pyglove/core/utils/formatting.py,sha256=Wn4d933LQLhuMIfjdRJgpxOThCxBxQrkRBa6Z1-hL_I,15591
|
143
|
+
pyglove/core/utils/formatting_test.py,sha256=hhg-nL6DyE5A2QA92ALHK5QtfAYKfPpTbBARF-IT1j0,14241
|
144
144
|
pyglove/core/utils/hierarchical.py,sha256=jwB-0FhqOspAymAkvJphRhPTQEsoShmKupCZpU3Vip4,19690
|
145
145
|
pyglove/core/utils/hierarchical_test.py,sha256=f382DMJPa_bavJGGQDjuw-hWcafUg5bkQCPX-nbzeiI,21077
|
146
146
|
pyglove/core/utils/json_conversion.py,sha256=I0mWn87aAEdaAok9nDvT0ZrmplU40eNmEDUAaNIzZXk,26590
|
@@ -212,8 +212,8 @@ pyglove/ext/scalars/randoms.py,sha256=LkMIIx7lOq_lvJvVS3BrgWGuWl7Pi91-lA-O8x_gZs
|
|
212
212
|
pyglove/ext/scalars/randoms_test.py,sha256=nEhiqarg8l_5EOucp59CYrpO2uKxS1pe0hmBdZUzRNM,2000
|
213
213
|
pyglove/ext/scalars/step_wise.py,sha256=IDw3tuTpv0KVh7AN44W43zqm1-E0HWPUlytWOQC9w3Y,3789
|
214
214
|
pyglove/ext/scalars/step_wise_test.py,sha256=TL1vJ19xVx2t5HKuyIzGoogF7N3Rm8YhLE6JF7i0iy8,2540
|
215
|
-
pyglove-0.4.5.
|
216
|
-
pyglove-0.4.5.
|
217
|
-
pyglove-0.4.5.
|
218
|
-
pyglove-0.4.5.
|
219
|
-
pyglove-0.4.5.
|
215
|
+
pyglove-0.4.5.dev202504230810.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
216
|
+
pyglove-0.4.5.dev202504230810.dist-info/METADATA,sha256=R5ML7dzXaFureIQjy76mwR2AHzaVU_ZskS2X4O_uXTM,7089
|
217
|
+
pyglove-0.4.5.dev202504230810.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
218
|
+
pyglove-0.4.5.dev202504230810.dist-info/top_level.txt,sha256=wITzJSKcj8GZUkbq-MvUQnFadkiuAv_qv5qQMw0fIow,8
|
219
|
+
pyglove-0.4.5.dev202504230810.dist-info/RECORD,,
|
File without changes
|
{pyglove-0.4.5.dev202504210810.dist-info → pyglove-0.4.5.dev202504230810.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{pyglove-0.4.5.dev202504210810.dist-info → pyglove-0.4.5.dev202504230810.dist-info}/top_level.txt
RENAMED
File without changes
|