holado 0.13.22__py3-none-any.whl
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.
- holado/__init__.py +358 -0
- holado/common/__init__.py +25 -0
- holado/common/context/__init__.py +25 -0
- holado/common/context/context.py +248 -0
- holado/common/context/service_manager.py +262 -0
- holado/common/context/session_context.py +516 -0
- holado/common/handlers/__init__.py +19 -0
- holado/common/handlers/enums.py +41 -0
- holado/common/handlers/object.py +175 -0
- holado/common/handlers/undefined.py +55 -0
- holado/common/tools/__init__.py +19 -0
- holado/common/tools/gc_manager.py +155 -0
- holado/holado_config.py +45 -0
- holado-0.13.22.dist-info/METADATA +194 -0
- holado-0.13.22.dist-info/RECORD +698 -0
- holado-0.13.22.dist-info/WHEEL +4 -0
- holado-0.13.22.dist-info/licenses/LICENSE +21 -0
- holado_ais/__init__.py +33 -0
- holado_ais/ais/MaritimeIdentificationDigits.csv +295 -0
- holado_ais/ais/ais_manager.py +151 -0
- holado_ais/ais/ais_messages.py +356 -0
- holado_ais/ais/ais_payload.py +35 -0
- holado_ais/ais/enums.py +37 -0
- holado_ais/ais/patch_pyais.py +1174 -0
- holado_ais/tests/behave/steps/__init__.py +17 -0
- holado_ais/tests/behave/steps/ais/__init__.py +0 -0
- holado_ais/tests/behave/steps/ais/ais_manager_steps.py +50 -0
- holado_ais/tests/behave/steps/ais/ais_messages_steps.py +237 -0
- holado_binary/__init__.py +17 -0
- holado_binary/ipc/binary.py +125 -0
- holado_binary/ipc/bit_series.py +307 -0
- holado_binary/tests/behave/steps/__init__.py +17 -0
- holado_binary/tests/behave/steps/ipc/binary_steps.py +57 -0
- holado_binary/tests/behave/steps/ipc/bit_series_steps.py +132 -0
- holado_context/__init__.py +16 -0
- holado_context/tests/behave/steps/__init__.py +16 -0
- holado_context/tests/behave/steps/private/__init__.py +16 -0
- holado_context/tests/behave/steps/private/common/context_steps.py +68 -0
- holado_core/__init__.py +32 -0
- holado_core/common/__init__.py +0 -0
- holado_core/common/actors/actions.py +97 -0
- holado_core/common/actors/actor.py +226 -0
- holado_core/common/actors/element_actor.py +32 -0
- holado_core/common/actors/find_actor.py +106 -0
- holado_core/common/actors/tree_actor.py +32 -0
- holado_core/common/actors/verify_actions.py +69 -0
- holado_core/common/block/base.py +122 -0
- holado_core/common/block/block_manager.py +173 -0
- holado_core/common/block/block_method.py +46 -0
- holado_core/common/block/block_steps.py +37 -0
- holado_core/common/block/function.py +42 -0
- holado_core/common/block/scope_function.py +28 -0
- holado_core/common/block/scope_manager.py +238 -0
- holado_core/common/block/scope_steps.py +141 -0
- holado_core/common/criterias/and_criteria.py +61 -0
- holado_core/common/criterias/criteria.py +78 -0
- holado_core/common/criterias/or_criteria.py +64 -0
- holado_core/common/criterias/tools/criteria_context.py +20 -0
- holado_core/common/criterias/tools/criteria_parameters.py +18 -0
- holado_core/common/drivers/driver.py +153 -0
- holado_core/common/drivers/element_driver.py +30 -0
- holado_core/common/drivers/element_internal_api.py +239 -0
- holado_core/common/drivers/internal_api.py +40 -0
- holado_core/common/drivers/tree_driver.py +30 -0
- holado_core/common/drivers/tree_internal_api.py +176 -0
- holado_core/common/exceptions/__init__.py +0 -0
- holado_core/common/exceptions/element_exception.py +28 -0
- holado_core/common/exceptions/exceptions.py +24 -0
- holado_core/common/exceptions/functional_exception.py +21 -0
- holado_core/common/exceptions/holado_exception.py +25 -0
- holado_core/common/exceptions/technical_exception.py +27 -0
- holado_core/common/exceptions/timeout_exception.py +20 -0
- holado_core/common/exceptions/verify_exception.py +20 -0
- holado_core/common/finders/after_in_tree_finder.py +87 -0
- holado_core/common/finders/element_finder.py +60 -0
- holado_core/common/finders/else_finder.py +105 -0
- holado_core/common/finders/finder.py +478 -0
- holado_core/common/finders/or_finder.py +98 -0
- holado_core/common/finders/then_finder.py +157 -0
- holado_core/common/finders/tools/enums.py +30 -0
- holado_core/common/finders/tools/find_builder.py +118 -0
- holado_core/common/finders/tools/find_context.py +405 -0
- holado_core/common/finders/tools/find_info.py +27 -0
- holado_core/common/finders/tools/find_parameters.py +240 -0
- holado_core/common/finders/tools/find_updater.py +95 -0
- holado_core/common/finders/tools/finder_info.py +26 -0
- holado_core/common/finders/tree_finder.py +146 -0
- holado_core/common/handlers/__init__.py +0 -0
- holado_core/common/handlers/abstracts/base_redo.py +702 -0
- holado_core/common/handlers/abstracts/get_or_create.py +120 -0
- holado_core/common/handlers/element_holder.py +122 -0
- holado_core/common/handlers/enums.py +23 -0
- holado_core/common/handlers/exceptions/redo_exceptions.py +28 -0
- holado_core/common/handlers/features/resource_by_name.py +187 -0
- holado_core/common/handlers/features/resource_by_type.py +174 -0
- holado_core/common/handlers/redo.py +119 -0
- holado_core/common/handlers/wait.py +127 -0
- holado_core/common/inspectors/element_inspector.py +57 -0
- holado_core/common/inspectors/inspector.py +221 -0
- holado_core/common/inspectors/tools/inspect_builder.py +169 -0
- holado_core/common/inspectors/tools/inspect_context.py +69 -0
- holado_core/common/inspectors/tools/inspect_parameters.py +181 -0
- holado_core/common/inspectors/tree_inspector.py +73 -0
- holado_core/common/resource/persisted_data_manager.py +113 -0
- holado_core/common/resource/persisted_method_to_call_manager.py +263 -0
- holado_core/common/resource/resource_manager.py +126 -0
- holado_core/common/resource/table_data_manager.py +110 -0
- holado_core/common/tables/__init__.py +1 -0
- holado_core/common/tables/comparators/__init__.py +0 -0
- holado_core/common/tables/comparators/boolean_table_cell_comparator.py +25 -0
- holado_core/common/tables/comparators/bytes_table_cell_comparator.py +25 -0
- holado_core/common/tables/comparators/datetime_table_cell_comparator.py +24 -0
- holado_core/common/tables/comparators/float_table_cell_comparator.py +31 -0
- holado_core/common/tables/comparators/integer_table_cell_comparator.py +25 -0
- holado_core/common/tables/comparators/internal_table_cell_comparator.py +30 -0
- holado_core/common/tables/comparators/string_table_cell_comparator.py +24 -0
- holado_core/common/tables/comparators/string_table_comparator.py +29 -0
- holado_core/common/tables/comparators/string_table_row_comparator.py +29 -0
- holado_core/common/tables/comparators/table_cell_comparator.py +40 -0
- holado_core/common/tables/comparators/table_comparator.py +209 -0
- holado_core/common/tables/comparators/table_comparator_manager.py +60 -0
- holado_core/common/tables/comparators/table_row_comparator.py +116 -0
- holado_core/common/tables/comparators/table_with_header_comparator.py +68 -0
- holado_core/common/tables/converters/__init__.py +0 -0
- holado_core/common/tables/converters/table_converter.py +233 -0
- holado_core/common/tables/enums.py +23 -0
- holado_core/common/tables/table.py +261 -0
- holado_core/common/tables/table_cell.py +126 -0
- holado_core/common/tables/table_manager.py +365 -0
- holado_core/common/tables/table_row.py +169 -0
- holado_core/common/tables/table_with_header.py +242 -0
- holado_core/common/tools/__init__.py +0 -0
- holado_core/common/tools/comparators/comparator.py +151 -0
- holado_core/common/tools/comparators/object_comparator.py +21 -0
- holado_core/common/tools/converters/converter.py +118 -0
- holado_core/common/tools/path_manager.py +238 -0
- holado_core/common/tools/string_tools.py +144 -0
- holado_core/common/tools/tools.py +197 -0
- holado_core/tests/behave/steps/__init__.py +20 -0
- holado_core/tests/behave/steps/common/__init__.py +0 -0
- holado_core/tests/behave/steps/common/common_steps.py +137 -0
- holado_core/tests/behave/steps/common/config_steps.py +42 -0
- holado_core/tests/behave/steps/common/resource_steps.py +62 -0
- holado_core/tests/behave/steps/common/tables_steps.py +560 -0
- holado_core/tools/__init__.py +0 -0
- holado_core/tools/abstracts/__init__.py +0 -0
- holado_core/tools/abstracts/blocking_command_service.py +64 -0
- holado_core/tools/abstracts/service.py +48 -0
- holado_crypto/__init__.py +31 -0
- holado_crypto/crypto/crypto.py +108 -0
- holado_crypto/crypto/key.py +92 -0
- holado_crypto/crypto/tcpbin.py +105 -0
- holado_crypto/crypto/transport/__init__.py +0 -0
- holado_crypto/crypto/transport/crc.py +40 -0
- holado_crypto/tests/behave/steps/__init__.py +18 -0
- holado_crypto/tests/behave/steps/crypto_steps.py +112 -0
- holado_crypto/tests/behave/steps/key_steps.py +82 -0
- holado_crypto/tests/behave/steps/tcpbin_steps.py +79 -0
- holado_data/__init__.py +31 -0
- holado_data/data/generator/base.py +93 -0
- holado_data/data/generator/generator_manager.py +27 -0
- holado_data/data/generator/python_generator.py +30 -0
- holado_data/tests/behave/steps/__init__.py +17 -0
- holado_data/tests/behave/steps/data/generator_steps.py +91 -0
- holado_data/tests/behave/steps/tools/utils_steps.py +59 -0
- holado_db/__init__.py +32 -0
- holado_db/tests/behave/steps/__init__.py +18 -0
- holado_db/tests/behave/steps/tools/db/db_client_steps.py +134 -0
- holado_db/tests/behave/steps/tools/db/postgresql_client_steps.py +59 -0
- holado_db/tests/behave/steps/tools/db/sqlite_client_steps.py +57 -0
- holado_db/tools/db/clients/base/db_audit.py +94 -0
- holado_db/tools/db/clients/base/db_client.py +344 -0
- holado_db/tools/db/clients/postgresql/postgresql_audit.py +75 -0
- holado_db/tools/db/clients/postgresql/postgresql_client.py +84 -0
- holado_db/tools/db/clients/sqlite/sqlite_audit.py +70 -0
- holado_db/tools/db/clients/sqlite/sqlite_client.py +60 -0
- holado_db/tools/db/db_manager.py +109 -0
- holado_db/tools/db/query/base/query_builder.py +138 -0
- holado_db/tools/db/query/pypika/pypika_query_builder.py +244 -0
- holado_db/tools/db/query/query_manager.py +77 -0
- holado_django/__init__.py +31 -0
- holado_django/server/HOWTO.txt +27 -0
- holado_django/server/django_projects/rest_api/db.sqlite3 +0 -0
- holado_django/server/django_projects/rest_api/manage.py +22 -0
- holado_django/server/django_projects/rest_api/rest_api/__init__.py +0 -0
- holado_django/server/django_projects/rest_api/rest_api/application/__init__.py +0 -0
- holado_django/server/django_projects/rest_api/rest_api/application/admin.py +3 -0
- holado_django/server/django_projects/rest_api/rest_api/application/apps.py +9 -0
- holado_django/server/django_projects/rest_api/rest_api/application/migrations/__init__.py +0 -0
- holado_django/server/django_projects/rest_api/rest_api/application/models.py +3 -0
- holado_django/server/django_projects/rest_api/rest_api/application/tests.py +3 -0
- holado_django/server/django_projects/rest_api/rest_api/application/views.py +6 -0
- holado_django/server/django_projects/rest_api/rest_api/asgi.py +16 -0
- holado_django/server/django_projects/rest_api/rest_api/settings.py +130 -0
- holado_django/server/django_projects/rest_api/rest_api/urls.py +35 -0
- holado_django/server/django_projects/rest_api/rest_api/wsgi.py +16 -0
- holado_django/server/django_server.py +110 -0
- holado_django/server/grpc_django_server.py +57 -0
- holado_django/server/patch_djangogrpcframework.py +46 -0
- holado_django/tests/behave/steps/__init__.py +16 -0
- holado_django/tests/behave/steps/django_server_steps.py +83 -0
- holado_docker/__init__.py +25 -0
- holado_docker/sdk/docker/container_logs.py +447 -0
- holado_docker/sdk/docker/docker_client.py +537 -0
- holado_docker/sdk/docker/docker_service.py +71 -0
- holado_docker/tests/behave/steps/__init__.py +16 -0
- holado_docker/tests/behave/steps/sdk/docker/container_logs_steps.py +47 -0
- holado_examples/projects/server_rest/server_rest_example/initialize_holado.py +72 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/db.sqlite3 +0 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/manage.py +22 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/__init__.py +0 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/application/__init__.py +0 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/application/admin.py +3 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/application/apps.py +7 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/application/migrations/__init__.py +0 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/application/models.py +3 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/application/serializers.py +15 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/application/tests.py +3 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/application/views.py +24 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/asgi.py +16 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/settings.py +130 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/urls.py +31 -0
- holado_examples/projects/server_rest/server_rest_example/rest_api/rest_api/wsgi.py +16 -0
- holado_examples/projects/server_rest/server_rest_example/rest_server.py +37 -0
- holado_examples/scripts/script_custom_initialization.py +16 -0
- holado_examples/scripts/script_minimal_initialization.py +23 -0
- holado_examples/tests/behave/testing_solution/__main__.py +13 -0
- holado_examples/tests/behave/testing_solution/behave_environment.py +35 -0
- holado_examples/tests/behave/testing_solution/environment.py +36 -0
- holado_examples/tests/behave/testing_solution/features/Configuration/Actions/configure_system.feature +10 -0
- holado_examples/tests/behave/testing_solution/features/NonReg/example.feature +26 -0
- holado_examples/tests/behave/testing_solution/initialize_holado.py +62 -0
- holado_examples/tests/behave/testing_solution/logging.conf +102 -0
- holado_examples/tests/behave/testing_solution/requirements.txt +5 -0
- holado_examples/tests/behave/testing_solution/run_test.sh +7 -0
- holado_examples/tests/behave/testing_solution/run_test_nonreg.sh +6 -0
- holado_examples/tests/behave/testing_solution/src/common/tools/path_manager.py +40 -0
- holado_examples/tests/behave/testing_solution/src/config/config_manager.py +30 -0
- holado_examples/tests/behave/testing_solution/src/context/session_context.py +45 -0
- holado_examples/tests/behave/testing_solution/steps/config_steps.py +21 -0
- holado_examples/tests/behave/testing_solution/steps/public_steps.py +10 -0
- holado_grpc/TODO +8 -0
- holado_grpc/__init__.py +40 -0
- holado_grpc/api/rpc/TODO.txt +4 -0
- holado_grpc/api/rpc/grpc_client.py +210 -0
- holado_grpc/api/rpc/grpc_manager.py +81 -0
- holado_grpc/ipc/rpc/__init__.py +0 -0
- holado_grpc/ipc/rpc/grpc_compiler.py +45 -0
- holado_grpc/ipc/rpc/grpc_services.py +165 -0
- holado_grpc/tests/behave/steps/__init__.py +16 -0
- holado_grpc/tests/behave/steps/api/grpc_client_steps.py +173 -0
- holado_grpc/tests/behave/steps/private/__init__.py +16 -0
- holado_grpc/tests/behave/steps/private/api/grpc_steps.py +77 -0
- holado_helper/__init__.py +35 -0
- holado_helper/debug/README.txt +32 -0
- holado_helper/debug/memory/memory_profiler.py +106 -0
- holado_helper/docker/init_user.sh +24 -0
- holado_helper/docker/logging.conf +44 -0
- holado_helper/docker/run_holado_test_nonreg_in_docker.sh +120 -0
- holado_helper/docker/run_terminal_in_docker.sh +101 -0
- holado_helper/holado_module_template/__init__.py +38 -0
- holado_helper/holado_module_template/tests/behave/steps/__init__.py +16 -0
- holado_helper/holado_module_template/tests/behave/steps/private/__init__.py +16 -0
- holado_helper/initialize_holado.py +72 -0
- holado_helper/script/action.py +130 -0
- holado_helper/script/action_script.py +477 -0
- holado_helper/script/any_action_script.py +126 -0
- holado_helper/script/behave_action_script.py +99 -0
- holado_helper/script/csv_action_script.py +142 -0
- holado_helper/script/initialize_script.py +95 -0
- holado_helper/script/input_output_script.py +136 -0
- holado_helper/script/job.py +75 -0
- holado_helper/script/json_action_script.py +104 -0
- holado_helper/script/script.py +110 -0
- holado_json/__init__.py +16 -0
- holado_json/filesystem/json_file.py +94 -0
- holado_json/filesystem/stream_json_file.py +117 -0
- holado_json/ipc/json.py +146 -0
- holado_json/ipc/json_converter.py +69 -0
- holado_json/ipc/json_types.py +183 -0
- holado_json/tests/behave/steps/__init__.py +16 -0
- holado_json/tests/behave/steps/ipc/__init__.py +0 -0
- holado_json/tests/behave/steps/ipc/json_steps.py +131 -0
- holado_keycloak/__init__.py +16 -0
- holado_keycloak/tests/behave/steps/__init__.py +16 -0
- holado_keycloak/tests/behave/steps/tools/keycloak_client_steps.py +73 -0
- holado_keycloak/tools/keycloak/__init__.py +0 -0
- holado_keycloak/tools/keycloak/keycloak_client.py +90 -0
- holado_logging/__init__.py +38 -0
- holado_logging/common/logging/holado_logger.py +71 -0
- holado_logging/common/logging/log_config.py +163 -0
- holado_logging/common/logging/log_manager.py +335 -0
- holado_multitask/__init__.py +33 -0
- holado_multitask/multiprocessing/context/process_context.py +35 -0
- holado_multitask/multiprocessing/function_process.py +102 -0
- holado_multitask/multiprocessing/periodic_function_process.py +137 -0
- holado_multitask/multiprocessing/process.py +213 -0
- holado_multitask/multiprocessing/processesmanager.py +137 -0
- holado_multitask/multitasking/multitask_manager.py +464 -0
- holado_multitask/multithreading/__init__.py +0 -0
- holado_multitask/multithreading/context/thread_context.py +86 -0
- holado_multitask/multithreading/functionthreaded.py +129 -0
- holado_multitask/multithreading/loopfunctionthreaded.py +45 -0
- holado_multitask/multithreading/loopthread.py +110 -0
- holado_multitask/multithreading/periodicfunctionthreaded.py +135 -0
- holado_multitask/multithreading/reflection/inspect.py +47 -0
- holado_multitask/multithreading/reflection/sys.py +29 -0
- holado_multitask/multithreading/reflection/traceback.py +35 -0
- holado_multitask/multithreading/thread.py +203 -0
- holado_multitask/multithreading/threadsmanager.py +167 -0
- holado_multitask/multithreading/timer.py +51 -0
- holado_multitask/tests/behave/steps/__init__.py +17 -0
- holado_multitask/tests/behave/steps/multiprocessing_steps.py +138 -0
- holado_multitask/tests/behave/steps/multithreading_steps.py +129 -0
- holado_protobuf/__init__.py +61 -0
- holado_protobuf/ipc/protobuf/__init__.py +0 -0
- holado_protobuf/ipc/protobuf/abstracts/type.py +45 -0
- holado_protobuf/ipc/protobuf/protobuf_compiler.py +118 -0
- holado_protobuf/ipc/protobuf/protobuf_converter.py +153 -0
- holado_protobuf/ipc/protobuf/protobuf_messages.py +968 -0
- holado_protobuf/ipc/protobuf/protobuf_modifier.py +65 -0
- holado_protobuf/ipc/protobuf/types/__init__.py +0 -0
- holado_protobuf/ipc/protobuf/types/google/__init__.py +0 -0
- holado_protobuf/ipc/protobuf/types/google/protobuf.py +124 -0
- holado_protobuf/tests/behave/steps/__init__.py +16 -0
- holado_protobuf/tests/behave/steps/ipc/protobuf_steps.py +297 -0
- holado_python/__init__.py +36 -0
- holado_python/common/enums.py +34 -0
- holado_python/common/iterables.py +38 -0
- holado_python/common/tools/comparators/boolean_comparator.py +37 -0
- holado_python/common/tools/comparators/bytes_comparator.py +48 -0
- holado_python/common/tools/comparators/datetime_comparator.py +74 -0
- holado_python/common/tools/comparators/float_comparator.py +97 -0
- holado_python/common/tools/comparators/integer_comparator.py +37 -0
- holado_python/common/tools/comparators/string_comparator.py +99 -0
- holado_python/common/tools/comparators/type_comparator.py +31 -0
- holado_python/common/tools/datetime.py +341 -0
- holado_python/standard_library/csv.py +207 -0
- holado_python/standard_library/hashlib.py +110 -0
- holado_python/standard_library/multiprocessing.py +62 -0
- holado_python/standard_library/queue.py +79 -0
- holado_python/standard_library/socket/blocking_socket.py +219 -0
- holado_python/standard_library/socket/echo_server.py +29 -0
- holado_python/standard_library/socket/message_socket.py +152 -0
- holado_python/standard_library/socket/non_blocking_socket.py +172 -0
- holado_python/standard_library/socket/socket.py +411 -0
- holado_python/standard_library/ssl/resources/certificates/NOTES.txt +5 -0
- holado_python/standard_library/ssl/resources/certificates/localhost.crt +19 -0
- holado_python/standard_library/ssl/resources/certificates/localhost.key +28 -0
- holado_python/standard_library/ssl/ssl.py +131 -0
- holado_python/standard_library/typing.py +192 -0
- holado_python/tests/behave/steps/__init__.py +27 -0
- holado_python/tests/behave/steps/builtins/str_steps.py +45 -0
- holado_python/tests/behave/steps/convert_steps.py +59 -0
- holado_python/tests/behave/steps/iterable_steps.py +87 -0
- holado_python/tests/behave/steps/standard_library/csv_steps.py +134 -0
- holado_python/tests/behave/steps/standard_library/datetime_steps.py +163 -0
- holado_python/tests/behave/steps/standard_library/hashlib_steps.py +57 -0
- holado_python/tests/behave/steps/standard_library/multiprocessing_steps.py +56 -0
- holado_python/tests/behave/steps/standard_library/queue_steps.py +358 -0
- holado_python/tests/behave/steps/standard_library/socket_steps.py +384 -0
- holado_python/tests/behave/steps/standard_library/ssl_steps.py +71 -0
- holado_rabbitmq/__init__.py +28 -0
- holado_rabbitmq/tests/behave/steps/__init__.py +17 -0
- holado_rabbitmq/tests/behave/steps/tools/rabbitmq_client_steps.py +565 -0
- holado_rabbitmq/tests/behave/steps/tools/rabbitmq_server_steps.py +64 -0
- holado_rabbitmq/tools/rabbitmq/rabbitmq_blocking_client.py +333 -0
- holado_rabbitmq/tools/rabbitmq/rabbitmq_client.py +678 -0
- holado_rabbitmq/tools/rabbitmq/rabbitmq_manager.py +146 -0
- holado_rabbitmq/tools/rabbitmq/rabbitmq_select_client.py +428 -0
- holado_rabbitmq/tools/rabbitmq/rabbitmq_server.py +24 -0
- holado_redis/__init__.py +17 -0
- holado_redis/tests/behave/steps/__init__.py +16 -0
- holado_redis/tests/behave/steps/tools/redis_client_steps.py +101 -0
- holado_redis/tools/redis/TODO.txt +7 -0
- holado_redis/tools/redis/redis_client.py +190 -0
- holado_redis/tools/redis/redis_manager.py +38 -0
- holado_report/__init__.py +36 -0
- holado_report/campaign/campaign_manager.py +348 -0
- holado_report/report/analyze/execution_historic_manager.py +96 -0
- holado_report/report/analyze/scenario_duration_manager.py +245 -0
- holado_report/report/builders/detailed_scenario_report_builder.py +172 -0
- holado_report/report/builders/execution_historic_report_builder.py +132 -0
- holado_report/report/builders/failure_report_builder.py +150 -0
- holado_report/report/builders/report_builder.py +64 -0
- holado_report/report/builders/short_scenario_report_builder.py +94 -0
- holado_report/report/builders/summary_by_category_report_builder.py +103 -0
- holado_report/report/builders/summary_report_builder.py +110 -0
- holado_report/report/builders/summary_scenario_by_category_report_builder.py +109 -0
- holado_report/report/builders/summary_scenario_report_builder.py +81 -0
- holado_report/report/execution_historic.py +144 -0
- holado_report/report/report_manager.py +424 -0
- holado_report/report/reports/base_report.py +163 -0
- holado_report/report/reports/feature_report.py +106 -0
- holado_report/report/reports/scenario_report.py +64 -0
- holado_rest/__init__.py +32 -0
- holado_rest/api/rest/TODO.txt +2 -0
- holado_rest/api/rest/rest_client.py +200 -0
- holado_rest/api/rest/rest_manager.py +72 -0
- holado_rest/tests/behave/steps/__init__.py +16 -0
- holado_rest/tests/behave/steps/api/__init__.py +0 -0
- holado_rest/tests/behave/steps/api/rest_client_steps.py +181 -0
- holado_rest/tests/behave/steps/private/__init__.py +16 -0
- holado_rest/tests/behave/steps/private/api/__init__.py +0 -0
- holado_rest/tests/behave/steps/private/api/rest_steps.py +75 -0
- holado_s3/__init__.py +17 -0
- holado_s3/tests/behave/steps/__init__.py +17 -0
- holado_s3/tests/behave/steps/private/__init__.py +16 -0
- holado_s3/tests/behave/steps/private/tools/s3_steps.py +89 -0
- holado_s3/tests/behave/steps/tools/s3_client_steps.py +403 -0
- holado_s3/tests/behave/steps/tools/s3_server_steps.py +57 -0
- holado_s3/tools/s3/__init__.py +0 -0
- holado_s3/tools/s3/boto3_s3_client.py +59 -0
- holado_s3/tools/s3/minio_client.py +75 -0
- holado_s3/tools/s3/moto_server.py +52 -0
- holado_scripting/__init__.py +54 -0
- holado_scripting/common/tools/dynamic_text_manager.py +73 -0
- holado_scripting/common/tools/evaluate_parameters.py +228 -0
- holado_scripting/common/tools/expression_evaluator.py +389 -0
- holado_scripting/common/tools/variable_manager.py +354 -0
- holado_scripting/tests/behave/steps/__init__.py +22 -0
- holado_scripting/tests/behave/steps/common/tools/variable_convert_steps.py +159 -0
- holado_scripting/tests/behave/steps/common/tools/variable_new_steps.py +130 -0
- holado_scripting/tests/behave/steps/common/tools/variable_steps.py +108 -0
- holado_scripting/tests/behave/steps/common/tools/variable_verify_steps.py +160 -0
- holado_scripting/tests/behave/steps/scenario/function_steps.py +77 -0
- holado_scripting/tests/behave/steps/scenario/if_steps.py +87 -0
- holado_scripting/tests/behave/steps/scenario/loop_steps.py +119 -0
- holado_scripting/text/base/base_function.py +25 -0
- holado_scripting/text/base/base_verify_function.py +25 -0
- holado_scripting/text/base/text_inspecter.py +204 -0
- holado_scripting/text/interpreter/exceptions/interpreter_exception.py +25 -0
- holado_scripting/text/interpreter/functions/function_apply_function.py +60 -0
- holado_scripting/text/interpreter/functions/function_cast.py +60 -0
- holado_scripting/text/interpreter/functions/function_convert.py +57 -0
- holado_scripting/text/interpreter/functions/function_dynamic_value.py +40 -0
- holado_scripting/text/interpreter/functions/function_escape_all_bytes.py +35 -0
- holado_scripting/text/interpreter/functions/function_exists_variable.py +39 -0
- holado_scripting/text/interpreter/functions/function_hex_to_bytes.py +49 -0
- holado_scripting/text/interpreter/functions/function_hex_to_int.py +53 -0
- holado_scripting/text/interpreter/functions/function_to_base_64.py +41 -0
- holado_scripting/text/interpreter/functions/function_to_bytes.py +50 -0
- holado_scripting/text/interpreter/functions/function_to_hex.py +42 -0
- holado_scripting/text/interpreter/functions/function_to_string.py +50 -0
- holado_scripting/text/interpreter/text_interpreter.py +219 -0
- holado_scripting/text/verifier/exceptions/verifier_exception.py +21 -0
- holado_scripting/text/verifier/functions/verify_function_extract_in.py +35 -0
- holado_scripting/text/verifier/functions/verify_function_match_pattern.py +63 -0
- holado_scripting/text/verifier/text_verifier.py +103 -0
- holado_sftp/__init__.py +16 -0
- holado_sftp/tests/behave/steps/__init__.py +17 -0
- holado_sftp/tests/behave/steps/private/__init__.py +16 -0
- holado_sftp/tests/behave/steps/private/tools/sftp_steps.py +78 -0
- holado_sftp/tests/behave/steps/tools/sftp_client_steps.py +94 -0
- holado_sftp/tests/behave/steps/tools/sftp_server_steps.py +82 -0
- holado_sftp/tools/sftp/__init__.py +0 -0
- holado_sftp/tools/sftp/sftp_client.py +103 -0
- holado_sftp/tools/sftp/sftp_server.py +39 -0
- holado_swagger/__init__.py +31 -0
- holado_swagger/swagger_hub/mockserver/mockserver_client.py +82 -0
- holado_swagger/swagger_hub/mockserver/mockserver_manager.py +33 -0
- holado_swagger/tests/behave/steps/__init__.py +16 -0
- holado_swagger/tests/behave/steps/swagger_hub/mockserver_steps.py +74 -0
- holado_system/system/command/command.py +247 -0
- holado_system/system/command/command_result.py +128 -0
- holado_system/system/command/curl_command.py +101 -0
- holado_system/system/command/exceptions.py +59 -0
- holado_system/system/filesystem/file.py +150 -0
- holado_system/system/global_system.py +187 -0
- holado_system/tests/behave/steps/__init__.py +18 -0
- holado_system/tests/behave/steps/system/commands_steps.py +92 -0
- holado_system/tests/behave/steps/system/file_steps.py +231 -0
- holado_system/tests/behave/steps/system/system_steps.py +84 -0
- holado_test/__init__.py +30 -0
- holado_test/behave/__init__.py +0 -0
- holado_test/behave/behave.py +400 -0
- holado_test/behave/behave_environment.py +169 -0
- holado_test/behave/behave_function.py +33 -0
- holado_test/behave/behave_manager.py +558 -0
- holado_test/behave/independant_runner.py +66 -0
- holado_test/behave/scenario/__init__.py +0 -0
- holado_test/behave/scenario/behave_step_tools.py +157 -0
- holado_test/common/context/feature_context.py +81 -0
- holado_test/common/context/scenario_context.py +169 -0
- holado_test/common/context/step_context.py +66 -0
- holado_test/common/exceptions/undefined_step_exception.py +21 -0
- holado_test/scenario/step_tools.py +547 -0
- holado_test/scenario/tester_tools.py +57 -0
- holado_test/test_config.py +26 -0
- holado_test/tests/behave/steps/__init__.py +18 -0
- holado_test/tests/behave/steps/scenario/exception_steps.py +87 -0
- holado_test/tests/behave/steps/scenario/scenario_steps.py +100 -0
- holado_test/tests/behave/steps/scenario/tester_steps.py +65 -0
- holado_test/tools/test_server/client/rest/test_server_client.py +150 -0
- holado_test/tools/test_server/server/Dockerfile +60 -0
- holado_test/tools/test_server/server/core/server_context.py +42 -0
- holado_test/tools/test_server/server/core/server_manager.py +41 -0
- holado_test/tools/test_server/server/requirements.txt +2 -0
- holado_test/tools/test_server/server/rest/README +2 -0
- holado_test/tools/test_server/server/rest/api/__init__.py +24 -0
- holado_test/tools/test_server/server/rest/api/campaign/__init__.py +32 -0
- holado_test/tools/test_server/server/rest/api/campaign/scenario.py +40 -0
- holado_test/tools/test_server/server/rest/initialize_holado.py +72 -0
- holado_test/tools/test_server/server/rest/logging.conf +51 -0
- holado_test/tools/test_server/server/rest/openapi.yaml +57 -0
- holado_test/tools/test_server/server/rest/run.py +41 -0
- holado_test/tools/test_server/server/run.sh +6 -0
- holado_test/tools/test_server/server/run_test_server_in_docker.sh +104 -0
- holado_tools/__init__.py +38 -0
- holado_tools/scripts/execute_persisted_post_processes/execute_persisted_post_processes.py +36 -0
- holado_tools/scripts/execute_persisted_post_processes/execute_persisted_post_processes.sh +6 -0
- holado_tools/scripts/execute_persisted_post_processes/initialize_holado.py +62 -0
- holado_tools/tests/behave/steps/__init__.py +16 -0
- holado_tools/tests/behave/steps/tools/host_controller/client_steps.py +97 -0
- holado_tools/tools/host_controller/client/rest/host_controller_client.py +275 -0
- holado_tools/tools/host_controller/server/Dockerfile +60 -0
- holado_tools/tools/host_controller/server/requirements.txt +2 -0
- holado_tools/tools/host_controller/server/rest/README +2 -0
- holado_tools/tools/host_controller/server/rest/api/__init__.py +24 -0
- holado_tools/tools/host_controller/server/rest/api/config.py +88 -0
- holado_tools/tools/host_controller/server/rest/api/docker/__init__.py +66 -0
- holado_tools/tools/host_controller/server/rest/api/docker/container.py +144 -0
- holado_tools/tools/host_controller/server/rest/api/docker/logs.py +66 -0
- holado_tools/tools/host_controller/server/rest/api/os.py +58 -0
- holado_tools/tools/host_controller/server/rest/initialize_holado.py +72 -0
- holado_tools/tools/host_controller/server/rest/openapi.yaml +561 -0
- holado_tools/tools/host_controller/server/rest/run.py +31 -0
- holado_tools/tools/host_controller/server/run_host_controller_in_docker.sh +107 -0
- holado_tools/tools/host_viewer/client/rest/host_viewer_client.py +190 -0
- holado_tools/tools/host_viewer/server/Dockerfile +60 -0
- holado_tools/tools/host_viewer/server/requirements.txt +2 -0
- holado_tools/tools/host_viewer/server/rest/README +2 -0
- holado_tools/tools/host_viewer/server/rest/api/__init__.py +24 -0
- holado_tools/tools/host_viewer/server/rest/api/docker/__init__.py +65 -0
- holado_tools/tools/host_viewer/server/rest/api/docker/container.py +87 -0
- holado_tools/tools/host_viewer/server/rest/api/os.py +58 -0
- holado_tools/tools/host_viewer/server/rest/initialize_holado.py +72 -0
- holado_tools/tools/host_viewer/server/rest/openapi.yaml +301 -0
- holado_tools/tools/host_viewer/server/rest/run.py +31 -0
- holado_tools/tools/host_viewer/server/run_host_viewer_in_docker.sh +107 -0
- holado_value/__init__.py +24 -0
- holado_value/common/tables/comparators/table_2_value_table_cell_comparator.py +196 -0
- holado_value/common/tables/comparators/table_2_value_table_comparator.py +27 -0
- holado_value/common/tables/comparators/table_2_value_table_row_comparator.py +27 -0
- holado_value/common/tables/comparators/table_2_value_table_with_header_comparator.py +27 -0
- holado_value/common/tables/converters/value_table_converter.py +267 -0
- holado_value/common/tables/value_table.py +29 -0
- holado_value/common/tables/value_table_cell.py +76 -0
- holado_value/common/tables/value_table_manager.py +48 -0
- holado_value/common/tables/value_table_row.py +43 -0
- holado_value/common/tables/value_table_with_header.py +28 -0
- holado_value/common/tools/unique_value_manager.py +109 -0
- holado_value/common/tools/value.py +191 -0
- holado_value/common/tools/value_types.py +41 -0
- holado_value/tests/behave/steps/__init__.py +16 -0
- holado_value/tests/behave/steps/private/__init__.py +16 -0
- holado_ws/__init__.py +16 -0
- holado_ws/api/ws/TODO.txt +2 -0
- holado_ws/tests/behave/steps/__init__.py +16 -0
- holado_ws/tests/behave/steps/api/web_service_steps.py +189 -0
- holado_xml/__init__.py +38 -0
- holado_xml/tests/behave/steps/__init__.py +16 -0
- holado_xml/tests/behave/steps/private/__init__.py +16 -0
- holado_xml/xml/stream_xml_file.py +181 -0
- holado_xml/xml/xml_file.py +97 -0
- holado_xml/xml/xml_manager.py +35 -0
- holado_yaml/__init__.py +31 -0
- holado_yaml/tests/behave/steps/__init__.py +16 -0
- holado_yaml/tests/behave/steps/yaml_steps.py +161 -0
- holado_yaml/yaml/enums.py +28 -0
- holado_yaml/yaml/pyyaml/pyyaml_client.py +72 -0
- holado_yaml/yaml/ruamel/ruamel_yaml_client.py +80 -0
- holado_yaml/yaml/yaml_client.py +203 -0
- holado_yaml/yaml/yaml_manager.py +94 -0
- test_holado/Dockerfile_test_holado +82 -0
- test_holado/__init__.py +4 -0
- test_holado/__main__.py +25 -0
- test_holado/build_docker_image_to_test_holado_in_docker.sh +7 -0
- test_holado/environment.py +60 -0
- test_holado/features/Configuration/Actions/execute_persisted_post_processes.feature +13 -0
- test_holado/features/NonReg/api/REST.feature +26 -0
- test_holado/features/NonReg/api/gRPC.feature +116 -0
- test_holado/features/NonReg/common/multiprocessing/simple.feature +60 -0
- test_holado/features/NonReg/common/system/commands.feature +43 -0
- test_holado/features/NonReg/common/system/system.feature +20 -0
- test_holado/features/NonReg/common/tables/table.feature +245 -0
- test_holado/features/NonReg/common/tables/value_table_conversion.feature +29 -0
- test_holado/features/NonReg/common/tools/DateTime.feature +88 -0
- test_holado/features/NonReg/common/tools/UniqueValueManager.feature +43 -0
- test_holado/features/NonReg/holado_ais/ais_message-bitarray_to_nmea.feature +135 -0
- test_holado/features/NonReg/holado_ais/ais_message-nmea_raw_to_dict.feature +93 -0
- test_holado/features/NonReg/holado_ais/message_types/type-10.feature +38 -0
- test_holado/features/NonReg/holado_ais/message_types/type-12.feature +37 -0
- test_holado/features/NonReg/holado_ais/message_types/type-14.feature +36 -0
- test_holado/features/NonReg/holado_ais/message_types/type-15.feature +36 -0
- test_holado/features/NonReg/holado_ais/message_types/type-16.feature +38 -0
- test_holado/features/NonReg/holado_ais/message_types/type-17.feature +46 -0
- test_holado/features/NonReg/holado_ais/message_types/type-18.feature +37 -0
- test_holado/features/NonReg/holado_ais/message_types/type-19.feature +38 -0
- test_holado/features/NonReg/holado_ais/message_types/type-1_2_3.feature +42 -0
- test_holado/features/NonReg/holado_ais/message_types/type-20.feature +38 -0
- test_holado/features/NonReg/holado_ais/message_types/type-21.feature +37 -0
- test_holado/features/NonReg/holado_ais/message_types/type-22.feature +84 -0
- test_holado/features/NonReg/holado_ais/message_types/type-23.feature +49 -0
- test_holado/features/NonReg/holado_ais/message_types/type-24.feature +72 -0
- test_holado/features/NonReg/holado_ais/message_types/type-25.feature +143 -0
- test_holado/features/NonReg/holado_ais/message_types/type-26.feature +144 -0
- test_holado/features/NonReg/holado_ais/message_types/type-27.feature +36 -0
- test_holado/features/NonReg/holado_ais/message_types/type-4_11.feature +39 -0
- test_holado/features/NonReg/holado_ais/message_types/type-5.feature +33 -0
- test_holado/features/NonReg/holado_ais/message_types/type-6.feature +37 -0
- test_holado/features/NonReg/holado_ais/message_types/type-7_13.feature +43 -0
- test_holado/features/NonReg/holado_ais/message_types/type-8.feature +37 -0
- test_holado/features/NonReg/holado_ais/message_types/type-9.feature +37 -0
- test_holado/features/NonReg/holado_binary/bit_series.error.feature +33 -0
- test_holado/features/NonReg/holado_binary/bit_series.feature +144 -0
- test_holado/features/NonReg/holado_protobuf/protobuf.feature +291 -0
- test_holado/features/NonReg/holado_python/convert.feature +20 -0
- test_holado/features/NonReg/holado_python/iterable.feature +61 -0
- test_holado/features/NonReg/holado_python/standard_library/socket/local_echo_server/socket_reset.feature +191 -0
- test_holado/features/NonReg/holado_python/standard_library/socket/local_echo_server/socket_with_tls_and_verify.feature +279 -0
- test_holado/features/NonReg/holado_python/standard_library/socket/local_echo_server/socket_with_tls_without_verify.feature +299 -0
- test_holado/features/NonReg/holado_python/standard_library/socket/local_echo_server/socket_without_tls.feature +163 -0
- test_holado/features/NonReg/holado_python/standard_library/socket/tcpbin.com/socket_with_mtls.feature +214 -0
- test_holado/features/NonReg/holado_python/standard_library/socket/tcpbin.com/socket_with_tls.feature +184 -0
- test_holado/features/NonReg/holado_python/standard_library/socket/tcpbin.com/socket_without_tls.feature +169 -0
- test_holado/features/NonReg/holado_scripting/common/tools/dynamic_text_manager.feature +18 -0
- test_holado/features/NonReg/holado_scripting/common/tools/expression_evaluator.feature +185 -0
- test_holado/features/NonReg/holado_scripting/common/tools/variable_manager.feature +71 -0
- test_holado/features/NonReg/holado_scripting/text/interpreter/interpreter.error.feature +21 -0
- test_holado/features/NonReg/holado_scripting/text/interpreter/interpreter.feature +120 -0
- test_holado/features/NonReg/holado_yaml/yaml.feature +514 -0
- test_holado/features/NonReg/ipc/json.feature +20 -0
- test_holado/features/NonReg/scenario/scenario.feature +183 -0
- test_holado/features/NonReg/test_steps/behave.feature +275 -0
- test_holado/features/NonReg/test_steps/common.feature +100 -0
- test_holado/features/NonReg/tools/RabbitMQ.feature +445 -0
- test_holado/features/NonReg/tools/RabbitMQ_steps.feature +276 -0
- test_holado/features/NonReg/tools/S3/boto3_client.feature +73 -0
- test_holado/features/NonReg/tools/S3/minio_client.feature +75 -0
- test_holado/features/NonReg/tools/db_sqlite3.feature +41 -0
- test_holado/features/NonReg/tools/sFTP.feature +25 -0
- test_holado/features/Test/logger.feature +28 -0
- test_holado/features/Test/test_host_controller.feature +13 -0
- test_holado/features/Test/test_parameter.feature +15 -0
- test_holado/features/__init__.py +0 -0
- test_holado/initialize_holado.py +62 -0
- test_holado/logging.conf +53 -0
- test_holado/resources/proto/definitions/protobuf/custom_types/field_types.proto +24 -0
- test_holado/resources/proto/definitions/protobuf/protobuf.dev/tutorial/addressbook.proto +56 -0
- test_holado/resources/proto/generated/protobuf/custom_types/field_types_pb2.py +34 -0
- test_holado/resources/proto/generated/protobuf/protobuf/dev/tutorial/addressbook_pb2.py +34 -0
- test_holado/resources/scripts/list_tags.sh +2 -0
- test_holado/resources/scripts/update_resources_proto_generated.py +70 -0
- test_holado/steps/__init__.py +0 -0
- test_holado/steps/private_steps.py +20 -0
- test_holado/steps/public_steps.py +23 -0
- test_holado/test_holado_session_context.py +43 -0
- test_holado/tools/connexion/api_rest/openapi.yaml +16 -0
- test_holado/tools/connexion/api_rest/run.py +19 -0
- test_holado/tools/django/README.txt +3 -0
- test_holado/tools/django/api_grpc/api_grpc/__init__.py +0 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/__init__.py +0 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/admin.py +3 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/apps.py +6 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/migrations/__init__.py +0 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/models.py +3 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/proto/__init__.py +0 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/proto/account.proto +27 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/proto/account_pb2.py +33 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/proto/account_pb2_grpc.py +199 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/serializers.py +12 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/services.py +11 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/tests.py +3 -0
- test_holado/tools/django/api_grpc/api_grpc/api1/views.py +3 -0
- test_holado/tools/django/api_grpc/api_grpc/asgi.py +16 -0
- test_holado/tools/django/api_grpc/api_grpc/settings.py +126 -0
- test_holado/tools/django/api_grpc/api_grpc/urls.py +27 -0
- test_holado/tools/django/api_grpc/api_grpc/wsgi.py +16 -0
- test_holado/tools/django/api_grpc/db.sqlite3 +0 -0
- test_holado/tools/django/api_grpc/manage.py +29 -0
- test_holado/tools/django/api_grpc/manual_test_commands.txt +25 -0
- test_holado/tools/django/api_grpc/patch_djangogrpcframework.py +42 -0
- test_holado/tools/django/api_rest/api_rest/__init__.py +0 -0
- test_holado/tools/django/api_rest/api_rest/api1/__init__.py +0 -0
- test_holado/tools/django/api_rest/api_rest/api1/admin.py +3 -0
- test_holado/tools/django/api_rest/api_rest/api1/apps.py +6 -0
- test_holado/tools/django/api_rest/api_rest/api1/migrations/__init__.py +0 -0
- test_holado/tools/django/api_rest/api_rest/api1/models.py +3 -0
- test_holado/tools/django/api_rest/api_rest/api1/serializers.py +15 -0
- test_holado/tools/django/api_rest/api_rest/api1/tests.py +3 -0
- test_holado/tools/django/api_rest/api_rest/api1/views.py +24 -0
- test_holado/tools/django/api_rest/api_rest/asgi.py +16 -0
- test_holado/tools/django/api_rest/api_rest/settings.py +133 -0
- test_holado/tools/django/api_rest/api_rest/urls.py +32 -0
- test_holado/tools/django/api_rest/api_rest/wsgi.py +16 -0
- test_holado/tools/django/api_rest/db.sqlite3 +0 -0
- test_holado/tools/django/api_rest/manage.py +22 -0
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
|
|
2
|
+
#################################################
|
|
3
|
+
# HolAdo (Holistic Automation do)
|
|
4
|
+
#
|
|
5
|
+
# (C) Copyright 2021-2025 by Eric Klumpp
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
8
|
+
#
|
|
9
|
+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
10
|
+
|
|
11
|
+
# The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
|
|
12
|
+
#################################################
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
from holado_core.common.exceptions.functional_exception import FunctionalException
|
|
16
|
+
from holado_core.common.exceptions.technical_exception import TechnicalException
|
|
17
|
+
from holado_core.common.tools.tools import Tools
|
|
18
|
+
from typing import NamedTuple
|
|
19
|
+
import threading
|
|
20
|
+
from holado.common.handlers.object import DeleteableObject, Object
|
|
21
|
+
from holado.common.handlers.enums import ObjectStates
|
|
22
|
+
from holado_multitask.multithreading.functionthreaded import FunctionThreaded
|
|
23
|
+
from holado_core.common.handlers.redo import Redo
|
|
24
|
+
from holado_system.system.filesystem.file import File
|
|
25
|
+
from holado_core.common.exceptions.verify_exception import VerifyException
|
|
26
|
+
import abc
|
|
27
|
+
from holado_multitask.multithreading.loopfunctionthreaded import LoopFunctionThreaded
|
|
28
|
+
from holado_multitask.multitasking.multitask_manager import MultitaskManager
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
import pika # @UnresolvedImport @UnusedImport
|
|
35
|
+
from pika.exceptions import ConnectionWrongStateError, StreamLostError
|
|
36
|
+
with_pika = True
|
|
37
|
+
except Exception as exc:
|
|
38
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
39
|
+
logger.debug(f"RMQClient is not available. Initialization failed on error: {exc}")
|
|
40
|
+
with_pika = False
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RMQClient(DeleteableObject):
|
|
45
|
+
__metaclass__ = abc.ABCMeta
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def is_available(cls):
|
|
49
|
+
return with_pika
|
|
50
|
+
|
|
51
|
+
def __init__(self, name):
|
|
52
|
+
super().__init__(name)
|
|
53
|
+
|
|
54
|
+
self.__connection_kwargs = None
|
|
55
|
+
self.__publisher_and_kwargs = []
|
|
56
|
+
self.__consumer_and_kwargs = []
|
|
57
|
+
self.__buffer_consumer_and_kwargs = []
|
|
58
|
+
|
|
59
|
+
self.__connection = None
|
|
60
|
+
self.__connection_thread_id = None
|
|
61
|
+
|
|
62
|
+
self.__is_consuming = False
|
|
63
|
+
self.__is_stopping_consuming = False
|
|
64
|
+
self.__rapid_close = False
|
|
65
|
+
|
|
66
|
+
self.__process_data_events_thread = None
|
|
67
|
+
self.__is_processing_data_events = False
|
|
68
|
+
self.__is_stopping_processing_data_events = False
|
|
69
|
+
|
|
70
|
+
def _delete_object(self):
|
|
71
|
+
try:
|
|
72
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
73
|
+
logger.debug(f"[{self.name}] Deleting RabbitMQ client...")
|
|
74
|
+
self.close()
|
|
75
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
76
|
+
logger.debug(f"[{self.name}] Finished to delete RabbitMQ client")
|
|
77
|
+
except StreamLostError as exc:
|
|
78
|
+
if self.object_state == ObjectStates.Deleting:
|
|
79
|
+
pass
|
|
80
|
+
else:
|
|
81
|
+
raise exc
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def connection(self):
|
|
85
|
+
return self.__connection
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def _connection_kwargs(self):
|
|
89
|
+
return self.__connection_kwargs
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def is_in_connection_thread(self):
|
|
93
|
+
return MultitaskManager.get_thread_id() == self.__connection_thread_id
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def is_consuming(self):
|
|
97
|
+
return self.__is_consuming
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def is_processing_data_events(self):
|
|
101
|
+
return self.__is_processing_data_events
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def rapid_close(self):
|
|
105
|
+
return self.__rapid_close
|
|
106
|
+
|
|
107
|
+
@rapid_close.setter
|
|
108
|
+
def rapid_close(self, rapid_close):
|
|
109
|
+
self.__rapid_close = rapid_close
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def has_consumer(self):
|
|
113
|
+
return len(self.__consumer_and_kwargs) > 0
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def _consumer_and_kwargs(self):
|
|
117
|
+
return self.__consumer_and_kwargs
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def has_buffer_consumer(self):
|
|
121
|
+
return len(self.__buffer_consumer_and_kwargs) > 0
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def _buffer_consumer_and_kwargs(self):
|
|
125
|
+
return self.__buffer_consumer_and_kwargs
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def has_publisher(self):
|
|
129
|
+
return len(self.__publisher_and_kwargs) > 0
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def _publisher_and_kwargs(self):
|
|
133
|
+
return self.__publisher_and_kwargs
|
|
134
|
+
|
|
135
|
+
def _set_connection(self, connection):
|
|
136
|
+
self.__connection = connection
|
|
137
|
+
self.__connection_thread_id = MultitaskManager.get_thread_id()
|
|
138
|
+
|
|
139
|
+
def _build_and_save_connection_parameters_kwargs(self, **connection_parameters_kwargs):
|
|
140
|
+
if Tools.has_sub_kwargs(connection_parameters_kwargs, "authentication."):
|
|
141
|
+
authentication = Tools.pop_sub_kwargs(connection_parameters_kwargs, "authentication.")
|
|
142
|
+
if 'user' in authentication:
|
|
143
|
+
if type(authentication['user']) is tuple:
|
|
144
|
+
connection_parameters_kwargs['credentials'] = pika.PlainCredentials(authentication['user'][0], authentication['user'][1])
|
|
145
|
+
else:
|
|
146
|
+
raise FunctionalException(f"[{self.name}]When authenticating by user, the value has to be in format: ('{{USER}}', '{{PASSWORD}}') (obtained: {authentication['user']})")
|
|
147
|
+
else:
|
|
148
|
+
raise TechnicalException(f"[{self.name}]Unmanaged authentication type '{authentication.keys()}' (possible authentication types: 'user'")
|
|
149
|
+
|
|
150
|
+
self.__connection_kwargs = connection_parameters_kwargs
|
|
151
|
+
|
|
152
|
+
def _new_connection_parameters(self):
|
|
153
|
+
return pika.ConnectionParameters(**self._connection_kwargs)
|
|
154
|
+
|
|
155
|
+
@abc.abstractmethod
|
|
156
|
+
def _new_connection(self):
|
|
157
|
+
raise NotImplementedError()
|
|
158
|
+
|
|
159
|
+
def connect(self, **connection_parameters_kwargs):
|
|
160
|
+
"""Connect with client appropriate connection"""
|
|
161
|
+
self._build_and_save_connection_parameters_kwargs(**connection_parameters_kwargs)
|
|
162
|
+
connection = self._new_connection()
|
|
163
|
+
self._set_connection(connection)
|
|
164
|
+
|
|
165
|
+
def close(self):
|
|
166
|
+
# Stop consuming
|
|
167
|
+
if self.is_consuming:
|
|
168
|
+
self.stop_consuming()
|
|
169
|
+
|
|
170
|
+
# Stop processing data events
|
|
171
|
+
if self.is_processing_data_events:
|
|
172
|
+
self.stop_process_data_events()
|
|
173
|
+
|
|
174
|
+
# Close connection
|
|
175
|
+
if self.__connection and self.__connection.is_open:
|
|
176
|
+
self._close_connection()
|
|
177
|
+
|
|
178
|
+
def _close_connection(self, connection=None):
|
|
179
|
+
if connection is None:
|
|
180
|
+
connection = self.connection
|
|
181
|
+
|
|
182
|
+
if connection is None or not connection.is_open:
|
|
183
|
+
raise TechnicalException(f"[{self.name}] Connection is not opened")
|
|
184
|
+
|
|
185
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
186
|
+
logger.debug(f"[{self.name}] Closing connection ({id(connection)})...")
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
self.__connection.close()
|
|
190
|
+
except (StreamLostError, ConnectionWrongStateError):
|
|
191
|
+
pass
|
|
192
|
+
except Exception as exc: # @UnusedVariable
|
|
193
|
+
#TODO: When this warning is logged during self.__del__, the log is cleared before, thus it is commented
|
|
194
|
+
# logger.warn(f"Error catched while closing RabbitMQ client connection:\n{Tools.represent_exception(exc)}")
|
|
195
|
+
# pass
|
|
196
|
+
raise exc
|
|
197
|
+
|
|
198
|
+
def __new_object_kwargs(self, obj, **kwargs):
|
|
199
|
+
res = NamedTuple('ObjectKwargs', object=object, kwargs=dict)
|
|
200
|
+
res.object = obj
|
|
201
|
+
res.kwargs = kwargs
|
|
202
|
+
return res
|
|
203
|
+
|
|
204
|
+
def new_publisher(self, queue, queue_args=None, exchange="", exchange_args=None, routing_key=None, nb_runners=None):
|
|
205
|
+
return self._new_publisher_with_connection(self.connection, queue, queue_args, exchange, exchange_args, routing_key, nb_runners)
|
|
206
|
+
|
|
207
|
+
def _new_publisher_with_connection(self, connection, queue, queue_args=None, exchange="", exchange_args=None, routing_key=None, nb_runners=None):
|
|
208
|
+
pub_channel = connection.channel()
|
|
209
|
+
|
|
210
|
+
queue_name = self._prepare_queue(pub_channel, queue, queue_args, exchange, exchange_args, bind_args=None)
|
|
211
|
+
if self.connection.publisher_confirms:
|
|
212
|
+
pub_channel.set_confirm_delivery()
|
|
213
|
+
else:
|
|
214
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
215
|
+
logger.debug(f"[{self.name}] Connection doesn't support publisher confirms")
|
|
216
|
+
|
|
217
|
+
if routing_key:
|
|
218
|
+
res = self._new_publisher(connection, pub_channel, exchange, routing_key, nb_runners)
|
|
219
|
+
else:
|
|
220
|
+
# TODO EKL: verify this case is functional
|
|
221
|
+
res = self._new_publisher(connection, pub_channel, exchange, queue_name, nb_runners)
|
|
222
|
+
|
|
223
|
+
self.__publisher_and_kwargs.append( self.__new_object_kwargs(res, queue=queue, queue_args=queue_args, exchange=exchange, exchange_args=exchange_args, routing_key=routing_key, nb_runners=nb_runners) )
|
|
224
|
+
return res
|
|
225
|
+
|
|
226
|
+
def _new_publisher(self, connection, channel, exchange, routing_key, nb_runners):
|
|
227
|
+
raise NotImplementedError
|
|
228
|
+
|
|
229
|
+
def new_consumer(self, queue, message_callback, queue_args=None, exchange="", exchange_args=None, bind_args=None):
|
|
230
|
+
return self._new_consumer_with_connection(self.connection, queue, message_callback, queue_args, exchange, exchange_args, bind_args)
|
|
231
|
+
|
|
232
|
+
def _new_consumer_with_connection(self, connection, queue, message_callback, queue_args=None, exchange="", exchange_args=None, bind_args=None):
|
|
233
|
+
con_channel = connection.channel()
|
|
234
|
+
|
|
235
|
+
if self.is_consuming:
|
|
236
|
+
raise FunctionalException(f"[{self.name}] Not allowed to create a new consumer while consuming is started")
|
|
237
|
+
queue_name = self._prepare_queue(con_channel, queue, queue_args, exchange, exchange_args, bind_args)
|
|
238
|
+
res = RMQConsumer(self, connection, con_channel, queue_name, message_callback)
|
|
239
|
+
self.__consumer_and_kwargs.append( self.__new_object_kwargs(res, queue=queue, message_callback=message_callback, queue_args=queue_args, exchange=exchange, exchange_args=exchange_args, bind_args=bind_args) )
|
|
240
|
+
return res
|
|
241
|
+
|
|
242
|
+
def new_buffer_consumer(self, queue, queue_args=None, exchange="", exchange_args=None, bind_args=None):
|
|
243
|
+
return self._new_buffer_consumer_with_connection(self.connection, queue, queue_args, exchange, exchange_args, bind_args)
|
|
244
|
+
|
|
245
|
+
def _new_buffer_consumer_with_connection(self, connection, queue, queue_args=None, exchange="", exchange_args=None, bind_args=None):
|
|
246
|
+
con_channel = connection.channel()
|
|
247
|
+
|
|
248
|
+
if self.is_consuming:
|
|
249
|
+
raise FunctionalException(f"[{self.name}] Not allowed to create a new consumer while consuming is started")
|
|
250
|
+
queue_name = self._prepare_queue(con_channel, queue, queue_args, exchange, exchange_args, bind_args)
|
|
251
|
+
res = RMQBufferConsumer(self, connection, con_channel, queue_name)
|
|
252
|
+
self.__buffer_consumer_and_kwargs.append( self.__new_object_kwargs(res, queue=queue, queue_args=queue_args, exchange=exchange, exchange_args=exchange_args, bind_args=bind_args) )
|
|
253
|
+
return res
|
|
254
|
+
|
|
255
|
+
def start_consuming(self):
|
|
256
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
257
|
+
logger.debug(f"[{self.name}] Start consuming...")
|
|
258
|
+
self.__is_consuming = True
|
|
259
|
+
|
|
260
|
+
for obj_kwargs in self.__consumer_and_kwargs:
|
|
261
|
+
obj_kwargs.object.start_consuming_in_thread()
|
|
262
|
+
|
|
263
|
+
for obj_kwargs in self.__buffer_consumer_and_kwargs:
|
|
264
|
+
obj_kwargs.object.start_consuming_in_thread()
|
|
265
|
+
|
|
266
|
+
def stop_consuming(self):
|
|
267
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
268
|
+
logger.debug(f"[{self.name}] Beginning stop consuming...")
|
|
269
|
+
self.__is_stopping_consuming = True
|
|
270
|
+
consumers_exceptions = []
|
|
271
|
+
try:
|
|
272
|
+
for obj_kwargs in self.__consumer_and_kwargs:
|
|
273
|
+
try:
|
|
274
|
+
obj_kwargs.object.stop_consuming()
|
|
275
|
+
except Exception as exc:
|
|
276
|
+
consumers_exceptions.append( (obj_kwargs.object, exc) )
|
|
277
|
+
for obj_kwargs in self.__buffer_consumer_and_kwargs:
|
|
278
|
+
try:
|
|
279
|
+
obj_kwargs.object.stop_consuming()
|
|
280
|
+
except Exception as exc:
|
|
281
|
+
consumers_exceptions.append( (obj_kwargs.object, exc) )
|
|
282
|
+
finally:
|
|
283
|
+
self.__is_stopping_consuming = False
|
|
284
|
+
self.__is_consuming = False
|
|
285
|
+
|
|
286
|
+
if consumers_exceptions:
|
|
287
|
+
logger.error(f"[{self.name}] Errors while stopping consuming on consumers: { {o.name:e for o,e in consumers_exceptions} }")
|
|
288
|
+
elif Tools.do_log(logger, logging.DEBUG):
|
|
289
|
+
logger.debug(f"[{self.name}] Finished stop consuming")
|
|
290
|
+
|
|
291
|
+
def start_process_data_events(self, raise_if_already_started=True):
|
|
292
|
+
if self.__process_data_events_thread is not None and self.__process_data_events_thread.is_alive():
|
|
293
|
+
if raise_if_already_started:
|
|
294
|
+
raise TechnicalException(f"[{self.name}] Thread processing data events is already running")
|
|
295
|
+
else:
|
|
296
|
+
return
|
|
297
|
+
|
|
298
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
299
|
+
logger.debug(f"[{self.name}] Start processing data events...")
|
|
300
|
+
self.__is_processing_data_events = True
|
|
301
|
+
|
|
302
|
+
self.__process_data_events_thread = LoopFunctionThreaded(self.connection.process_data_events, kwargs={'time_limit':1}, register_thread=True, delay_before_run_sec=None, delay_between_run_sec=0.01)
|
|
303
|
+
self.__process_data_events_thread.start()
|
|
304
|
+
|
|
305
|
+
def stop_process_data_events(self):
|
|
306
|
+
if not self.__is_processing_data_events:
|
|
307
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
308
|
+
logger.debug(f"[{self.name}] Client is not processing data events")
|
|
309
|
+
return
|
|
310
|
+
if self.__is_stopping_processing_data_events:
|
|
311
|
+
raise TechnicalException(f"[{self.name}] Data events processing is already under stop")
|
|
312
|
+
|
|
313
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
314
|
+
logger.debug(f"[{self.name}] Beginning stop data events processing...")
|
|
315
|
+
self.__is_stopping_processing_data_events = True
|
|
316
|
+
try:
|
|
317
|
+
self.__process_data_events_thread.interrupt()
|
|
318
|
+
self.__process_data_events_thread.join()
|
|
319
|
+
finally:
|
|
320
|
+
self.__is_stopping_processing_data_events = False
|
|
321
|
+
self.__is_processing_data_events = False
|
|
322
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
323
|
+
logger.debug(f"[{self.name}] Finished stop data events processing")
|
|
324
|
+
|
|
325
|
+
def _prepare_queue(self, channel, queue, queue_args=None, exchange="", exchange_args=None, bind_args=None):
|
|
326
|
+
if exchange is not None and exchange != "":
|
|
327
|
+
self._exchange_declare(channel, exchange, exchange_args)
|
|
328
|
+
|
|
329
|
+
if queue is not None and queue != "":
|
|
330
|
+
self._queue_declare(channel, queue, queue_args)
|
|
331
|
+
queue_name = queue
|
|
332
|
+
else:
|
|
333
|
+
q_args = dict(queue_args) if queue_args else {}
|
|
334
|
+
q_args['exclusive'] = True
|
|
335
|
+
result = self._queue_declare(channel, queue, q_args)
|
|
336
|
+
queue_name = result.method.queue
|
|
337
|
+
|
|
338
|
+
if exchange is not None and exchange != "":
|
|
339
|
+
self._queue_bind(channel, queue_name, exchange, bind_args)
|
|
340
|
+
|
|
341
|
+
return queue_name
|
|
342
|
+
|
|
343
|
+
def delete_queue(self, queue):
|
|
344
|
+
self.connection.channel().queue_delete(queue=queue)
|
|
345
|
+
|
|
346
|
+
def purge_queue(self, queue):
|
|
347
|
+
self.connection.channel().queue_purge(queue)
|
|
348
|
+
|
|
349
|
+
def _exchange_declare(self, channel, exchange, exchange_args=None):
|
|
350
|
+
kwargs = {}
|
|
351
|
+
arguments = None
|
|
352
|
+
if exchange_args:
|
|
353
|
+
arguments = dict(exchange_args)
|
|
354
|
+
for name in ['exchange_type', 'passive', 'durable', 'auto_delete', 'internal']:
|
|
355
|
+
if name in arguments:
|
|
356
|
+
kwargs[name] = arguments.pop(name)
|
|
357
|
+
return channel.exchange_declare(exchange, arguments=arguments, **kwargs)
|
|
358
|
+
|
|
359
|
+
def _queue_declare(self, channel, queue, queue_args=None):
|
|
360
|
+
kwargs = {}
|
|
361
|
+
arguments = None
|
|
362
|
+
if queue_args:
|
|
363
|
+
arguments = dict(queue_args)
|
|
364
|
+
for name in ['passive', 'durable', 'exclusive', 'auto_delete']:
|
|
365
|
+
if name in arguments:
|
|
366
|
+
kwargs[name] = arguments.pop(name)
|
|
367
|
+
return channel.queue_declare(queue, arguments=arguments, **kwargs)
|
|
368
|
+
|
|
369
|
+
def _queue_bind(self, channel, queue, exchange, bind_args=None):
|
|
370
|
+
kwargs = {}
|
|
371
|
+
arguments = None
|
|
372
|
+
if bind_args:
|
|
373
|
+
arguments = dict(bind_args)
|
|
374
|
+
for name in ['routing_key']:
|
|
375
|
+
if name in arguments:
|
|
376
|
+
kwargs[name] = arguments.pop(name)
|
|
377
|
+
return channel.queue_bind(queue, exchange, arguments=arguments, **kwargs)
|
|
378
|
+
|
|
379
|
+
def get_queue_message_count(self, queue):
|
|
380
|
+
channel = self.connection.channel()
|
|
381
|
+
status = self._queue_declare(channel, queue, {'passive':True})
|
|
382
|
+
return status.method.message_count
|
|
383
|
+
|
|
384
|
+
def is_queue_empty(self, queue, raise_exception=False):
|
|
385
|
+
nb = self.get_queue_message_count(queue)
|
|
386
|
+
res = (nb == 0)
|
|
387
|
+
|
|
388
|
+
if not res and raise_exception:
|
|
389
|
+
raise VerifyException(f"[{self.name}] Queue '{queue}' is not empty, it contains {nb} messages.")
|
|
390
|
+
return res
|
|
391
|
+
|
|
392
|
+
def flush(self):
|
|
393
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
394
|
+
logger.debug(f"[{self.name}] Flushing...")
|
|
395
|
+
for obj_kwargs in self._publisher_and_kwargs:
|
|
396
|
+
obj_kwargs.object.flush()
|
|
397
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
398
|
+
logger.debug(f"[{self.name}] Flushed")
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
class RMQPublisher(Object):
|
|
403
|
+
def __init__(self, client, connection, channel, exchange, routing_key):
|
|
404
|
+
super().__init__(f"RMQPublisher({routing_key})")
|
|
405
|
+
self.__client = client
|
|
406
|
+
self.__connection = connection
|
|
407
|
+
self.__channel = channel
|
|
408
|
+
self.__exchange = exchange
|
|
409
|
+
self.__routing_key = routing_key
|
|
410
|
+
|
|
411
|
+
@property
|
|
412
|
+
def client(self):
|
|
413
|
+
return self.__client
|
|
414
|
+
|
|
415
|
+
@property
|
|
416
|
+
def connection(self):
|
|
417
|
+
return self.__connection
|
|
418
|
+
|
|
419
|
+
@property
|
|
420
|
+
def channel(self):
|
|
421
|
+
return self.__channel
|
|
422
|
+
|
|
423
|
+
def publish(self, body, **kwargs):
|
|
424
|
+
kwargs['properties'] = pika.BasicProperties(delivery_mode=pika.DeliveryMode.Transient)
|
|
425
|
+
# kwargs['properties'] = pika.BasicProperties(delivery_mode=pika.DeliveryMode.Persistent)
|
|
426
|
+
# if self.__channel.has_confirm_delivery:
|
|
427
|
+
# kwargs['mandatory'] = True
|
|
428
|
+
self.__channel.basic_publish(exchange=self.__exchange, routing_key=self.__routing_key, body=body, **kwargs)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
class RMQConsumer(DeleteableObject):
|
|
432
|
+
def __init__(self, client, connection, channel, queue, message_callback):
|
|
433
|
+
super().__init__(f"RMQConsumer({queue})")
|
|
434
|
+
|
|
435
|
+
self.__client = client
|
|
436
|
+
self.__connection = connection
|
|
437
|
+
self.__channel = channel
|
|
438
|
+
self.__queue = queue
|
|
439
|
+
self.__message_callback = message_callback
|
|
440
|
+
|
|
441
|
+
# self.__consuming_thread_id = None
|
|
442
|
+
self.__is_consuming = False
|
|
443
|
+
self.__is_stopping_consuming = False
|
|
444
|
+
|
|
445
|
+
self.__consumer_tag = self.__channel.basic_consume(queue=self.__queue, on_message_callback=self.__message_callback, auto_ack=True)
|
|
446
|
+
|
|
447
|
+
@property
|
|
448
|
+
def connection(self):
|
|
449
|
+
return self.__connection
|
|
450
|
+
|
|
451
|
+
@property
|
|
452
|
+
def channel(self):
|
|
453
|
+
return self.__channel
|
|
454
|
+
|
|
455
|
+
@property
|
|
456
|
+
def queue(self):
|
|
457
|
+
return self.__queue
|
|
458
|
+
|
|
459
|
+
@property
|
|
460
|
+
def consumer_tag(self):
|
|
461
|
+
return self.__consumer_tag
|
|
462
|
+
|
|
463
|
+
# @property
|
|
464
|
+
# def consuming_thread_id(self):
|
|
465
|
+
# return self.__consuming_thread_id
|
|
466
|
+
#
|
|
467
|
+
# @consuming_thread_id.setter
|
|
468
|
+
# def consuming_thread_id(self, thread_id):
|
|
469
|
+
# self.__consuming_thread_id = thread_id
|
|
470
|
+
|
|
471
|
+
@property
|
|
472
|
+
def is_consuming(self):
|
|
473
|
+
return self.__is_consuming
|
|
474
|
+
|
|
475
|
+
def _delete_object(self):
|
|
476
|
+
try:
|
|
477
|
+
# Cancel consumer
|
|
478
|
+
# self.__channel.basic_cancel(self.consumer_tag)
|
|
479
|
+
|
|
480
|
+
# Stop consuming
|
|
481
|
+
if self.is_consuming:
|
|
482
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
483
|
+
logger.debug(f"[{self.name}] Deleting RabbitMQClient: Stopping consuming...")
|
|
484
|
+
self.stop_consuming()
|
|
485
|
+
|
|
486
|
+
# Close channel
|
|
487
|
+
if self.__channel.is_open:
|
|
488
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
489
|
+
logger.debug(f"[{self.name}] Deleting RabbitMQClient: Closing channel...")
|
|
490
|
+
self.__channel.close()
|
|
491
|
+
except StreamLostError as exc:
|
|
492
|
+
if self.object_state == ObjectStates.Deleting:
|
|
493
|
+
pass
|
|
494
|
+
else:
|
|
495
|
+
raise exc
|
|
496
|
+
|
|
497
|
+
def start_consuming_in_thread(self):
|
|
498
|
+
func = FunctionThreaded(self.start_consuming, register_thread=True, delay_before_run_sec=None)
|
|
499
|
+
func.start()
|
|
500
|
+
# self.consuming_thread_id = MultitaskManager.get_thread_id(thread=func)
|
|
501
|
+
|
|
502
|
+
def start_consuming(self):
|
|
503
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
504
|
+
logger.debug(f"[{self.name}] Beginning start consuming...")
|
|
505
|
+
|
|
506
|
+
# Workaround:
|
|
507
|
+
# Sometimes "When start consuming" is called rather than "Then client is consuming"
|
|
508
|
+
# cf implementation of step @Given(r"start consuming in a thread \(RMQ client: (?P<var_client>\w+)\)")
|
|
509
|
+
# Workaround: register the thread_id allowed to start consuming.
|
|
510
|
+
# Note: A possible reason is that execute_steps is not thread safe. If it's true, the new implementation
|
|
511
|
+
# of the step with the wait of 0.01 seconds has resolved the problem, and thus this workaround is not needed anymore.
|
|
512
|
+
# if self.consuming_thread_id is not None:
|
|
513
|
+
# thread_id = MultitaskManager.get_thread_id()
|
|
514
|
+
# if thread_id != self.consuming_thread_id:
|
|
515
|
+
# logger.error(f"Only thread {self.consuming_thread_id} is allowed to start consuming. Tried to start consuming in thread {thread_id} with traceback:\n{traceback.represent_stack(indent=4)}")
|
|
516
|
+
# return
|
|
517
|
+
|
|
518
|
+
self.__is_consuming = True
|
|
519
|
+
try:
|
|
520
|
+
self.channel.start_consuming()
|
|
521
|
+
except Exception as exc:
|
|
522
|
+
if self.__is_stopping_consuming:
|
|
523
|
+
if isinstance(exc, pika.exceptions.StreamLostError) \
|
|
524
|
+
or isinstance(exc, AttributeError) and "NoneType' object has no attribute 'clear'" in str(exc) \
|
|
525
|
+
or isinstance(exc, AssertionError):
|
|
526
|
+
logger.info(f"[{self.name}] Caught exception in consuming thread while stopping consuming: {exc}")
|
|
527
|
+
else:
|
|
528
|
+
logger.warn(f"[{self.name}] Caught unexpected exception in consuming thread while stopping consuming: {Tools.represent_exception(exc)}")
|
|
529
|
+
else:
|
|
530
|
+
raise TechnicalException(f"[{self.name}] Failed to start consuming: {str(exc)}") from exc
|
|
531
|
+
finally:
|
|
532
|
+
# In all cases, self.__is_consuming must began False, otherwise stopping processing is broken in case of "raise exc"
|
|
533
|
+
self.__is_consuming = False
|
|
534
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
535
|
+
logger.debug(f"[{self.name}] Finished start consuming")
|
|
536
|
+
|
|
537
|
+
def stop_consuming(self):
|
|
538
|
+
if not self.__is_consuming:
|
|
539
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
540
|
+
logger.debug(f"[{self.name}] Consumer is not consuming")
|
|
541
|
+
return
|
|
542
|
+
if self.__is_stopping_consuming:
|
|
543
|
+
raise TechnicalException(f"[{self.name}] Consuming is already under stop")
|
|
544
|
+
|
|
545
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
546
|
+
logger.debug(f"[{self.name}] Beginning stop consuming...")
|
|
547
|
+
self.__is_stopping_consuming = True
|
|
548
|
+
try:
|
|
549
|
+
self.__stop_consuming_by_channel_stop_consuming()
|
|
550
|
+
# self.__stop_consuming_by_deleting_channel_consumer_infos()
|
|
551
|
+
|
|
552
|
+
# gc.collect()
|
|
553
|
+
|
|
554
|
+
# Wait end of consuming
|
|
555
|
+
if self.__is_consuming:
|
|
556
|
+
logger.info(f"[{self.name}] Waiting consuming thread is stopped...")
|
|
557
|
+
|
|
558
|
+
class StopRedo(Redo):
|
|
559
|
+
def __init__(self2): # @NoSelf
|
|
560
|
+
super().__init__(f"[{self.name}] Stop consuming on consumer {self.consumer_tag}")
|
|
561
|
+
|
|
562
|
+
def _process(self2): # @NoSelf
|
|
563
|
+
return self.is_consuming
|
|
564
|
+
redo = StopRedo()
|
|
565
|
+
redo.redo_while(True)
|
|
566
|
+
redo.with_timeout(30*60) # Timeout of 30 min
|
|
567
|
+
redo.polling_every(0.01) # Wait 0.1 s beetween each try
|
|
568
|
+
redo.with_process_in_thread(False) # Run process in thread is not needed
|
|
569
|
+
redo.execute()
|
|
570
|
+
|
|
571
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
572
|
+
logger.debug(f"[{self.name}] Finished waiting consuming thread is stopped")
|
|
573
|
+
finally:
|
|
574
|
+
self.__is_stopping_consuming = False
|
|
575
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
576
|
+
logger.debug(f"[{self.name}] Finished stop consuming")
|
|
577
|
+
|
|
578
|
+
def __stop_consuming_by_channel_stop_consuming(self):
|
|
579
|
+
try:
|
|
580
|
+
self.channel.stop_consuming()
|
|
581
|
+
except Exception as exc:
|
|
582
|
+
if isinstance(exc, pika.exceptions.StreamLostError) \
|
|
583
|
+
or isinstance(exc, AttributeError) and "NoneType' object has no attribute 'clear'" in str(exc) \
|
|
584
|
+
or isinstance(exc, AssertionError):
|
|
585
|
+
logger.info(f"[{self.name}] Caught exception while executing consuming stopping method: {exc}")
|
|
586
|
+
else:
|
|
587
|
+
logger.warn(f"[{self.name}] Caught exception while executing consuming stopping method: {Tools.represent_exception(exc)}")
|
|
588
|
+
|
|
589
|
+
def __stop_consuming_by_deleting_channel_consumer_infos(self):
|
|
590
|
+
del self.channel._consumer_infos[self.consumer_tag]
|
|
591
|
+
# Schedule termination of connection.process_data_events using a
|
|
592
|
+
# negative channel number
|
|
593
|
+
# self.connection._request_channel_dispatch(-self.channel.channel_number)
|
|
594
|
+
self.client.connection._request_channel_dispatch(-self.channel.channel_number)
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
class RMQBufferConsumer(Object):
|
|
599
|
+
def __init__(self, client, connection, channel, queue):
|
|
600
|
+
super().__init__(f"RMQBufferConsumer({queue})")
|
|
601
|
+
self.__consumer = RMQConsumer(client, connection, channel, queue, self.__message_callback)
|
|
602
|
+
|
|
603
|
+
self.__messages = []
|
|
604
|
+
self.__messages_lock = threading.Lock()
|
|
605
|
+
|
|
606
|
+
@property
|
|
607
|
+
def connection(self):
|
|
608
|
+
return self.__consumer.connection
|
|
609
|
+
|
|
610
|
+
@property
|
|
611
|
+
def nb_messages(self):
|
|
612
|
+
with self.__messages_lock:
|
|
613
|
+
return len(self.__messages)
|
|
614
|
+
|
|
615
|
+
@property
|
|
616
|
+
def messages(self):
|
|
617
|
+
with self.__messages_lock:
|
|
618
|
+
return list(self.__messages)
|
|
619
|
+
|
|
620
|
+
@property
|
|
621
|
+
def consumer_tag(self):
|
|
622
|
+
return self.__consumer.consumer_tag
|
|
623
|
+
|
|
624
|
+
# @property
|
|
625
|
+
# def consuming_thread_id(self):
|
|
626
|
+
# return self.__consumer.consuming_thread_id
|
|
627
|
+
#
|
|
628
|
+
# @consuming_thread_id.setter
|
|
629
|
+
# def consuming_thread_id(self, thread_id):
|
|
630
|
+
# self.__consumer.consuming_thread_id = thread_id
|
|
631
|
+
|
|
632
|
+
def start_consuming_in_thread(self):
|
|
633
|
+
self.__consumer.start_consuming_in_thread()
|
|
634
|
+
|
|
635
|
+
def start_consuming(self):
|
|
636
|
+
self.__consumer.start_consuming()
|
|
637
|
+
|
|
638
|
+
def stop_consuming(self):
|
|
639
|
+
self.__consumer.stop_consuming()
|
|
640
|
+
|
|
641
|
+
def __message_callback(self, channel, method, properties, body):
|
|
642
|
+
with self.__messages_lock:
|
|
643
|
+
self.__messages.append( (channel, method, properties, body) )
|
|
644
|
+
# logger.debug(f"[Consumer '{self.__consumer.queue}'] New message (total: {len(self.__messages)}): {channel=} ; {method=} ; {properties=} ; {body=}")
|
|
645
|
+
if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
|
|
646
|
+
logger.trace(f"[{self.name}] New message (total: {len(self.__messages)}): {body}")
|
|
647
|
+
elif Tools.do_log(logger, logging.DEBUG):
|
|
648
|
+
logger.debug(f"[{self.name}] New message (total: {len(self.__messages)})")
|
|
649
|
+
|
|
650
|
+
def reset_messages(self):
|
|
651
|
+
with self.__messages_lock:
|
|
652
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
653
|
+
logger.debug(f"[{self.name}] Reset messages (delete {len(self.__messages)} messages)")
|
|
654
|
+
self.__messages.clear()
|
|
655
|
+
|
|
656
|
+
def pop_first_message(self):
|
|
657
|
+
with self.__messages_lock:
|
|
658
|
+
res = self.__messages.pop(0)
|
|
659
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
660
|
+
logger.debug(f"[{self.name}] Pop first message (remaining: {len(self.__messages)}): {res}")
|
|
661
|
+
return res
|
|
662
|
+
|
|
663
|
+
def pop_and_save_messages(self, file:File, max_messages=None):
|
|
664
|
+
res = 0
|
|
665
|
+
|
|
666
|
+
nb_messages = self.nb_messages
|
|
667
|
+
while nb_messages > 0 and (max_messages is None or res < nb_messages):
|
|
668
|
+
msg = self.pop_first_message()
|
|
669
|
+
file.writelines([msg[3].hex()])
|
|
670
|
+
res += 1
|
|
671
|
+
|
|
672
|
+
nb_messages = self.nb_messages
|
|
673
|
+
if Tools.do_log(logger, logging.DEBUG):
|
|
674
|
+
logger.debug(f"[{self.name}] Saved a message (nb saved: {res} ; remaining: {nb_messages})")
|
|
675
|
+
|
|
676
|
+
return res
|
|
677
|
+
|
|
678
|
+
|