leaf-common 1.4.3__tar.gz → 1.4.4__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.4.3 → leaf_common-1.4.4}/PKG-INFO +1 -1
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/config/config_filter.py +2 -2
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/config/config_filter_chain.py +4 -3
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/config/config_handler.py +39 -37
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/config/config_util.py +6 -1
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/config/dictionary_overlay.py +40 -33
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/config/file_of_class.py +2 -5
- leaf_common-1.4.4/leaf_common/filters/composite_string_filter.py +59 -0
- leaf_common-1.4.4/leaf_common/filters/string_filter.py +35 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/dictionary_extractor.py +2 -3
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/field_extractor.py +12 -14
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common.egg-info/PKG-INFO +1 -1
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common.egg-info/SOURCES.txt +2 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/.coveragerc +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/.flake8 +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/.github/workflows/checkmarx.yml +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/.github/workflows/codeql.yml +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/.github/workflows/publish.yml +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/.github/workflows/tests.yml +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/.gitignore +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/.pylintrc +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/CODE_OF_CONDUCT.md +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/CONTRIBUTING.md +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/LICENSE.txt +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/Makefile +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/NOTICE.txt +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/README.md +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/SECURITY.md +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/SUPPORT.md +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/build_scripts/copyright_config.json +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/build_scripts/run_flake8.sh +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/build_scripts/run_pylint.sh +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/build_scripts/source_available_copyright.txt +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/asyncio/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/asyncio/async_to_sync_generator.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/asyncio/asyncio_executor.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/asyncio/asyncio_executor_pool.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/asyncio/asyncio_threadpool_executor.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/asyncio/event_loop_factory.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/asyncio/event_loop_lag_monitor.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/asyncio/task_executor.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/config/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/config/environment_defaults.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/conditional_logger.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/example_logging_config.hocon +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/logging_setup.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/message_types.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/sensitive_logger.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/service_log_record.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/stream_to_logger.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/logging/structured_log_record.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/boolean_list_parser.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/boolean_parser.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/canonical_multi_config_parser.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/list_parser.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/parser.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/parsers/string_parser.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/easy/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/easy/abstract_easy_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/easy/composite_persistor.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/easy/easy_hocon_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/easy/easy_json_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/easy/easy_txt_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/easy/easy_yaml_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/README.md +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/abstract_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/hocon_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/json_gzip_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/json_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/null_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/override_file_extension_provider.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/persistence_factory.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/raw_bytes_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/reference_helper.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/simple_file_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/text_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/factory/yaml_persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/interface/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/interface/persistence.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/interface/persistence_mechanism.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/interface/persistor.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/interface/restorer.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/abstract_persistence_mechanism.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/local_file_persistence_mechanism.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/persistence_mechanism_factory.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/persistence_mechanisms.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/s3_file_persistence_mechanism.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/profiling/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/profiling/async_profiling_lock.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/profiling/memory_util.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/profiling/profiling_lock.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/resolution/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/resolution/deprecation_redirect.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/resolution/resolver.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/resolution/resolver_util.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/buffered_gzip_serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/chained_serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/conversion_policy.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/gzip_serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/hocon_serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/json_serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/raw_bytes_serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/serialization_formats.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/text_serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/format/yaml_serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/interface/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/interface/deserializer.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/interface/dictionary_converter.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/interface/file_extension_provider.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/interface/reference_pruner.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/interface/serialization_format.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/interface/serializer.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/prep/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/prep/empty_dictionary_converter.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/prep/pass_through_dictionary_converter.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/prep/pass_through_reference_pruner.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/prep/redactor_dictionary_converter.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/util/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/util/bytes_decoder.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/serialization/util/text_file_reader.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/time/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/time/time_util.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/time/timeout.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/time/timeout_reached_exception.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/utils/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/utils/async_atomic_counter.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/utils/atomic_counter.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/utils/exception_util.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/utils/startable.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/validation/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/validation/composite_dictionary_validator.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common/validation/dictionary_validator.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common.egg-info/dependency_links.txt +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common.egg-info/requires.txt +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/leaf_common.egg-info/top_level.txt +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/pyproject.toml +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/requirements-build.txt +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/requirements.txt +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/setup.cfg +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/async_test_helpers.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_metrics_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_not_started_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_pool_dump_tasks_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_pool_gc_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_pool_metrics_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_started_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/asyncio_threadpool_executor_metrics_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/callable_class.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/event_loop_factory_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/asyncio/sync_test_helpers.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/config/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/config/dictionary_overlay_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/config/test_config_util.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/parsers/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/parsers/boolean_parser_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/parsers/canonical_multi_config_parser_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/resolution/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/resolution/resolver_util_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/resolution/test_deprecation_redirect.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/serialization/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/serialization/encoding/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/serialization/encoding/decode_text_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/serialization/encoding/text_file_reader_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/serialization/format/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/serialization/format/hocon_serialization_format_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/serialization/prep/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/serialization/prep/redactor_dictionary_converter_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/time/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/time/timeout_test.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/utils/__init__.py +0 -0
- {leaf_common-1.4.3 → leaf_common-1.4.4}/tests/utils/test_exception_util.py +0 -0
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
See class comment for details
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
+
from typing import Any
|
|
21
22
|
from typing import Dict
|
|
22
23
|
|
|
23
24
|
|
|
@@ -32,8 +33,7 @@ class ConfigFilter():
|
|
|
32
33
|
thus allowing config modification at an early stage in an app's lifecyle.
|
|
33
34
|
"""
|
|
34
35
|
|
|
35
|
-
def filter_config(self, basis_config: Dict[str,
|
|
36
|
-
-> Dict[str, object]:
|
|
36
|
+
def filter_config(self, basis_config: Dict[str, Any]) -> Dict[str, Any]:
|
|
37
37
|
"""
|
|
38
38
|
Filters the given basis config.
|
|
39
39
|
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"""
|
|
18
18
|
See class comment for details.
|
|
19
19
|
"""
|
|
20
|
+
from typing import Any
|
|
20
21
|
from typing import Dict
|
|
21
22
|
from typing import List
|
|
22
23
|
|
|
@@ -48,8 +49,7 @@ class ConfigFilterChain(ConfigFilter):
|
|
|
48
49
|
"""
|
|
49
50
|
self._filters.append(one_filter)
|
|
50
51
|
|
|
51
|
-
def filter_config(self, basis_config: Dict[str,
|
|
52
|
-
-> Dict[str, object]:
|
|
52
|
+
def filter_config(self, basis_config: Dict[str, Any]) -> Dict[str, Any]:
|
|
53
53
|
"""
|
|
54
54
|
Filters the given basis config.
|
|
55
55
|
|
|
@@ -62,9 +62,10 @@ class ConfigFilterChain(ConfigFilter):
|
|
|
62
62
|
:return: A config dictionary, potentially modified as per the
|
|
63
63
|
policy encapsulated by the implementation
|
|
64
64
|
"""
|
|
65
|
-
filtered = basis_config
|
|
65
|
+
filtered: Dict[str, Any] = basis_config
|
|
66
66
|
|
|
67
67
|
# Go through the filter chain
|
|
68
|
+
one_filter: ConfigFilter = None
|
|
68
69
|
for one_filter in self._filters:
|
|
69
70
|
filtered = one_filter.filter_config(filtered)
|
|
70
71
|
|
|
@@ -14,11 +14,9 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
# END COPYRIGHT
|
|
17
|
-
"""
|
|
18
|
-
See class comment for details.
|
|
19
|
-
"""
|
|
20
17
|
from typing import Any
|
|
21
18
|
from typing import Dict
|
|
19
|
+
from typing import Union
|
|
22
20
|
|
|
23
21
|
from copy import deepcopy
|
|
24
22
|
from collections.abc import Mapping
|
|
@@ -33,8 +31,9 @@ class ConfigHandler():
|
|
|
33
31
|
An abstract class which handles configuration dictionaries
|
|
34
32
|
"""
|
|
35
33
|
|
|
36
|
-
def import_config(self, config_source,
|
|
37
|
-
|
|
34
|
+
def import_config(self, config_source: Union[str, Dict[str, Any]],
|
|
35
|
+
default_config: Dict[str, Any] = None,
|
|
36
|
+
must_exist: bool = True) -> Dict[str, Any]:
|
|
38
37
|
"""
|
|
39
38
|
Main entry point for reading config files
|
|
40
39
|
:param config_source: Either a string filename reference to a
|
|
@@ -54,12 +53,12 @@ class ConfigHandler():
|
|
|
54
53
|
"""
|
|
55
54
|
|
|
56
55
|
# Set up a very basic config dictionary
|
|
57
|
-
config = {}
|
|
56
|
+
config: Dict[str, Any] = {}
|
|
58
57
|
if default_config is not None and isinstance(default_config, dict):
|
|
59
58
|
config = deepcopy(default_config)
|
|
60
59
|
|
|
61
60
|
# Potentially read config from a file, if config arg is a string filename
|
|
62
|
-
update_source = {}
|
|
61
|
+
update_source: Dict[str, Any] = {}
|
|
63
62
|
if isinstance(config_source, str):
|
|
64
63
|
update_source = self.read_config_from_file(config_source, must_exist)
|
|
65
64
|
|
|
@@ -68,23 +67,25 @@ class ConfigHandler():
|
|
|
68
67
|
elif isinstance(config_source, dict):
|
|
69
68
|
update_source = config_source
|
|
70
69
|
|
|
71
|
-
new_config = self.deep_update(config, update_source)
|
|
70
|
+
new_config: Dict[str, Any] = self.deep_update(config, update_source)
|
|
72
71
|
return new_config
|
|
73
72
|
|
|
74
|
-
def deep_update(self, dest, source):
|
|
73
|
+
def deep_update(self, dest: Dict[str, Any], source: Dict[str, Any]) -> Dict[str, Any]:
|
|
75
74
|
"""
|
|
76
75
|
Performs overlay functionality
|
|
77
76
|
DEF: Use DictionaryOverlay class instead.
|
|
78
77
|
"""
|
|
78
|
+
key: str = None
|
|
79
|
+
value: Any = None
|
|
79
80
|
for key, value in source.items():
|
|
80
81
|
if isinstance(value, Mapping):
|
|
81
|
-
recurse = self.deep_update(dest.get(key, {}), value)
|
|
82
|
+
recurse: Dict[str, Any] = self.deep_update(dest.get(key, {}), value)
|
|
82
83
|
dest[key] = recurse
|
|
83
84
|
else:
|
|
84
85
|
dest[key] = source[key]
|
|
85
86
|
return dest
|
|
86
87
|
|
|
87
|
-
def read_config_from_file(self, filepath, must_exist) -> Dict[str, Any]:
|
|
88
|
+
def read_config_from_file(self, filepath: str, must_exist: bool) -> Dict[str, Any]:
|
|
88
89
|
"""
|
|
89
90
|
:param filepath: The file to parse
|
|
90
91
|
:param must_exist: When True, an error is
|
|
@@ -96,23 +97,24 @@ class ConfigHandler():
|
|
|
96
97
|
"""
|
|
97
98
|
|
|
98
99
|
# Create a map of our parser methods
|
|
99
|
-
file_extension_to_parser_map = {
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
file_extension_to_parser_map: Dict[str, str] = {
|
|
101
|
+
".conf": "parse_hocon",
|
|
102
|
+
".hocon": "parse_hocon",
|
|
102
103
|
# Treat json separately as it's been shown that large json files
|
|
103
104
|
# are really slow for the hocon parser to load.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
".json": "parse_json",
|
|
106
|
+
".properties": "parse_hocon",
|
|
107
|
+
".yaml": "parse_yaml"
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
# See what the filepath extension says to use
|
|
110
|
-
parser = None
|
|
111
|
+
parser: str = None
|
|
112
|
+
file_extension: str = None
|
|
111
113
|
for file_extension in list(file_extension_to_parser_map.keys()):
|
|
112
114
|
if filepath.endswith(file_extension):
|
|
113
115
|
parser = file_extension_to_parser_map.get(file_extension)
|
|
114
116
|
|
|
115
|
-
message = f"Could not read {filepath} as config. Unknown file extension."
|
|
117
|
+
message: str = f"Could not read {filepath} as config. Unknown file extension."
|
|
116
118
|
|
|
117
119
|
config: Dict[str, Any] = {}
|
|
118
120
|
if parser is not None:
|
|
@@ -127,7 +129,7 @@ class ConfigHandler():
|
|
|
127
129
|
|
|
128
130
|
return config
|
|
129
131
|
|
|
130
|
-
def parse_with_method(self, parser, filepath, must_exist):
|
|
132
|
+
def parse_with_method(self, parser: str, filepath: str, must_exist: bool) -> Dict[str, Any]:
|
|
131
133
|
"""
|
|
132
134
|
:param parser: The parser method on this class to use
|
|
133
135
|
:param filepath: The file to parse
|
|
@@ -137,14 +139,17 @@ class ConfigHandler():
|
|
|
137
139
|
ignored and a dictionary value of None is returned
|
|
138
140
|
:return: The dictionary parsed from the config file
|
|
139
141
|
"""
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
config: Dict[str, Any] = None
|
|
143
|
+
|
|
144
|
+
if parser == "parse_hocon":
|
|
145
|
+
config = self.parse_hocon(filepath, must_exist)
|
|
146
|
+
elif parser == "parse_json":
|
|
147
|
+
config = self.parse_json(filepath, must_exist)
|
|
148
|
+
elif parser == "parse_yaml":
|
|
149
|
+
config = self.parse_yaml(filepath, must_exist)
|
|
145
150
|
return config
|
|
146
151
|
|
|
147
|
-
def parse_json(self, filepath, must_exist):
|
|
152
|
+
def parse_json(self, filepath: str, must_exist: bool) -> Dict[str, Any]:
|
|
148
153
|
"""
|
|
149
154
|
:param filepath: The json file to parse
|
|
150
155
|
:param must_exist: When True, an error is
|
|
@@ -153,12 +158,11 @@ class ConfigHandler():
|
|
|
153
158
|
ignored and a dictionary value of None is returned
|
|
154
159
|
:return: The dictionary parsed from the hocon config file
|
|
155
160
|
"""
|
|
156
|
-
persistence = EasyJsonPersistence(full_ref=filepath,
|
|
157
|
-
|
|
158
|
-
config = persistence.restore()
|
|
161
|
+
persistence = EasyJsonPersistence(full_ref=filepath, must_exist=must_exist)
|
|
162
|
+
config: Dict[str, Any] = persistence.restore(None)
|
|
159
163
|
return config
|
|
160
164
|
|
|
161
|
-
def parse_hocon(self, filepath, must_exist):
|
|
165
|
+
def parse_hocon(self, filepath: str, must_exist: bool) -> Dict[str, Any]:
|
|
162
166
|
"""
|
|
163
167
|
:param filepath: The hocon file to parse
|
|
164
168
|
:param must_exist: When True, an error is
|
|
@@ -167,12 +171,11 @@ class ConfigHandler():
|
|
|
167
171
|
ignored and a dictionary value of None is returned
|
|
168
172
|
:return: The dictionary parsed from the hocon config file
|
|
169
173
|
"""
|
|
170
|
-
persistence = EasyHoconPersistence(full_ref=filepath,
|
|
171
|
-
|
|
172
|
-
config = persistence.restore()
|
|
174
|
+
persistence = EasyHoconPersistence(full_ref=filepath, must_exist=must_exist)
|
|
175
|
+
config: Dict[str, Any] = persistence.restore(None)
|
|
173
176
|
return config
|
|
174
177
|
|
|
175
|
-
def parse_yaml(self, filepath, must_exist):
|
|
178
|
+
def parse_yaml(self, filepath: str, must_exist: bool) -> Dict[str, Any]:
|
|
176
179
|
"""
|
|
177
180
|
:param filepath: The yaml file to parse
|
|
178
181
|
:param must_exist: When True, an error is
|
|
@@ -181,7 +184,6 @@ class ConfigHandler():
|
|
|
181
184
|
ignored and a dictionary value of None is returned
|
|
182
185
|
:return: The dictionary parsed from the yaml config file
|
|
183
186
|
"""
|
|
184
|
-
persistence = EasyYamlPersistence(full_ref=filepath,
|
|
185
|
-
|
|
186
|
-
config = persistence.restore()
|
|
187
|
+
persistence = EasyYamlPersistence(full_ref=filepath, must_exist=must_exist)
|
|
188
|
+
config: Dict[str, Any] = persistence.restore(None)
|
|
187
189
|
return config
|
|
@@ -56,16 +56,21 @@ class ConfigUtil:
|
|
|
56
56
|
"""
|
|
57
57
|
if key not in config:
|
|
58
58
|
return default
|
|
59
|
+
|
|
59
60
|
value: Any = config[key]
|
|
60
61
|
if isinstance(value, bool):
|
|
61
62
|
return value
|
|
63
|
+
|
|
62
64
|
if isinstance(value, str):
|
|
63
|
-
|
|
65
|
+
string_value: str = value
|
|
66
|
+
lowered: str = string_value.strip().lower()
|
|
64
67
|
if lowered in ("true", "yes"):
|
|
65
68
|
return True
|
|
66
69
|
if lowered in ("false", "no"):
|
|
67
70
|
return False
|
|
68
71
|
return default
|
|
72
|
+
|
|
69
73
|
if isinstance(value, int):
|
|
70
74
|
return value != 0
|
|
75
|
+
|
|
71
76
|
return default
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
# END COPYRIGHT
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
from typing import Any
|
|
18
|
+
from typing import Dict
|
|
19
|
+
from typing import List
|
|
20
|
+
from typing import Set
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class DictionaryOverlay():
|
|
@@ -24,7 +25,8 @@ class DictionaryOverlay():
|
|
|
24
25
|
Policy class assisting with deep dictionary updates.
|
|
25
26
|
"""
|
|
26
27
|
|
|
27
|
-
def overlay(self, basis, overlay,
|
|
28
|
+
def overlay(self, basis: Dict[str, Any], overlay: Dict[str, Any],
|
|
29
|
+
allow_overlay_only_items: bool = True) -> Dict[str, Any]:
|
|
28
30
|
"""
|
|
29
31
|
:param basis: The basis dictionary to be overlayed.
|
|
30
32
|
Unmodified on exit.
|
|
@@ -42,20 +44,21 @@ class DictionaryOverlay():
|
|
|
42
44
|
are both dictionaries, this method recurses.
|
|
43
45
|
"""
|
|
44
46
|
|
|
45
|
-
overlay_only_items = set()
|
|
46
|
-
result = self._do_overlay(basis, overlay, overlay_only_items, '')
|
|
47
|
+
overlay_only_items: Set[str] = set()
|
|
48
|
+
result: Dict[str, Any] = self._do_overlay(basis, overlay, overlay_only_items, '')
|
|
47
49
|
# Now, let's check if we had items present in "overlay"
|
|
48
50
|
# but not in "basis" dictionary.
|
|
49
51
|
# If YES - always print out warning message;
|
|
50
52
|
# and if we don't allow overlay-only items, raise an exception.
|
|
51
|
-
if len(overlay_only_items) > 0
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
message = separator.join(
|
|
53
|
+
if len(overlay_only_items) > 0 and not allow_overlay_only_items:
|
|
54
|
+
separator: str = ", "
|
|
55
|
+
overlay_only_list: List[str] = sorted(list(overlay_only_items))
|
|
56
|
+
message: str = separator.join(overlay_only_list)
|
|
55
57
|
raise ValueError(f"overlay items not present in basis: {message}")
|
|
56
58
|
return result
|
|
57
59
|
|
|
58
|
-
def _do_overlay(self, basis, overlay,
|
|
60
|
+
def _do_overlay(self, basis: Dict[str, Any], overlay: Dict[str, Any],
|
|
61
|
+
overlay_only_items: Set[str], items_prefix: str) -> Dict[str, Any]:
|
|
59
62
|
"""
|
|
60
63
|
:param basis: The basis dictionary to be overlayed.
|
|
61
64
|
Unmodified on exit.
|
|
@@ -77,46 +80,49 @@ class DictionaryOverlay():
|
|
|
77
80
|
if basis is None and overlay is None:
|
|
78
81
|
return None
|
|
79
82
|
|
|
83
|
+
use_basis: Dict[str, Any] = basis
|
|
80
84
|
if basis is None:
|
|
81
|
-
|
|
85
|
+
use_basis = {}
|
|
82
86
|
|
|
83
|
-
if not isinstance(
|
|
87
|
+
if not isinstance(use_basis, dict):
|
|
84
88
|
raise ValueError("basis is not a dictionary")
|
|
85
89
|
|
|
90
|
+
use_overlay: Dict[str, Any] = overlay
|
|
86
91
|
if overlay is None:
|
|
87
|
-
|
|
92
|
+
use_overlay = {}
|
|
88
93
|
|
|
89
|
-
if not isinstance(
|
|
94
|
+
if not isinstance(use_overlay, dict):
|
|
90
95
|
raise ValueError("overlay is not a dictionary")
|
|
91
96
|
|
|
92
97
|
# Do not modify any incoming arguments
|
|
93
|
-
result = {}
|
|
94
|
-
result.update(
|
|
98
|
+
result: Dict[str, Any] = {}
|
|
99
|
+
result.update(use_basis)
|
|
95
100
|
|
|
96
|
-
|
|
101
|
+
key: str = None
|
|
102
|
+
for key in use_overlay.keys():
|
|
97
103
|
|
|
98
104
|
# Any key we do not have, we just copy over the value from overlay.
|
|
99
|
-
if key not in
|
|
100
|
-
result[key] =
|
|
101
|
-
|
|
105
|
+
if key not in use_basis.keys():
|
|
106
|
+
result[key] = use_overlay[key]
|
|
107
|
+
add_key: str = items_prefix + key
|
|
108
|
+
overlay_only_items.add(add_key)
|
|
102
109
|
continue
|
|
103
110
|
|
|
104
|
-
basis_value =
|
|
105
|
-
overlay_value =
|
|
111
|
+
basis_value: Any = use_basis.get(key)
|
|
112
|
+
overlay_value: Any = use_overlay.get(key)
|
|
106
113
|
|
|
107
|
-
if basis_value is not None
|
|
108
|
-
and overlay_value is not None:
|
|
114
|
+
if basis_value is not None and overlay_value is not None:
|
|
109
115
|
# Adjust overlay value type here:
|
|
110
116
|
# if "basis" contains say A = 3 and overlay contains A = '3',
|
|
111
117
|
# we try to convert overlay string to numeric type
|
|
112
118
|
# by parsing it. This takes care of situation
|
|
113
119
|
# when overlay value comes from environment variable,
|
|
114
120
|
# which is always a string.
|
|
115
|
-
overlay_value = self._convert_overlay_value(basis_value, overlay_value)
|
|
121
|
+
overlay_value: Any = self._convert_overlay_value(basis_value, overlay_value)
|
|
116
122
|
|
|
117
123
|
# By default, the result value for the key will be the overlay
|
|
118
124
|
# value itself.
|
|
119
|
-
result_value = overlay_value
|
|
125
|
+
result_value: Any = overlay_value
|
|
120
126
|
|
|
121
127
|
# ... except if both values are dictionaries.
|
|
122
128
|
# In that case, recurse.
|
|
@@ -131,7 +137,7 @@ class DictionaryOverlay():
|
|
|
131
137
|
|
|
132
138
|
return result
|
|
133
139
|
|
|
134
|
-
def _convert_overlay_value(self, basis_value, overlay_value):
|
|
140
|
+
def _convert_overlay_value(self, basis_value: Any, overlay_value: Any) -> Any:
|
|
135
141
|
"""
|
|
136
142
|
Given basis value from configuration and overlay value
|
|
137
143
|
we need to replace it with, convert overlay value if necessary.
|
|
@@ -145,12 +151,13 @@ class DictionaryOverlay():
|
|
|
145
151
|
in configuration.
|
|
146
152
|
"""
|
|
147
153
|
|
|
154
|
+
use_value: Any = overlay_value
|
|
148
155
|
if isinstance(overlay_value, str):
|
|
156
|
+
string_value: str = overlay_value
|
|
149
157
|
if isinstance(basis_value, bool):
|
|
150
|
-
|
|
151
|
-
bool(overlay_value.strip().lower() == 'true')
|
|
158
|
+
use_value = bool(string_value.strip().lower() == 'true')
|
|
152
159
|
elif isinstance(basis_value, int):
|
|
153
|
-
|
|
160
|
+
use_value = int(float(string_value))
|
|
154
161
|
elif isinstance(basis_value, float):
|
|
155
|
-
|
|
156
|
-
return
|
|
162
|
+
use_value = float(string_value)
|
|
163
|
+
return use_value
|
|
@@ -14,12 +14,9 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
# END COPYRIGHT
|
|
17
|
-
"""
|
|
18
|
-
See class comment for details.
|
|
19
|
-
"""
|
|
20
17
|
|
|
21
18
|
from pathlib import Path
|
|
22
|
-
import
|
|
19
|
+
from os.path import expanduser
|
|
23
20
|
|
|
24
21
|
|
|
25
22
|
class FileOfClass:
|
|
@@ -105,7 +102,7 @@ class FileOfClass:
|
|
|
105
102
|
|
|
106
103
|
if basis == "~":
|
|
107
104
|
# Special case if we are looking under user's home directory
|
|
108
|
-
basis =
|
|
105
|
+
basis = expanduser("~")
|
|
109
106
|
basis_abs_path: str = str(Path(basis).resolve())
|
|
110
107
|
|
|
111
108
|
if not test_abs_path.startswith(basis_abs_path):
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
from typing import List
|
|
18
|
+
|
|
19
|
+
from leaf_common.filters.string_filter import StringFilter
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CompositeStringFilter(StringFilter):
|
|
23
|
+
"""
|
|
24
|
+
An implementation of the StringFilter interface which puts together
|
|
25
|
+
multiple string filter operations in a certain order
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, filters: List[StringFilter] = None):
|
|
29
|
+
"""
|
|
30
|
+
Constructor
|
|
31
|
+
|
|
32
|
+
:param filters: A list of StringFilter class instances to apply in order
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
self._filters: List[StringFilter] = []
|
|
36
|
+
|
|
37
|
+
if filters is not None:
|
|
38
|
+
one_filter: StringFilter = None
|
|
39
|
+
for one_filter in filters:
|
|
40
|
+
self.add_filter(one_filter)
|
|
41
|
+
|
|
42
|
+
def add_filter(self, new_filter: StringFilter):
|
|
43
|
+
"""
|
|
44
|
+
:param new_filter: The StringFilter to be added to the list to be applied
|
|
45
|
+
"""
|
|
46
|
+
self._filters.append(new_filter)
|
|
47
|
+
|
|
48
|
+
def filter(self, in_string: str) -> str:
|
|
49
|
+
"""
|
|
50
|
+
:param in_string: an input string to filter
|
|
51
|
+
:return: a filtered version of the in_string, according to implementation policy
|
|
52
|
+
"""
|
|
53
|
+
accumulator: str = in_string
|
|
54
|
+
|
|
55
|
+
string_filter: StringFilter = None
|
|
56
|
+
for string_filter in self._filters:
|
|
57
|
+
accumulator = string_filter.filter(accumulator)
|
|
58
|
+
|
|
59
|
+
return accumulator
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
|
|
19
|
+
# pylint: disable=too-few-public-methods
|
|
20
|
+
class StringFilter:
|
|
21
|
+
"""
|
|
22
|
+
Interface whose filter() method takes one string and returns another string
|
|
23
|
+
which is a filtered version of the input.
|
|
24
|
+
|
|
25
|
+
These kinds of things are necessary for the following reasons:
|
|
26
|
+
* Tensorflow only likes column names with certain characters in them
|
|
27
|
+
* HTML UI sometimes only likes certain characters in strings.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def filter(self, in_string: str) -> str:
|
|
31
|
+
"""
|
|
32
|
+
:param in_string: an input string to filter
|
|
33
|
+
:return: a filtered version of the in_string, according to implementation policy
|
|
34
|
+
"""
|
|
35
|
+
raise NotImplementedError
|
|
@@ -29,8 +29,7 @@ class DictionaryExtractor():
|
|
|
29
29
|
Policy class that pairs a specific dictionary instance with a FieldExtractor.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
def __init__(self, dictionary: Dict[str, Any],
|
|
33
|
-
delimiter: str = "."):
|
|
32
|
+
def __init__(self, dictionary: Dict[str, Any], delimiter: str = "."):
|
|
34
33
|
"""
|
|
35
34
|
Constructor
|
|
36
35
|
|
|
@@ -41,7 +40,7 @@ class DictionaryExtractor():
|
|
|
41
40
|
self.delimiter: str = delimiter
|
|
42
41
|
self.extractor = FieldExtractor()
|
|
43
42
|
|
|
44
|
-
def get(self, field_name, default_value=None):
|
|
43
|
+
def get(self, field_name: str, default_value: Any = None) -> Any:
|
|
45
44
|
"""
|
|
46
45
|
:param field_name: the fully specified field name.
|
|
47
46
|
:param default_value: a default value if the field is not found.
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
# END COPYRIGHT
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
from typing import Any
|
|
18
|
+
from typing import Dict
|
|
19
|
+
from typing import List
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class FieldExtractor():
|
|
@@ -26,8 +26,8 @@ class FieldExtractor():
|
|
|
26
26
|
values imply nested dictionary lookup.
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
|
-
def get_field(self, dictionary, field_name, default_value=None,
|
|
30
|
-
delimiter="."):
|
|
29
|
+
def get_field(self, dictionary: Dict[str, Any], field_name: str, default_value: Any = None,
|
|
30
|
+
delimiter: str = ".") -> Any:
|
|
31
31
|
"""
|
|
32
32
|
:param dictionary: the dictionary in which the field
|
|
33
33
|
is supposed exist.
|
|
@@ -57,23 +57,21 @@ class FieldExtractor():
|
|
|
57
57
|
return dictionary.get(field_name, default_value)
|
|
58
58
|
|
|
59
59
|
# Handle the more complex case of a delimited key
|
|
60
|
-
field_split = field_name.split(delimiter)
|
|
61
|
-
use_field_name = field_split[0]
|
|
60
|
+
field_split: List[str] = field_name.split(delimiter)
|
|
61
|
+
use_field_name: str = field_split[0]
|
|
62
62
|
|
|
63
63
|
# Get the value for the segment of the field name
|
|
64
64
|
# If it's not a dictionary, return the default value,
|
|
65
65
|
# as we know we have more to look for.
|
|
66
|
-
value = dictionary.get(use_field_name, None)
|
|
67
|
-
if value is None or
|
|
68
|
-
not isinstance(value, dict):
|
|
66
|
+
value: Any = dictionary.get(use_field_name, None)
|
|
67
|
+
if value is None or not isinstance(value, dict):
|
|
69
68
|
return default_value
|
|
70
69
|
|
|
71
70
|
# We know the value is a dictionary.
|
|
72
71
|
# Get the remaining bit of the delimited field
|
|
73
72
|
# into its own string for recursion
|
|
74
|
-
remaining_split = field_split[1:len(field_split)+1]
|
|
75
|
-
remaining_field = delimiter.join(remaining_split)
|
|
73
|
+
remaining_split: List[str] = field_split[1:len(field_split)+1]
|
|
74
|
+
remaining_field: str = delimiter.join(remaining_split)
|
|
76
75
|
|
|
77
|
-
deep_value = self.get_field(value, remaining_field,
|
|
78
|
-
default_value, delimiter)
|
|
76
|
+
deep_value: Any = self.get_field(value, remaining_field, default_value, delimiter)
|
|
79
77
|
return deep_value
|
|
@@ -43,6 +43,8 @@ leaf_common/config/config_util.py
|
|
|
43
43
|
leaf_common/config/dictionary_overlay.py
|
|
44
44
|
leaf_common/config/environment_defaults.py
|
|
45
45
|
leaf_common/config/file_of_class.py
|
|
46
|
+
leaf_common/filters/composite_string_filter.py
|
|
47
|
+
leaf_common/filters/string_filter.py
|
|
46
48
|
leaf_common/logging/__init__.py
|
|
47
49
|
leaf_common/logging/conditional_logger.py
|
|
48
50
|
leaf_common/logging/example_logging_config.hocon
|
|
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
|