pyglove 0.5.0.dev202510220812__tar.gz → 0.5.0.dev202510230131__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.

Potentially problematic release.


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

Files changed (230) hide show
  1. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/PKG-INFO +1 -1
  2. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/base.py +7 -3
  3. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/base.py +64 -27
  4. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/base_test.py +3 -3
  5. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/dict.py +13 -5
  6. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/dict_test.py +26 -0
  7. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/list.py +17 -3
  8. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/list_test.py +23 -0
  9. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/object.py +1 -0
  10. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/ref.py +19 -7
  11. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/ref_test.py +94 -7
  12. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/annotation_conversion.py +5 -1
  13. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/annotation_conversion_test.py +3 -0
  14. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/__init__.py +1 -0
  15. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/json_conversion.py +254 -15
  16. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/json_conversion_test.py +61 -3
  17. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove.egg-info/PKG-INFO +1 -1
  18. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/LICENSE +0 -0
  19. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/README.md +0 -0
  20. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/__init__.py +0 -0
  21. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/__init__.py +0 -0
  22. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/__init__.py +0 -0
  23. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/errors.py +0 -0
  24. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/errors_test.py +0 -0
  25. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/execution.py +0 -0
  26. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/execution_test.py +0 -0
  27. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/function_generation.py +0 -0
  28. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/function_generation_test.py +0 -0
  29. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/parsing.py +0 -0
  30. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/parsing_test.py +0 -0
  31. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/permissions.py +0 -0
  32. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/coding/permissions_test.py +0 -0
  33. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/detouring/__init__.py +0 -0
  34. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/detouring/class_detour.py +0 -0
  35. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/detouring/class_detour_test.py +0 -0
  36. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/__init__.py +0 -0
  37. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/base_test.py +0 -0
  38. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/categorical.py +0 -0
  39. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/categorical_test.py +0 -0
  40. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/custom.py +0 -0
  41. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/custom_test.py +0 -0
  42. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/deduping.py +0 -0
  43. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/deduping_test.py +0 -0
  44. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/dna_generator.py +0 -0
  45. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/dna_generator_test.py +0 -0
  46. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/numerical.py +0 -0
  47. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/numerical_test.py +0 -0
  48. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/random.py +0 -0
  49. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/random_test.py +0 -0
  50. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/space.py +0 -0
  51. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/space_test.py +0 -0
  52. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/sweeping.py +0 -0
  53. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/geno/sweeping_test.py +0 -0
  54. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/__init__.py +0 -0
  55. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/base.py +0 -0
  56. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/categorical.py +0 -0
  57. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/categorical_test.py +0 -0
  58. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/custom.py +0 -0
  59. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/custom_test.py +0 -0
  60. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/derived.py +0 -0
  61. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/derived_test.py +0 -0
  62. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/dynamic_evaluation.py +0 -0
  63. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/dynamic_evaluation_test.py +0 -0
  64. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/evolvable.py +0 -0
  65. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/evolvable_test.py +0 -0
  66. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/iter.py +0 -0
  67. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/iter_test.py +0 -0
  68. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/numerical.py +0 -0
  69. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/numerical_test.py +0 -0
  70. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/object_template.py +0 -0
  71. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/hyper/object_template_test.py +0 -0
  72. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/io/__init__.py +0 -0
  73. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/io/file_system.py +0 -0
  74. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/io/file_system_test.py +0 -0
  75. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/io/sequence.py +0 -0
  76. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/io/sequence_test.py +0 -0
  77. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/logging.py +0 -0
  78. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/logging_test.py +0 -0
  79. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/monitoring.py +0 -0
  80. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/monitoring_test.py +0 -0
  81. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/patching/__init__.py +0 -0
  82. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/patching/object_factory.py +0 -0
  83. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/patching/object_factory_test.py +0 -0
  84. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/patching/pattern_based.py +0 -0
  85. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/patching/pattern_based_test.py +0 -0
  86. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/patching/rule_based.py +0 -0
  87. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/patching/rule_based_test.py +0 -0
  88. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/__init__.py +0 -0
  89. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/boilerplate.py +0 -0
  90. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/boilerplate_test.py +0 -0
  91. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/class_wrapper.py +0 -0
  92. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/class_wrapper_test.py +0 -0
  93. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/compounding.py +0 -0
  94. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/compounding_test.py +0 -0
  95. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/contextual_object.py +0 -0
  96. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/contextual_object_test.py +0 -0
  97. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/diff.py +0 -0
  98. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/diff_test.py +0 -0
  99. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/error_info.py +0 -0
  100. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/error_info_test.py +0 -0
  101. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/flags.py +0 -0
  102. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/flags_test.py +0 -0
  103. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/functor.py +0 -0
  104. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/functor_test.py +0 -0
  105. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/inferred.py +0 -0
  106. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/inferred_test.py +0 -0
  107. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/object_test.py +0 -0
  108. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/origin.py +0 -0
  109. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/origin_test.py +0 -0
  110. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/pure_symbolic.py +0 -0
  111. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/symbolize.py +0 -0
  112. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/symbolic/symbolize_test.py +0 -0
  113. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/__init__.py +0 -0
  114. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/backend.py +0 -0
  115. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/backend_test.py +0 -0
  116. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/early_stopping.py +0 -0
  117. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/local_backend.py +0 -0
  118. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/protocols.py +0 -0
  119. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/protocols_test.py +0 -0
  120. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/sample.py +0 -0
  121. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/tuning/sample_test.py +0 -0
  122. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/__init__.py +0 -0
  123. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/annotated.py +0 -0
  124. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/annotated_test.py +0 -0
  125. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/annotation_future_test.py +0 -0
  126. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/callable_ext.py +0 -0
  127. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/callable_ext_test.py +0 -0
  128. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/callable_signature.py +0 -0
  129. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/callable_signature_test.py +0 -0
  130. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/class_schema.py +0 -0
  131. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/class_schema_test.py +0 -0
  132. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/custom_typing.py +0 -0
  133. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/inspect.py +0 -0
  134. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/inspect_test.py +0 -0
  135. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/json_schema.py +0 -0
  136. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/json_schema_test.py +0 -0
  137. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/key_specs.py +0 -0
  138. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/key_specs_test.py +0 -0
  139. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/pytype_support.py +0 -0
  140. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/type_conversion.py +0 -0
  141. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/type_conversion_test.py +0 -0
  142. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/typed_missing.py +0 -0
  143. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/typed_missing_test.py +0 -0
  144. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/value_specs.py +0 -0
  145. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/typing/value_specs_test.py +0 -0
  146. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/common_traits.py +0 -0
  147. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/common_traits_test.py +0 -0
  148. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/contextual.py +0 -0
  149. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/contextual_test.py +0 -0
  150. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/docstr_utils.py +0 -0
  151. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/docstr_utils_test.py +0 -0
  152. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/error_utils.py +0 -0
  153. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/error_utils_test.py +0 -0
  154. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/formatting.py +0 -0
  155. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/formatting_test.py +0 -0
  156. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/hierarchical.py +0 -0
  157. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/hierarchical_test.py +0 -0
  158. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/missing.py +0 -0
  159. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/missing_test.py +0 -0
  160. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/text_color.py +0 -0
  161. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/text_color_test.py +0 -0
  162. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/thread_local.py +0 -0
  163. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/thread_local_test.py +0 -0
  164. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/timing.py +0 -0
  165. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/timing_test.py +0 -0
  166. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/value_location.py +0 -0
  167. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/utils/value_location_test.py +0 -0
  168. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/__init__.py +0 -0
  169. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/base.py +0 -0
  170. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/base_test.py +0 -0
  171. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/__init__.py +0 -0
  172. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/base.py +0 -0
  173. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/base_test.py +0 -0
  174. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/__init__.py +0 -0
  175. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/base.py +0 -0
  176. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/label.py +0 -0
  177. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/label_test.py +0 -0
  178. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/progress_bar.py +0 -0
  179. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/progress_bar_test.py +0 -0
  180. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/tab.py +0 -0
  181. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/tab_test.py +0 -0
  182. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/tooltip.py +0 -0
  183. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/controls/tooltip_test.py +0 -0
  184. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/tree_view.py +0 -0
  185. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/core/views/html/tree_view_test.py +0 -0
  186. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/__init__.py +0 -0
  187. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/early_stopping/__init__.py +0 -0
  188. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/early_stopping/base.py +0 -0
  189. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/early_stopping/base_test.py +0 -0
  190. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/early_stopping/step_wise.py +0 -0
  191. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/early_stopping/step_wise_test.py +0 -0
  192. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/__init__.py +0 -0
  193. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/base.py +0 -0
  194. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/base_test.py +0 -0
  195. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/hill_climb.py +0 -0
  196. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/hill_climb_test.py +0 -0
  197. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/mutators.py +0 -0
  198. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/mutators_test.py +0 -0
  199. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/neat.py +0 -0
  200. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/neat_test.py +0 -0
  201. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/nsga2.py +0 -0
  202. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/nsga2_test.py +0 -0
  203. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/recombinators.py +0 -0
  204. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/recombinators_test.py +0 -0
  205. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/regularized_evolution.py +0 -0
  206. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/regularized_evolution_test.py +0 -0
  207. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/selectors.py +0 -0
  208. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/selectors_test.py +0 -0
  209. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/where.py +0 -0
  210. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/evolution/where_test.py +0 -0
  211. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/mutfun/__init__.py +0 -0
  212. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/mutfun/base.py +0 -0
  213. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/mutfun/base_test.py +0 -0
  214. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/mutfun/basic_ops.py +0 -0
  215. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/mutfun/basic_ops_test.py +0 -0
  216. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/__init__.py +0 -0
  217. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/base.py +0 -0
  218. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/base_test.py +0 -0
  219. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/maths.py +0 -0
  220. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/maths_test.py +0 -0
  221. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/randoms.py +0 -0
  222. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/randoms_test.py +0 -0
  223. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/step_wise.py +0 -0
  224. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove/ext/scalars/step_wise_test.py +0 -0
  225. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove.egg-info/SOURCES.txt +0 -0
  226. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove.egg-info/dependency_links.txt +0 -0
  227. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove.egg-info/requires.txt +0 -0
  228. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/pyglove.egg-info/top_level.txt +0 -0
  229. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/setup.cfg +0 -0
  230. {pyglove-0.5.0.dev202510220812 → pyglove-0.5.0.dev202510230131}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyglove
