pyglove 0.4.5.dev202505150810__tar.gz → 0.4.5.dev202505160313__tar.gz

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.
Files changed (228) hide show
  1. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/PKG-INFO +1 -1
  2. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/__init__.py +1 -0
  3. pyglove-0.4.5.dev202505160313/pyglove/core/symbolic/error_info.py +127 -0
  4. pyglove-0.4.5.dev202505160313/pyglove/core/symbolic/error_info_test.py +92 -0
  5. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/object.py +17 -2
  6. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/object_test.py +28 -0
  7. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/error_utils.py +22 -40
  8. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/error_utils_test.py +0 -56
  9. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/text_color_test.py +5 -2
  10. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/timing_test.py +1 -0
  11. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove.egg-info/PKG-INFO +1 -1
  12. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove.egg-info/SOURCES.txt +2 -0
  13. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/LICENSE +0 -0
  14. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/README.md +0 -0
  15. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/__init__.py +0 -0
  16. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/__init__.py +0 -0
  17. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/__init__.py +0 -0
  18. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/errors.py +0 -0
  19. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/errors_test.py +0 -0
  20. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/execution.py +0 -0
  21. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/execution_test.py +0 -0
  22. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/function_generation.py +0 -0
  23. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/function_generation_test.py +0 -0
  24. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/parsing.py +0 -0
  25. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/parsing_test.py +0 -0
  26. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/permissions.py +0 -0
  27. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/coding/permissions_test.py +0 -0
  28. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/detouring/__init__.py +0 -0
  29. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/detouring/class_detour.py +0 -0
  30. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/detouring/class_detour_test.py +0 -0
  31. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/__init__.py +0 -0
  32. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/base.py +0 -0
  33. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/base_test.py +0 -0
  34. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/categorical.py +0 -0
  35. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/categorical_test.py +0 -0
  36. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/custom.py +0 -0
  37. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/custom_test.py +0 -0
  38. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/deduping.py +0 -0
  39. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/deduping_test.py +0 -0
  40. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/dna_generator.py +0 -0
  41. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/dna_generator_test.py +0 -0
  42. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/numerical.py +0 -0
  43. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/numerical_test.py +0 -0
  44. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/random.py +0 -0
  45. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/random_test.py +0 -0
  46. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/space.py +0 -0
  47. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/space_test.py +0 -0
  48. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/sweeping.py +0 -0
  49. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/geno/sweeping_test.py +0 -0
  50. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/__init__.py +0 -0
  51. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/base.py +0 -0
  52. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/categorical.py +0 -0
  53. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/categorical_test.py +0 -0
  54. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/custom.py +0 -0
  55. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/custom_test.py +0 -0
  56. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/derived.py +0 -0
  57. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/derived_test.py +0 -0
  58. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/dynamic_evaluation.py +0 -0
  59. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/dynamic_evaluation_test.py +0 -0
  60. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/evolvable.py +0 -0
  61. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/evolvable_test.py +0 -0
  62. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/iter.py +0 -0
  63. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/iter_test.py +0 -0
  64. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/numerical.py +0 -0
  65. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/numerical_test.py +0 -0
  66. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/object_template.py +0 -0
  67. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/hyper/object_template_test.py +0 -0
  68. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/io/__init__.py +0 -0
  69. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/io/file_system.py +0 -0
  70. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/io/file_system_test.py +0 -0
  71. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/io/sequence.py +0 -0
  72. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/io/sequence_test.py +0 -0
  73. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/logging.py +0 -0
  74. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/logging_test.py +0 -0
  75. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/patching/__init__.py +0 -0
  76. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/patching/object_factory.py +0 -0
  77. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/patching/object_factory_test.py +0 -0
  78. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/patching/pattern_based.py +0 -0
  79. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/patching/pattern_based_test.py +0 -0
  80. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/patching/rule_based.py +0 -0
  81. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/patching/rule_based_test.py +0 -0
  82. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/base.py +0 -0
  83. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/base_test.py +0 -0
  84. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/boilerplate.py +0 -0
  85. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/boilerplate_test.py +0 -0
  86. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/class_wrapper.py +0 -0
  87. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/class_wrapper_test.py +0 -0
  88. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/compounding.py +0 -0
  89. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/compounding_test.py +0 -0
  90. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/contextual_object.py +0 -0
  91. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/contextual_object_test.py +0 -0
  92. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/dict.py +0 -0
  93. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/dict_test.py +0 -0
  94. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/diff.py +0 -0
  95. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/diff_test.py +0 -0
  96. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/flags.py +0 -0
  97. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/flags_test.py +0 -0
  98. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/functor.py +0 -0
  99. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/functor_test.py +0 -0
  100. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/inferred.py +0 -0
  101. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/inferred_test.py +0 -0
  102. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/list.py +0 -0
  103. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/list_test.py +0 -0
  104. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/origin.py +0 -0
  105. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/origin_test.py +0 -0
  106. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/pure_symbolic.py +0 -0
  107. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/ref.py +0 -0
  108. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/ref_test.py +0 -0
  109. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/symbolize.py +0 -0
  110. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/symbolic/symbolize_test.py +0 -0
  111. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/__init__.py +0 -0
  112. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/backend.py +0 -0
  113. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/backend_test.py +0 -0
  114. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/early_stopping.py +0 -0
  115. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/local_backend.py +0 -0
  116. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/protocols.py +0 -0
  117. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/protocols_test.py +0 -0
  118. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/sample.py +0 -0
  119. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/tuning/sample_test.py +0 -0
  120. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/__init__.py +0 -0
  121. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/annotated.py +0 -0
  122. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/annotated_test.py +0 -0
  123. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/annotation_conversion.py +0 -0
  124. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/annotation_conversion_test.py +0 -0
  125. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/annotation_future_test.py +0 -0
  126. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/callable_ext.py +0 -0
  127. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/callable_ext_test.py +0 -0
  128. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/callable_signature.py +0 -0
  129. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/callable_signature_test.py +0 -0
  130. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/class_schema.py +0 -0
  131. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/class_schema_test.py +0 -0
  132. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/custom_typing.py +0 -0
  133. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/inspect.py +0 -0
  134. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/inspect_test.py +0 -0
  135. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/json_schema.py +0 -0
  136. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/json_schema_test.py +0 -0
  137. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/key_specs.py +0 -0
  138. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/key_specs_test.py +0 -0
  139. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/pytype_support.py +0 -0
  140. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/type_conversion.py +0 -0
  141. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/type_conversion_test.py +0 -0
  142. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/typed_missing.py +0 -0
  143. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/typed_missing_test.py +0 -0
  144. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/value_specs.py +0 -0
  145. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/typing/value_specs_test.py +0 -0
  146. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/__init__.py +0 -0
  147. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/common_traits.py +0 -0
  148. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/common_traits_test.py +0 -0
  149. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/contextual.py +0 -0
  150. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/contextual_test.py +0 -0
  151. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/docstr_utils.py +0 -0
  152. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/docstr_utils_test.py +0 -0
  153. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/formatting.py +0 -0
  154. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/formatting_test.py +0 -0
  155. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/hierarchical.py +0 -0
  156. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/hierarchical_test.py +0 -0
  157. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/json_conversion.py +0 -0
  158. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/json_conversion_test.py +0 -0
  159. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/missing.py +0 -0
  160. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/missing_test.py +0 -0
  161. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/text_color.py +0 -0
  162. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/thread_local.py +0 -0
  163. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/thread_local_test.py +0 -0
  164. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/timing.py +0 -0
  165. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/value_location.py +0 -0
  166. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/utils/value_location_test.py +0 -0
  167. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/__init__.py +0 -0
  168. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/base.py +0 -0
  169. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/base_test.py +0 -0
  170. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/__init__.py +0 -0
  171. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/base.py +0 -0
  172. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/base_test.py +0 -0
  173. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/__init__.py +0 -0
  174. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/base.py +0 -0
  175. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/label.py +0 -0
  176. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/label_test.py +0 -0
  177. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/progress_bar.py +0 -0
  178. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/progress_bar_test.py +0 -0
  179. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/tab.py +0 -0
  180. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/tab_test.py +0 -0
  181. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/tooltip.py +0 -0
  182. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/controls/tooltip_test.py +0 -0
  183. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/tree_view.py +0 -0
  184. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/core/views/html/tree_view_test.py +0 -0
  185. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/__init__.py +0 -0
  186. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/early_stopping/__init__.py +0 -0
  187. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/early_stopping/base.py +0 -0
  188. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/early_stopping/base_test.py +0 -0
  189. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/early_stopping/step_wise.py +0 -0
  190. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/early_stopping/step_wise_test.py +0 -0
  191. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/__init__.py +0 -0
  192. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/base.py +0 -0
  193. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/base_test.py +0 -0
  194. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/hill_climb.py +0 -0
  195. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/hill_climb_test.py +0 -0
  196. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/mutators.py +0 -0
  197. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/mutators_test.py +0 -0
  198. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/neat.py +0 -0
  199. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/neat_test.py +0 -0
  200. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/nsga2.py +0 -0
  201. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/nsga2_test.py +0 -0
  202. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/recombinators.py +0 -0
  203. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/recombinators_test.py +0 -0
  204. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/regularized_evolution.py +0 -0
  205. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/regularized_evolution_test.py +0 -0
  206. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/selectors.py +0 -0
  207. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/selectors_test.py +0 -0
  208. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/where.py +0 -0
  209. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/evolution/where_test.py +0 -0
  210. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/mutfun/__init__.py +0 -0
  211. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/mutfun/base.py +0 -0
  212. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/mutfun/base_test.py +0 -0
  213. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/mutfun/basic_ops.py +0 -0
  214. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/mutfun/basic_ops_test.py +0 -0
  215. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/__init__.py +0 -0
  216. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/base.py +0 -0
  217. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/base_test.py +0 -0
  218. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/maths.py +0 -0
  219. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/maths_test.py +0 -0
  220. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/randoms.py +0 -0
  221. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/randoms_test.py +0 -0
  222. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/step_wise.py +0 -0
  223. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove/ext/scalars/step_wise_test.py +0 -0
  224. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove.egg-info/dependency_links.txt +0 -0
  225. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove.egg-info/requires.txt +0 -0
  226. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/pyglove.egg-info/top_level.txt +0 -0
  227. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/setup.cfg +0 -0
  228. {pyglove-0.4.5.dev202505150810 → pyglove-0.4.5.dev202505160313}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyglove
