pyglove 0.5.0.dev202511161718__tar.gz → 0.5.0.dev202511250811__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.
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/PKG-INFO +8 -1
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/io/file_system.py +199 -9
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/io/file_system_test.py +117 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/__init__.py +7 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/base.py +24 -9
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/object.py +2 -1
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/object_test.py +13 -10
- pyglove-0.5.0.dev202511250811/pyglove/core/symbolic/unknown_symbols.py +147 -0
- pyglove-0.5.0.dev202511250811/pyglove/core/symbolic/unknown_symbols_test.py +100 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/value_specs.py +5 -1
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/value_specs_test.py +5 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/json_conversion.py +107 -49
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/json_conversion_test.py +83 -9
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove.egg-info/PKG-INFO +8 -1
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove.egg-info/SOURCES.txt +2 -0
- pyglove-0.5.0.dev202511250811/pyglove.egg-info/requires.txt +10 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/setup.py +36 -14
- pyglove-0.5.0.dev202511161718/pyglove.egg-info/requires.txt +0 -2
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/LICENSE +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/README.md +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/errors.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/errors_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/execution.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/execution_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/function_generation.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/function_generation_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/parsing.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/parsing_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/permissions.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/coding/permissions_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/detouring/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/detouring/class_detour.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/detouring/class_detour_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/base_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/categorical.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/categorical_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/custom.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/custom_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/deduping.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/deduping_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/dna_generator.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/dna_generator_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/numerical.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/numerical_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/random.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/random_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/space.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/space_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/sweeping.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/geno/sweeping_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/categorical.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/categorical_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/custom.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/custom_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/derived.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/derived_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/dynamic_evaluation.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/dynamic_evaluation_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/evolvable.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/evolvable_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/iter.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/iter_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/numerical.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/numerical_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/object_template.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/hyper/object_template_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/io/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/io/sequence.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/io/sequence_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/logging.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/logging_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/monitoring.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/monitoring_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/patching/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/patching/object_factory.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/patching/object_factory_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/patching/pattern_based.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/patching/pattern_based_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/patching/rule_based.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/patching/rule_based_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/base_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/boilerplate.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/boilerplate_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/class_wrapper.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/class_wrapper_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/compounding.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/compounding_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/contextual_object.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/contextual_object_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/dict.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/dict_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/diff.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/diff_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/error_info.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/error_info_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/flags.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/flags_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/functor.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/functor_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/inferred.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/inferred_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/list.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/list_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/origin.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/origin_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/pure_symbolic.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/ref.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/ref_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/symbolize.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/symbolize_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/backend.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/backend_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/early_stopping.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/local_backend.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/protocols.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/protocols_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/sample.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/tuning/sample_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/annotated.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/annotated_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/annotation_conversion.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/annotation_conversion_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/annotation_future_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/callable_ext.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/callable_ext_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/callable_signature.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/callable_signature_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/class_schema.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/class_schema_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/custom_typing.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/inspect.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/inspect_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/json_schema.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/json_schema_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/key_specs.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/key_specs_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/pytype_support.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/type_conversion.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/type_conversion_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/typed_missing.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/typing/typed_missing_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/common_traits.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/common_traits_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/contextual.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/contextual_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/docstr_utils.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/docstr_utils_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/error_utils.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/error_utils_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/formatting.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/formatting_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/hierarchical.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/hierarchical_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/missing.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/missing_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/text_color.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/text_color_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/thread_local.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/thread_local_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/timing.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/timing_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/value_location.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/utils/value_location_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/base_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/base_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/label.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/label_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/progress_bar.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/progress_bar_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/tab.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/tab_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/tooltip.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/controls/tooltip_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/tree_view.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/views/html/tree_view_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/early_stopping/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/early_stopping/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/early_stopping/base_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/early_stopping/step_wise.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/early_stopping/step_wise_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/base_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/hill_climb.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/hill_climb_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/mutators.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/mutators_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/neat.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/neat_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/nsga2.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/nsga2_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/recombinators.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/recombinators_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/regularized_evolution.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/regularized_evolution_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/selectors.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/selectors_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/where.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/evolution/where_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/mutfun/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/mutfun/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/mutfun/base_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/mutfun/basic_ops.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/mutfun/basic_ops_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/__init__.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/base.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/base_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/maths.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/maths_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/randoms.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/randoms_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/step_wise.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/ext/scalars/step_wise_test.py +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove.egg-info/dependency_links.txt +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove.egg-info/top_level.txt +0 -0
- {pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyglove
|
|
3
|
-
Version: 0.5.0.
|
|
3
|
+
Version: 0.5.0.dev202511250811
|
|
4
4
|
Summary: PyGlove: A library for manipulating Python objects.
|
|
5
5
|
Home-page: https://github.com/google/pyglove
|
|
6
6
|
Author: PyGlove Authors
|
|
@@ -23,6 +23,12 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
License-File: LICENSE
|
|
24
24
|
Requires-Dist: docstring-parser>=0.12
|
|
25
25
|
Requires-Dist: termcolor>=1.1.0
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: docstring-parser>=0.12; extra == "all"
|
|
28
|
+
Requires-Dist: termcolor>=1.1.0; extra == "all"
|
|
29
|
+
Requires-Dist: fsspec>=2023.3.0; extra == "all"
|
|
30
|
+
Provides-Extra: io
|
|
31
|
+
Requires-Dist: fsspec>=2023.3.0; extra == "io"
|
|
26
32
|
Dynamic: author
|
|
27
33
|
Dynamic: author-email
|
|
28
34
|
Dynamic: classifier
|
|
@@ -32,6 +38,7 @@ Dynamic: home-page
|
|
|
32
38
|
Dynamic: keywords
|
|
33
39
|
Dynamic: license
|
|
34
40
|
Dynamic: license-file
|
|
41
|
+
Dynamic: provides-extra
|
|
35
42
|
Dynamic: requires-dist
|
|
36
43
|
Dynamic: summary
|
|
37
44
|
|
{pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/io/file_system.py
RENAMED
|
@@ -19,7 +19,6 @@ import glob as std_glob
|
|
|
19
19
|
import io
|
|
20
20
|
import os
|
|
21
21
|
import re
|
|
22
|
-
import time
|
|
23
22
|
from typing import Any, Literal, Optional, Union
|
|
24
23
|
|
|
25
24
|
|
|
@@ -179,14 +178,6 @@ class StdFile(File):
|
|
|
179
178
|
def close(self) -> None:
|
|
180
179
|
self._file_object.close()
|
|
181
180
|
|
|
182
|
-
# For some file systems, the file might not be immediately available
|
|
183
|
-
# after writing. We retry for a few times to ensure the file is
|
|
184
|
-
# world-readable.
|
|
185
|
-
while True:
|
|
186
|
-
if os.path.exists(self._path):
|
|
187
|
-
break
|
|
188
|
-
time.sleep(0.1)
|
|
189
|
-
|
|
190
181
|
|
|
191
182
|
class StdFileSystem(FileSystem):
|
|
192
183
|
"""The standard file system."""
|
|
@@ -502,6 +493,205 @@ def add_file_system(prefix: str, fs: FileSystem) -> None:
|
|
|
502
493
|
add_file_system('/mem/', MemoryFileSystem('/mem/'))
|
|
503
494
|
|
|
504
495
|
|
|
496
|
+
try:
|
|
497
|
+
# pylint: disable=g-import-not-at-top
|
|
498
|
+
# pytype: disable=import-error
|
|
499
|
+
import fsspec
|
|
500
|
+
# pytype: enable=import-error
|
|
501
|
+
# pylint: enable=g-import-not-at-top
|
|
502
|
+
except ImportError:
|
|
503
|
+
fsspec = None
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
class FsspecFile(File):
|
|
507
|
+
"""File object based on fsspec."""
|
|
508
|
+
|
|
509
|
+
def __init__(self, f):
|
|
510
|
+
self._f = f
|
|
511
|
+
|
|
512
|
+
def read(self, size: Optional[int] = None) -> Union[str, bytes]:
|
|
513
|
+
return self._f.read(size)
|
|
514
|
+
|
|
515
|
+
def readline(self) -> Union[str, bytes]:
|
|
516
|
+
return self._f.readline()
|
|
517
|
+
|
|
518
|
+
def write(self, content: Union[str, bytes]) -> None:
|
|
519
|
+
self._f.write(content)
|
|
520
|
+
|
|
521
|
+
def seek(self, offset: int, whence: Literal[0, 1, 2] = 0) -> int:
|
|
522
|
+
return self._f.seek(offset, whence)
|
|
523
|
+
|
|
524
|
+
def tell(self) -> int:
|
|
525
|
+
return self._f.tell()
|
|
526
|
+
|
|
527
|
+
def flush(self) -> None:
|
|
528
|
+
self._f.flush()
|
|
529
|
+
|
|
530
|
+
def close(self) -> None:
|
|
531
|
+
self._f.close()
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
class FsspecFileSystem(FileSystem):
|
|
535
|
+
"""File system based on fsspec."""
|
|
536
|
+
|
|
537
|
+
def open(
|
|
538
|
+
self, path: Union[str, os.PathLike[str]], mode: str = 'r', **kwargs
|
|
539
|
+
) -> File:
|
|
540
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
541
|
+
return FsspecFile(fsspec.open(path, mode, **kwargs).open())
|
|
542
|
+
|
|
543
|
+
def chmod(self, path: Union[str, os.PathLike[str]], mode: int) -> None:
|
|
544
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
545
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
546
|
+
if hasattr(fs, 'chmod'):
|
|
547
|
+
fs.chmod(path, mode)
|
|
548
|
+
|
|
549
|
+
def exists(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
550
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
551
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
552
|
+
return fs.exists(path)
|
|
553
|
+
|
|
554
|
+
def glob(self, pattern: Union[str, os.PathLike[str]]) -> list[str]:
|
|
555
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
556
|
+
fs, path = fsspec.core.url_to_fs(pattern)
|
|
557
|
+
protocol = fsspec.utils.get_protocol(pattern)
|
|
558
|
+
return [f'{protocol}:///{r.lstrip("/")}' for r in fs.glob(path)]
|
|
559
|
+
|
|
560
|
+
def listdir(self, path: Union[str, os.PathLike[str]]) -> list[str]:
|
|
561
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
562
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
563
|
+
return [os.path.basename(f) for f in fs.ls(path, detail=False)]
|
|
564
|
+
|
|
565
|
+
def isdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
566
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
567
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
568
|
+
return fs.isdir(path)
|
|
569
|
+
|
|
570
|
+
def mkdir(
|
|
571
|
+
self,
|
|
572
|
+
path: Union[str, os.PathLike[str]], mode: int = 0o777
|
|
573
|
+
) -> None:
|
|
574
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
575
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
576
|
+
fs.mkdir(path)
|
|
577
|
+
|
|
578
|
+
def mkdirs(
|
|
579
|
+
self,
|
|
580
|
+
path: Union[str, os.PathLike[str]],
|
|
581
|
+
mode: int = 0o777,
|
|
582
|
+
exist_ok: bool = True,
|
|
583
|
+
) -> None:
|
|
584
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
585
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
586
|
+
fs.makedirs(path, exist_ok=exist_ok)
|
|
587
|
+
|
|
588
|
+
def rm(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
589
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
590
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
591
|
+
fs.rm(path)
|
|
592
|
+
|
|
593
|
+
def rename(
|
|
594
|
+
self,
|
|
595
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
596
|
+
newpath: Union[str, os.PathLike[str]],
|
|
597
|
+
) -> None:
|
|
598
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
599
|
+
fs, old_path = fsspec.core.url_to_fs(oldpath)
|
|
600
|
+
fs2, new_path = fsspec.core.url_to_fs(newpath)
|
|
601
|
+
if fs.__class__ != fs2.__class__:
|
|
602
|
+
raise ValueError(
|
|
603
|
+
f'Rename across different filesystems is not supported: '
|
|
604
|
+
f'{type(fs)} vs {type(fs2)}'
|
|
605
|
+
)
|
|
606
|
+
fs.rename(old_path, new_path)
|
|
607
|
+
|
|
608
|
+
def rmdir(self, path: Union[str, os.PathLike[str]]) -> None: # pytype: disable=signature-mismatch
|
|
609
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
610
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
611
|
+
fs.rmdir(path)
|
|
612
|
+
|
|
613
|
+
def rmdirs(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
614
|
+
assert fsspec is not None, '`fsspec` is not installed.'
|
|
615
|
+
fs, path = fsspec.core.url_to_fs(path)
|
|
616
|
+
fs.rm(path, recursive=True)
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
class _FsspecUriCatcher(FileSystem):
|
|
620
|
+
"""File system to catch URI paths and redirect to FsspecFileSystem."""
|
|
621
|
+
|
|
622
|
+
# Catch all paths that contains '://' but not registered by
|
|
623
|
+
# available_protocols.
|
|
624
|
+
_URI_PATTERN = re.compile(r'^[a-zA-Z][a-zA-Z0-9+-.]*://.*')
|
|
625
|
+
|
|
626
|
+
def __init__(self):
|
|
627
|
+
super().__init__()
|
|
628
|
+
self._std_fs = StdFileSystem()
|
|
629
|
+
self._fsspec_fs = FsspecFileSystem()
|
|
630
|
+
|
|
631
|
+
def get_fs(self, path: Union[str, os.PathLike[str]]) -> FileSystem:
|
|
632
|
+
if self._URI_PATTERN.match(resolve_path(path)):
|
|
633
|
+
return self._fsspec_fs
|
|
634
|
+
return self._std_fs
|
|
635
|
+
|
|
636
|
+
def open(
|
|
637
|
+
self, path: Union[str, os.PathLike[str]], mode: str = 'r', **kwargs
|
|
638
|
+
) -> File:
|
|
639
|
+
return self.get_fs(path).open(path, mode, **kwargs)
|
|
640
|
+
|
|
641
|
+
def chmod(self, path: Union[str, os.PathLike[str]], mode: int) -> None:
|
|
642
|
+
self.get_fs(path).chmod(path, mode)
|
|
643
|
+
|
|
644
|
+
def exists(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
645
|
+
return self.get_fs(path).exists(path)
|
|
646
|
+
|
|
647
|
+
def glob(self, pattern: Union[str, os.PathLike[str]]) -> list[str]:
|
|
648
|
+
return self.get_fs(pattern).glob(pattern)
|
|
649
|
+
|
|
650
|
+
def listdir(self, path: Union[str, os.PathLike[str]]) -> list[str]:
|
|
651
|
+
return self.get_fs(path).listdir(path)
|
|
652
|
+
|
|
653
|
+
def isdir(self, path: Union[str, os.PathLike[str]]) -> bool:
|
|
654
|
+
return self.get_fs(path).isdir(path)
|
|
655
|
+
|
|
656
|
+
def mkdir(
|
|
657
|
+
self,
|
|
658
|
+
path: Union[str, os.PathLike[str]],
|
|
659
|
+
mode: int = 0o777
|
|
660
|
+
) -> None:
|
|
661
|
+
self.get_fs(path).mkdir(path, mode)
|
|
662
|
+
|
|
663
|
+
def mkdirs(
|
|
664
|
+
self,
|
|
665
|
+
path: Union[str, os.PathLike[str]],
|
|
666
|
+
mode: int = 0o777,
|
|
667
|
+
exist_ok: bool = True,
|
|
668
|
+
) -> None:
|
|
669
|
+
self.get_fs(path).mkdirs(path, mode, exist_ok)
|
|
670
|
+
|
|
671
|
+
def rm(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
672
|
+
self.get_fs(path).rm(path)
|
|
673
|
+
|
|
674
|
+
def rename(
|
|
675
|
+
self,
|
|
676
|
+
oldpath: Union[str, os.PathLike[str]],
|
|
677
|
+
newpath: Union[str, os.PathLike[str]],
|
|
678
|
+
) -> None:
|
|
679
|
+
self.get_fs(oldpath).rename(oldpath, newpath)
|
|
680
|
+
|
|
681
|
+
def rmdir(self, path: Union[str, os.PathLike[str]]) -> None: # pytype: disable=signature-mismatch
|
|
682
|
+
self.get_fs(path).rmdir(path)
|
|
683
|
+
|
|
684
|
+
def rmdirs(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
685
|
+
self.get_fs(path).rmdirs(path)
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
if fsspec is not None:
|
|
689
|
+
fsspec_fs = FsspecFileSystem()
|
|
690
|
+
for p in fsspec.available_protocols():
|
|
691
|
+
add_file_system(p + '://', fsspec_fs)
|
|
692
|
+
add_file_system('', _FsspecUriCatcher())
|
|
693
|
+
|
|
694
|
+
|
|
505
695
|
#
|
|
506
696
|
# APIs for file IO.
|
|
507
697
|
#
|
{pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/io/file_system_test.py
RENAMED
|
@@ -16,6 +16,8 @@ import os
|
|
|
16
16
|
import pathlib
|
|
17
17
|
import tempfile
|
|
18
18
|
import unittest
|
|
19
|
+
from unittest import mock
|
|
20
|
+
import fsspec
|
|
19
21
|
from pyglove.core.io import file_system
|
|
20
22
|
|
|
21
23
|
|
|
@@ -423,5 +425,120 @@ class FileIoApiTest(unittest.TestCase):
|
|
|
423
425
|
['/mem/g/a/b', '/mem/g/a/b/bar.txt', '/mem/g/a/foo2.txt'])
|
|
424
426
|
|
|
425
427
|
|
|
428
|
+
class FsspecFileSystemTest(unittest.TestCase):
|
|
429
|
+
|
|
430
|
+
def setUp(self):
|
|
431
|
+
super().setUp()
|
|
432
|
+
self.fs = fsspec.filesystem('memory')
|
|
433
|
+
self.fs.pipe('memory:///a/b/c', b'abc')
|
|
434
|
+
self.fs.pipe('memory:///a/b/d', b'abd')
|
|
435
|
+
self.fs.mkdir('memory:///a/e')
|
|
436
|
+
|
|
437
|
+
def tearDown(self):
|
|
438
|
+
super().tearDown()
|
|
439
|
+
fsspec.filesystem('memory').rm('/', recursive=True)
|
|
440
|
+
|
|
441
|
+
def test_read_file(self):
|
|
442
|
+
self.assertEqual(file_system.readfile('memory:///a/b/c', mode='rb'), b'abc')
|
|
443
|
+
with file_system.open('memory:///a/b/d', 'rb') as f:
|
|
444
|
+
self.assertEqual(f.read(), b'abd')
|
|
445
|
+
|
|
446
|
+
def test_fsspec_file_ops(self):
|
|
447
|
+
file_system.writefile('memory:///f', b'hello\nworld\n', mode='wb')
|
|
448
|
+
with file_system.open('memory:///f', 'rb') as f:
|
|
449
|
+
self.assertIsInstance(f, file_system.FsspecFile)
|
|
450
|
+
self.assertEqual(f.readline(), b'hello\n')
|
|
451
|
+
self.assertEqual(f.tell(), 6)
|
|
452
|
+
self.assertEqual(f.seek(8), 8)
|
|
453
|
+
self.assertEqual(f.read(), b'rld\n')
|
|
454
|
+
f.flush()
|
|
455
|
+
|
|
456
|
+
def test_write_file(self):
|
|
457
|
+
file_system.writefile('memory:///a/b/e', b'abe', mode='wb')
|
|
458
|
+
self.assertTrue(self.fs.exists('memory:///a/b/e'))
|
|
459
|
+
self.assertEqual(self.fs.cat('memory:///a/b/e'), b'abe')
|
|
460
|
+
|
|
461
|
+
def test_exists(self):
|
|
462
|
+
self.assertTrue(file_system.path_exists('memory:///a/b/c'))
|
|
463
|
+
self.assertFalse(file_system.path_exists('memory:///a/b/nonexist'))
|
|
464
|
+
|
|
465
|
+
def test_isdir(self):
|
|
466
|
+
self.assertTrue(file_system.isdir('memory:///a/b'))
|
|
467
|
+
self.assertTrue(file_system.isdir('memory:///a/e'))
|
|
468
|
+
self.assertFalse(file_system.isdir('memory:///a/b/c'))
|
|
469
|
+
|
|
470
|
+
def test_listdir(self):
|
|
471
|
+
self.assertCountEqual(file_system.listdir('memory:///a'), ['b', 'e'])
|
|
472
|
+
self.assertCountEqual(file_system.listdir('memory:///a/b'), ['c', 'd'])
|
|
473
|
+
|
|
474
|
+
def test_glob(self):
|
|
475
|
+
self.assertCountEqual(
|
|
476
|
+
file_system.glob('memory:///a/b/*'),
|
|
477
|
+
['memory:///a/b/c', 'memory:///a/b/d']
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
def test_mkdir(self):
|
|
481
|
+
file_system.mkdir('memory:///a/f')
|
|
482
|
+
self.assertTrue(self.fs.isdir('memory:///a/f'))
|
|
483
|
+
|
|
484
|
+
def test_mkdirs(self):
|
|
485
|
+
file_system.mkdirs('memory:///g/h/i')
|
|
486
|
+
self.assertTrue(self.fs.isdir('memory:///g/h/i'))
|
|
487
|
+
|
|
488
|
+
def test_rm(self):
|
|
489
|
+
file_system.rm('memory:///a/b/c')
|
|
490
|
+
self.assertFalse(self.fs.exists('memory:///a/b/c'))
|
|
491
|
+
|
|
492
|
+
def test_rename(self):
|
|
493
|
+
file_system.rename('memory:///a/b/c', 'memory:///a/b/c_new')
|
|
494
|
+
self.assertFalse(self.fs.exists('memory:///a/b/c'))
|
|
495
|
+
self.assertTrue(self.fs.exists('memory:///a/b/c_new'))
|
|
496
|
+
with self.assertRaisesRegex(ValueError, 'Rename across different'):
|
|
497
|
+
file_system.rename('memory:///a/b/c_new', 'file:///a/b/c_d')
|
|
498
|
+
|
|
499
|
+
def test_chmod(self):
|
|
500
|
+
mock_fs = mock.Mock()
|
|
501
|
+
mock_fs.chmod = mock.Mock()
|
|
502
|
+
with mock.patch('fsspec.core.url_to_fs', return_value=(mock_fs, 'path')):
|
|
503
|
+
file_system.chmod('protocol:///path', 0o777)
|
|
504
|
+
mock_fs.chmod.assert_called_once_with('path', 0o777)
|
|
505
|
+
|
|
506
|
+
def test_rmdir(self):
|
|
507
|
+
file_system.rmdir('memory:///a/e')
|
|
508
|
+
self.assertFalse(self.fs.exists('memory:///a/e'))
|
|
509
|
+
|
|
510
|
+
def test_rmdirs(self):
|
|
511
|
+
file_system.mkdirs('memory:///x/y/z')
|
|
512
|
+
self.assertTrue(file_system.isdir('memory:///x/y/z'))
|
|
513
|
+
file_system.rmdirs('memory:///x')
|
|
514
|
+
self.assertFalse(file_system.path_exists('memory:///x'))
|
|
515
|
+
|
|
516
|
+
def test_fsspec_uri_catcher(self):
|
|
517
|
+
with mock.patch.object(
|
|
518
|
+
file_system.FsspecFileSystem, 'exists', return_value=True
|
|
519
|
+
) as mock_fsspec_exists:
|
|
520
|
+
# We use a protocol that is not registered in
|
|
521
|
+
# fsspec.available_protocols() to make sure _FsspecUriCatcher is used.
|
|
522
|
+
self.assertTrue(file_system.path_exists('some-proto://foo'))
|
|
523
|
+
mock_fsspec_exists.assert_called_once_with('some-proto://foo')
|
|
524
|
+
|
|
525
|
+
# For full coverage of _FsspecUriCatcher.get_fs returning StdFileSystem,
|
|
526
|
+
# we need to test a non-URI path that doesn't match other prefixes.
|
|
527
|
+
# We mock StdFileSystem.exists to check if it's called.
|
|
528
|
+
with mock.patch.object(
|
|
529
|
+
file_system.StdFileSystem, 'exists', return_value=True
|
|
530
|
+
) as mock_std_exists:
|
|
531
|
+
self.assertTrue(file_system.path_exists('/foo/bar/baz'))
|
|
532
|
+
mock_std_exists.assert_called_once_with('/foo/bar/baz')
|
|
533
|
+
|
|
534
|
+
with mock.patch.object(
|
|
535
|
+
file_system.FsspecFileSystem, 'rename', return_value=None
|
|
536
|
+
) as mock_fsspec_rename:
|
|
537
|
+
file_system.rename('some-proto://foo', 'some-proto://bar')
|
|
538
|
+
mock_fsspec_rename.assert_called_once_with(
|
|
539
|
+
'some-proto://foo', 'some-proto://bar'
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
|
|
426
543
|
if __name__ == '__main__':
|
|
427
544
|
unittest.main()
|
{pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/__init__.py
RENAMED
|
@@ -147,4 +147,11 @@ from pyglove.core.symbolic.list import mark_as_insertion
|
|
|
147
147
|
from pyglove.core.symbolic.base import WritePermissionError
|
|
148
148
|
from pyglove.core.symbolic.error_info import ErrorInfo
|
|
149
149
|
|
|
150
|
+
# Unknown symbols.
|
|
151
|
+
from pyglove.core.symbolic.unknown_symbols import UnknownSymbol
|
|
152
|
+
from pyglove.core.symbolic.unknown_symbols import UnknownType
|
|
153
|
+
from pyglove.core.symbolic.unknown_symbols import UnknownFunction
|
|
154
|
+
from pyglove.core.symbolic.unknown_symbols import UnknownMethod
|
|
155
|
+
from pyglove.core.symbolic.unknown_symbols import UnknownTypedObject
|
|
156
|
+
|
|
150
157
|
# pylint: enable=g-bad-import-order
|
{pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/base.py
RENAMED
|
@@ -2042,7 +2042,7 @@ def from_json(
|
|
|
2042
2042
|
context: Optional[utils.JSONConversionContext] = None,
|
|
2043
2043
|
auto_symbolic: bool = True,
|
|
2044
2044
|
auto_import: bool = True,
|
|
2045
|
-
|
|
2045
|
+
convert_unknown: bool = False,
|
|
2046
2046
|
allow_partial: bool = False,
|
|
2047
2047
|
root_path: Optional[utils.KeyPath] = None,
|
|
2048
2048
|
value_spec: Optional[pg_typing.ValueSpec] = None,
|
|
@@ -2073,8 +2073,13 @@ def from_json(
|
|
|
2073
2073
|
identify its parent module and automatically import it. For example,
|
|
2074
2074
|
if the type is 'foo.bar.A', PyGlove will try to import 'foo.bar' and
|
|
2075
2075
|
find the class 'A' within the imported module.
|
|
2076
|
-
|
|
2077
|
-
|
|
2076
|
+
convert_unknown: If True, when a '_type' is not registered and cannot
|
|
2077
|
+
be imported, PyGlove will create objects of:
|
|
2078
|
+
- `pg.symbolic.UnknownType` for unknown types;
|
|
2079
|
+
- `pg.symbolic.UnknownTypedObject` for objects of unknown types;
|
|
2080
|
+
- `pg.symbolic.UnknownFunction` for unknown functions;
|
|
2081
|
+
- `pg.symbolic.UnknownMethod` for unknown methods.
|
|
2082
|
+
If False, TypeError will be raised.
|
|
2078
2083
|
allow_partial: Whether to allow elements of the list to be partial.
|
|
2079
2084
|
root_path: KeyPath of loaded object in its object tree.
|
|
2080
2085
|
value_spec: The value spec for the symbolic list or dict.
|
|
@@ -2095,7 +2100,12 @@ def from_json(
|
|
|
2095
2100
|
if context is None:
|
|
2096
2101
|
if (isinstance(json_value, dict) and (
|
|
2097
2102
|
context_node := json_value.get(utils.JSONConvertible.CONTEXT_KEY))):
|
|
2098
|
-
context = utils.JSONConversionContext.from_json(
|
|
2103
|
+
context = utils.JSONConversionContext.from_json(
|
|
2104
|
+
context_node,
|
|
2105
|
+
auto_import=auto_import,
|
|
2106
|
+
convert_unknown=convert_unknown,
|
|
2107
|
+
**kwargs
|
|
2108
|
+
)
|
|
2099
2109
|
json_value = json_value[utils.JSONConvertible.ROOT_VALUE_KEY]
|
|
2100
2110
|
else:
|
|
2101
2111
|
context = utils.JSONConversionContext()
|
|
@@ -2103,7 +2113,7 @@ def from_json(
|
|
|
2103
2113
|
typename_resolved = kwargs.pop('_typename_resolved', False)
|
|
2104
2114
|
if not typename_resolved:
|
|
2105
2115
|
json_value = utils.json_conversion.resolve_typenames(
|
|
2106
|
-
json_value, auto_import,
|
|
2116
|
+
json_value, auto_import, convert_unknown
|
|
2107
2117
|
)
|
|
2108
2118
|
|
|
2109
2119
|
def _load_child(k, v):
|
|
@@ -2177,7 +2187,7 @@ def from_json_str(
|
|
|
2177
2187
|
*,
|
|
2178
2188
|
context: Optional[utils.JSONConversionContext] = None,
|
|
2179
2189
|
auto_import: bool = True,
|
|
2180
|
-
|
|
2190
|
+
convert_unknown: bool = False,
|
|
2181
2191
|
allow_partial: bool = False,
|
|
2182
2192
|
root_path: Optional[utils.KeyPath] = None,
|
|
2183
2193
|
value_spec: Optional[pg_typing.ValueSpec] = None,
|
|
@@ -2205,8 +2215,13 @@ def from_json_str(
|
|
|
2205
2215
|
identify its parent module and automatically import it. For example,
|
|
2206
2216
|
if the type is 'foo.bar.A', PyGlove will try to import 'foo.bar' and
|
|
2207
2217
|
find the class 'A' within the imported module.
|
|
2208
|
-
|
|
2209
|
-
|
|
2218
|
+
convert_unknown: If True, when a '_type' is not registered and cannot
|
|
2219
|
+
be imported, PyGlove will create objects of:
|
|
2220
|
+
- `pg.symbolic.UnknownType` for unknown types;
|
|
2221
|
+
- `pg.symbolic.UnknownTypedObject` for objects of unknown types;
|
|
2222
|
+
- `pg.symbolic.UnknownFunction` for unknown functions;
|
|
2223
|
+
- `pg.symbolic.UnknownMethod` for unknown methods.
|
|
2224
|
+
If False, TypeError will be raised.
|
|
2210
2225
|
allow_partial: If True, allow a partial symbolic object to be created.
|
|
2211
2226
|
Otherwise error will be raised on partial value.
|
|
2212
2227
|
root_path: The symbolic path used for the deserialized root object.
|
|
@@ -2236,7 +2251,7 @@ def from_json_str(
|
|
|
2236
2251
|
_decode_int_keys(json.loads(json_str)),
|
|
2237
2252
|
context=context,
|
|
2238
2253
|
auto_import=auto_import,
|
|
2239
|
-
|
|
2254
|
+
convert_unknown=convert_unknown,
|
|
2240
2255
|
allow_partial=allow_partial,
|
|
2241
2256
|
root_path=root_path,
|
|
2242
2257
|
value_spec=value_spec,
|
{pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/object.py
RENAMED
|
@@ -339,7 +339,8 @@ class Object(base.Symbolic, metaclass=ObjectMeta):
|
|
|
339
339
|
|
|
340
340
|
# Set `__serialization_key__` before JSONConvertible.__init_subclass__
|
|
341
341
|
# is called.
|
|
342
|
-
|
|
342
|
+
if '__serialization_key__' not in cls.__dict__:
|
|
343
|
+
setattr(cls, '__serialization_key__', cls.__type_name__)
|
|
343
344
|
|
|
344
345
|
super().__init_subclass__()
|
|
345
346
|
|
{pyglove-0.5.0.dev202511161718 → pyglove-0.5.0.dev202511250811}/pyglove/core/symbolic/object_test.py
RENAMED
|
@@ -38,6 +38,7 @@ from pyglove.core.symbolic.object import use_init_args as pg_use_init_args
|
|
|
38
38
|
from pyglove.core.symbolic.origin import Origin
|
|
39
39
|
from pyglove.core.symbolic.pure_symbolic import NonDeterministic
|
|
40
40
|
from pyglove.core.symbolic.pure_symbolic import PureSymbolic
|
|
41
|
+
from pyglove.core.symbolic.unknown_symbols import UnknownTypedObject
|
|
41
42
|
from pyglove.core.views.html import tree_view # pylint: disable=unused-import
|
|
42
43
|
|
|
43
44
|
|
|
@@ -3158,7 +3159,7 @@ class SerializationTest(unittest.TestCase):
|
|
|
3158
3159
|
Q.partial(P.partial()).to_json_str(), allow_partial=True),
|
|
3159
3160
|
Q.partial(P.partial()))
|
|
3160
3161
|
|
|
3161
|
-
def
|
|
3162
|
+
def test_serialization_with_convert_unknown(self):
|
|
3162
3163
|
|
|
3163
3164
|
class P(Object):
|
|
3164
3165
|
auto_register = False
|
|
@@ -3181,15 +3182,17 @@ class SerializationTest(unittest.TestCase):
|
|
|
3181
3182
|
}
|
|
3182
3183
|
)
|
|
3183
3184
|
self.assertEqual(
|
|
3184
|
-
base.from_json_str(
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3185
|
+
base.from_json_str(
|
|
3186
|
+
Q(P(1), y='foo').to_json_str(), convert_unknown=True
|
|
3187
|
+
),
|
|
3188
|
+
UnknownTypedObject(
|
|
3189
|
+
type_name=Q.__type_name__,
|
|
3190
|
+
p=UnknownTypedObject(
|
|
3191
|
+
type_name=P.__type_name__,
|
|
3192
|
+
x=1
|
|
3193
|
+
),
|
|
3194
|
+
y='foo'
|
|
3195
|
+
)
|
|
3193
3196
|
)
|
|
3194
3197
|
|
|
3195
3198
|
def test_serialization_with_converter(self):
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Copyright 2021 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 types for reprenting unknown types and objects."""
|
|
15
|
+
|
|
16
|
+
from typing import Annotated, Any, ClassVar, Literal
|
|
17
|
+
from pyglove.core import typing as pg_typing
|
|
18
|
+
from pyglove.core import utils
|
|
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
|
+
|
|
22
|
+
|
|
23
|
+
class UnknownSymbol(pg_object.Object, pg_typing.CustomTyping):
|
|
24
|
+
"""Interface for symbolic representation of unknown symbols."""
|
|
25
|
+
auto_register = False
|
|
26
|
+
|
|
27
|
+
def custom_apply(self, *args, **kwargs) -> tuple[bool, Any]:
|
|
28
|
+
"""Bypass PyGlove type check."""
|
|
29
|
+
return (False, self)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class UnknownType(UnknownSymbol):
|
|
33
|
+
"""Symbolic object for representing unknown types."""
|
|
34
|
+
|
|
35
|
+
auto_register = True
|
|
36
|
+
__serialization_key__ = 'unknown_type'
|
|
37
|
+
|
|
38
|
+
# TODO(daiyip): Revisit the design on how `pg.typing.Object()` handles
|
|
39
|
+
# UnknownType. This hacky solution should be removed in the future.
|
|
40
|
+
__no_type_check__ = True
|
|
41
|
+
|
|
42
|
+
name: str
|
|
43
|
+
args: list[Any] = []
|
|
44
|
+
|
|
45
|
+
def sym_jsonify(self, **kwargs) -> utils.JSONValueType:
|
|
46
|
+
json_dict = {'_type': 'type', 'name': self.name}
|
|
47
|
+
if self.args:
|
|
48
|
+
json_dict['args'] = utils.to_json(self.args, **kwargs)
|
|
49
|
+
return json_dict
|
|
50
|
+
|
|
51
|
+
def format(
|
|
52
|
+
self,
|
|
53
|
+
compact: bool = False,
|
|
54
|
+
verbose: bool = True,
|
|
55
|
+
root_indent: int = 0,
|
|
56
|
+
**kwargs
|
|
57
|
+
) -> str:
|
|
58
|
+
s = f'<unknown-type {self.name}>'
|
|
59
|
+
if self.args:
|
|
60
|
+
s += f'[{", ".join(repr(x) for x in self.args)}]'
|
|
61
|
+
return s
|
|
62
|
+
|
|
63
|
+
def __call__(self, **kwargs):
|
|
64
|
+
return UnknownTypedObject(
|
|
65
|
+
type_name=self.name, **kwargs
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class UnknownCallable(UnknownSymbol):
|
|
70
|
+
"""Symbolic object for representing unknown callables."""
|
|
71
|
+
|
|
72
|
+
auto_register = False
|
|
73
|
+
name: str
|
|
74
|
+
CALLABLE_TYPE: ClassVar[Literal['function', 'method']]
|
|
75
|
+
|
|
76
|
+
def sym_jsonify(self, **kwargs) -> utils.JSONValueType:
|
|
77
|
+
return {'_type': self.CALLABLE_TYPE, 'name': self.name}
|
|
78
|
+
|
|
79
|
+
def format(
|
|
80
|
+
self,
|
|
81
|
+
compact: bool = False,
|
|
82
|
+
verbose: bool = True,
|
|
83
|
+
root_indent: int = 0,
|
|
84
|
+
**kwargs
|
|
85
|
+
) -> str:
|
|
86
|
+
return f'<unknown-{self.CALLABLE_TYPE} {self.name}>'
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class UnknownFunction(UnknownCallable):
|
|
90
|
+
"""Symbolic objject for representing unknown functions."""
|
|
91
|
+
|
|
92
|
+
auto_register = True
|
|
93
|
+
__serialization_key__ = 'unknown_function'
|
|
94
|
+
CALLABLE_TYPE = 'function'
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class UnknownMethod(UnknownCallable):
|
|
98
|
+
"""Symbolic object for representing unknown methods."""
|
|
99
|
+
|
|
100
|
+
auto_register = True
|
|
101
|
+
__serialization_key__ = 'unknown_method'
|
|
102
|
+
CALLABLE_TYPE = 'method'
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class UnknownTypedObject(UnknownSymbol):
|
|
106
|
+
"""Symbolic object for representing objects of unknown-type."""
|
|
107
|
+
|
|
108
|
+
auto_register = True
|
|
109
|
+
__serialization_key__ = 'unknown_object'
|
|
110
|
+
|
|
111
|
+
type_name: str
|
|
112
|
+
__kwargs__: Annotated[
|
|
113
|
+
Any,
|
|
114
|
+
(
|
|
115
|
+
'Fields of the original object will be kept as symbolic attributes '
|
|
116
|
+
'of this object so they can be accessed through `__getattr__`.'
|
|
117
|
+
)
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
def sym_jsonify(self, **kwargs) -> utils.JSONValueType:
|
|
121
|
+
"""Converts current object to a dict of plain Python objects."""
|
|
122
|
+
json_dict = self._sym_attributes.to_json(
|
|
123
|
+
exclude_keys=set(['type_name']), **kwargs
|
|
124
|
+
)
|
|
125
|
+
assert isinstance(json_dict, dict)
|
|
126
|
+
json_dict[utils.JSONConvertible.TYPE_NAME_KEY] = self.type_name
|
|
127
|
+
return json_dict
|
|
128
|
+
|
|
129
|
+
def format(
|
|
130
|
+
self,
|
|
131
|
+
compact: bool = False,
|
|
132
|
+
verbose: bool = True,
|
|
133
|
+
root_indent: int = 0,
|
|
134
|
+
**kwargs
|
|
135
|
+
) -> str:
|
|
136
|
+
exclude_keys = kwargs.pop('exclude_keys', set())
|
|
137
|
+
exclude_keys.add('type_name')
|
|
138
|
+
kwargs['exclude_keys'] = exclude_keys
|
|
139
|
+
return self._sym_attributes.format(
|
|
140
|
+
compact,
|
|
141
|
+
verbose,
|
|
142
|
+
root_indent,
|
|
143
|
+
cls_name=f'<unknown-type {self.type_name}>',
|
|
144
|
+
key_as_attribute=True,
|
|
145
|
+
bracket_type=utils.BracketType.ROUND,
|
|
146
|
+
**kwargs,
|
|
147
|
+
)
|