3
- Version: 0.5.0.dev202510220812
3
+ Version: 0.5.0.dev202510230131
4
4
  Summary: PyGlove: A library for manipulating Python objects.
5
5
  Home-page: https://github.com/google/pyglove
6
6
  Author: PyGlove Authors
@@ -1447,6 +1447,7 @@ class DNA(symbolic.Object):
1447
1447
  *,
1448
1448
  allow_partial: bool = False,
1449
1449
  root_path: Optional[utils.KeyPath] = None,
1450
+ **kwargs,
1450
1451
  ) -> 'DNA':
1451
1452
  """Class method that load a DNA from a JSON value.
1452
1453
 
@@ -1454,6 +1455,7 @@ class DNA(symbolic.Object):
1454
1455
  json_value: Input JSON value, only JSON dict is acceptable.
1455
1456
  allow_partial: Whether to allow elements of the list to be partial.
1456
1457
  root_path: KeyPath of loaded object in its object tree.
1458
+ **kwargs: Keyword arguments that will be passed to symbolic.from_json.
1457
1459
 
1458
1460
  Returns:
1459
1461
  A DNA object.
@@ -1463,16 +1465,18 @@ class DNA(symbolic.Object):
1463
1465
  # NOTE(daiyip): DNA.parse will validate the input. Therefore, we can
1464
1466
  # disable runtime type check during constructing the DNA objects.
1465
1467
  with symbolic.enable_type_check(False):
1466
- dna = DNA.parse(symbolic.from_json(json_value.get('value')))
1468
+ dna = DNA.parse(symbolic.from_json(json_value.get('value'), **kwargs))
1467
1469
  if 'metadata' in json_value:
1468
1470
  dna.rebind(
1469
- metadata=symbolic.from_json(json_value.get('metadata')),
1471
+ metadata=symbolic.from_json(json_value.get('metadata'), **kwargs),
1470
1472
  raise_on_no_change=False, skip_notification=True)
1471
1473
  else:
1472
1474
  dna = super(DNA, cls).from_json(
1473
1475
  json_value,
1474
1476
  allow_partial=allow_partial,
1475
- root_path=root_path) # pytype: disable=bad-return-type
1477
+ root_path=root_path,
1478
+ **kwargs,
1479
+ ) # pytype: disable=bad-return-type
1476
1480
  assert isinstance(dna, DNA)
1477
1481
  if cloneable_metadata_keys:
1478
1482
  dna._cloneable_metadata_keys = set(cloneable_metadata_keys) # pylint: disable=protected-access
@@ -946,7 +946,7 @@ class Symbolic(
946
946
 
947
947
  def to_json(self, **kwargs) -> utils.JSONValueType:
948
948
  """Alias for `sym_jsonify`."""
949
- return to_json(self, **kwargs)
949
+ return utils.to_json(self, **kwargs)
950
950
 
951
951
  def to_json_str(self, json_indent: Optional[int] = None, **kwargs) -> str:
952
952
  """Serializes current object into a JSON string."""
@@ -1985,10 +1985,12 @@ def is_abstract(x: Any) -> bool:
1985
1985
  def contains(
1986
1986
  x: Any,
1987
1987
  value: Any = None,
1988
- type: Optional[Union[ # pylint: disable=redefined-builtin
1988
+ type: Union[ # pylint: disable=redefined-builtin
1989
1989
  Type[Any],
1990
- Tuple[Type[Any]]]]=None
1991
- ) -> bool:
1990
+ Tuple[Type[Any], ...],
1991
+ None,
1992
+ ]=None,
1993
+ ) -> bool:
1992
1994
  """Returns if a value contains values of specific type.