3
- Version: 0.4.5.dev202505150810
3
+ Version: 0.4.5.dev202505160313
4
4
  Summary: PyGlove: A library for manipulating Python objects.
5
5
  Home-page: https://github.com/google/pyglove
6
6
  Author: PyGlove Authors
@@ -145,5 +145,6 @@ from pyglove.core.symbolic.list import mark_as_insertion
145
145
 
146
146
  # Error types.
147
147
  from pyglove.core.symbolic.base import WritePermissionError
148
+ from pyglove.core.symbolic.error_info import ErrorInfo
148
149
 
149
150
  # pylint: enable=g-bad-import-order
@@ -0,0 +1,127 @@
1
+ # Copyright 2025 The PyGlove Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """Symbolic class for capture error information."""
15
+
16
+ from typing import Annotated, List
17
+ from pyglove.core import utils
18
+ from pyglove.core.symbolic import dict as pg_dict # pylint: disable=unused-import
19
+ from pyglove.core.symbolic import list as pg_list # pylint: disable=unused-import
20
+ from pyglove.core.symbolic import object as pg_object
21
+ from pyglove.core.views.html import controls
22
+ from pyglove.core.views.html import tree_view
23
+
24
+
25
+ @pg_object.members(
26
+ [],
27
+ # For backwards compatibility.
28
+ additional_keys=['pyglove.core.utils.error_utils.ErrorInfo']
29
+ )
30
+ class ErrorInfo(
31
+ pg_object.Object,
32
+ utils.ErrorInfo,
33
+ tree_view.HtmlTreeView.Extension
34
+ ):
35
+ """Symbolic error info."""
36
+
37
+ tag: Annotated[
38
+ str,
39
+ (
40
+ 'A path of the error types in the exception chain. For example, '
41
+ '`ValueError.ZeroDivisionError` means the error is a '
42
+ '`ZeroDivisionError` raised at the first place and then reraised as '
43
+ 'a `ValueError`.'
44
+ )
45
+ ]
46
+
47
+ description: Annotated[
48
+ str,
49
+ 'The description of the error.',
50
+ ]
51
+
52
+ stacktrace: Annotated[
53
+ str,
54
+ 'The stacktrace of the error.',
55
+ ]
56
+
57
+ def _html_tree_view_summary(
58
+ self,
59
+ *,
60
+ view: tree_view.HtmlTreeView,
61
+ **kwargs
62
+ ) -> tree_view.Html:
63
+ kwargs.pop('title', None)
64
+ kwargs.pop('enable_summary_tooltip', None)
65
+ return view.summary(
66
+ self,
67
+ title=tree_view.Html.element(
68
+ 'div',
69
+ [
70
+ 'ErrorInfo',
71
+ controls.Label(self.tag, css_classes=['error_tag']),
72
+ ],
73
+ styles=dict(display='inline-block')
74
+ ),
75
+ enable_summary_tooltip=False,
76
+ **kwargs
77
+ )
78
+
79
+ def _html_tree_view_content(self, **kwargs) -> tree_view.Html:
80
+ del kwargs
81
+ return controls.TabControl([
82
+ controls.Tab(
83
+ 'description',
84
+ tree_view.Html.element(
85
+ 'div',
86
+ [
87
+ tree_view.Html.escape(utils.decolor(self.description))
88
+ ],
89
+ css_classes=['error_text']
90
+ )
91
+ ),
92
+ controls.Tab(
93
+ 'stacktrace',
94
+ tree_view.Html.element(
95
+ 'div',
96
+ [
97
+ tree_view.Html.escape(utils.decolor(self.stacktrace))
98
+ ],
99
+ css_classes=['error_text']
100
+ )
101
+ )
102
+ ]).to_html()
103
+
104
+ @classmethod
105
+ def _html_tree_view_css_styles(cls) -> List[str]:
106
+ return super()._html_tree_view_css_styles() + [
107
+ '''
108
+ .error_tag {
109
+ background-color: red;
110
+ border-radius: 5px;
111
+ padding: 5px;
112
+ margin-left: 5px;
113
+ color: white;
114
+ font-size: small;
115
+ }
116
+ .error_text {
117
+ display: block;
118
+ white-space: pre-wrap;
119
+ padding: 0.5em;
120
+ margin-top: 0.15em;
121
+ background-color: #f2f2f2;
122
+ }
123
+ '''
124
+ ]
125
+
126
+ # Use the symbolic error info class as the default ErrorInfo implementation.
127
+ utils.ErrorInfo._IMPLEMENTATION = ErrorInfo # pylint: disable=protected-access
@@ -0,0 +1,92 @@
1
+ # Copyright 2025 The PyGlove Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import inspect
16
+ import unittest
17
+ from pyglove.core.symbolic import base
18
+ from pyglove.core.symbolic import error_info as error_info_lib # pylint: disable=g-bad-import-order
19
+
20
+
21
+ class ErrorInfoTest(unittest.TestCase):
22
+ """Tests for ErrorInfo."""
23
+
24
+ def test_from_exception(self):
25
+
26
+ def foo():
27
+ return 1 / 0
28
+
29
+ def bar():
30
+ try:
31
+ foo()
32
+ except ZeroDivisionError as e:
33
+ raise ValueError('Bad call to `foo`') from e
34
+
35
+ error_info = None
36
+ try:
37
+ bar()
38
+ except ValueError as e:
39
+ error_info = error_info_lib.ErrorInfo.from_exception(e)
40
+ self.assertIsNotNone(error_info)
41
+ self.assertEqual(error_info.tag, 'ValueError.ZeroDivisionError')
42
+ self.assertEqual(error_info.description, 'Bad call to `foo`')
43
+ self.assertIn('Traceback (most recent call last)', error_info.stacktrace)
44
+
45
+ def test_to_json(self):
46
+ error_info = error_info_lib.ErrorInfo(
47
+ tag='ValueError.ZeroDivisionError',
48
+ description='Bad call to `foo`',
49
+ stacktrace='Traceback (most recent call last)',
50
+ )
51
+ json_dict = error_info.to_json()
52
+ error_info2 = base.from_json(json_dict)
53
+ self.assertIsNot(error_info2, error_info)
54
+ self.assertEqual(error_info2, error_info)
55
+ json_dict['_type'] = 'pyglove.core.utils.error_utils.ErrorInfo'
56
+ error_info2 = base.from_json(json_dict)
57
+ self.assertEqual(error_info2, error_info)
58
+
59
+ def test_format(self):
60
+ error_info = error_info_lib.ErrorInfo(
61
+ tag='ValueError.ZeroDivisionError',
62
+ description='Bad call to `foo`',
63
+ stacktrace='Traceback (most recent call last)',
64
+ )
65
+ self.assertEqual(
66
+ error_info.format(compact=False),
67
+ inspect.cleandoc(
68
+ """
69
+ ErrorInfo(
70
+ tag = 'ValueError.ZeroDivisionError',
71
+ description = 'Bad call to `foo`',
72
+ stacktrace = 'Traceback (most recent call last)'
73
+ )
74
+ """
75
+ )
76
+ )
77
+
78
+ def test_to_html(self):
79
+ error_info = error_info_lib.ErrorInfo(
80
+ tag='ValueError.ZeroDivisionError',
81
+ description='Bad call to `foo`',
82
+ stacktrace='Traceback (most recent call last)',
83
+ )
84
+ html = error_info.to_html()
85
+ self.assertIn('ErrorInfo', html.content)
86
+ self.assertIn('ValueError.ZeroDivisionError', html.content)
87
+ self.assertIn('Bad call to `foo`', html.content)
88
+ self.assertIn('Traceback (most recent call last)', html.content)
89
+
90
+
91
+ if __name__ == '__main__':
92
+ unittest.main()
@@ -101,6 +101,18 @@ class ObjectMeta(abc.ABCMeta):
101
101
  )
