holado 0.2.1__py3-none-any.whl → 0.2.3__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.

Potentially problematic release.


This version of holado might be problematic. Click here for more details.

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