1993
1995
 
1994
1996
  Example::
@@ -2037,10 +2039,12 @@ def contains(
2037
2039
  def from_json(
2038
2040
  json_value: Any,
2039
2041
  *,
2040
- allow_partial: bool = False,
2041
- root_path: Optional[utils.KeyPath] = None,
2042
+ context: Optional[utils.JSONConversionContext] = None,
2043
+ auto_symbolic: bool = True,
2042
2044
  auto_import: bool = True,
2043
2045
  auto_dict: bool = False,
2046
+ allow_partial: bool = False,
2047
+ root_path: Optional[utils.KeyPath] = None,
2044
2048
  value_spec: Optional[pg_typing.ValueSpec] = None,
2045
2049
  **kwargs,
2046
2050
  ) -> Any:
@@ -2061,14 +2065,18 @@ def from_json(
2061
2065
 
2062
2066
  Args:
2063
2067
  json_value: Input JSON value.
2064
- allow_partial: Whether to allow elements of the list to be partial.
2065
- root_path: KeyPath of loaded object in its object tree.
2068
+ context: JSON conversion context.
2069
+ auto_symbolic: If True, list and dict will be automatically converted to
2070
+ `pg.List` and `pg.Dict`. Otherwise, they will be plain lists
2071
+ and dicts.
2066
2072
  auto_import: If True, when a '_type' is not registered, PyGlove will
2067
2073
  identify its parent module and automatically import it. For example,
2068
2074
  if the type is 'foo.bar.A', PyGlove will try to import 'foo.bar' and
2069
2075
  find the class 'A' within the imported module.
2070
2076
  auto_dict: If True, dict with '_type' that cannot be loaded will remain
2071
2077
  as dict, with '_type' renamed to 'type_name'.
2078
+ allow_partial: Whether to allow elements of the list to be partial.
2079
+ root_path: KeyPath of loaded object in its object tree.
2072
2080
  value_spec: The value spec for the symbolic list or dict.
2073
2081
  **kwargs: Allow passing through keyword arguments to from_json of specific
2074
2082
  types.
@@ -2084,10 +2092,18 @@ def from_json(
2084
2092
  if isinstance(json_value, Symbolic):
2085
2093
  return json_value
2086
2094
 
2095
+ if context is None:
2096
+ if (isinstance(json_value, dict) and (
2097
+ context_node := json_value.get(utils.JSONConvertible.CONTEXT_KEY))):
2098
+ context = utils.JSONConversionContext.from_json(context_node, **kwargs)
2099
+ json_value = json_value[utils.JSONConvertible.ROOT_VALUE_KEY]
2100
+ else:
2101
+ context = utils.JSONConversionContext()
2102
+
2087
2103
  typename_resolved = kwargs.pop('_typename_resolved', False)
2088
2104
  if not typename_resolved:
2089
2105
  json_value = utils.json_conversion.resolve_typenames(
2090
- json_value, auto_import=auto_import, auto_dict=auto_dict
2106
+ json_value, auto_import, auto_dict
2091
2107
  )
2092
2108
 
2093
2109
  def _load_child(k, v):
@@ -2096,6 +2112,7 @@ def from_json(
2096
2112
  root_path=utils.KeyPath(k, root_path),
2097
2113
  _typename_resolved=True,
2098
2114
  allow_partial=allow_partial,
2115
+ context=context,
2099
2116
  **kwargs,
2100
2117
  )
2101
2118
 
@@ -2111,24 +2128,42 @@ def from_json(
2111
2128
  )
2112
2129
  )
2113
2130
  return tuple(_load_child(i, v) for i, v in enumerate(json_value[1:]))
2114
- return Symbolic.ListType.from_json( # pytype: disable=attribute-error
2131
+ if json_value and json_value[0] == utils.JSONConvertible.SYMBOLIC_MARKER:
2132
+ auto_symbolic = True
2133
+ if auto_symbolic:
2134
+ from_json_fn = Symbolic.ListType.from_json # pytype: disable=attribute-error
2135
+ else:
2136
+ from_json_fn = utils.from_json
2137
+ return from_json_fn(
2115
2138
  json_value,
2139
+ context=context,
2116
2140
  value_spec=value_spec,
2117
2141
  root_path=root_path,
2118
2142
  allow_partial=allow_partial,
2119
2143
  **kwargs,
2120
2144
  )
2121
2145
  elif isinstance(json_value, dict):
2146
+ if utils.JSONConvertible.REF_KEY in json_value:
2147
+ x = context.get_shared(
2148
+ json_value[utils.JSONConvertible.REF_KEY]
2149
+ ).value
2150
+ return x
2122
2151
  if utils.JSONConvertible.TYPE_NAME_KEY not in json_value:
2123
- return Symbolic.DictType.from_json( # pytype: disable=attribute-error
2124
- json_value,
2125
- value_spec=value_spec,
2126
- root_path=root_path,
2127
- allow_partial=allow_partial,
2128
- **kwargs,
2152
+ auto_symbolic = json_value.get(
2153
+ utils.JSONConvertible.SYMBOLIC_MARKER, auto_symbolic
2129
2154
  )
2155
+ if auto_symbolic:
2156
+ return Symbolic.DictType.from_json( # pytype: disable=attribute-error
2157
+ json_value,
2158
+ context=context,
2159
+ value_spec=value_spec,
2160
+ root_path=root_path,
2161
+ allow_partial=allow_partial,
2162
+ **kwargs,
2163
+ )
2130
2164
  return utils.from_json(
2131
2165
  json_value,
2166
+ context=context,
2132
2167
  _typename_resolved=True,
2133
2168
  root_path=root_path,
2134
2169
  allow_partial=allow_partial,
@@ -2140,10 +2175,12 @@ def from_json(
2140
2175
  def from_json_str(
2141
2176
  json_str: str,
2142
2177
  *,
2143
- allow_partial: bool = False,
2144
- root_path: Optional[utils.KeyPath] = None,
2178
+ context: Optional[utils.JSONConversionContext] = None,
2145
2179
  auto_import: bool = True,
2146
2180
  auto_dict: bool = False,
2181
+ allow_partial: bool = False,
2182
+ root_path: Optional[utils.KeyPath] = None,
2183
+ value_spec: Optional[pg_typing.ValueSpec] = None,
2147
2184
  **kwargs,
2148
2185
  ) -> Any:
2149
2186
  """Deserialize (maybe) symbolic object from JSON string.
@@ -2163,15 +2200,17 @@ def from_json_str(
2163
2200
 
2164
2201
  Args:
2165
2202
  json_str: JSON string.
2166
- allow_partial: If True, allow a partial symbolic object to be created.
2167
- Otherwise error will be raised on partial value.
2168
- root_path: The symbolic path used for the deserialized root object.
2203
+ context: JSON conversion context.
2169
2204
  auto_import: If True, when a '_type' is not registered, PyGlove will
2170
2205
  identify its parent module and automatically import it. For example,
2171
2206
  if the type is 'foo.bar.A', PyGlove will try to import 'foo.bar' and
2172
2207
  find the class 'A' within the imported module.
2173
2208
  auto_dict: If True, dict with '_type' that cannot be loaded will remain
2174
2209
  as dict, with '_type' renamed to 'type_name'.
2210
+ allow_partial: If True, allow a partial symbolic object to be created.
2211
+ Otherwise error will be raised on partial value.
2212
+ root_path: The symbolic path used for the deserialized root object.
2213
+ value_spec: The value spec for the symbolic list or dict.
2175
2214
  **kwargs: Additional keyword arguments that will be passed to
2176
2215
  ``pg.from_json``.
2177
2216
 
@@ -2195,10 +2234,12 @@ def from_json_str(
2195
2234
 
2196
2235
  return from_json(
2197
2236
  _decode_int_keys(json.loads(json_str)),
2198
- allow_partial=allow_partial,
2199
- root_path=root_path,
2237
+ context=context,
2200
2238
  auto_import=auto_import,
2201
2239
  auto_dict=auto_dict,
2240
+ allow_partial=allow_partial,
2241
+ root_path=root_path,
2242
+ value_spec=value_spec,
2202
2243
  **kwargs
2203
2244
  )
2204
2245
 
@@ -2234,10 +2275,6 @@ def to_json(value: Any, **kwargs) -> Any:
2234
2275
  Returns:
2235
2276
  JSON value.
2236
2277
  """
2237
- # NOTE(daiyip): special handling `sym_jsonify` since symbolized
2238
- # classes may have conflicting `to_json` method in their existing classes.
2239
- if isinstance(value, Symbolic):
2240
- return value.sym_jsonify(**kwargs)
2241
2278
  return utils.to_json(value, **kwargs)
2242
2279
 
2243
2280
 
@@ -20,9 +20,9 @@ from pyglove.core import typing as pg_typing
20
20
  from pyglove.core import utils
21
21
  from pyglove.core import views
22
22
  from pyglove.core.symbolic import base
23
- from pyglove.core.symbolic.dict import Dict
24
- from pyglove.core.symbolic.inferred import ValueFromParentChain
25
- from pyglove.core.symbolic.object import Object
23
+ from pyglove.core.symbolic.dict import Dict # pylint: disable=g-importing-member
24
+ from pyglove.core.symbolic.inferred import ValueFromParentChain # pylint: disable=g-importing-member
25
+ from pyglove.core.symbolic.object import Object # pylint: disable=g-importing-member
26
26
 
27
27
 
28
28
  class FieldUpdateTest(unittest.TestCase):
@@ -156,6 +156,8 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
156
156
  # Not okay:
157
157
  d.a.f2.abc = 1
158
158
  """
159
+ # Remove symbolic marker if present.
160
+ json_value.pop(utils.JSONConvertible.SYMBOLIC_MARKER, None)
159
161
  return cls(
160
162
  {
161
163
  k: base.from_json(
@@ -835,12 +837,15 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
835
837
  hide_default_values: bool = False,
836
838
  exclude_keys: Optional[Sequence[Union[str, int]]] = None,
837
839
  use_inferred: bool = False,
840
+ omit_symbolic_marker: bool = True,
838
841
  **kwargs,
839
842
  ) -> utils.JSONValueType:
840
843
  """Converts current object to a dict with plain Python objects."""
841
844
  exclude_keys = set(exclude_keys or [])
845
+ json_repr = {}
846
+ if not omit_symbolic_marker:
847
+ json_repr[utils.JSONConvertible.SYMBOLIC_MARKER] = True
842
848
  if self._value_spec and self._value_spec.schema:
843
- json_repr = dict()
844
849
  matched_keys, _ = self._value_spec.schema.resolve(self.keys()) # pytype: disable=attribute-error
845
850
  for key_spec, keys in matched_keys.items():
846
851
  # NOTE(daiyip): The key values of frozen field can safely be excluded
@@ -862,20 +867,23 @@ class Dict(dict, base.Symbolic, pg_typing.CustomTyping):
862
867
  hide_frozen=hide_frozen,
863
868
  hide_default_values=hide_default_values,
864
869
  use_inferred=use_inferred,
865
- **kwargs)
866
- return json_repr
870
+ omit_symbolic_marker=omit_symbolic_marker,
871
+ **kwargs
872
+ )
867
873
  else:
868
- return {
874
+ json_repr.update({
869
875
  k: base.to_json(
870
876
  self.sym_inferred(k, default=v) if (
871
877
  use_inferred and isinstance(v, base.Inferential)) else v,
872
878
  hide_frozen=hide_frozen,
873
879
  hide_default_values=hide_default_values,
874
880
  use_inferred=use_inferred,
881
+ omit_symbolic_marker=omit_symbolic_marker,
875
882
  **kwargs)
876
883
  for k, v in self.sym_items()
877
884
  if k not in exclude_keys
878
- }
885
+ })
886
+ return json_repr
879
887
 
880
888
  def custom_apply(
881
889
  self,
@@ -946,6 +946,14 @@ class DictTest(unittest.TestCase):
946
946
  sd.sym_jsonify(),
947
947
  {'x': 1, 'y': inferred.ValueFromParentChain().to_json()},
948
948
  )
949
+ self.assertEqual(
950
+ sd.sym_jsonify(omit_symbolic_marker=False),
951
+ {
952
+ '__symbolic__': True,
953
+ 'x': 1,
954
+ 'y': inferred.ValueFromParentChain().to_json()
955
+ },
956
+ )
949
957
 
950
958
  def test_sym_rebind(self):
951
959
  # Refer to RebindTest for more detailed tests.
@@ -1964,6 +1972,24 @@ class SerializationTest(unittest.TestCase):
1964
1972
  self.assertEqual(sd.to_json_str(), '{"x": 1, "y": 2.0}')
1965
1973
  self.assertEqual(base.from_json_str(sd.to_json_str(), value_spec=spec), sd)
1966
1974
 
1975
+ def test_auto_symbolic(self):
1976
+ value = base.from_json({'x': 1}, auto_symbolic=True)
1977
+ self.assertIsInstance(value, Dict)
1978
+
1979
+ value = base.from_json({'x': 1}, auto_symbolic=False)
1980
+ self.assertNotIsInstance(value, Dict)
1981
+
1982
+ def test_omit_symbolic_marker(self):
1983
+ sd = Dict(x=1)
1984
+ self.assertEqual(sd.to_json(omit_symbolic_marker=True), {'x': 1})
1985
+ self.assertEqual(
1986
+ sd.to_json(omit_symbolic_marker=False),
1987
+ {'__symbolic__': True, 'x': 1}
1988
+ )
1989
+ sd = base.from_json({'__symbolic__': True, 'x': 1}, auto_symbolic=False)
1990
+ self.assertIsInstance(sd, Dict)
1991
+ self.assertEqual(sd, {'x': 1})
1992
+
1967
1993
  def test_hide_frozen(self):
1968
1994
 
1969
1995
  class A(pg_object.Object):
@@ -137,6 +137,9 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
137
137
  Returns:
138
138
  A schema-less symbolic list, but its items maybe symbolic.
139
139
  """
140
+ # Remove symbolic marker if present.
141
+ if json_value and json_value[0] == utils.JSONConvertible.SYMBOLIC_MARKER:
142
+ json_value.pop(0)
140
143
  return cls(
141
144
  [
142
145
  base.from_json(
@@ -770,15 +773,26 @@ class List(list, base.Symbolic, pg_typing.CustomTyping):
770
773
  return (proceed_with_standard_apply, self)
771
774
 
772
775
  def sym_jsonify(
773
- self, use_inferred: bool = False, **kwargs
776
+ self,
777
+ use_inferred: bool = False,
778
+ omit_symbolic_marker: bool = True,
779
+ **kwargs
774
780
  ) -> utils.JSONValueType:
775
781
  """Converts current list to a list of plain Python objects."""
776
782
  def json_item(idx):
777
783
  v = self.sym_getattr(idx)
778
784
  if use_inferred and isinstance(v, base.Inferential):
779
785
  v = self.sym_inferred(idx, default=v)
780
- return base.to_json(v, use_inferred=use_inferred, **kwargs)
781
- return [json_item(i) for i in range(len(self))]
786
+ return base.to_json(
787
+ v,
788
+ use_inferred=use_inferred,
789
+ omit_symbolic_marker=omit_symbolic_marker,
790
+ **kwargs
791
+ )
792
+ json_value = [json_item(i) for i in range(len(self))]
793
+ if not omit_symbolic_marker:
794
+ json_value.insert(0, utils.JSONConvertible.SYMBOLIC_MARKER)
795
+ return json_value
782
796
 
783
797
  def format(
784
798
  self,
@@ -799,6 +799,10 @@ class ListTest(unittest.TestCase):
799
799
  self.assertEqual(
800
800
  sl.sym_jsonify(), [0, inferred.ValueFromParentChain().to_json()]
801
801
  )
802
+ self.assertEqual(
803
+ sl.sym_jsonify(omit_symbolic_marker=False),
804
+ ['__symbolic__', 0, inferred.ValueFromParentChain().to_json()]
805
+ )
802
806
 
803
807
  def test_sym_rebind(self):
804
808
  # Refer to RebindTest for more detailed tests.
@@ -1633,6 +1637,25 @@ class SerializationTest(unittest.TestCase):
1633
1637
  'Tuple should have at least one element besides \'__tuple__\'.'):
1634
1638
  base.from_json_str('["__tuple__"]')
1635
1639
 
1640
+ def test_auto_symbolic(self):
1641
+ value = base.from_json([1, 2, 3], auto_symbolic=True)
1642
+ self.assertIsInstance(value, List)
1643
+
1644
+ value = base.from_json([1, 2, 3], auto_symbolic=False)
1645
+ self.assertNotIsInstance(value, List)
1646
+
1647
+ def test_omit_symbolic_marker(self):
1648
+ sl = List([0])
1649
+ self.assertEqual(sl.to_json(omit_symbolic_marker=True), [0])
1650
+ self.assertEqual(
1651
+ sl.to_json(omit_symbolic_marker=False),
1652
+ ['__symbolic__', 0]
1653
+ )
1654
+ sl = base.from_json(['__symbolic__', 0], auto_symbolic=False)
1655
+ self.assertEqual(sl.to_json(omit_symbolic_marker=True), [0])
1656
+ self.assertIsInstance(sl, List)
1657
+ self.assertEqual(sl, [0])
1658
+
1636
1659
  def test_hide_default_values(self):
1637
1660
  sl = List.partial(
1638
1661
  [dict(x=1)],
@@ -994,6 +994,7 @@ class Object(base.Symbolic, metaclass=ObjectMeta):
994
994
  self.__class__.__serialization_key__
995
995
  )
996
996
  }
997
+ kwargs['omit_symbolic_marker'] = True
997
998
  json_dict.update(self._sym_attributes.to_json(**kwargs))
998
999
  return json_dict
999
1000
 
@@ -138,9 +138,7 @@ class Ref(
138
138
  del child_transform
139
139
  # Check if the field being assigned could accept the referenced value.
140
140
  # We do not do any transformation, thus not passing the child transform.
141
- value_spec.apply(
142
- self._value,
143
- allow_partial=allow_partial)
141
+ value_spec.apply(self._value, allow_partial=allow_partial)
144
142
  return (False, self)
145
143
 
146
144
  def _sym_clone(self, deep: bool, memo: Any = None) -> 'Ref':
@@ -152,10 +150,24 @@ class Ref(
152
150
  def sym_eq(self, other: Any) -> bool:
153
151
  return isinstance(other, Ref) and self.value is other.value
154
152
 
155
- def sym_jsonify(self, *, save_ref_value: bool = False, **kwargs: Any) -> Any:
156
- if save_ref_value:
157
- return base.to_json(self._value, save_ref_value=save_ref_value, **kwargs)
158
- raise TypeError(f'{self!r} cannot be serialized at the moment.')
153
+ def sym_jsonify(
154
+ self,
155
+ *,
156
+ context: utils.JSONConversionContext,
157
+ **kwargs: Any
158
+ ) -> Any:
159
+ # Disable auto_symbolic for Ref value. This allows Ref to create a sub-tree
160
+ # for reference sharing.
161
+ kwargs['omit_symbolic_marker'] = False
162
+ return {
163
+ utils.JSONConvertible.TYPE_NAME_KEY: self.__class__.__type_name__,
164
+ 'value': context.serialize_maybe_shared(self._value, **kwargs)
165
+ }
166
+
167
+ @classmethod
168
+ def from_json(cls, json: Any, **kwargs):
169
+ kwargs['auto_symbolic'] = False
170
+ return super().from_json(json, **kwargs)
159
171
 
160
172
  def __getstate__(self):
161
173
  raise TypeError(f'{self!r} cannot be pickled at the moment.')
@@ -21,8 +21,11 @@ from typing import Any
21
21
  import unittest
22
22
 
23
23
  from pyglove.core import typing as pg_typing
24
+ from pyglove.core.symbolic import list as pg_list # pylint: disable=unused-import
24
25
  from pyglove.core.symbolic import ref
25
26
  from pyglove.core.symbolic.base import contains
27
+ from pyglove.core.symbolic.base import from_json
28
+ from pyglove.core.symbolic.base import to_json
26
29
  from pyglove.core.symbolic.dict import Dict
27
30
  from pyglove.core.symbolic.object import Object
28
31
 
@@ -33,6 +36,10 @@ class A(Object):
33
36
 
34
37
  class RefTest(unittest.TestCase):
35
38
 
39
+ def setUp(self):
40
+ super().setUp()
41
+ self.maxDiff = None
42
+
36
43
  def test_basics(self):
37
44
 
38
45
  a = A(1)
@@ -109,14 +116,94 @@ class RefTest(unittest.TestCase):
109
116
  """))
110
117
 
111
118
  def test_to_json(self):
112
- with self.assertRaisesRegex(
113
- TypeError, '.* cannot be serialized at the moment'):
114
- ref.Ref(A(1)).to_json()
119
+ class B(Object):
120
+ y: Any
115
121
 
116
- self.assertEqual(
117
- ref.Ref(A(1)).to_json(save_ref_value=True),
118
- A(1).to_json()
119
- )
122
+ a = A(1)
123
+ r1 = ref.Ref(a)
124
+ r2 = ref.Ref({'z': a})
125
+ r3 = ref.Ref(Dict(t=r1, p=r2))
126
+ v = Dict(a=r1, b=[B(r2), [r3], r1])
127
+ self.assertIs(v.a, v.b[0].y['z'])
128
+ self.assertIs(v.a, v.b[1][0].t)
129
+ self.assertIs(v.b[0].y, v.b[1][0].p)
130
+ self.assertIs(v.a, v.b[2])
131
+ self.assertIsInstance(v, dict)
132
+ self.assertIsInstance(v.b[0].y, dict)
133
+ self.assertNotIsInstance(v.b[0].y, Dict)
134
+ self.assertIsInstance(v.b[1][0], Dict)
135
+
136
+ json = to_json(v)
137
+ expected = {
138
+ '__context__': {
139
+ 'shared_objects': [
140
+ {
141
+ '_type': A.__type_name__,
142
+ 'x': 1
143
+ },
144
+ {
145
+ 'z': {
146
+ '__ref__': 0
147
+ }
148
+ }
149
+ ]
150
+ },
151
+ '__root__': {
152
+ 'a': {
153
+ '_type': ref.Ref.__type_name__,
154
+ 'value': {
155
+ '__ref__': 0
156
+ }
157
+ },
158
+ 'b': [
159
+ {
160
+ '_type': B.__type_name__,
161
+ 'y': {
162
+ '_type': ref.Ref.__type_name__,
163
+ 'value': {
164
+ '__ref__': 1
165
+ }
166
+ }
167
+ },
168
+ [
169
+ {
170
+ '_type': ref.Ref.__type_name__,
171
+ 'value': {
172
+ '__symbolic__': True,
173
+ 't': {
174
+ '_type': ref.Ref.__type_name__,
175
+ 'value': {
176
+ '__ref__': 0
177
+ }
178
+ },
179
+ 'p': {
180
+ '_type': ref.Ref.__type_name__,
181
+ 'value': {
182
+ '__ref__': 1
183
+ }
184
+ }
185
+ }
186
+ }
187
+ ],
188
+ {
189
+ '_type': ref.Ref.__type_name__,
190
+ 'value': {
191
+ '__ref__': 0
192
+ }
193
+ }
194
+ ]
195
+ }
196
+ }
197
+ self.assertEqual(json, expected)
198
+ v = from_json(json)
199
+ self.assertIs(v.a, v.b[0].y['z'])
200
+ self.assertIs(v.a, v.b[1][0].t)
201
+ self.assertIs(v.b[0].y, v.b[1][0].p)
202
+ self.assertIs(v.a, v.b[2])
203
+ self.assertIsInstance(v, dict)
204
+ self.assertIsInstance(v.b[0].y, dict)
205
+ self.assertNotIsInstance(v.b[0].y, Dict)
206
+ self.assertIsInstance(v.b[1][0], Dict)
120
207
 
121
208
  def test_pickle(self):
122
209
  with self.assertRaisesRegex(
@@ -318,6 +318,9 @@ def _value_spec_from_type_annotation(
318
318
  parent_module: typing.Optional[types.ModuleType] = None
319
319
  ) -> class_schema.ValueSpec:
320
320
  """Creates a value spec from type annotation."""
321
+ if isinstance(annotation, class_schema.ValueSpec):
322
+ return annotation
323
+
321
324
  if isinstance(annotation, str) and not accept_value_as_annotation:
322
325
  annotation = annotation_from_str(annotation, parent_module)
323
326
 
@@ -454,7 +457,8 @@ def _value_spec_from_annotation(
454
457
  """Creates a value spec from annotation."""
455
458
  if isinstance(annotation, class_schema.ValueSpec):
456
459
  return annotation
457
- elif annotation == inspect.Parameter.empty:
460
+
461
+ if annotation == inspect.Parameter.empty:
458
462
  return vs.Any()
459
463
 
460
464
  if annotation is None:
@@ -396,6 +396,9 @@ class ValueSpecFromAnnotationTest(unittest.TestCase):
396
396
  self.assertEqual(
397
397
  ValueSpec.from_annotation(typing.Dict[str, int], True),
398
398
  vs.Dict([(ks.StrKey(), vs.Int())]))
399
+ self.assertEqual(
400
+ ValueSpec.from_annotation(typing.Dict[str, vs.Int()], True),
401
+ vs.Dict([(ks.StrKey(), vs.Int())]))
399
402
  self.assertEqual(
400
403
  ValueSpec.from_annotation(typing.Mapping[str, int], True),
401
404
  vs.Dict([(ks.StrKey(), vs.Int())]))
@@ -74,6 +74,7 @@ modules with the following features:
74
74
  from pyglove.core.utils.json_conversion import Nestable
75
75
  from pyglove.core.utils.json_conversion import JSONValueType
76
76
 
77
+ from pyglove.core.utils.json_conversion import JSONConversionContext
77
78
  from pyglove.core.utils.json_conversion import JSONConvertible
78
79
  from pyglove.core.utils.json_conversion import from_json
79
80
  from pyglove.core.utils.json_conversion import to_json