102
102
  cls.apply_schema(schema)
103
103
 
104
+ # Update abstract methods.
105
+ # abc.update_abstractmethods is only available in Python 3.10 and above.
106
+ if sys.version_info >= (3, 10):
107
+ abc.update_abstractmethods(cls)
108
+ elif cls.allow_symbolic_attribute:
109
+ abstract_methods = getattr(cls, '__abstractmethods__', frozenset())
110
+ new_abstract_methods = []
111
+ for name in abstract_methods:
112
+ if name not in cls.__schema__.fields:
113
+ new_abstract_methods.append(name)
114
+ setattr(cls, '__abstractmethods__', frozenset(new_abstract_methods))
115
+
104
116
  def register_for_deserialization(
105
117
  cls,
106
118
  serialization_key: Optional[str] = None,
@@ -506,7 +518,10 @@ class Object(base.Symbolic, metaclass=ObjectMeta):
506
518
  attr_value = getattr(cls, attr_name, pg_typing.MISSING_VALUE)
507
519
  if attr_value == pg_typing.MISSING_VALUE or (
508
520
  not inspect.isfunction(attr_value)
509
- and not isinstance(attr_value, property)
521
+ and (
522
+ not isinstance(attr_value, property)
523
+ or getattr(attr_value, '__isabstractmethod__', False)
524
+ )
510
525
  ):
511
526
  setattr(cls, attr_name, cls._create_sym_attribute(attr_name, field))
512
527
 
@@ -517,7 +532,7 @@ class Object(base.Symbolic, metaclass=ObjectMeta):
517
532
  coding.make_function(
518
533
  attr_name,
519
534
  ['self'],
520
- [f"return self.sym_inferred('{attr_name}')"],
535
+ [f'return self.sym_inferred(\'{attr_name}\')'],
521
536
  return_type=field.value.annotation,
522
537
  )
523
538
  )
