leaf-common 1.2.37__tar.gz → 1.2.38__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.
- leaf_common-1.2.38/.github/workflows/tests.yml +29 -0
- {leaf_common-1.2.37/leaf_common.egg-info → leaf_common-1.2.38}/PKG-INFO +1 -1
- {leaf_common-1.2.37 → leaf_common-1.2.38}/build_scripts/run_flake8.sh +6 -6
- {leaf_common-1.2.37 → leaf_common-1.2.38}/build_scripts/run_pylint.sh +3 -3
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/resolver.py +32 -10
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/resolver_util.py +15 -5
- {leaf_common-1.2.37 → leaf_common-1.2.38/leaf_common.egg-info}/PKG-INFO +1 -1
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common.egg-info/SOURCES.txt +1 -0
- leaf_common-1.2.38/tests/config/resolver_util_test.py +243 -0
- leaf_common-1.2.37/.github/workflows/tests.yml +0 -67
- {leaf_common-1.2.37 → leaf_common-1.2.38}/.coveragerc +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/.flake8 +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/.github/workflows/codeql.yml +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/.github/workflows/publish.yml +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/.gitignore +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/.pylintrc +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/CODE_OF_CONDUCT.md +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/CONTRIBUTING.md +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/LICENSE.txt +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/NOTICE.txt +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/README.md +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/SECURITY.md +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/SUPPORT.md +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/build_scripts/copyright_config.json +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/build_scripts/source_available_copyright.txt +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/asyncio/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/asyncio/async_to_sync_generator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/asyncio/asyncio_executor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/asyncio/asyncio_executor_pool.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/asyncio/task_executor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/candidates/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/candidates/constants.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/candidates/representation_types.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/config_filter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/config_filter_chain.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/config_handler.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/dictionary_overlay.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/environment_defaults.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/config/file_of_class.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/evaluation/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/evaluation/component_evaluator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/evaluation/metrics_merger.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/composite_string_filter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/inclusionary_replacement_string_filter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/replacement_string_filter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/sanitizer_util.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/string_filter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/strip_whitespace_string_filter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/tensorflow_field_name_filter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/candidate_metrics_provider.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/cmp_to_key.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/comparator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/fitness_objective.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/fitness_objectives.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/fitness_objectives_builder.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/fitness_objectives_from_config.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/metrics_based_individual_comparator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/metrics_provider.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/none_comparator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/number_comparator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/reversed_comparator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/log_utils/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/log_utils/message_type.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/log_utils/structured_message.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/logging/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/logging/example_logging_config.hocon +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/logging/logging_setup.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/logging/stream_to_logger.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/boolean_list_parser.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/boolean_parser.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/canonical_multi_config_parser.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/dictionary_extractor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/field_extractor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/list_parser.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/parser.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/parsers/string_parser.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/easy/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/easy/abstract_easy_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/easy/composite_persistor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/easy/easy_hocon_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/easy/easy_json_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/easy/easy_txt_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/easy/easy_yaml_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/README.md +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/abstract_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/hocon_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/json_gzip_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/json_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/null_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/override_file_extension_provider.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/persistence_factory.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/raw_bytes_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/reference_helper.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/simple_file_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/text_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/factory/yaml_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/interface/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/interface/persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/interface/persistence_mechanism.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/interface/persistor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/interface/restorer.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/mechanism/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/mechanism/abstract_persistence_mechanism.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/mechanism/local_file_persistence_mechanism.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/mechanism/persistence_mechanism_factory.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/mechanism/persistence_mechanisms.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/persistence/mechanism/s3_file_persistence_mechanism.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/progress/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/progress/composite_progress_reporter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/progress/iterating_progress_reporter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/progress/json_progress_reporter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/progress/progress_reporter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/progress/status_dict_progress_reporter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/progress/worker_progress_reporter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/registry/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/registry/representation_file_extension_provider_registry.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/registry/representation_persistence_registry.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/registry/representation_serialization_format_registry.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/registry/self_identifying_restorer.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/config/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/config/rule_set_config_helper.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/data/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/data/condition.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/data/features.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/data/rule.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/data/rule_set.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/data/rule_set_binding.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/data/rules_constants.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/evaluation/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/evaluation/condition_evaluator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/evaluation/rule_evaluator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/evaluation/rule_metrics_merger.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/evaluation/rule_set_binding_evaluator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/evaluation/rule_set_evaluator.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/evaluation/rule_set_metrics_merger.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/persistence/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/persistence/rule_set_binding_file_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/persistence/rule_set_file_persistence.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/serialization/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/serialization/condition_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/serialization/rule_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/serialization/rule_set_binding_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/serialization/rule_set_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/representation/rule_based/serialization/rule_set_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/service/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/service/auth0_direct_service_accessor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/service/leaf_service_access.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/service/service_accessor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/service/service_accessor_factory.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/service/static_token_service_accessor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/service/vault_dynamic_token_service_accessor.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/vault/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/vault/github_vault_login.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/vault/kubernetes_vault_login.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/vault/token_vault_login.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/vault/vault_login.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/security/vault/vault_login_factory.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/buffered_gzip_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/chained_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/conversion_policy.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/gzip_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/hocon_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/json_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/raw_bytes_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/serialization_formats.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/text_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/format/yaml_serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/interface/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/interface/deserializer.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/interface/dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/interface/file_extension_provider.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/interface/reference_pruner.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/interface/self_identifying_representation_error.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/interface/serialization_format.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/interface/serializer.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/prep/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/prep/empty_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/prep/metrics_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/prep/pass_through_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/prep/pass_through_reference_pruner.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/prep/redactor_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/util/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/serialization/util/bytes_decoder.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/abstract_service_session.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/async_abstract_service_session.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/async_grpc_client_retry.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/extension_packaging.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/grpc_channel_security.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/grpc_client_retry.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/grpc_metadata_util.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/population_response_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/population_session.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/population_session_factory.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/session/response_candidate_dictionary_converter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/time/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/time/time_util.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/time/timeout.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/time/timeout_reached_exception.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/utils/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/utils/async_atomic_counter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/utils/atomic_counter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common.egg-info/dependency_links.txt +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common.egg-info/requires.txt +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common.egg-info/top_level.txt +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/pyproject.toml +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/requirements-build.txt +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/requirements.txt +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/setup.cfg +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/asyncio/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/asyncio/async_test_helpers.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/asyncio/asyncio_executor_not_started_test.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/asyncio/asyncio_executor_started_test.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/asyncio/callable_class.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/asyncio/sync_test_helpers.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/candidates/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/candidates/test_representation_types.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/config/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/config/dictionary_overlay_test.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/filters/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/filters/test_sanitizer_util.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/filters/test_tensorflow_field_name_filter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/fitness/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/fitness/fitness_objectives_from_config_test.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/fixtures/saved_rule_set.rules +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/fixtures/saved_rules_model.json +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/parsers/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/parsers/canonical_multi_config_parser_test.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/progress/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/progress/test_status_dict_progress_reporter.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/representation/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/representation/rule_based/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/representation/rule_based/test_condition.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/representation/rule_based/test_rule.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/representation/rule_based/test_rule_set.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/serialization/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/serialization/encoding/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/serialization/encoding/decode_text_test.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/serialization/prep/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/serialization/prep/redactor_dictionary_converter_test.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/session/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/session/test_extension_packaging.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/time/__init__.py +0 -0
- {leaf_common-1.2.37 → leaf_common-1.2.38}/tests/time/timeout_test.py +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Test
|
|
3
|
+
|
|
4
|
+
"on":
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
# 455db3c = build-common 1.0.0
|
|
16
|
+
# https://github.com/cognizant-ai-lab/build-common/releases
|
|
17
|
+
uses: cognizant-ai-lab/build-common/.github/workflows/_python-quality-gate.yml@455db3cc40e9ed6a0fb9bbaf8188888c1ae315c2
|
|
18
|
+
with:
|
|
19
|
+
lint-toolchain: "legacy"
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
pylint-command: "build_scripts/run_pylint.sh"
|
|
22
|
+
run-shellcheck: true
|
|
23
|
+
pytest-markers: "not integration"
|
|
24
|
+
pytest-extra-args: "--timer-top-n 10 --cov-config=.coveragerc --cov"
|
|
25
|
+
check-readme-pypi: true
|
|
26
|
+
secrets:
|
|
27
|
+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
28
|
+
|
|
29
|
+
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
# set -euo pipefail
|
|
4
4
|
|
|
5
|
-
UP_TO_SNUFF_DIRS
|
|
5
|
+
UP_TO_SNUFF_DIRS=$(ls -1)
|
|
6
6
|
IGNORE="build_scripts"
|
|
7
7
|
|
|
8
8
|
dirs=$1
|
|
9
|
-
if [ "
|
|
9
|
+
if [ "${dirs}" == "" ]
|
|
10
10
|
then
|
|
11
11
|
dirs=${UP_TO_SNUFF_DIRS}
|
|
12
12
|
fi
|
|
@@ -26,18 +26,18 @@ do
|
|
|
26
26
|
# See if it's a directory we specifically want to ignore
|
|
27
27
|
for ignore_dir in ${IGNORE}
|
|
28
28
|
do
|
|
29
|
-
if [ "
|
|
29
|
+
if [ "${ignore_dir}" == "${dir}" ]
|
|
30
30
|
then
|
|
31
31
|
ignore_this=${dir}
|
|
32
32
|
fi
|
|
33
33
|
done
|
|
34
34
|
|
|
35
35
|
# If we do not need to ignore...
|
|
36
|
-
if [ "
|
|
36
|
+
if [ "" == "${ignore_this}" ]
|
|
37
37
|
then
|
|
38
38
|
echo "Running flake8 on directory '${dir}':"
|
|
39
|
-
find "${dir}" -iname "*.py" | \
|
|
40
|
-
xargs flake8
|
|
39
|
+
find "${dir}" -iname "*.py" -print0 | \
|
|
40
|
+
xargs --null flake8 --jobs 0
|
|
41
41
|
current_retval=$?
|
|
42
42
|
if [ ${current_retval} -ne 0 ]
|
|
43
43
|
then
|
|
@@ -8,7 +8,7 @@ DEPENDENCY_DIRS=""
|
|
|
8
8
|
IGNORE="${DEPENDENCY_DIRS} build_scripts"
|
|
9
9
|
|
|
10
10
|
dirs=$1
|
|
11
|
-
if [ "
|
|
11
|
+
if [ "${dirs}" == "" ]
|
|
12
12
|
then
|
|
13
13
|
dirs=${UP_TO_SNUFF_DIRS}
|
|
14
14
|
fi
|
|
@@ -30,14 +30,14 @@ do
|
|
|
30
30
|
# See if it's a directory we specifically want to ignore
|
|
31
31
|
for ignore_dir in ${IGNORE}
|
|
32
32
|
do
|
|
33
|
-
if [ "
|
|
33
|
+
if [ "${ignore_dir}" == "${dir}" ]
|
|
34
34
|
then
|
|
35
35
|
ignore_this=${dir}
|
|
36
36
|
fi
|
|
37
37
|
done
|
|
38
38
|
|
|
39
39
|
# If we do not need to ignore...
|
|
40
|
-
if [ "
|
|
40
|
+
if [ "" == "${ignore_this}" ]
|
|
41
41
|
then
|
|
42
42
|
use_dirs="${use_dirs} ${dir}"
|
|
43
43
|
fi
|
|
@@ -75,16 +75,7 @@ class Resolver():
|
|
|
75
75
|
if verbose:
|
|
76
76
|
logger.info("Attempting to resolve module %s", use_module_name)
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
for package in self.packages:
|
|
80
|
-
fully_qualified_module: str = f"{package}.{use_module_name}"
|
|
81
|
-
found_module: Any = self.try_to_import_module(fully_qualified_module,
|
|
82
|
-
messages, install_if_missing)
|
|
83
|
-
if found_module is not None:
|
|
84
|
-
break
|
|
85
|
-
else:
|
|
86
|
-
found_module: Any = self.try_to_import_module(use_module_name, messages,
|
|
87
|
-
install_if_missing)
|
|
78
|
+
found_module: Any = self._find_module(use_module_name, messages, install_if_missing)
|
|
88
79
|
|
|
89
80
|
if found_module is None:
|
|
90
81
|
message: str = f"Could not find code for {use_module_name}"
|
|
@@ -108,6 +99,37 @@ class Resolver():
|
|
|
108
99
|
|
|
109
100
|
return my_class
|
|
110
101
|
|
|
102
|
+
def _find_module(self, use_module_name: str, messages: List[str],
|
|
103
|
+
install_if_missing: str = None) -> Any:
|
|
104
|
+
"""
|
|
105
|
+
Searches for a module by name, trying each configured package in turn.
|
|
106
|
+
Also tries the module name as a top-level module if packages are configured.
|
|
107
|
+
|
|
108
|
+
:param use_module_name: The module name to search for
|
|
109
|
+
:param messages: a list of messages where logs of failed attempts can go
|
|
110
|
+
:param install_if_missing: Optional name of a package to install if the module is missing.
|
|
111
|
+
:return: The python module if found. None if not found.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
if self.packages is None:
|
|
115
|
+
return self.try_to_import_module(use_module_name, messages, install_if_missing)
|
|
116
|
+
|
|
117
|
+
for package in self.packages:
|
|
118
|
+
fully_qualified_module: str = f"{package}.{use_module_name}"
|
|
119
|
+
found_module: Any = self.try_to_import_module(fully_qualified_module,
|
|
120
|
+
messages, install_if_missing)
|
|
121
|
+
|
|
122
|
+
if found_module is not None:
|
|
123
|
+
return found_module
|
|
124
|
+
|
|
125
|
+
# check main package
|
|
126
|
+
check_main_package: Any = self.try_to_import_module(package,
|
|
127
|
+
messages, install_if_missing)
|
|
128
|
+
if check_main_package is not None:
|
|
129
|
+
return check_main_package
|
|
130
|
+
|
|
131
|
+
return None
|
|
132
|
+
|
|
111
133
|
def try_to_import_module(self, module: str, messages: List[str],
|
|
112
134
|
install_if_missing: str = None) -> Any:
|
|
113
135
|
"""
|
|
@@ -80,20 +80,30 @@ class ResolverUtil:
|
|
|
80
80
|
if class_name is None or len(class_name) == 0:
|
|
81
81
|
return None
|
|
82
82
|
|
|
83
|
+
value_error_message: str = (f"Value from {class_name_source} '{class_name}' "
|
|
84
|
+
"must be of the form <package_name>.<module_name>.<ClassName> "
|
|
85
|
+
"or <package_name>.<ClassName> ")
|
|
83
86
|
# Split the single string into package, module, and class name
|
|
84
87
|
class_split: List[str] = class_name.split(".")
|
|
85
|
-
if len(class_split)
|
|
86
|
-
raise ValueError(
|
|
87
|
-
"must be of the form <package_name>.<module_name>.<ClassName>")
|
|
88
|
+
if len(class_split) < 2:
|
|
89
|
+
raise ValueError(value_error_message)
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
# Extract module and class details
|
|
92
|
+
if len(class_split) <= 2:
|
|
93
|
+
# handles <package_name>.<ClassName>
|
|
94
|
+
packages: List[str] = [class_split[0]]
|
|
95
|
+
module_name = class_split[0]
|
|
96
|
+
else:
|
|
97
|
+
# handles <package_name>.<module_name>.<ClassName>
|
|
98
|
+
packages: List[str] = [".".join(class_split[:-2])]
|
|
99
|
+
module_name = class_split[-2]
|
|
90
100
|
class_name: str = class_split[-1]
|
|
91
101
|
resolver = Resolver(packages)
|
|
92
102
|
|
|
93
103
|
# Resolve the class name
|
|
94
104
|
class_reference: Type[Any] = None
|
|
95
105
|
try:
|
|
96
|
-
class_reference = resolver.resolve_class_in_module(class_name, module_name=
|
|
106
|
+
class_reference = resolver.resolve_class_in_module(class_name, module_name=module_name)
|
|
97
107
|
except AttributeError as exception:
|
|
98
108
|
raise ValueError(f"Class '{class_name}' from {class_name_source} "
|
|
99
109
|
"not found in PYTHONPATH") from exception
|
|
@@ -226,6 +226,7 @@ tests/candidates/__init__.py
|
|
|
226
226
|
tests/candidates/test_representation_types.py
|
|
227
227
|
tests/config/__init__.py
|
|
228
228
|
tests/config/dictionary_overlay_test.py
|
|
229
|
+
tests/config/resolver_util_test.py
|
|
229
230
|
tests/filters/__init__.py
|
|
230
231
|
tests/filters/test_sanitizer_util.py
|
|
231
232
|
tests/filters/test_tensorflow_field_name_filter.py
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
|
|
2
|
+
# Copyright © 2019-2026 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
# END COPYRIGHT
|
|
17
|
+
"""
|
|
18
|
+
See class comment for details
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from unittest import TestCase
|
|
22
|
+
from unittest.mock import MagicMock
|
|
23
|
+
from unittest.mock import patch
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
from leaf_common.config.resolver_util import ResolverUtil
|
|
27
|
+
|
|
28
|
+
RESOLVER_PATH = "leaf_common.config.resolver.Resolver.resolve_class_in_module"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ResolverUtilTest(TestCase):
|
|
32
|
+
"""
|
|
33
|
+
Tests for ResolverUtil.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# -------------------------------------------------------------------------
|
|
37
|
+
# create_class tests
|
|
38
|
+
# -------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
def test_create_class_none_returns_none(self):
|
|
41
|
+
"""
|
|
42
|
+
None class_name should return None without raising.
|
|
43
|
+
"""
|
|
44
|
+
result = ResolverUtil.create_class(None, "test_source", object)
|
|
45
|
+
self.assertIsNone(result)
|
|
46
|
+
|
|
47
|
+
def test_create_class_empty_string_returns_none(self):
|
|
48
|
+
"""
|
|
49
|
+
Empty class_name should return None without raising.
|
|
50
|
+
"""
|
|
51
|
+
result = ResolverUtil.create_class("", "test_source", object)
|
|
52
|
+
self.assertIsNone(result)
|
|
53
|
+
|
|
54
|
+
def test_create_class_too_few_parts_raises(self):
|
|
55
|
+
"""
|
|
56
|
+
A class_name with no dots (single part) should raise ValueError.
|
|
57
|
+
"""
|
|
58
|
+
with self.assertRaises(ValueError):
|
|
59
|
+
ResolverUtil.create_class("ClassName", "test_source", object)
|
|
60
|
+
|
|
61
|
+
def test_create_class_two_part_name(self):
|
|
62
|
+
"""
|
|
63
|
+
<package_name>.<ClassName> form should resolve correctly.
|
|
64
|
+
"""
|
|
65
|
+
mock_class = MagicMock()
|
|
66
|
+
mock_class.__mro__ = [mock_class, object]
|
|
67
|
+
|
|
68
|
+
with patch(RESOLVER_PATH, return_value=mock_class) as mock_resolve, \
|
|
69
|
+
patch("builtins.issubclass", return_value=True):
|
|
70
|
+
result = ResolverUtil.create_class("my_package.MyClass", "test_source", object)
|
|
71
|
+
|
|
72
|
+
mock_resolve.assert_called_once_with("MyClass", module_name="my_package")
|
|
73
|
+
self.assertIs(result, mock_class)
|
|
74
|
+
|
|
75
|
+
def test_create_class_three_part_name(self):
|
|
76
|
+
"""
|
|
77
|
+
<package_name>.<module_name>.<ClassName> form should resolve correctly.
|
|
78
|
+
"""
|
|
79
|
+
mock_class = MagicMock()
|
|
80
|
+
|
|
81
|
+
with patch(RESOLVER_PATH, return_value=mock_class) as mock_resolve, \
|
|
82
|
+
patch("builtins.issubclass", return_value=True):
|
|
83
|
+
result = ResolverUtil.create_class(
|
|
84
|
+
"my_package.my_module.MyClass", "test_source", object
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
mock_resolve.assert_called_once_with("MyClass", module_name="my_module")
|
|
88
|
+
self.assertIs(result, mock_class)
|
|
89
|
+
|
|
90
|
+
def test_create_class_multi_part_package(self):
|
|
91
|
+
"""
|
|
92
|
+
<pkg>.<sub>.<module>.<ClassName> — everything before the last two parts
|
|
93
|
+
is treated as the package path.
|
|
94
|
+
"""
|
|
95
|
+
mock_class = MagicMock()
|
|
96
|
+
|
|
97
|
+
with patch(RESOLVER_PATH, return_value=mock_class) as mock_resolve, \
|
|
98
|
+
patch("builtins.issubclass", return_value=True):
|
|
99
|
+
result = ResolverUtil.create_class(
|
|
100
|
+
"my_pkg.sub_pkg.my_module.MyClass", "test_source", object
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
mock_resolve.assert_called_once_with("MyClass", module_name="my_module")
|
|
104
|
+
self.assertIs(result, mock_class)
|
|
105
|
+
|
|
106
|
+
def test_create_class_attribute_error_raises_value_error(self):
|
|
107
|
+
"""
|
|
108
|
+
If resolve_class_in_module raises AttributeError, a ValueError is raised.
|
|
109
|
+
"""
|
|
110
|
+
with patch(RESOLVER_PATH, side_effect=AttributeError("not found")):
|
|
111
|
+
with self.assertRaises(ValueError):
|
|
112
|
+
ResolverUtil.create_class(
|
|
113
|
+
"my_package.my_module.MyClass", "test_source", object
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def test_create_class_wrong_type_raises_value_error(self):
|
|
117
|
+
"""
|
|
118
|
+
If the resolved class is not a subclass of type_of_class, a ValueError is raised.
|
|
119
|
+
"""
|
|
120
|
+
class Base:
|
|
121
|
+
"""Base class for type-check testing."""
|
|
122
|
+
|
|
123
|
+
class NotBase:
|
|
124
|
+
"""Class that does not inherit from Base."""
|
|
125
|
+
|
|
126
|
+
with patch(RESOLVER_PATH, return_value=NotBase):
|
|
127
|
+
with self.assertRaises(ValueError):
|
|
128
|
+
ResolverUtil.create_class(
|
|
129
|
+
"my_package.my_module.NotBase", "test_source", Base
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# -------------------------------------------------------------------------
|
|
133
|
+
# create_instance tests
|
|
134
|
+
# -------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
def test_create_instance_none_returns_none(self):
|
|
137
|
+
"""
|
|
138
|
+
None class_name propagates through create_class and returns None.
|
|
139
|
+
"""
|
|
140
|
+
result = ResolverUtil.create_instance(None, "test_source", object)
|
|
141
|
+
self.assertIsNone(result)
|
|
142
|
+
|
|
143
|
+
def test_create_instance_creates_object(self):
|
|
144
|
+
"""
|
|
145
|
+
A valid class_name should produce an instance of the resolved class.
|
|
146
|
+
"""
|
|
147
|
+
mock_instance = MagicMock()
|
|
148
|
+
mock_class = MagicMock(return_value=mock_instance)
|
|
149
|
+
|
|
150
|
+
with patch(RESOLVER_PATH, return_value=mock_class), \
|
|
151
|
+
patch("builtins.issubclass", return_value=True):
|
|
152
|
+
result = ResolverUtil.create_instance(
|
|
153
|
+
"my_package.my_module.MyClass", "test_source", object
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
mock_class.assert_called_once_with()
|
|
157
|
+
self.assertIs(result, mock_instance)
|
|
158
|
+
|
|
159
|
+
def test_create_instance_no_args_constructor_raises_value_error(self):
|
|
160
|
+
"""
|
|
161
|
+
If the class cannot be instantiated without args, a ValueError is raised.
|
|
162
|
+
"""
|
|
163
|
+
mock_class = MagicMock(side_effect=TypeError("__init__ requires args"))
|
|
164
|
+
|
|
165
|
+
with patch(RESOLVER_PATH, return_value=mock_class), \
|
|
166
|
+
patch("builtins.issubclass", return_value=True):
|
|
167
|
+
with self.assertRaises(ValueError):
|
|
168
|
+
ResolverUtil.create_instance(
|
|
169
|
+
"my_package.my_module.MyClass", "test_source", object
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# -------------------------------------------------------------------------
|
|
173
|
+
# create_type tests
|
|
174
|
+
# -------------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
def test_create_type_none_returns_none(self):
|
|
177
|
+
"""
|
|
178
|
+
None or empty fully_qualified_name should return None.
|
|
179
|
+
"""
|
|
180
|
+
self.assertIsNone(ResolverUtil.create_type(None))
|
|
181
|
+
self.assertIsNone(ResolverUtil.create_type(""))
|
|
182
|
+
|
|
183
|
+
def test_create_type_resolves_class(self):
|
|
184
|
+
"""
|
|
185
|
+
A fully qualified name should resolve to the correct class via Resolver.
|
|
186
|
+
"""
|
|
187
|
+
mock_class = MagicMock()
|
|
188
|
+
|
|
189
|
+
with patch(RESOLVER_PATH, return_value=mock_class) as mock_resolve:
|
|
190
|
+
result = ResolverUtil.create_type("my_package.my_module.MyClass")
|
|
191
|
+
|
|
192
|
+
mock_resolve.assert_called_once_with(
|
|
193
|
+
"MyClass",
|
|
194
|
+
module_name="my_package.my_module",
|
|
195
|
+
raise_if_not_found=True,
|
|
196
|
+
install_if_missing=None,
|
|
197
|
+
)
|
|
198
|
+
self.assertIs(result, mock_class)
|
|
199
|
+
|
|
200
|
+
# -------------------------------------------------------------------------
|
|
201
|
+
# create_type_tuple tests
|
|
202
|
+
# -------------------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
def test_create_type_tuple_empty_list(self):
|
|
205
|
+
"""
|
|
206
|
+
An empty or None type_list should return an empty tuple.
|
|
207
|
+
"""
|
|
208
|
+
self.assertEqual(ResolverUtil.create_type_tuple([]), ())
|
|
209
|
+
self.assertEqual(ResolverUtil.create_type_tuple(None), ())
|
|
210
|
+
|
|
211
|
+
def test_create_type_tuple_resolves_types(self):
|
|
212
|
+
"""
|
|
213
|
+
Each resolvable name in the list should appear in the returned tuple.
|
|
214
|
+
"""
|
|
215
|
+
mock_class_a = MagicMock()
|
|
216
|
+
mock_class_b = MagicMock()
|
|
217
|
+
|
|
218
|
+
side_effects = [mock_class_a, mock_class_b]
|
|
219
|
+
|
|
220
|
+
with patch(RESOLVER_PATH, side_effect=side_effects):
|
|
221
|
+
result = ResolverUtil.create_type_tuple([
|
|
222
|
+
"pkg.mod.ClassA",
|
|
223
|
+
"pkg.mod.ClassB",
|
|
224
|
+
])
|
|
225
|
+
|
|
226
|
+
self.assertEqual(len(result), 2)
|
|
227
|
+
self.assertIn(mock_class_a, result)
|
|
228
|
+
self.assertIn(mock_class_b, result)
|
|
229
|
+
|
|
230
|
+
def test_create_type_tuple_skips_unresolvable(self):
|
|
231
|
+
"""
|
|
232
|
+
Types that cannot be resolved (raise_if_not_found=False) are skipped.
|
|
233
|
+
"""
|
|
234
|
+
mock_class_a = MagicMock()
|
|
235
|
+
|
|
236
|
+
with patch(RESOLVER_PATH, side_effect=[mock_class_a, None]):
|
|
237
|
+
result = ResolverUtil.create_type_tuple([
|
|
238
|
+
"pkg.mod.ClassA",
|
|
239
|
+
"pkg.mod.Missing",
|
|
240
|
+
])
|
|
241
|
+
|
|
242
|
+
self.assertEqual(len(result), 1)
|
|
243
|
+
self.assertIn(mock_class_a, result)
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
name: Test
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
- "**"
|
|
8
|
-
pull_request:
|
|
9
|
-
|
|
10
|
-
permissions:
|
|
11
|
-
contents: read
|
|
12
|
-
|
|
13
|
-
jobs:
|
|
14
|
-
test:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
|
-
container:
|
|
17
|
-
image: python:3.12-slim
|
|
18
|
-
|
|
19
|
-
steps:
|
|
20
|
-
- name: Checkout
|
|
21
|
-
uses: actions/checkout@v4
|
|
22
|
-
|
|
23
|
-
- name: Install dependencies
|
|
24
|
-
run: |
|
|
25
|
-
pip install -r requirements-build.txt
|
|
26
|
-
pip install -r requirements.txt
|
|
27
|
-
|
|
28
|
-
- name: Show installed packages
|
|
29
|
-
run: pip freeze
|
|
30
|
-
|
|
31
|
-
- name: Run pylint
|
|
32
|
-
run: build_scripts/run_pylint.sh
|
|
33
|
-
|
|
34
|
-
- name: Run flake8
|
|
35
|
-
run: flake8
|
|
36
|
-
|
|
37
|
-
- name: Run pytest (excluding integration tests)
|
|
38
|
-
run: pytest --verbose -m "not integration" --timer-top-n 10 --cov-config=.coveragerc --cov
|
|
39
|
-
|
|
40
|
-
- name: Check README renders correctly on PyPI
|
|
41
|
-
run: |
|
|
42
|
-
pip install readme_renderer readme_renderer[md]
|
|
43
|
-
python -m readme_renderer README.md
|
|
44
|
-
|
|
45
|
-
- name: Notify Slack on success
|
|
46
|
-
if: success()
|
|
47
|
-
uses: slackapi/slack-github-action@v1.24.0
|
|
48
|
-
with:
|
|
49
|
-
payload: |
|
|
50
|
-
{
|
|
51
|
-
"text": "✅ *Tests Passed* for `${{ github.repository }}` on `${{ github.ref_name }}`"
|
|
52
|
-
}
|
|
53
|
-
env:
|
|
54
|
-
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
55
|
-
|
|
56
|
-
- name: Notify Slack on failure
|
|
57
|
-
if: failure()
|
|
58
|
-
uses: slackapi/slack-github-action@v1.24.0
|
|
59
|
-
with:
|
|
60
|
-
payload: |
|
|
61
|
-
{
|
|
62
|
-
"text": "❌ *Tests Failed* for `${{ github.repository }}` on `${{ github.ref_name }}`"
|
|
63
|
-
}
|
|
64
|
-
env:
|
|
65
|
-
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
66
|
-
|
|
67
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/strip_whitespace_string_filter.py
RENAMED
|
File without changes
|
{leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/filters/tensorflow_field_name_filter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/fitness_objectives_from_config.py
RENAMED
|
File without changes
|
{leaf_common-1.2.37 → leaf_common-1.2.38}/leaf_common/fitness/metrics_based_individual_comparator.py
RENAMED
|
File without changes
|
|
File without changes
|