pyglove 0.4.5.dev202502040809__tar.gz → 0.4.5.dev202502060809__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.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/PKG-INFO +1 -1
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/object.py +4 -1
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/__init__.py +3 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/annotation_conversion.py +236 -6
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/annotation_conversion_test.py +180 -9
- pyglove-0.4.5.dev202502060809/pyglove/core/typing/annotation_future_test.py +135 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/class_schema.py +36 -18
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/class_schema_test.py +15 -7
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove.egg-info/PKG-INFO +1 -1
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove.egg-info/SOURCES.txt +1 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/LICENSE +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/README.md +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/errors.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/errors_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/execution.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/execution_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/function_generation.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/function_generation_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/parsing.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/parsing_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/permissions.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/coding/permissions_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/detouring/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/detouring/class_detour.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/detouring/class_detour_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/base_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/categorical.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/categorical_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/custom.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/custom_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/deduping.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/deduping_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/dna_generator.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/dna_generator_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/numerical.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/numerical_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/random.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/random_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/space.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/space_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/sweeping.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/geno/sweeping_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/categorical.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/categorical_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/custom.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/custom_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/derived.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/derived_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/dynamic_evaluation.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/dynamic_evaluation_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/evolvable.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/evolvable_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/iter.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/iter_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/numerical.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/numerical_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/object_template.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/hyper/object_template_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/io/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/io/file_system.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/io/file_system_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/io/sequence.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/io/sequence_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/logging.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/logging_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/patching/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/patching/object_factory.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/patching/object_factory_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/patching/pattern_based.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/patching/pattern_based_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/patching/rule_based.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/patching/rule_based_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/base_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/boilerplate.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/boilerplate_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/class_wrapper.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/class_wrapper_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/compounding.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/compounding_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/contextual_object.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/contextual_object_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/dict.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/dict_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/diff.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/diff_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/flags.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/flags_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/functor.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/functor_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/inferred.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/inferred_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/list.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/list_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/object_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/origin.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/origin_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/pure_symbolic.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/ref.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/ref_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/symbolize.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/symbolize_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/backend.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/backend_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/early_stopping.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/local_backend.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/protocols.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/protocols_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/sample.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/tuning/sample_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/annotated.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/annotated_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/callable_ext.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/callable_ext_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/callable_signature.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/callable_signature_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/custom_typing.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/inspect.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/inspect_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/key_specs.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/key_specs_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/pytype_support.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/type_conversion.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/type_conversion_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/typed_missing.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/typed_missing_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/value_specs.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/value_specs_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/common_traits.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/common_traits_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/contextual.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/contextual_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/docstr_utils.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/docstr_utils_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/error_utils.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/error_utils_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/formatting.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/formatting_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/hierarchical.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/hierarchical_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/json_conversion.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/json_conversion_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/missing.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/missing_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/text_color.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/text_color_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/thread_local.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/thread_local_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/timing.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/timing_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/value_location.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/utils/value_location_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/base_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/base_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/label.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/label_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/progress_bar.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/progress_bar_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/tab.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/tab_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/tooltip.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/controls/tooltip_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/tree_view.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/views/html/tree_view_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/early_stopping/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/early_stopping/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/early_stopping/base_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/early_stopping/step_wise.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/early_stopping/step_wise_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/base_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/hill_climb.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/hill_climb_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/mutators.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/mutators_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/neat.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/neat_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/nsga2.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/nsga2_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/recombinators.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/recombinators_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/regularized_evolution.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/regularized_evolution_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/selectors.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/selectors_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/where.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/evolution/where_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/mutfun/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/mutfun/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/mutfun/base_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/mutfun/basic_ops.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/mutfun/basic_ops_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/__init__.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/base.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/base_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/maths.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/maths_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/randoms.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/randoms_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/step_wise.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/ext/scalars/step_wise_test.py +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove.egg-info/dependency_links.txt +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove.egg-info/requires.txt +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove.egg-info/top_level.txt +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/setup.cfg +0 -0
- {pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/setup.py +0 -0
{pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/symbolic/object.py
RENAMED
@@ -16,6 +16,7 @@
|
|
16
16
|
import abc
|
17
17
|
import functools
|
18
18
|
import inspect
|
19
|
+
import sys
|
19
20
|
import typing
|
20
21
|
from typing import Any, Dict, Iterator, List, Optional, Sequence, Union
|
21
22
|
|
@@ -154,7 +155,9 @@ class ObjectMeta(abc.ABCMeta):
|
|
154
155
|
if typing.get_origin(attr_annotation) is typing.ClassVar:
|
155
156
|
continue
|
156
157
|
|
157
|
-
field = pg_typing.Field.from_annotation(
|
158
|
+
field = pg_typing.Field.from_annotation(
|
159
|
+
key, attr_annotation, parent_module=sys.modules[cls.__module__]
|
160
|
+
)
|
158
161
|
if isinstance(key, pg_typing.ConstStrKey):
|
159
162
|
attr_value = cls.__dict__.get(attr_name, pg_typing.MISSING_VALUE)
|
160
163
|
if attr_value != pg_typing.MISSING_VALUE:
|
{pyglove-0.4.5.dev202502040809 → pyglove-0.4.5.dev202502060809}/pyglove/core/typing/__init__.py
RENAMED
@@ -375,6 +375,9 @@ import pyglove.core.typing.annotation_conversion # pylint: disable=unused-impor
|
|
375
375
|
# Interface for custom typing.
|
376
376
|
from pyglove.core.typing.custom_typing import CustomTyping
|
377
377
|
|
378
|
+
# Annotation conversion
|
379
|
+
from pyglove.core.typing.annotation_conversion import annotation_from_str
|
380
|
+
|
378
381
|
# Callable signature.
|
379
382
|
from pyglove.core.typing.callable_signature import Argument
|
380
383
|
from pyglove.core.typing.callable_signature import CallableType
|
@@ -13,11 +13,13 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
"""Conversion from annotations to PyGlove value specs."""
|
15
15
|
|
16
|
+
import builtins
|
16
17
|
import collections
|
17
18
|
import inspect
|
18
19
|
import types
|
19
20
|
import typing
|
20
21
|
|
22
|
+
from pyglove.core import coding
|
21
23
|
from pyglove.core import utils
|
22
24
|
from pyglove.core.typing import annotated
|
23
25
|
from pyglove.core.typing import class_schema
|
@@ -35,6 +37,231 @@ _Annotated = getattr(typing, 'Annotated', None) # pylint: disable=invalid-name
|
|
35
37
|
_UnionType = getattr(types, 'UnionType', None) # pylint: disable=invalid-name
|
36
38
|
|
37
39
|
|
40
|
+
def annotation_from_str(
|
41
|
+
annotation_str: str,
|
42
|
+
parent_module: typing.Optional[types.ModuleType] = None,
|
43
|
+
) -> typing.Any:
|
44
|
+
"""Parses annotations from str.
|
45
|
+
|
46
|
+
BNF for PyType annotations:
|
47
|
+
|
48
|
+
```
|
49
|
+
<maybe_union> ::= <type> | <type> "|" <maybe_union>
|
50
|
+
<type> ::= <literal_type> | <non_literal_type>
|
51
|
+
|
52
|
+
<literal_type> ::= "Literal"<literal_params>
|
53
|
+
<literal_params> ::= "["<python_values>"]" (parsed by `pg.coding.evaluate`)
|
54
|
+
|
55
|
+
<non_literal_type> ::= <type_id> | <type_id>"["<type_arg>"]"
|
56
|
+
<type_arg> ::= <maybe_type_list> | <maybe_type_list>","<maybe_type_list>
|
57
|
+
<maybe_type_list> ::= "["<type_arg>"]" | <maybe_union>
|
58
|
+
<type_id> ::= 'aAz_.1-9'
|
59
|
+
```
|
60
|
+
|
61
|
+
Args:
|
62
|
+
annotation_str: String form of type annotations. E.g. "list[str]"
|
63
|
+
parent_module: The module where the annotation was defined.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
Object form of the annotation.
|
67
|
+
|
68
|
+
Raises:
|
69
|
+
SyntaxError: If the annotation string is invalid.
|
70
|
+
"""
|
71
|
+
s = annotation_str
|
72
|
+
context = dict(pos=0)
|
73
|
+
|
74
|
+
def _eof() -> bool:
|
75
|
+
return context['pos'] == len(s)
|
76
|
+
|
77
|
+
def _pos() -> int:
|
78
|
+
return context['pos']
|
79
|
+
|
80
|
+
def _next(n: int = 1, offset: int = 0) -> str:
|
81
|
+
if _eof():
|
82
|
+
return '<EOF>'
|
83
|
+
return s[_pos() + offset:_pos() + offset + n]
|
84
|
+
|
85
|
+
def _advance(n: int) -> None:
|
86
|
+
context['pos'] += n
|
87
|
+
|
88
|
+
def _error_illustration() -> str:
|
89
|
+
return f'{s}\n{" " * _pos()}' + '^'
|
90
|
+
|
91
|
+
def _match(ch) -> bool:
|
92
|
+
if _next(len(ch)) == ch:
|
93
|
+
_advance(len(ch))
|
94
|
+
return True
|
95
|
+
return False
|
96
|
+
|
97
|
+
def _skip_whitespaces() -> None:
|
98
|
+
while _next() in ' \t':
|
99
|
+
_advance(1)
|
100
|
+
|
101
|
+
def _maybe_union():
|
102
|
+
t = _type()
|
103
|
+
while not _eof():
|
104
|
+
_skip_whitespaces()
|
105
|
+
if _match('|'):
|
106
|
+
t = t | _type()
|
107
|
+
else:
|
108
|
+
break
|
109
|
+
return t
|
110
|
+
|
111
|
+
def _type():
|
112
|
+
type_id = _type_id()
|
113
|
+
t = _resolve(type_id)
|
114
|
+
if t is typing.Literal:
|
115
|
+
return t[_literal_params()]
|
116
|
+
elif _match('['):
|
117
|
+
arg = _type_arg()
|
118
|
+
if not _match(']'):
|
119
|
+
raise SyntaxError(
|
120
|
+
f'Expected "]" at position {_pos()}.\n\n' + _error_illustration()
|
121
|
+
)
|
122
|
+
return t[arg]
|
123
|
+
return t
|
124
|
+
|
125
|
+
def _literal_params():
|
126
|
+
if not _match('['):
|
127
|
+
raise SyntaxError(
|
128
|
+
f'Expected "[" at position {_pos()}.\n\n' + _error_illustration()
|
129
|
+
)
|
130
|
+
arg_start = _pos()
|
131
|
+
in_str = False
|
132
|
+
escape_mode = False
|
133
|
+
num_open_bracket = 1
|
134
|
+
|
135
|
+
while num_open_bracket > 0:
|
136
|
+
ch = _next()
|
137
|
+
if _eof():
|
138
|
+
raise SyntaxError(
|
139
|
+
f'Unexpected end of annotation at position {_pos()}.\n\n'
|
140
|
+
+ _error_illustration()
|
141
|
+
)
|
142
|
+
if ch == '\\':
|
143
|
+
escape_mode = not escape_mode
|
144
|
+
else:
|
145
|
+
escape_mode = False
|
146
|
+
|
147
|
+
if ch == "'" and not escape_mode:
|
148
|
+
in_str = not in_str
|
149
|
+
elif not in_str:
|
150
|
+
if ch == '[':
|
151
|
+
num_open_bracket += 1
|
152
|
+
elif ch == ']':
|
153
|
+
num_open_bracket -= 1
|
154
|
+
_advance(1)
|
155
|
+
|
156
|
+
arg_str = s[arg_start:_pos() - 1]
|
157
|
+
return coding.evaluate(
|
158
|
+
'(' + arg_str + ')', permission=coding.CodePermission.BASIC
|
159
|
+
)
|
160
|
+
|
161
|
+
def _type_arg():
|
162
|
+
t_args = []
|
163
|
+
t_args.append(_maybe_type_list())
|
164
|
+
while _match(','):
|
165
|
+
t_args.append(_maybe_type_list())
|
166
|
+
return tuple(t_args) if len(t_args) > 1 else t_args[0]
|
167
|
+
|
168
|
+
def _maybe_type_list():
|
169
|
+
if _match('['):
|
170
|
+
ret = _type_arg()
|
171
|
+
if not _match(']'):
|
172
|
+
raise SyntaxError(
|
173
|
+
f'Expected "]" at position {_pos()}.\n\n' + _error_illustration()
|
174
|
+
)
|
175
|
+
return list(ret) if isinstance(ret, tuple) else [ret]
|
176
|
+
return _maybe_union()
|
177
|
+
|
178
|
+
def _type_id() -> str:
|
179
|
+
_skip_whitespaces()
|
180
|
+
if _match('...'):
|
181
|
+
return '...'
|
182
|
+
start = _pos()
|
183
|
+
while not _eof():
|
184
|
+
c = _next()
|
185
|
+
if c.isalnum() or c in '_.':
|
186
|
+
_advance(1)
|
187
|
+
else:
|
188
|
+
break
|
189
|
+
t_id = s[start:_pos()]
|
190
|
+
if not all(x.isidentifier() for x in t_id.split('.')):
|
191
|
+
raise SyntaxError(
|
192
|
+
f'Expected type identifier, got {t_id!r} at position {start}.\n\n'
|
193
|
+
+ _error_illustration()
|
194
|
+
)
|
195
|
+
return t_id
|
196
|
+
|
197
|
+
def _resolve(type_id: str):
|
198
|
+
|
199
|
+
def _as_forward_ref() -> typing.ForwardRef:
|
200
|
+
return typing.ForwardRef(type_id, False, parent_module) # pytype: disable=not-callable
|
201
|
+
|
202
|
+
def _resolve_name(name: str, parent_obj: typing.Any):
|
203
|
+
if name == 'None':
|
204
|
+
return None, True
|
205
|
+
if parent_obj is not None and hasattr(parent_obj, name):
|
206
|
+
return getattr(parent_obj, name), False
|
207
|
+
if hasattr(builtins, name):
|
208
|
+
return getattr(builtins, name), True
|
209
|
+
if type_id == '...':
|
210
|
+
return ..., True
|
211
|
+
return utils.MISSING_VALUE, False
|
212
|
+
|
213
|
+
names = type_id.split('.')
|
214
|
+
if len(names) == 1:
|
215
|
+
reference, is_builtin = _resolve_name(names[0], parent_module)
|
216
|
+
if is_builtin:
|
217
|
+
return reference
|
218
|
+
if not is_builtin and (
|
219
|
+
# When reference is not found, we should treat it as a forward
|
220
|
+
# reference.
|
221
|
+
reference == utils.MISSING_VALUE
|
222
|
+
# When module is being reloaded, we should treat all non-builtin
|
223
|
+
# references as forward references.
|
224
|
+
or getattr(parent_module, '__reloading__', False)
|
225
|
+
):
|
226
|
+
return _as_forward_ref()
|
227
|
+
return reference
|
228
|
+
|
229
|
+
root_obj, _ = _resolve_name(names[0], parent_module)
|
230
|
+
# When root object is not found, we should treat it as a forward reference.
|
231
|
+
if root_obj == utils.MISSING_VALUE:
|
232
|
+
return _as_forward_ref()
|
233
|
+
|
234
|
+
parent_obj = root_obj
|
235
|
+
# When root object is a module, we should treat reference to its children
|
236
|
+
# as non-forward references.
|
237
|
+
if inspect.ismodule(root_obj):
|
238
|
+
for name in names[1:]:
|
239
|
+
parent_obj, _ = _resolve_name(name, parent_obj)
|
240
|
+
if parent_obj == utils.MISSING_VALUE:
|
241
|
+
raise TypeError(f'{type_id!r} does not exist.')
|
242
|
+
return parent_obj
|
243
|
+
# When root object is non-module variable of current module, and when the
|
244
|
+
# module is being reloaded, we should treat reference to its children as
|
245
|
+
# forward references.
|
246
|
+
elif getattr(parent_module, '__reloading__', False):
|
247
|
+
return _as_forward_ref()
|
248
|
+
# When root object is non-module variable of current module, we should treat
|
249
|
+
# unresolved reference to its children as forward references.
|
250
|
+
else:
|
251
|
+
for name in names[1:]:
|
252
|
+
parent_obj, _ = _resolve_name(name, parent_obj)
|
253
|
+
if parent_obj == utils.MISSING_VALUE:
|
254
|
+
return _as_forward_ref()
|
255
|
+
return parent_obj
|
256
|
+
|
257
|
+
root = _maybe_union()
|
258
|
+
if _pos() != len(s):
|
259
|
+
raise SyntaxError(
|
260
|
+
'Unexpected end of annotation.\n\n' + _error_illustration()
|
261
|
+
)
|
262
|
+
return root
|
263
|
+
|
264
|
+
|
38
265
|
def _field_from_annotation(
|
39
266
|
key: typing.Union[str, class_schema.KeySpec],
|
40
267
|
annotation: typing.Any,
|
@@ -91,7 +318,12 @@ def _value_spec_from_type_annotation(
|
|
91
318
|
parent_module: typing.Optional[types.ModuleType] = None
|
92
319
|
) -> class_schema.ValueSpec:
|
93
320
|
"""Creates a value spec from type annotation."""
|
94
|
-
if annotation
|
321
|
+
if isinstance(annotation, str) and not accept_value_as_annotation:
|
322
|
+
annotation = annotation_from_str(annotation, parent_module)
|
323
|
+
|
324
|
+
if annotation is None:
|
325
|
+
return vs.Object(type(None))
|
326
|
+
elif annotation is bool:
|
95
327
|
return vs.Bool()
|
96
328
|
elif annotation is int:
|
97
329
|
return vs.Int()
|
@@ -193,10 +425,7 @@ def _value_spec_from_type_annotation(
|
|
193
425
|
elif (
|
194
426
|
inspect.isclass(annotation)
|
195
427
|
or pg_inspect.is_generic(annotation)
|
196
|
-
or (isinstance(annotation, str) and not accept_value_as_annotation)
|
197
428
|
):
|
198
|
-
if isinstance(annotation, str) and parent_module is not None:
|
199
|
-
annotation = class_schema.ForwardRef(parent_module, annotation)
|
200
429
|
return vs.Object(annotation)
|
201
430
|
|
202
431
|
if accept_value_as_annotation:
|
@@ -227,11 +456,12 @@ def _value_spec_from_annotation(
|
|
227
456
|
return annotation
|
228
457
|
elif annotation == inspect.Parameter.empty:
|
229
458
|
return vs.Any()
|
230
|
-
|
459
|
+
|
460
|
+
if annotation is None:
|
231
461
|
if accept_value_as_annotation:
|
232
462
|
return vs.Any().noneable()
|
233
463
|
else:
|
234
|
-
return vs.
|
464
|
+
return vs.Object(type(None))
|
235
465
|
|
236
466
|
if auto_typing:
|
237
467
|
return _value_spec_from_type_annotation(
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright
|
1
|
+
# Copyright 2025 The PyGlove Authors
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -11,13 +11,12 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
|
-
"""Tests for pyglove.core.typing.annotation_conversion."""
|
15
|
-
|
16
14
|
import inspect
|
17
15
|
import sys
|
18
16
|
import typing
|
19
17
|
import unittest
|
20
18
|
|
19
|
+
from pyglove.core import coding
|
21
20
|
from pyglove.core.typing import annotated
|
22
21
|
from pyglove.core.typing import annotation_conversion
|
23
22
|
from pyglove.core.typing import key_specs as ks
|
@@ -28,7 +27,168 @@ from pyglove.core.typing.class_schema import ValueSpec
|
|
28
27
|
|
29
28
|
|
30
29
|
class Foo:
|
31
|
-
|
30
|
+
class Bar:
|
31
|
+
pass
|
32
|
+
|
33
|
+
|
34
|
+
_MODULE = sys.modules[__name__]
|
35
|
+
|
36
|
+
|
37
|
+
class AnnotationFromStrTest(unittest.TestCase):
|
38
|
+
"""Tests for annotation_from_str."""
|
39
|
+
|
40
|
+
def test_basic_types(self):
|
41
|
+
self.assertIsNone(annotation_conversion.annotation_from_str('None'))
|
42
|
+
self.assertEqual(annotation_conversion.annotation_from_str('str'), str)
|
43
|
+
self.assertEqual(annotation_conversion.annotation_from_str('int'), int)
|
44
|
+
self.assertEqual(annotation_conversion.annotation_from_str('float'), float)
|
45
|
+
self.assertEqual(annotation_conversion.annotation_from_str('bool'), bool)
|
46
|
+
self.assertEqual(annotation_conversion.annotation_from_str('list'), list)
|
47
|
+
self.assertEqual(
|
48
|
+
annotation_conversion.annotation_from_str('list[int]'), list[int]
|
49
|
+
)
|
50
|
+
self.assertEqual(annotation_conversion.annotation_from_str('tuple'), tuple)
|
51
|
+
self.assertEqual(
|
52
|
+
annotation_conversion.annotation_from_str('tuple[int]'), tuple[int]
|
53
|
+
)
|
54
|
+
self.assertEqual(
|
55
|
+
annotation_conversion.annotation_from_str('tuple[int, ...]'),
|
56
|
+
tuple[int, ...]
|
57
|
+
)
|
58
|
+
self.assertEqual(
|
59
|
+
annotation_conversion.annotation_from_str('tuple[int, str]'),
|
60
|
+
tuple[int, str]
|
61
|
+
)
|
62
|
+
self.assertEqual(
|
63
|
+
annotation_conversion.annotation_from_str('list[Foo]', _MODULE),
|
64
|
+
list[Foo]
|
65
|
+
)
|
66
|
+
self.assertEqual(
|
67
|
+
annotation_conversion.annotation_from_str('list[Foo.Bar]', _MODULE),
|
68
|
+
list[Foo.Bar]
|
69
|
+
)
|
70
|
+
self.assertEqual(
|
71
|
+
annotation_conversion.annotation_from_str('list[Foo.Baz]', _MODULE),
|
72
|
+
list[typing.ForwardRef('Foo.Baz', False, _MODULE)]
|
73
|
+
)
|
74
|
+
|
75
|
+
def test_generic_types(self):
|
76
|
+
self.assertEqual(
|
77
|
+
annotation_conversion.annotation_from_str('typing.List[str]', _MODULE),
|
78
|
+
typing.List[str]
|
79
|
+
)
|
80
|
+
|
81
|
+
def test_union(self):
|
82
|
+
self.assertEqual(
|
83
|
+
annotation_conversion.annotation_from_str(
|
84
|
+
'typing.Union[str, typing.Union[int, float]]', _MODULE),
|
85
|
+
typing.Union[str, int, float]
|
86
|
+
)
|
87
|
+
if sys.version_info >= (3, 10):
|
88
|
+
self.assertEqual(
|
89
|
+
annotation_conversion.annotation_from_str(
|
90
|
+
'str | int | float', _MODULE),
|
91
|
+
typing.Union[str, int, float]
|
92
|
+
)
|
93
|
+
|
94
|
+
def test_literal(self):
|
95
|
+
self.assertEqual(
|
96
|
+
annotation_conversion.annotation_from_str(
|
97
|
+
'typing.Literal[1, True, "a", \'"b"\', "\\"c\\"", "\\\\"]',
|
98
|
+
_MODULE
|
99
|
+
),
|
100
|
+
typing.Literal[1, True, 'a', '"b"', '"c"', '\\']
|
101
|
+
)
|
102
|
+
self.assertEqual(
|
103
|
+
annotation_conversion.annotation_from_str(
|
104
|
+
'typing.Literal[(1, 1), f"A {[1]}"]', _MODULE),
|
105
|
+
typing.Literal[(1, 1), 'A [1]']
|
106
|
+
)
|
107
|
+
with self.assertRaisesRegex(SyntaxError, 'Expected "\\["'):
|
108
|
+
annotation_conversion.annotation_from_str('typing.Literal', _MODULE)
|
109
|
+
|
110
|
+
with self.assertRaisesRegex(SyntaxError, 'Unexpected end of annotation'):
|
111
|
+
annotation_conversion.annotation_from_str('typing.Literal[1', _MODULE)
|
112
|
+
|
113
|
+
with self.assertRaisesRegex(
|
114
|
+
coding.CodeError, 'Function definition is not allowed'
|
115
|
+
):
|
116
|
+
annotation_conversion.annotation_from_str(
|
117
|
+
'typing.Literal[lambda x: x]', _MODULE
|
118
|
+
)
|
119
|
+
|
120
|
+
def test_callable(self):
|
121
|
+
self.assertEqual(
|
122
|
+
annotation_conversion.annotation_from_str(
|
123
|
+
'typing.Callable[int, int]', _MODULE),
|
124
|
+
typing.Callable[[int], int]
|
125
|
+
)
|
126
|
+
self.assertEqual(
|
127
|
+
annotation_conversion.annotation_from_str(
|
128
|
+
'typing.Callable[[int], int]', _MODULE),
|
129
|
+
typing.Callable[[int], int]
|
130
|
+
)
|
131
|
+
self.assertEqual(
|
132
|
+
annotation_conversion.annotation_from_str(
|
133
|
+
'typing.Callable[..., None]', _MODULE),
|
134
|
+
typing.Callable[..., None]
|
135
|
+
)
|
136
|
+
|
137
|
+
def test_forward_ref(self):
|
138
|
+
self.assertEqual(
|
139
|
+
annotation_conversion.annotation_from_str(
|
140
|
+
'AAA', _MODULE),
|
141
|
+
typing.ForwardRef(
|
142
|
+
'AAA', False, _MODULE
|
143
|
+
)
|
144
|
+
)
|
145
|
+
self.assertEqual(
|
146
|
+
annotation_conversion.annotation_from_str(
|
147
|
+
'typing.List[AAA]', _MODULE),
|
148
|
+
typing.List[
|
149
|
+
typing.ForwardRef(
|
150
|
+
'AAA', False, _MODULE
|
151
|
+
)
|
152
|
+
]
|
153
|
+
)
|
154
|
+
|
155
|
+
def test_reloading(self):
|
156
|
+
setattr(_MODULE, '__reloading__', True)
|
157
|
+
self.assertEqual(
|
158
|
+
annotation_conversion.annotation_from_str(
|
159
|
+
'typing.List[Foo]', _MODULE),
|
160
|
+
typing.List[
|
161
|
+
typing.ForwardRef(
|
162
|
+
'Foo', False, _MODULE
|
163
|
+
)
|
164
|
+
]
|
165
|
+
)
|
166
|
+
self.assertEqual(
|
167
|
+
annotation_conversion.annotation_from_str(
|
168
|
+
'typing.List[Foo.Bar]', _MODULE),
|
169
|
+
typing.List[
|
170
|
+
typing.ForwardRef(
|
171
|
+
'Foo.Bar', False, _MODULE
|
172
|
+
)
|
173
|
+
]
|
174
|
+
)
|
175
|
+
delattr(_MODULE, '__reloading__')
|
176
|
+
|
177
|
+
def test_bad_annotation(self):
|
178
|
+
with self.assertRaisesRegex(SyntaxError, 'Expected type identifier'):
|
179
|
+
annotation_conversion.annotation_from_str('typing.List[]')
|
180
|
+
|
181
|
+
with self.assertRaisesRegex(SyntaxError, 'Expected "]"'):
|
182
|
+
annotation_conversion.annotation_from_str('typing.List[int')
|
183
|
+
|
184
|
+
with self.assertRaisesRegex(SyntaxError, 'Unexpected end of annotation'):
|
185
|
+
annotation_conversion.annotation_from_str('typing.List[int]1', _MODULE)
|
186
|
+
|
187
|
+
with self.assertRaisesRegex(SyntaxError, 'Expected "]"'):
|
188
|
+
annotation_conversion.annotation_from_str('typing.Callable[[x')
|
189
|
+
|
190
|
+
with self.assertRaisesRegex(TypeError, '.* does not exist'):
|
191
|
+
annotation_conversion.annotation_from_str('typing.Foo', _MODULE)
|
32
192
|
|
33
193
|
|
34
194
|
class FieldFromAnnotationTest(unittest.TestCase):
|
@@ -132,17 +292,24 @@ class ValueSpecFromAnnotationTest(unittest.TestCase):
|
|
132
292
|
|
133
293
|
def test_none(self):
|
134
294
|
self.assertEqual(
|
135
|
-
ValueSpec.from_annotation(None, False), vs.
|
295
|
+
ValueSpec.from_annotation(None, False), vs.Object(type(None)))
|
136
296
|
self.assertEqual(
|
137
|
-
ValueSpec.from_annotation(None, True), vs.
|
297
|
+
ValueSpec.from_annotation('None', True), vs.Object(type(None)))
|
138
298
|
self.assertEqual(
|
139
|
-
ValueSpec.from_annotation(
|
140
|
-
|
299
|
+
ValueSpec.from_annotation(None, True), vs.Object(type(None)))
|
300
|
+
self.assertEqual(
|
301
|
+
ValueSpec.from_annotation(None, accept_value_as_annotation=True),
|
302
|
+
vs.Any().noneable()
|
303
|
+
)
|
141
304
|
|
142
305
|
def test_any(self):
|
143
306
|
self.assertEqual(
|
144
307
|
ValueSpec.from_annotation(typing.Any, False),
|
145
308
|
vs.Any(annotation=typing.Any))
|
309
|
+
self.assertEqual(
|
310
|
+
ValueSpec.from_annotation('typing.Any', True, parent_module=_MODULE),
|
311
|
+
vs.Any(annotation=typing.Any)
|
312
|
+
)
|
146
313
|
self.assertEqual(
|
147
314
|
ValueSpec.from_annotation(typing.Any, True),
|
148
315
|
vs.Any(annotation=typing.Any))
|
@@ -152,6 +319,7 @@ class ValueSpecFromAnnotationTest(unittest.TestCase):
|
|
152
319
|
|
153
320
|
def test_bool(self):
|
154
321
|
self.assertEqual(ValueSpec.from_annotation(bool, True), vs.Bool())
|
322
|
+
self.assertEqual(ValueSpec.from_annotation('bool', True), vs.Bool())
|
155
323
|
self.assertEqual(
|
156
324
|
ValueSpec.from_annotation(bool, False), vs.Any(annotation=bool))
|
157
325
|
self.assertEqual(
|
@@ -159,6 +327,7 @@ class ValueSpecFromAnnotationTest(unittest.TestCase):
|
|
159
327
|
|
160
328
|
def test_int(self):
|
161
329
|
self.assertEqual(ValueSpec.from_annotation(int, True), vs.Int())
|
330
|
+
self.assertEqual(ValueSpec.from_annotation('int', True), vs.Int())
|
162
331
|
self.assertEqual(ValueSpec.from_annotation(int, True, True), vs.Int())
|
163
332
|
self.assertEqual(
|
164
333
|
ValueSpec.from_annotation(int, False), vs.Any(annotation=int))
|
@@ -182,7 +351,9 @@ class ValueSpecFromAnnotationTest(unittest.TestCase):
|
|
182
351
|
ValueSpec.from_annotation(str, False, True), vs.Any(annotation=str))
|
183
352
|
|
184
353
|
self.assertEqual(
|
185
|
-
ValueSpec.from_annotation('A', False, False),
|
354
|
+
ValueSpec.from_annotation('A', False, False),
|
355
|
+
vs.Any(annotation='A')
|
356
|
+
)
|
186
357
|
self.assertEqual(
|
187
358
|
ValueSpec.from_annotation('A', False, True), vs.Str('A'))
|
188
359
|
self.assertEqual(
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# Copyright 2025 The PyGlove Authors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
import sys
|
17
|
+
import typing
|
18
|
+
from typing import List, Literal, Union
|
19
|
+
import unittest
|
20
|
+
|
21
|
+
from pyglove.core import symbolic as pg
|
22
|
+
from pyglove.core.typing import key_specs as ks
|
23
|
+
from pyglove.core.typing import value_specs as vs
|
24
|
+
|
25
|
+
|
26
|
+
class AnnotationFutureConversionTest(unittest.TestCase):
|
27
|
+
|
28
|
+
# Class with forward declaration must not be defined in functions.
|
29
|
+
class A(pg.Object):
|
30
|
+
a: typing.Optional[AnnotationFutureConversionTest.A]
|
31
|
+
b: List[AnnotationFutureConversionTest.A]
|
32
|
+
|
33
|
+
def assert_value_spec(self, cls, field_name, expected_value_spec):
|
34
|
+
self.assertEqual(cls.__schema__[field_name].value, expected_value_spec)
|
35
|
+
|
36
|
+
def test_basics(self):
|
37
|
+
|
38
|
+
class Foo(pg.Object):
|
39
|
+
a: int
|
40
|
+
b: float
|
41
|
+
c: bool
|
42
|
+
d: str
|
43
|
+
e: typing.Any
|
44
|
+
f: typing.Dict[str, typing.Any]
|
45
|
+
g: typing.List[str]
|
46
|
+
h: typing.Tuple[int, int]
|
47
|
+
i: typing.Callable[[int, int], None]
|
48
|
+
|
49
|
+
self.assert_value_spec(Foo, 'a', vs.Int())
|
50
|
+
self.assert_value_spec(Foo, 'b', vs.Float())
|
51
|
+
self.assert_value_spec(Foo, 'c', vs.Bool())
|
52
|
+
self.assert_value_spec(Foo, 'd', vs.Str())
|
53
|
+
self.assert_value_spec(Foo, 'e', vs.Any(annotation=typing.Any))
|
54
|
+
self.assert_value_spec(
|
55
|
+
Foo, 'f', vs.Dict([(ks.StrKey(), vs.Any(annotation=typing.Any))])
|
56
|
+
)
|
57
|
+
self.assert_value_spec(Foo, 'g', vs.List(vs.Str()))
|
58
|
+
self.assert_value_spec(Foo, 'h', vs.Tuple([vs.Int(), vs.Int()]))
|
59
|
+
self.assert_value_spec(
|
60
|
+
Foo, 'i',
|
61
|
+
vs.Callable([vs.Int(), vs.Int()], returns=vs.Object(type(None)))
|
62
|
+
)
|
63
|
+
|
64
|
+
def test_list(self):
|
65
|
+
if sys.version_info >= (3, 10):
|
66
|
+
|
67
|
+
class Bar(pg.Object):
|
68
|
+
x: list[int | None]
|
69
|
+
|
70
|
+
self.assert_value_spec(Bar, 'x', vs.List(vs.Int().noneable()))
|
71
|
+
|
72
|
+
def test_var_length_tuple(self):
|
73
|
+
|
74
|
+
class Foo(pg.Object):
|
75
|
+
x: typing.Tuple[int, ...]
|
76
|
+
|
77
|
+
self.assert_value_spec(Foo, 'x', vs.Tuple(vs.Int()))
|
78
|
+
|
79
|
+
if sys.version_info >= (3, 10):
|
80
|
+
|
81
|
+
class Bar(pg.Object):
|
82
|
+
x: tuple[int, ...]
|
83
|
+
|
84
|
+
self.assert_value_spec(Bar, 'x', vs.Tuple(vs.Int()))
|
85
|
+
|
86
|
+
def test_optional(self):
|
87
|
+
|
88
|
+
class Foo(pg.Object):
|
89
|
+
x: typing.Optional[int]
|
90
|
+
|
91
|
+
self.assert_value_spec(Foo, 'x', vs.Int().noneable())
|
92
|
+
|
93
|
+
if sys.version_info >= (3, 10):
|
94
|
+
class Bar(pg.Object):
|
95
|
+
x: int | None
|
96
|
+
|
97
|
+
self.assert_value_spec(Bar, 'x', vs.Int().noneable())
|
98
|
+
|
99
|
+
def test_union(self):
|
100
|
+
|
101
|
+
class Foo(pg.Object):
|
102
|
+
x: Union[int, typing.Union[str, bool], None]
|
103
|
+
|
104
|
+
self.assert_value_spec(
|
105
|
+
Foo, 'x', vs.Union([vs.Int(), vs.Str(), vs.Bool()]).noneable()
|
106
|
+
)
|
107
|
+
|
108
|
+
if sys.version_info >= (3, 10):
|
109
|
+
|
110
|
+
class Bar(pg.Object):
|
111
|
+
x: int | str | bool
|
112
|
+
|
113
|
+
self.assert_value_spec(
|
114
|
+
Bar, 'x', vs.Union([vs.Int(), vs.Str(), vs.Bool()])
|
115
|
+
)
|
116
|
+
|
117
|
+
def test_literal(self):
|
118
|
+
|
119
|
+
class Foo(pg.Object):
|
120
|
+
x: Literal[1, True, 'abc']
|
121
|
+
|
122
|
+
self.assert_value_spec(
|
123
|
+
Foo, 'x', vs.Enum(vs.MISSING_VALUE, [1, True, 'abc'])
|
124
|
+
)
|
125
|
+
|
126
|
+
def test_self_referencial(self):
|
127
|
+
self.assert_value_spec(
|
128
|
+
self.A, 'a', vs.Object(self.A).noneable()
|
129
|
+
)
|
130
|
+
self.assert_value_spec(
|
131
|
+
self.A, 'b', vs.List(vs.Object(self.A))
|
132
|
+
)
|
133
|
+
|
134
|
+
if __name__ == '__main__':
|
135
|
+
unittest.main()
|