@@ -11,6 +11,7 @@
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
+ import abc
14
15
  import copy
15
16
  import inspect
16
17
  import io
@@ -493,6 +494,33 @@ class ObjectTest(unittest.TestCase):
493
494
  self.assertEqual(b.x, 2)
494
495
  self.assertEqual(b.sym_init_args.x, 1)
495
496
 
497
+ def test_override_abstract_property(self):
498
+ class A(metaclass=abc.ABCMeta):
499
+
500
+ @property
501
+ @abc.abstractmethod
502
+ def x(self):
503
+ pass
504
+
505
+ class B(Object, A):
506
+ x: int
507
+
508
+ self.assertEqual(B(1).x, 1)
509
+
510
+ def test_override_abstract_property_with_members_decorator(self):
511
+ class A(metaclass=abc.ABCMeta):
512
+
513
+ @property
514
+ @abc.abstractmethod
515
+ def x(self):
516
+ pass
517
+
518
+ class B(Object, A):
519
+ pass
520
+
521
+ pg_members([('x', pg_typing.Int())])(B)
522
+ self.assertEqual(B(1).x, 1) # pylint: disable=abstract-class-instantiated
523
+
496
524
  def test_runtime_type_check(self):
497
525
 
498
526
  @pg_members([
@@ -13,33 +13,37 @@
13
13
  # limitations under the License.
14
14
  """Utilities for working with errors."""
15
15
 
16
+ import abc
16
17
  import contextlib
17
18
  import dataclasses
18
19
  import inspect
19
20
  import re
20
21
  import sys
21
22
  import traceback
22
- from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, Union
23
+ from typing import Callable, Dict, List, Optional, Sequence, Tuple, Type, Union
23
24
 
24
- from pyglove.core.utils import formatting
25
- from pyglove.core.utils import json_conversion
26
25
 
26
+ class ErrorInfo(metaclass=abc.ABCMeta):
27
+ """Interface for error information."""
27
28
 
28
- @dataclasses.dataclass(frozen=True)
29
- class ErrorInfo(json_conversion.JSONConvertible, formatting.Formattable):
30
- """Serializable error information.
29
+ # The implementation of ErrorInfo will be a symbolic class, which is
30
+ # defined in pyglove.core.symbolic.error_info and will be assigned later.
31
+ _IMPLEMENTATION = None
31
32
 
32
- Attributes:
33
- tag: A path of the error types in the exception chain. For example,
34
- `ValueError.ZeroDivisionError` means the error is a `ZeroDivisionError`
35
- raised at the first place and then reraised as a `ValueError`.
36
- description: The description of the error.
37
- stacktrace: The stacktrace of the error.
38
- """
33
+ @property
34
+ @abc.abstractmethod
35
+ def tag(self) -> str:
36
+ """A path of the error types in the exception chain."""
37
+
38
+ @property
39
+ @abc.abstractmethod
40
+ def description(self) -> str:
41
+ """The description of the error."""
39
42
 
40
- tag: str
41
- description: str
42
- stacktrace: str
43
+ @property
44
+ @abc.abstractmethod
45
+ def stacktrace(self) -> str:
46
+ """The stacktrace of the error."""
43
47
 
44
48
  @classmethod
45
49
  def _compute_tag(cls, error: BaseException):
@@ -52,7 +56,8 @@ class ErrorInfo(json_conversion.JSONConvertible, formatting.Formattable):
52
56
  @classmethod
53
57
  def from_exception(cls, error: BaseException) -> 'ErrorInfo':
54
58
  """Creates an error info from an exception."""
55
- return cls(
59
+ assert cls._IMPLEMENTATION is not None, 'ErrorInfo is not implemented.'
60
+ return cls._IMPLEMENTATION( # pytype: disable=wrong-arg-types
56
61
  tag=cls._compute_tag(error),
57
62
  description=str(error),
58
63
  stacktrace=''.join(
@@ -60,29 +65,6 @@ class ErrorInfo(json_conversion.JSONConvertible, formatting.Formattable):
60
65
  )
61
66
  )
62
67
 
63
- def to_json(self, **kwargs) -> Dict[str, Any]:
64
- return self.to_json_dict(
65
- fields=dict(
66
- tag=(self.tag, None),
67
- description=(self.description, None),
68
- stacktrace=(self.stacktrace, None),
69
- ),
70
- exclude_default=True,
71
- **kwargs,
72
- )
73
-
74
- def format(self, *args, **kwargs) -> str:
75
- return formatting.kvlist_str(
76
- [
77
- ('tag', self.tag, None),
78
- ('description', self.description, None),
79
- ('stacktrace', self.stacktrace, None),
80
- ],
81
- *args,
82
- label=self.__class__.__name__,
83
- **kwargs,
84
- )
85
-
86
68
 
87
69
  @dataclasses.dataclass()
88
70
  class CatchErrorsContext:
@@ -11,66 +11,10 @@
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
- import inspect
15
14
  import unittest
16
15
  from pyglove.core.utils import error_utils
17
16
 
18
17
 
19
- class ErrorInfoTest(unittest.TestCase):
20
- """Tests for ErrorInfo."""
21
-
22
- def test_from_exception(self):
23
-
24
- def foo():
25
- return 1 / 0
26
-
27
- def bar():
28
- try:
29
- foo()
30
- except ZeroDivisionError as e:
31
- raise ValueError('Bad call to `foo`') from e
32
-
33
- error_info = None
34
- try:
35
- bar()
36
- except ValueError as e:
37
- error_info = error_utils.ErrorInfo.from_exception(e)
38
- self.assertIsNotNone(error_info)
39
- self.assertEqual(error_info.tag, 'ValueError.ZeroDivisionError')
40
- self.assertEqual(error_info.description, 'Bad call to `foo`')
41
- self.assertIn('Traceback (most recent call last)', error_info.stacktrace)
42
-
43
- def test_to_json(self):
44
- error_info = error_utils.ErrorInfo(
45
- tag='ValueError.ZeroDivisionError',
46
- description='Bad call to `foo`',
47
- stacktrace='Traceback (most recent call last)',
48
- )
49
- json_dict = error_info.to_json()
50
- error_info2 = error_utils.ErrorInfo.from_json(json_dict)
51
- self.assertIsNot(error_info2, error_info)
52
- self.assertEqual(error_info2, error_info)
53
-
54
- def test_format(self):
55
- error_info = error_utils.ErrorInfo(
56
- tag='ValueError.ZeroDivisionError',
57
- description='Bad call to `foo`',
58
- stacktrace='Traceback (most recent call last)',
59
- )
60
- self.assertEqual(
61
- error_info.format(compact=False),
62
- inspect.cleandoc(
63
- """
64
- ErrorInfo(
65
- tag='ValueError.ZeroDivisionError',
66
- description='Bad call to `foo`',
67
- stacktrace='Traceback (most recent call last)'
68
- )
69
- """
70
- )
71
- )
72
-
73
-
74
18
  class CatchErrorsTest(unittest.TestCase):
75
19
 
76
20
  def assert_caught_error(self, func, errors_to_catch):
@@ -48,13 +48,16 @@ class TextColorTest(unittest.TestCase):
48
48
  block_color = text_color.colored(
49
49
  'TEXT', color='white', background='blue'
50
50
  ).split('TEXT')[0]
51
- self.assertEqual(
52
- colored_text,
51
+ expected = (
53
52
  f'{origin_color}Hi {block_color}<< foo >>{reset}{origin_color}\n'
54
53
  '<# print x if x is present #>\n<% if x %>\n'
55
54
  f'{block_color}<< x >>{reset}{origin_color}\n'
56
55
  f'<% endif %>{reset}'
57
56
  )
57
+ self.assertTrue(
58
+ # On some termcolor versions, the color codes are not applied.
59
+ colored_text == expected or colored_text == original_text
60
+ )
58
61
  self.assertEqual(text_color.decolor(colored_text), original_text)
59
62
 
60
63
  def test_colored_block_without_full_match(self):
@@ -14,6 +14,7 @@
14
14
  import time
15
15
  import unittest
16
16
 
17
+ from pyglove.core.symbolic import error_info # pylint: disable=unused-import
17
18
  from pyglove.core.utils import json_conversion
18
19
  from pyglove.core.utils import timing
19
20
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyglove
3
- Version: 0.4.5.dev202505150810
3
+ Version: 0.4.5.dev202505160313
4
4
  Summary: PyGlove: A library for manipulating Python objects.
5
5
  Home-page: https://github.com/google/pyglove
6
6
  Author: PyGlove Authors
@@ -88,6 +88,8 @@ pyglove/core/symbolic/dict.py
88
88
  pyglove/core/symbolic/dict_test.py
89
89
  pyglove/core/symbolic/diff.py
90
90
  pyglove/core/symbolic/diff_test.py
91
+ pyglove/core/symbolic/error_info.py
92
+ pyglove/core/symbolic/error_info_test.py
91
93
  pyglove/core/symbolic/flags.py
92
94
  pyglove/core/symbolic/flags_test.py
93
95
  pyglove/core/symbolic/functor.py