leaf-common 1.4.2__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.2 → leaf_common-1.4.4}/PKG-INFO +1 -1
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/asyncio/asyncio_executor.py +18 -12
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/config/config_filter.py +2 -2
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/config/config_filter_chain.py +4 -3
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/config/config_handler.py +39 -37
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/config/config_util.py +6 -1
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/config/dictionary_overlay.py +40 -33
- {leaf_common-1.4.2 → 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.2 → leaf_common-1.4.4}/leaf_common/parsers/dictionary_extractor.py +2 -3
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/parsers/field_extractor.py +12 -14
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/resolution/resolver_util.py +5 -2
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/utils/exception_util.py +3 -1
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common.egg-info/PKG-INFO +1 -1
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common.egg-info/SOURCES.txt +2 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/.coveragerc +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/.flake8 +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/.github/workflows/checkmarx.yml +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/.github/workflows/codeql.yml +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/.github/workflows/publish.yml +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/.github/workflows/tests.yml +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/.gitignore +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/.pylintrc +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/CODE_OF_CONDUCT.md +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/CONTRIBUTING.md +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/LICENSE.txt +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/Makefile +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/NOTICE.txt +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/README.md +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/SECURITY.md +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/SUPPORT.md +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/build_scripts/copyright_config.json +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/build_scripts/run_flake8.sh +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/build_scripts/run_pylint.sh +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/build_scripts/source_available_copyright.txt +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/asyncio/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/asyncio/async_to_sync_generator.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/asyncio/asyncio_executor_pool.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/asyncio/asyncio_threadpool_executor.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/asyncio/event_loop_factory.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/asyncio/event_loop_lag_monitor.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/asyncio/task_executor.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/config/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/config/environment_defaults.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/conditional_logger.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/example_logging_config.hocon +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/logging_setup.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/message_types.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/sensitive_logger.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/service_log_record.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/stream_to_logger.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/logging/structured_log_record.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/parsers/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/parsers/boolean_list_parser.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/parsers/boolean_parser.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/parsers/canonical_multi_config_parser.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/parsers/list_parser.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/parsers/parser.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/parsers/string_parser.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/easy/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/easy/abstract_easy_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/easy/composite_persistor.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/easy/easy_hocon_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/easy/easy_json_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/easy/easy_txt_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/easy/easy_yaml_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/README.md +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/abstract_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/hocon_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/json_gzip_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/json_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/null_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/override_file_extension_provider.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/persistence_factory.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/raw_bytes_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/reference_helper.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/simple_file_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/text_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/factory/yaml_persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/interface/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/interface/persistence.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/interface/persistence_mechanism.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/interface/persistor.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/interface/restorer.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/abstract_persistence_mechanism.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/local_file_persistence_mechanism.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/persistence_mechanism_factory.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/persistence_mechanisms.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/persistence/mechanism/s3_file_persistence_mechanism.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/profiling/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/profiling/async_profiling_lock.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/profiling/memory_util.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/profiling/profiling_lock.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/resolution/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/resolution/deprecation_redirect.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/resolution/resolver.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/buffered_gzip_serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/chained_serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/conversion_policy.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/gzip_serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/hocon_serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/json_serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/raw_bytes_serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/serialization_formats.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/text_serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/format/yaml_serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/interface/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/interface/deserializer.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/interface/dictionary_converter.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/interface/file_extension_provider.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/interface/reference_pruner.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/interface/serialization_format.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/interface/serializer.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/prep/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/prep/empty_dictionary_converter.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/prep/pass_through_dictionary_converter.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/prep/pass_through_reference_pruner.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/prep/redactor_dictionary_converter.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/util/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/util/bytes_decoder.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/serialization/util/text_file_reader.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/time/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/time/time_util.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/time/timeout.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/time/timeout_reached_exception.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/utils/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/utils/async_atomic_counter.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/utils/atomic_counter.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/utils/startable.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/validation/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/validation/composite_dictionary_validator.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common/validation/dictionary_validator.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common.egg-info/dependency_links.txt +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common.egg-info/requires.txt +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/leaf_common.egg-info/top_level.txt +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/pyproject.toml +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/requirements-build.txt +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/requirements.txt +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/setup.cfg +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/async_test_helpers.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_metrics_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_not_started_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_pool_dump_tasks_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_pool_gc_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_pool_metrics_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/asyncio_executor_started_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/asyncio_threadpool_executor_metrics_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/callable_class.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/event_loop_factory_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/asyncio/sync_test_helpers.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/config/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/config/dictionary_overlay_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/config/test_config_util.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/parsers/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/parsers/boolean_parser_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/parsers/canonical_multi_config_parser_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/resolution/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/resolution/resolver_util_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/resolution/test_deprecation_redirect.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/serialization/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/serialization/encoding/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/serialization/encoding/decode_text_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/serialization/encoding/text_file_reader_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/serialization/format/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/serialization/format/hocon_serialization_format_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/serialization/prep/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/serialization/prep/redactor_dictionary_converter_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/time/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/time/timeout_test.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/utils/__init__.py +0 -0
- {leaf_common-1.4.2 → leaf_common-1.4.4}/tests/utils/test_exception_util.py +0 -0
|
@@ -22,6 +22,7 @@ from typing import Awaitable
|
|
|
22
22
|
from typing import Callable
|
|
23
23
|
from typing import Dict
|
|
24
24
|
from typing import List
|
|
25
|
+
from typing import Set
|
|
25
26
|
from typing import Tuple
|
|
26
27
|
|
|
27
28
|
from functools import partial
|
|
@@ -161,7 +162,7 @@ class AsyncioExecutor(TaskExecutor):
|
|
|
161
162
|
|
|
162
163
|
# If we reach here, the loop was stopped.
|
|
163
164
|
# We should gather any remaining tasks and finish them.
|
|
164
|
-
pending = all_tasks(loop=loop)
|
|
165
|
+
pending: Set[Task] = all_tasks(loop=loop)
|
|
165
166
|
if pending:
|
|
166
167
|
# We want all possibly pending tasks to execute -
|
|
167
168
|
# don't need them to raise exceptions.
|
|
@@ -185,9 +186,9 @@ class AsyncioExecutor(TaskExecutor):
|
|
|
185
186
|
# Call the default exception handler first
|
|
186
187
|
loop.default_exception_handler(context)
|
|
187
188
|
|
|
188
|
-
message = context.get("message", None)
|
|
189
|
-
exception = context.get("exception", None)
|
|
190
|
-
formatted_exception = format_exception(exception)
|
|
189
|
+
message: str = context.get("message", None)
|
|
190
|
+
exception: Exception = context.get("exception", None)
|
|
191
|
+
formatted_exception: List[str] = format_exception(exception)
|
|
191
192
|
print(f"Event loop traceback ({message}):\n{formatted_exception}")
|
|
192
193
|
|
|
193
194
|
def get_function_name(self, function, submitter_id: str) -> str:
|
|
@@ -345,7 +346,7 @@ class AsyncioExecutor(TaskExecutor):
|
|
|
345
346
|
"task": task,
|
|
346
347
|
"raise_exception": raise_exception
|
|
347
348
|
}
|
|
348
|
-
task_id = id(task)
|
|
349
|
+
task_id: int = id(task)
|
|
349
350
|
self._background_tasks[task_id] = task_info_dict
|
|
350
351
|
task.add_done_callback(self.submission_done)
|
|
351
352
|
return task
|
|
@@ -353,11 +354,13 @@ class AsyncioExecutor(TaskExecutor):
|
|
|
353
354
|
@staticmethod
|
|
354
355
|
async def _cancel_and_drain(tasks: List[AsyncFuture]):
|
|
355
356
|
# Request cancellation for tasks that are not already done:
|
|
356
|
-
pending = []
|
|
357
|
+
pending: List[AsyncFuture] = []
|
|
357
358
|
for task in tasks:
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
359
|
+
test_task: AsyncFuture = task
|
|
360
|
+
test_task_done: bool = test_task.done()
|
|
361
|
+
if not test_task_done:
|
|
362
|
+
test_task.cancel("cancel-and-drain")
|
|
363
|
+
pending.append(test_task)
|
|
361
364
|
# Don't raise exceptions in the tasks being cancelled -
|
|
362
365
|
# we don't really need to react to them.
|
|
363
366
|
_ = await gather(*pending, return_exceptions=True)
|
|
@@ -457,11 +460,14 @@ class AsyncioExecutor(TaskExecutor):
|
|
|
457
460
|
# pylint: disable=broad-exception-caught
|
|
458
461
|
except Exception as exc:
|
|
459
462
|
formatted_exception: List[str] = format_exception(exc)
|
|
463
|
+
sensitive_logger = SensitiveLogger(self.logger)
|
|
460
464
|
for line in formatted_exception:
|
|
465
|
+
# Respect const-ness
|
|
466
|
+
use_line: str = line
|
|
461
467
|
if line.endswith("\n"):
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
sensitive_logger.info("%s",
|
|
468
|
+
# Remove the newline
|
|
469
|
+
use_line = line[:-1]
|
|
470
|
+
sensitive_logger.info("%s", use_line)
|
|
465
471
|
|
|
466
472
|
# As a last gesture, remove the background task from the map
|
|
467
473
|
# we use to keep its reference around. Do it safely:
|
|
@@ -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.
|