holado 0.2.2__py3-none-any.whl → 0.2.4__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 +11 -1
  2. {holado-0.2.2.dist-info → holado-0.2.4.dist-info}/METADATA +13 -9
  3. holado-0.2.4.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 +204 -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 +37 -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 +968 -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 +674 -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.2.dist-info/RECORD +0 -17
  523. {holado-0.2.2.dist-info → holado-0.2.4.dist-info}/WHEEL +0 -0
  524. {holado-0.2.2.dist-info → holado-0.2.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,674 @@
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 holado.common.tools.gc_manager import GcManager
31
+
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+ try:
36
+ import pika # @UnresolvedImport @UnusedImport
37
+ from pika.exceptions import ConnectionWrongStateError, StreamLostError
38
+ with_pika = True
39
+ except Exception as exc:
40
+ if Tools.do_log(logger, logging.DEBUG):
41
+ logger.debug(f"RMQClient is not available. Initialization failed on error: {exc}")
42
+ with_pika = False
43
+
44
+
45
+
46
+ class RMQClient(DeleteableObject):
47
+ __metaclass__ = abc.ABCMeta
48
+
49
+ @classmethod
50
+ def is_available(cls):
51
+ return with_pika
52
+
53
+ def __init__(self, name):
54
+ super().__init__(name)
55
+
56
+ self.__connection_kwargs = None
57
+ self.__publisher_and_kwargs = []
58
+ self.__consumer_and_kwargs = []
59
+ self.__buffer_consumer_and_kwargs = []
60
+
61
+ self.__connection = None
62
+ self.__connection_thread_id = None
63
+
64
+ self.__is_consuming = False
65
+ self.__is_stopping_consuming = False
66
+ self.__rapid_close = False
67
+
68
+ self.__process_data_events_thread = None
69
+ self.__is_processing_data_events = False
70
+ self.__is_stopping_processing_data_events = False
71
+
72
+ def _delete_object(self):
73
+ try:
74
+ if Tools.do_log(logger, logging.DEBUG):
75
+ logger.debug(f"[{self.name}] Deleting RabbitMQ client...")
76
+ self.close()
77
+ if Tools.do_log(logger, logging.DEBUG):
78
+ logger.debug(f"[{self.name}] Finished to delete RabbitMQ client")
79
+ except StreamLostError as exc:
80
+ if self.object_state == ObjectStates.Deleting:
81
+ pass
82
+ else:
83
+ raise exc
84
+
85
+ @property
86
+ def connection(self):
87
+ return self.__connection
88
+
89
+ @property
90
+ def _connection_kwargs(self):
91
+ return self.__connection_kwargs
92
+
93
+ @property
94
+ def is_in_connection_thread(self):
95
+ return MultitaskManager.get_thread_id() == self.__connection_thread_id
96
+
97
+ @property
98
+ def is_consuming(self):
99
+ return self.__is_consuming
100
+
101
+ @property
102
+ def is_processing_data_events(self):
103
+ return self.__is_processing_data_events
104
+
105
+ @property
106
+ def rapid_close(self):
107
+ return self.__rapid_close
108
+
109
+ @rapid_close.setter
110
+ def rapid_close(self, rapid_close):
111
+ self.__rapid_close = rapid_close
112
+
113
+ @property
114
+ def has_consumer(self):
115
+ return len(self.__consumer_and_kwargs) > 0
116
+
117
+ @property
118
+ def _consumer_and_kwargs(self):
119
+ return self.__consumer_and_kwargs
120
+
121
+ @property
122
+ def has_buffer_consumer(self):
123
+ return len(self.__buffer_consumer_and_kwargs) > 0
124
+
125
+ @property
126
+ def _buffer_consumer_and_kwargs(self):
127
+ return self.__buffer_consumer_and_kwargs
128
+
129
+ @property
130
+ def has_publisher(self):
131
+ return len(self.__publisher_and_kwargs) > 0
132
+
133
+ @property
134
+ def _publisher_and_kwargs(self):
135
+ return self.__publisher_and_kwargs
136
+
137
+ def _set_connection(self, connection):
138
+ self.__connection = connection
139
+ self.__connection_thread_id = MultitaskManager.get_thread_id()
140
+
141
+ def _build_and_save_connection_parameters_kwargs(self, **connection_parameters_kwargs):
142
+ if Tools.has_sub_kwargs(connection_parameters_kwargs, "authentication."):
143
+ authentication = Tools.pop_sub_kwargs(connection_parameters_kwargs, "authentication.")
144
+ if 'user' in authentication:
145
+ if type(authentication['user']) is tuple:
146
+ connection_parameters_kwargs['credentials'] = pika.PlainCredentials(authentication['user'][0], authentication['user'][1])
147
+ else:
148
+ raise FunctionalException(f"[{self.name}]When authenticating by user, the value has to be in format: ('{{USER}}', '{{PASSWORD}}') (obtained: {authentication['user']})")
149
+ else:
150
+ raise TechnicalException(f"[{self.name}]Unmanaged authentication type '{authentication.keys()}' (possible authentication types: 'user'")
151
+
152
+ self.__connection_kwargs = connection_parameters_kwargs
153
+
154
+ def _new_connection_parameters(self):
155
+ return pika.ConnectionParameters(**self._connection_kwargs)
156
+
157
+ @abc.abstractmethod
158
+ def _new_connection(self):
159
+ raise NotImplementedError()
160
+
161
+ def connect(self, **connection_parameters_kwargs):
162
+ """Connect with client appropriate connection"""
163
+ self._build_and_save_connection_parameters_kwargs(**connection_parameters_kwargs)
164
+ connection = self._new_connection()
165
+ self._set_connection(connection)
166
+
167
+ def close(self):
168
+ # Stop consuming
169
+ if self.is_consuming:
170
+ self.stop_consuming()
171
+
172
+ # Stop processing data events
173
+ if self.is_processing_data_events:
174
+ self.stop_process_data_events()
175
+
176
+ # Close connection
177
+ if self.__connection and self.__connection.is_open:
178
+ self._close_connection()
179
+
180
+ def _close_connection(self, connection=None):
181
+ if connection is None:
182
+ connection = self.connection
183
+
184
+ if connection is None or not connection.is_open:
185
+ raise TechnicalException(f"[{self.name}] Connection is not opened")
186
+
187
+ if Tools.do_log(logger, logging.DEBUG):
188
+ logger.debug(f"[{self.name}] Closing connection ({id(connection)})...")
189
+
190
+ try:
191
+ self.__connection.close()
192
+ except (StreamLostError, ConnectionWrongStateError):
193
+ pass
194
+ except Exception as exc: # @UnusedVariable
195
+ #TODO: When this warning is logged during self.__del__, the log is cleared before, thus it is commented
196
+ # logger.warn(f"Error catched while closing RabbitMQ client connection:\n{Tools.represent_exception(exc)}")
197
+ # pass
198
+ raise exc
199
+
200
+ def __new_object_kwargs(self, obj, **kwargs):
201
+ res = NamedTuple('ObjectKwargs', object=object, kwargs=dict)
202
+ res.object = obj
203
+ res.kwargs = kwargs
204
+ return res
205
+
206
+ def new_publisher(self, queue, queue_args=None, exchange="", exchange_args=None, routing_key=None, nb_runners=None):
207
+ return self._new_publisher_with_connection(self.connection, queue, queue_args, exchange, exchange_args, routing_key, nb_runners)
208
+
209
+ def _new_publisher_with_connection(self, connection, queue, queue_args=None, exchange="", exchange_args=None, routing_key=None, nb_runners=None):
210
+ pub_channel = connection.channel()
211
+
212
+ queue_name = self.__prepare_queue(pub_channel, queue, queue_args, exchange, exchange_args, bind_args=None)
213
+ if self.connection.publisher_confirms:
214
+ pub_channel.set_confirm_delivery()
215
+ else:
216
+ if Tools.do_log(logger, logging.DEBUG):
217
+ logger.debug(f"[{self.name}] Connection doesn't support publisher confirms")
218
+
219
+ if routing_key:
220
+ res = self._new_publisher(connection, pub_channel, exchange, routing_key, nb_runners)
221
+ else:
222
+ # TODO EKL: verify this case is functional
223
+ res = self._new_publisher(connection, pub_channel, exchange, queue_name, nb_runners)
224
+
225
+ 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) )
226
+ return res
227
+
228
+ def _new_publisher(self, connection, channel, exchange, routing_key, nb_runners):
229
+ raise NotImplementedError
230
+
231
+ def new_consumer(self, queue, message_callback, queue_args=None, exchange="", exchange_args=None, bind_args=None):
232
+ return self._new_consumer_with_connection(self.connection, queue, message_callback, queue_args, exchange, exchange_args, bind_args)
233
+
234
+ def _new_consumer_with_connection(self, connection, queue, message_callback, queue_args=None, exchange="", exchange_args=None, bind_args=None):
235
+ con_channel = connection.channel()
236
+
237
+ if self.is_consuming:
238
+ raise FunctionalException(f"[{self.name}] Not allowed to create a new consumer while consuming is started")
239
+ queue_name = self.__prepare_queue(con_channel, queue, queue_args, exchange, exchange_args, bind_args)
240
+ res = RMQConsumer(self, connection, con_channel, queue_name, message_callback)
241
+ 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) )
242
+ return res
243
+
244
+ def new_buffer_consumer(self, queue, queue_args=None, exchange="", exchange_args=None, bind_args=None):
245
+ return self._new_buffer_consumer_with_connection(self.connection, queue, queue_args, exchange, exchange_args, bind_args)
246
+
247
+ def _new_buffer_consumer_with_connection(self, connection, queue, queue_args=None, exchange="", exchange_args=None, bind_args=None):
248
+ con_channel = connection.channel()
249
+
250
+ if self.is_consuming:
251
+ raise FunctionalException(f"[{self.name}] Not allowed to create a new consumer while consuming is started")
252
+ queue_name = self.__prepare_queue(con_channel, queue, queue_args, exchange, exchange_args, bind_args)
253
+ res = RMQBufferConsumer(self, connection, con_channel, queue_name)
254
+ 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) )
255
+ return res
256
+
257
+ def start_consuming(self):
258
+ if Tools.do_log(logger, logging.DEBUG):
259
+ logger.debug(f"[{self.name}] Start consuming...")
260
+ self.__is_consuming = True
261
+
262
+ for obj_kwargs in self.__consumer_and_kwargs:
263
+ obj_kwargs.object.start_consuming_in_thread()
264
+
265
+ for obj_kwargs in self.__buffer_consumer_and_kwargs:
266
+ obj_kwargs.object.start_consuming_in_thread()
267
+
268
+ def stop_consuming(self):
269
+ if Tools.do_log(logger, logging.DEBUG):
270
+ logger.debug(f"[{self.name}] Beginning stop consuming...")
271
+ self.__is_stopping_consuming = True
272
+ consumers_exceptions = []
273
+ try:
274
+ for obj_kwargs in self.__consumer_and_kwargs:
275
+ try:
276
+ obj_kwargs.object.stop_consuming()
277
+ except Exception as exc:
278
+ consumers_exceptions.append( (obj_kwargs.object, exc) )
279
+ for obj_kwargs in self.__buffer_consumer_and_kwargs:
280
+ try:
281
+ obj_kwargs.object.stop_consuming()
282
+ except Exception as exc:
283
+ consumers_exceptions.append( (obj_kwargs.object, exc) )
284
+ finally:
285
+ self.__is_stopping_consuming = False
286
+ self.__is_consuming = False
287
+
288
+ if consumers_exceptions:
289
+ logger.error(f"[{self.name}] Errors while stopping consuming on consumers: { {o.name:e for o,e in consumers_exceptions} }")
290
+ elif Tools.do_log(logger, logging.DEBUG):
291
+ logger.debug(f"[{self.name}] Finished stop consuming")
292
+
293
+ def start_process_data_events(self, raise_if_already_started=True):
294
+ if self.__process_data_events_thread is not None and self.__process_data_events_thread.is_alive():
295
+ if raise_if_already_started:
296
+ raise TechnicalException(f"[{self.name}] Thread processing data events is already running")
297
+ else:
298
+ return
299
+
300
+ if Tools.do_log(logger, logging.DEBUG):
301
+ logger.debug(f"[{self.name}] Start processing data events...")
302
+ self.__is_processing_data_events = True
303
+
304
+ self.__process_data_events_thread = LoopFunctionThreaded(self.connection.process_data_events, kwargs={'time_limit':1}, register_thread=True, delay_before_run_sec=None)
305
+ self.__process_data_events_thread.start()
306
+
307
+ def stop_process_data_events(self):
308
+ if not self.__is_processing_data_events:
309
+ if Tools.do_log(logger, logging.DEBUG):
310
+ logger.debug(f"[{self.name}] Client is not processing data events")
311
+ return
312
+ if self.__is_stopping_processing_data_events:
313
+ raise TechnicalException(f"[{self.name}] Data events processing is already under stop")
314
+
315
+ if Tools.do_log(logger, logging.DEBUG):
316
+ logger.debug(f"[{self.name}] Beginning stop data events processing...")
317
+ self.__is_stopping_processing_data_events = True
318
+ try:
319
+ self.__process_data_events_thread.interrupt()
320
+ self.__process_data_events_thread.join()
321
+ finally:
322
+ self.__is_stopping_processing_data_events = False
323
+ self.__is_processing_data_events = False
324
+ if Tools.do_log(logger, logging.DEBUG):
325
+ logger.debug(f"[{self.name}] Finished stop data events processing")
326
+
327
+ def __prepare_queue(self, channel, queue, queue_args=None, exchange="", exchange_args=None, bind_args=None):
328
+ if exchange is not None and exchange != "":
329
+ self.__exchange_declare(channel, exchange, exchange_args)
330
+
331
+ if queue is not None and queue != "":
332
+ self.__queue_declare(channel, queue, queue_args)
333
+ queue_name = queue
334
+ else:
335
+ q_args = dict(queue_args) if queue_args else {}
336
+ q_args['exclusive'] = True
337
+ result = self.__queue_declare(channel, queue, q_args)
338
+ queue_name = result.method.queue
339
+
340
+ if exchange is not None and exchange != "":
341
+ self.__queue_bind(channel, queue_name, exchange, bind_args)
342
+
343
+ return queue_name
344
+
345
+ def __exchange_declare(self, channel, exchange, exchange_args=None):
346
+ kwargs = {}
347
+ arguments = None
348
+ if exchange_args:
349
+ arguments = dict(exchange_args)
350
+ for name in ['exchange_type', 'passive', 'durable', 'auto_delete', 'internal']:
351
+ if name in arguments:
352
+ kwargs[name] = arguments.pop(name)
353
+ return channel.exchange_declare(exchange, arguments=arguments, **kwargs)
354
+
355
+ def __queue_declare(self, channel, queue, queue_args=None):
356
+ kwargs = {}
357
+ arguments = None
358
+ if queue_args:
359
+ arguments = dict(queue_args)
360
+ for name in ['passive', 'durable', 'exclusive', 'auto_delete']:
361
+ if name in arguments:
362
+ kwargs[name] = arguments.pop(name)
363
+ return channel.queue_declare(queue, arguments=arguments, **kwargs)
364
+
365
+ def __queue_bind(self, channel, queue, exchange, bind_args=None):
366
+ kwargs = {}
367
+ arguments = None
368
+ if bind_args:
369
+ arguments = dict(bind_args)
370
+ for name in ['routing_key']:
371
+ if name in arguments:
372
+ kwargs[name] = arguments.pop(name)
373
+ return channel.queue_bind(queue, exchange, arguments=arguments, **kwargs)
374
+
375
+ def get_queue_message_count(self, queue):
376
+ channel = self.connection.channel()
377
+ status = self.__queue_declare(channel, queue, {'passive':True})
378
+ return status.method.message_count
379
+
380
+ def is_queue_empty(self, queue, raise_exception=False):
381
+ nb = self.get_queue_message_count(queue)
382
+ res = (nb == 0)
383
+
384
+ if not res and raise_exception:
385
+ raise VerifyException(f"[{self.name}] Queue '{queue}' is not empty, it contains {nb} messages.")
386
+ return res
387
+
388
+ def flush(self):
389
+ if Tools.do_log(logger, logging.DEBUG):
390
+ logger.debug(f"[{self.name}] Flushing...")
391
+ for obj_kwargs in self._publisher_and_kwargs:
392
+ obj_kwargs.object.flush()
393
+ if Tools.do_log(logger, logging.DEBUG):
394
+ logger.debug(f"[{self.name}] Flushed")
395
+
396
+
397
+
398
+ class RMQPublisher(Object):
399
+ def __init__(self, client, connection, channel, exchange, routing_key):
400
+ super().__init__(f"RMQPublisher({routing_key})")
401
+ self.__client = client
402
+ self.__connection = connection
403
+ self.__channel = channel
404
+ self.__exchange = exchange
405
+ self.__routing_key = routing_key
406
+
407
+ @property
408
+ def client(self):
409
+ return self.__client
410
+
411
+ @property
412
+ def connection(self):
413
+ return self.__connection
414
+
415
+ @property
416
+ def channel(self):
417
+ return self.__channel
418
+
419
+ def publish(self, body, **kwargs):
420
+ kwargs['properties'] = pika.BasicProperties(delivery_mode=pika.DeliveryMode.Transient)
421
+ # kwargs['properties'] = pika.BasicProperties(delivery_mode=pika.DeliveryMode.Persistent)
422
+ # if self.__channel.has_confirm_delivery:
423
+ # kwargs['mandatory'] = True
424
+ self.__channel.basic_publish(exchange=self.__exchange, routing_key=self.__routing_key, body=body, **kwargs)
425
+
426
+
427
+ class RMQConsumer(DeleteableObject):
428
+ def __init__(self, client, connection, channel, queue, message_callback):
429
+ super().__init__(f"RMQConsumer({queue})")
430
+
431
+ self.__client = client
432
+ self.__connection = connection
433
+ self.__channel = channel
434
+ self.__queue = queue
435
+ self.__message_callback = message_callback
436
+
437
+ # self.__consuming_thread_id = None
438
+ self.__is_consuming = False
439
+ self.__is_stopping_consuming = False
440
+
441
+ self.__consumer_tag = self.__channel.basic_consume(queue=self.__queue, on_message_callback=self.__message_callback, auto_ack=True)
442
+
443
+ @property
444
+ def connection(self):
445
+ return self.__connection
446
+
447
+ @property
448
+ def channel(self):
449
+ return self.__channel
450
+
451
+ @property
452
+ def queue(self):
453
+ return self.__queue
454
+
455
+ @property
456
+ def consumer_tag(self):
457
+ return self.__consumer_tag
458
+
459
+ # @property
460
+ # def consuming_thread_id(self):
461
+ # return self.__consuming_thread_id
462
+ #
463
+ # @consuming_thread_id.setter
464
+ # def consuming_thread_id(self, thread_id):
465
+ # self.__consuming_thread_id = thread_id
466
+
467
+ @property
468
+ def is_consuming(self):
469
+ return self.__is_consuming
470
+
471
+ def _delete_object(self):
472
+ try:
473
+ # Cancel consumer
474
+ # self.__channel.basic_cancel(self.consumer_tag)
475
+
476
+ # Stop consuming
477
+ if self.is_consuming:
478
+ if Tools.do_log(logger, logging.DEBUG):
479
+ logger.debug(f"[{self.name}] Deleting RabbitMQClient: Stopping consuming...")
480
+ self.stop_consuming()
481
+
482
+ # Close channel
483
+ if self.__channel.is_open:
484
+ if Tools.do_log(logger, logging.DEBUG):
485
+ logger.debug(f"[{self.name}] Deleting RabbitMQClient: Closing channel...")
486
+ self.__channel.close()
487
+ except StreamLostError as exc:
488
+ if self.object_state == ObjectStates.Deleting:
489
+ pass
490
+ else:
491
+ raise exc
492
+
493
+ def start_consuming_in_thread(self):
494
+ func = FunctionThreaded(self.start_consuming, register_thread=True, delay_before_run_sec=None)
495
+ func.start()
496
+ # self.consuming_thread_id = MultitaskManager.get_thread_id(thread=func)
497
+
498
+ def start_consuming(self):
499
+ if Tools.do_log(logger, logging.DEBUG):
500
+ logger.debug(f"[{self.name}] Beginning start consuming...")
501
+
502
+ # Workaround:
503
+ # Sometimes "When start consuming" is called rather than "Then client is consuming"
504
+ # cf implementation of step @Given(r"start consuming in a thread \(RMQ client: (?P<var_client>\w+)\)")
505
+ # Workaround: register the thread_id allowed to start consuming.
506
+ # Note: A possible reason is that execute_steps is not thread safe. If it's true, the new implementation
507
+ # of the step with the wait of 0.01 seconds has resolved the problem, and thus this workaround is not needed anymore.
508
+ # if self.consuming_thread_id is not None:
509
+ # thread_id = MultitaskManager.get_thread_id()
510
+ # if thread_id != self.consuming_thread_id:
511
+ # 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)}")
512
+ # return
513
+
514
+ self.__is_consuming = True
515
+ try:
516
+ self.channel.start_consuming()
517
+ except Exception as exc:
518
+ if self.__is_stopping_consuming:
519
+ if isinstance(exc, pika.exceptions.StreamLostError) \
520
+ or isinstance(exc, AttributeError) and "NoneType' object has no attribute 'clear'" in str(exc) \
521
+ or isinstance(exc, AssertionError):
522
+ logger.info(f"[{self.name}] Caught exception in consuming thread while stopping consuming: {exc}")
523
+ else:
524
+ logger.warn(f"[{self.name}] Caught unexpected exception in consuming thread while stopping consuming: {Tools.represent_exception(exc)}")
525
+ else:
526
+ raise TechnicalException(f"[{self.name}] Failed to start consuming: {str(exc)}") from exc
527
+ finally:
528
+ # In all cases, self.__is_consuming must began False, otherwise stopping processing is broken in case of "raise exc"
529
+ self.__is_consuming = False
530
+ if Tools.do_log(logger, logging.DEBUG):
531
+ logger.debug(f"[{self.name}] Finished start consuming")
532
+
533
+ def stop_consuming(self):
534
+ if not self.__is_consuming:
535
+ if Tools.do_log(logger, logging.DEBUG):
536
+ logger.debug(f"[{self.name}] Consumer is not consuming")
537
+ return
538
+ if self.__is_stopping_consuming:
539
+ raise TechnicalException(f"[{self.name}] Consuming is already under stop")
540
+
541
+ if Tools.do_log(logger, logging.DEBUG):
542
+ logger.debug(f"[{self.name}] Beginning stop consuming...")
543
+ self.__is_stopping_consuming = True
544
+ try:
545
+ self.__stop_consuming_by_channel_stop_consuming()
546
+ # self.__stop_consuming_by_deleting_channel_consumer_infos()
547
+
548
+ # gc.collect()
549
+
550
+ # Wait end of consuming
551
+ if self.__is_consuming:
552
+ logger.info(f"[{self.name}] Waiting consuming thread is stopped...")
553
+
554
+ class StopRedo(Redo):
555
+ def __init__(self2): # @NoSelf
556
+ super().__init__(f"[{self.name}] Stop consuming on consumer {self.consumer_tag}")
557
+
558
+ def _process(self2): # @NoSelf
559
+ time.sleep(0.1)
560
+ GcManager.collect(max_duration_until_next_collect_in_seconds=0)
561
+ return self.is_consuming
562
+ redo = StopRedo()
563
+ redo.redo_while(True)
564
+ redo.with_timeout(30*60) # Timeout of 30 min
565
+ redo.execute()
566
+
567
+ if Tools.do_log(logger, logging.DEBUG):
568
+ logger.debug(f"[{self.name}] Finished waiting consuming thread is stopped")
569
+ finally:
570
+ self.__is_stopping_consuming = False
571
+ if Tools.do_log(logger, logging.DEBUG):
572
+ logger.debug(f"[{self.name}] Finished stop consuming")
573
+
574
+ def __stop_consuming_by_channel_stop_consuming(self):
575
+ try:
576
+ self.channel.stop_consuming()
577
+ except Exception as exc:
578
+ if isinstance(exc, pika.exceptions.StreamLostError) \
579
+ or isinstance(exc, AttributeError) and "NoneType' object has no attribute 'clear'" in str(exc) \
580
+ or isinstance(exc, AssertionError):
581
+ logger.info(f"[{self.name}] Caught exception while executing consuming stopping method: {exc}")
582
+ else:
583
+ logger.warn(f"[{self.name}] Caught exception while executing consuming stopping method: {Tools.represent_exception(exc)}")
584
+
585
+ def __stop_consuming_by_deleting_channel_consumer_infos(self):
586
+ del self.channel._consumer_infos[self.consumer_tag]
587
+ # Schedule termination of connection.process_data_events using a
588
+ # negative channel number
589
+ # self.connection._request_channel_dispatch(-self.channel.channel_number)
590
+ self.client.connection._request_channel_dispatch(-self.channel.channel_number)
591
+
592
+
593
+
594
+ class RMQBufferConsumer(Object):
595
+ def __init__(self, client, connection, channel, queue):
596
+ super().__init__(f"RMQBufferConsumer({queue})")
597
+ self.__consumer = RMQConsumer(client, connection, channel, queue, self.__message_callback)
598
+
599
+ self.__messages = []
600
+ self.__messages_lock = threading.Lock()
601
+
602
+ @property
603
+ def connection(self):
604
+ return self.__consumer.connection
605
+
606
+ @property
607
+ def nb_messages(self):
608
+ with self.__messages_lock:
609
+ return len(self.__messages)
610
+
611
+ @property
612
+ def messages(self):
613
+ with self.__messages_lock:
614
+ return list(self.__messages)
615
+
616
+ @property
617
+ def consumer_tag(self):
618
+ return self.__consumer.consumer_tag
619
+
620
+ # @property
621
+ # def consuming_thread_id(self):
622
+ # return self.__consumer.consuming_thread_id
623
+ #
624
+ # @consuming_thread_id.setter
625
+ # def consuming_thread_id(self, thread_id):
626
+ # self.__consumer.consuming_thread_id = thread_id
627
+
628
+ def start_consuming_in_thread(self):
629
+ self.__consumer.start_consuming_in_thread()
630
+
631
+ def start_consuming(self):
632
+ self.__consumer.start_consuming()
633
+
634
+ def stop_consuming(self):
635
+ self.__consumer.stop_consuming()
636
+
637
+ def __message_callback(self, channel, method, properties, body):
638
+ with self.__messages_lock:
639
+ self.__messages.append( (channel, method, properties, body) )
640
+ # logger.debug(f"[Consumer '{self.__consumer.queue}'] New message (total: {len(self.__messages)}): {channel=} ; {method=} ; {properties=} ; {body=}")
641
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
642
+ logger.trace(f"[{self.name}] New message (total: {len(self.__messages)}): {body}")
643
+ elif Tools.do_log(logger, logging.DEBUG):
644
+ logger.debug(f"[{self.name}] New message (total: {len(self.__messages)})")
645
+
646
+ def reset_messages(self):
647
+ with self.__messages_lock:
648
+ if Tools.do_log(logger, logging.DEBUG):
649
+ logger.debug(f"[{self.name}] Reset messages (delete {len(self.__messages)} messages)")
650
+ self.__messages.clear()
651
+
652
+ def pop_first_message(self):
653
+ with self.__messages_lock:
654
+ res = self.__messages.pop(0)
655
+ if Tools.do_log(logger, logging.DEBUG):
656
+ logger.debug(f"[{self.name}] Pop first message (remaining: {len(self.__messages)}): {res}")
657
+ return res
658
+
659
+ def pop_and_save_messages(self, file:File, max_messages=None):
660
+ res = 0
661
+
662
+ nb_messages = self.nb_messages
663
+ while nb_messages > 0 and (max_messages is None or res < nb_messages):
664
+ msg = self.pop_first_message()
665
+ file.writelines([msg[3].hex()])
666
+ res += 1
667
+
668
+ nb_messages = self.nb_messages
669
+ if Tools.do_log(logger, logging.DEBUG):
670
+ logger.debug(f"[{self.name}] Saved a message (nb saved: {res} ; remaining: {nb_messages})")
671
+
672
+ return res
673
+
674
+