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

holado/holado_config.py CHANGED
@@ -1,3 +1,4 @@
1
+ import logging
1
2
 
2
3
  #################################################
3
4
  # HolAdo (Holistic Automation do)
@@ -39,4 +40,8 @@ class Config(object):
39
40
  UNIQUE_SYMBOL = u"#"
40
41
  NOT_APPLICABLE_SYMBOL = u"N/A"
41
42
  NONE_SYMBOL = u"None"
43
+
44
+ # Default log levels
45
+ log_level_grpc_request = logging.INFO
46
+ log_level_rest_request = logging.INFO
42
47
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: holado
3
- Version: 0.6.5
3
+ Version: 0.7.0
4
4
  Summary: HolAdo framework
5
5
  Project-URL: Homepage, https://gitlab.com/holado_framework/python
6
6
  Project-URL: Issues, https://gitlab.com/holado_framework/python/-/issues
@@ -1,5 +1,5 @@
1
1
  holado/__init__.py,sha256=ibxjS0XIck0rguf8FT_3HftofWmJqyfWraxjczMzzrw,14895
2
- holado/holado_config.py,sha256=-HPwBdEcdG1kLfqSq4bH_esXbndVkNX4WW0VSpqoxu4,2459
2
+ holado/holado_config.py,sha256=H1Wgndhz133nm0OcqS5hD6oDxZbDD_DeHJsKOuenQrI,2588
3
3
  holado/common/__init__.py,sha256=ZjXM-FRQgnfzRNXqcvJOGewDHVRR-U5-ugStSs8U2Xs,1525
4
4
  holado/common/context/__init__.py,sha256=3jJBLm8myrYF9jbdV1EhIA6BtnlmjX33eeoDpTzwmLA,1604
5
5
  holado/common/context/context.py,sha256=XPrdZw_9j096AI9EZwMT4xVd58c1ZH6VGxT5Yb-qYYU,6660
@@ -123,11 +123,11 @@ holado_core/common/tables/comparators/table_comparator_manager.py,sha256=A5a1xQK
123
123
  holado_core/common/tables/comparators/table_row_comparator.py,sha256=1_3N2E-PD6QyFwO9a-D3VpNVX8R7lSj0imyVTLajciI,6842
124
124
  holado_core/common/tables/comparators/table_with_header_comparator.py,sha256=j7BcT8thQtz5fCYZik78tdMbhrQqB5lC8g_zFwRgFnM,4642
125
125
  holado_core/common/tables/converters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
126
- holado_core/common/tables/converters/table_converter.py,sha256=TLKLOXIAhxM2ENu1ajtyr6MRtZxgizhsx0_7w5wZHCg,10165
126
+ holado_core/common/tables/converters/table_converter.py,sha256=PD7NJoxtejpr4aS1l3YKcXW1aEn1xBxdi4Ljs5G7R4g,10251
127
127
  holado_core/common/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
128
  holado_core/common/tools/path_manager.py,sha256=dgdm8wAaVubh-krpquCXXeGUTtGqRKDpuEKmvhA9dKA,8899
129
129
  holado_core/common/tools/string_tools.py,sha256=bQuMlI_yS7OoSPFL7qyfyXkrnjC8xHVpIsfmEC6JxhI,5590
130
- holado_core/common/tools/tools.py,sha256=FLQ55BeksEu3Tqg6mZC7UwkmY0ZX1pHr78qZv-iDnpU,9555
130
+ holado_core/common/tools/tools.py,sha256=zkDz7u8S_02bfyN6K-p7-Ey_SkDxzu9DJljnczY0OAo,9683
131
131
  holado_core/common/tools/comparators/comparator.py,sha256=K4LcXIRORHX5vkmDibI6P6Bu1L-6Xezb63ZzzOMKrWY,6812
132
132
  holado_core/common/tools/comparators/object_comparator.py,sha256=RPI319h_tij6z75UVbZII3gBggQolRFMNMD4cN6z37Y,1399
133
133
  holado_core/common/tools/converters/converter.py,sha256=a77OzLC_bp6-jRVNVYcSXyixOrk_lg4hhs-jj9pYqaA,4136
@@ -159,11 +159,11 @@ holado_db/tests/behave/steps/tools/db/postgresql_client_steps.py,sha256=HtO-NSlT
159
159
  holado_db/tests/behave/steps/tools/db/sqlite_client_steps.py,sha256=6B8GGBJxxG6Z49cGCPykm8BP7nQQZWUrWpw0XgaYGaE,2930
160
160
  holado_db/tools/db/db_manager.py,sha256=0llXc6YhXfLr6oNfncPNjh4_ZInIm8XYywutQYvvLso,5400
161
161
  holado_db/tools/db/clients/base/db_audit.py,sha256=eJ1r_0YUhvq50JngpWAdyEeVHWjAD4YCvWCJsLc1zmc,4368
162
- holado_db/tools/db/clients/base/db_client.py,sha256=sdMKDbnhO0zMCxq3n6vHcn5d5Asm6N5WhKDss89v_PU,15298
162
+ holado_db/tools/db/clients/base/db_client.py,sha256=Uj1S-dOVmx-gHRj7x7VpYbyeE0Vde6fKTAlHOJX7p4E,15294
163
163
  holado_db/tools/db/clients/postgresql/postgresql_audit.py,sha256=yoy4-Yt4lZHJw7xAcuTj2Thg4aTDCYJBt-6HzQeEE80,3939
164
164
  holado_db/tools/db/clients/postgresql/postgresql_client.py,sha256=FW9t4kGh3ClDr1NfOymSMAYSrguPcKeqbwE6BM4ognI,4746
165
165
  holado_db/tools/db/clients/sqlite/sqlite_audit.py,sha256=cK7hBE7aKCFOX5xnT-QnYD_1loQPgPP9Gf6qTT1XuI4,3966
166
- holado_db/tools/db/clients/sqlite/sqlite_client.py,sha256=-EvKAeaOc1Iv_wmuAgvzpS5hEfDFvZgP9OkFc9L5M-s,2891
166
+ holado_db/tools/db/clients/sqlite/sqlite_client.py,sha256=x1ZiS_6AvDGrCz2a1FzP-IkYC7JHThE5daDZebbhDvE,2913
167
167
  holado_db/tools/db/query/query_manager.py,sha256=7n-d_Q373hlsKQshY3accIH8XfqaLScqnhMdTT2oWC4,3642
168
168
  holado_db/tools/db/query/base/query_builder.py,sha256=-nCyBe8zsRhOX39uCV0P7OY_YKobQJVIpJDL2sUA_H8,5926
169
169
  holado_db/tools/db/query/pypika/pypika_query_builder.py,sha256=9x2-7B4p3eXSq3vLWWLscoFWJZakhcPxmNrpGR2ysdw,10964
@@ -255,7 +255,7 @@ holado_examples/tests/behave/testing_solution/steps/public_steps.py,sha256=nnxgB
255
255
  holado_grpc/TODO,sha256=ESjES2-J6-3AJYdt6olcz_YGt4YTxw80CjIt-tjJ0z4,206
256
256
  holado_grpc/__init__.py,sha256=SaAz66iSTqMw7oIDrj94rGcO8W7BgS15B78p--OogHc,2266
257
257
  holado_grpc/api/rpc/TODO.txt,sha256=uWZT-WtrGuWbiOVU8-6xNiNyx_kKx-htM691zprLjh0,130
258
- holado_grpc/api/rpc/grpc_client.py,sha256=sCsNzwHY8QAXvcqMd-Wt-gXy3VKrsqVbB8ncBf_EcRA,8990
258
+ holado_grpc/api/rpc/grpc_client.py,sha256=7j6DOdrkAXZpas2hsIOSr-kkOEZNhw9hAAluHY8m3BE,10433
259
259
  holado_grpc/api/rpc/grpc_manager.py,sha256=v3e7b1JCNlUoCnWUPgB9aWKde-AbseRCZAxFwz5gPN8,4115
260
260
  holado_grpc/ipc/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
261
261
  holado_grpc/ipc/rpc/grpc_compiler.py,sha256=f_v1Rj6gDpLSCpkN8a6Jn4w9d826JqNRII16HSPPrWA,2477
@@ -287,7 +287,7 @@ holado_helper/script/job.py,sha256=hb7WenhQP1qFMsxWGMsgbA-Z-zixynjRWjmZdx9wHEI,4
287
287
  holado_helper/script/json_action_script.py,sha256=angdSt6e385lKwYSGJBqytVb4sp3-HjMKziVEFSz6ro,5147
288
288
  holado_helper/script/script.py,sha256=77LRYUWiNwiXRDGiwlKqZJ40-lKD40dtR31w1bQW178,4494
289
289
  holado_json/__init__.py,sha256=z0SNFOdBBWUouC12WKDmL18T_OH3TdmfcgIbnNQzbjU,1247
290
- holado_json/ipc/json.py,sha256=MuMBa_KrDdIXtikl6CF84jMfBXmRHQRwVmIdRbQ3ejI,6203
290
+ holado_json/ipc/json.py,sha256=Q8b4HtrQGCAcT3i5CHtKADZfjilK29UwuFpclZ5JNa0,7178
291
291
  holado_json/ipc/json_converter.py,sha256=i4sPg9jZ2EziW8L6K-Rlm5-ubweFIWHq2R19avmsjkM,3433
292
292
  holado_json/ipc/json_types.py,sha256=MP72SmSUqFnoNC_YFMLUmU4prJv4uzO1VUoUBVLYwD8,7883
293
293
  holado_json/tests/behave/steps/__init__.py,sha256=FVGM5by0yswjfo8yC58x3onJKjKcQx919TOcYEUOWEw,1276
@@ -408,8 +408,8 @@ holado_report/report/reports/feature_report.py,sha256=i0wpk3LQLArVjWDsP9UcNSJzAU
408
408
  holado_report/report/reports/scenario_report.py,sha256=eMyqw9EzaKMmX3pGFJN1rqAOQ5eqO2ISZdxAfK3XQR4,2945
409
409
  holado_rest/__init__.py,sha256=BOeE6t6ejeqRYd44SE4vYJVTNz01BwcVCIWfwRQ5axg,1526
410
410
  holado_rest/api/rest/TODO.txt,sha256=Oz8BYPkBEs9OAEgyYLLm7i5tJ1bRE5POBpT3SRFWTi4,29
411
- holado_rest/api/rest/rest_client.py,sha256=rJipR3_I4c90GR38c-gwOE49Iz6QDbf8KbMFUoobKqQ,7024
412
- holado_rest/api/rest/rest_manager.py,sha256=lo8zUAXsi86Diw5dego-AOn3vUbwKj5xK7i0atIgwlA,4013
411
+ holado_rest/api/rest/rest_client.py,sha256=_Ck9CZxAF01kZMz8anIhSK_rH57poa7fNm-t0SSFu_I,8099
412
+ holado_rest/api/rest/rest_manager.py,sha256=XldPjNgj73GlzAmlsEcQYaHiDRk7SGU6VEFOLBnHjQM,4010
413
413
  holado_rest/tests/behave/steps/__init__.py,sha256=lEH5NYkKtpgDV2ZAO1qAGNN4ipwILWMpgvQgnamgYKk,1283
414
414
  holado_rest/tests/behave/steps/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
415
415
  holado_rest/tests/behave/steps/api/rest_client_steps.py,sha256=naN0YcRVQyM--RhV0jPhnlsjZS6luijwGvVC5lM0XCY,9749
@@ -498,7 +498,7 @@ holado_test/common/context/feature_context.py,sha256=GhC0lihnvTBhv5tE4JzPt39eP7g
498
498
  holado_test/common/context/scenario_context.py,sha256=pmo-xGtn6oHtbTmcH6Vtp8Dj2iGrYVdHd0b6smtlhbY,10527
499
499
  holado_test/common/context/step_context.py,sha256=j6S4ozTPrdlpV9Slopc998fYOV8KfMLAUSW4mcEFUI8,2383
500
500
  holado_test/common/exceptions/undefined_step_exception.py,sha256=SHHX22iz4Ip-V4Y3aM2EJFDt30CCS5EaauN6KB-JORo,1461
501
- holado_test/scenario/step_tools.py,sha256=eovzeSDmkfyrRjGga-bVW9VcoLRCdGjN1z8xlBNovmc,25506
501
+ holado_test/scenario/step_tools.py,sha256=Sqm7M0vVA9O2lRnv3pK5ryrSPOCGr5P7xD7C3esTpGg,25482
502
502
  holado_test/scenario/tester_tools.py,sha256=Tv035FyXPjQ46Ep8KuPOjOvzJFvxnbv9EsrSihUzAwg,2479
503
503
  holado_test/tests/behave/steps/__init__.py,sha256=rdqrp-UN7vRplIqORx4sXyKwMUkptRizyLWudsmYehM,1362
504
504
  holado_test/tests/behave/steps/scenario/exception_steps.py,sha256=ZIE92Dz7a6O_c0jAP_0dj6Hc0tnW6YRgNKd4_aBpeR0,4054
@@ -514,7 +514,7 @@ holado_value/common/tables/comparators/table_2_value_table_cell_comparator.py,sh
514
514
  holado_value/common/tables/comparators/table_2_value_table_comparator.py,sha256=rITxTgXami05plxk1qaCVqDcwZaKWoXpKAzur4ingTE,1807
515
515
  holado_value/common/tables/comparators/table_2_value_table_row_comparator.py,sha256=_VglWUQWspG1Fo2iAo41auCwWYR24q0TniFck99BF_E,1752
516
516
  holado_value/common/tables/comparators/table_2_value_table_with_header_comparator.py,sha256=VKwA7PbXnE-gFSKWlDCsJv0tkWVuNY-C4aWt2tyIybE,1911
517
- holado_value/common/tables/converters/value_table_converter.py,sha256=OESQ-wghR7gc42lDHSF1__Swfxj56bvNsLJq3u76gJE,12067
517
+ holado_value/common/tables/converters/value_table_converter.py,sha256=o8r2VZytUAwBlT9yORL4i5gyPvgZNFhvjuPqv32cqgM,12397
518
518
  holado_value/common/tools/unique_value_manager.py,sha256=UXKdDKWznp4auYKQeWB7zYEzfm_0GxAiGfyoFM5ZM3s,5223
519
519
  holado_value/common/tools/value.py,sha256=BwAx9L_xHA-v4K55osnXjI9z9bQn_MKQ8Cvk3mhqBjA,9108
520
520
  holado_value/common/tools/value_types.py,sha256=7nJp5D7xdoT9jMeeOxHIuPRykDyI9fXpve37ndK32gs,1801
@@ -650,7 +650,7 @@ test_holado/tools/django/api_rest/api_rest/api1/serializers.py,sha256=o_YxFr-tgC
650
650
  test_holado/tools/django/api_rest/api_rest/api1/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
651
651
  test_holado/tools/django/api_rest/api_rest/api1/views.py,sha256=kOt2xT6bxO47_z__5yYR9kcYIWWv4qYzpX0K8Tqonik,758
652
652
  test_holado/tools/django/api_rest/api_rest/api1/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
653
- holado-0.6.5.dist-info/METADATA,sha256=EdMArFb9UkUD8IoDHuHYu8OzbXpO8akW1kh0tSmgExg,7885
654
- holado-0.6.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
655
- holado-0.6.5.dist-info/licenses/LICENSE,sha256=IgGmNlcFHnbp7UWrLJqAFvs_HIgjJDTmjCNRircJLsk,1070
656
- holado-0.6.5.dist-info/RECORD,,
653
+ holado-0.7.0.dist-info/METADATA,sha256=54tIA8nZfmiafWGDsusb9S0W1hQX8PmNylQS870V4wk,7885
654
+ holado-0.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
655
+ holado-0.7.0.dist-info/licenses/LICENSE,sha256=IgGmNlcFHnbp7UWrLJqAFvs_HIgjJDTmjCNRircJLsk,1070
656
+ holado-0.7.0.dist-info/RECORD,,
@@ -113,21 +113,22 @@ class TableConverter(object):
113
113
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
114
114
  logger.trace(f"Converting Name/Value table to dict (table = {table})")
115
115
 
116
- # Verify table structure
117
- TableManager.verify_table_is_name_value_table(table)
118
-
119
116
  res = {}
120
- for row in table.rows:
121
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
122
- logger.trace("Converting row (%s)", row)
117
+ if table is not None:
118
+ # Verify table structure
119
+ TableManager.verify_table_is_name_value_table(table)
123
120
 
124
- name = row.get_cell(0).content
125
- value = row.get_cell(1).content
126
-
127
- if name in res:
128
- raise FunctionalException("Name '{}' appears several times in table".format(name))
129
- else:
130
- res[name] = value
121
+ for row in table.rows:
122
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
123
+ logger.trace("Converting row (%s)", row)
124
+
125
+ name = row.get_cell(0).content
126
+ value = row.get_cell(1).content
127
+
128
+ if name in res:
129
+ raise FunctionalException("Name '{}' appears several times in table".format(name))
130
+ else:
131
+ res[name] = value
131
132
 
132
133
  if Tools.do_log(logger, logging.DEBUG):
133
134
  logger.debug(f"Converting Name/Value table to dict (table = {table}) => {res}")
@@ -78,11 +78,11 @@ class Tools(object):
78
78
  return Tools.indent_string(indent, "".join(list_format))
79
79
 
80
80
  @classmethod
81
- def represent_object(cls, obj, indent=0, *, do_indent_first_line=True, full_details=False, access_type=AccessType.Public):
82
- return cls.__represent_object(obj, indent, do_indent_first_line, full_details, access_type, [])
81
+ def represent_object(cls, obj, indent=0, *, do_indent_first_line=True, full_details=False, access_type=AccessType.Public, max_level=3):
82
+ return cls.__represent_object(obj, indent, do_indent_first_line, full_details, access_type, max_level, [])
83
83
 
84
84
  @classmethod
85
- def __represent_object(cls, obj, indent, do_indent_first_line, full_details, access_type, _internal):
85
+ def __represent_object(cls, obj, indent, do_indent_first_line, full_details, access_type, max_level, _internal):
86
86
  from holado_core.common.tools.converters.converter import Converter
87
87
 
88
88
  if Converter.is_primitive(obj) and not Converter.is_dict(obj) and not Converter.is_list(obj):
@@ -102,7 +102,7 @@ class Tools(object):
102
102
  keys = list(obj.keys())
103
103
  for key in keys:
104
104
  # logger.print(f"+++++ Tools.__represent_object: key: {key}")
105
- val_str = cls.__represent_object(obj[key], 0, True, full_details, access_type, _internal)
105
+ val_str = cls.__represent_object(obj[key], 0, True, full_details, access_type, max_level-1, _internal)
106
106
  if '\n' in val_str:
107
107
  res_list.append(f" {key}:")
108
108
  res_list.append(Tools.indent_string(4, val_str))
@@ -116,7 +116,7 @@ class Tools(object):
116
116
  for el in obj:
117
117
  # for index, el in enumerate(obj):
118
118
  # logger.print(f"+++++ Tools.__represent_object: index: {index}")
119
- el_str = cls.__represent_object(el, 0, True, full_details, access_type, _internal)
119
+ el_str = cls.__represent_object(el, 0, True, full_details, access_type, max_level-1, _internal)
120
120
  if '\n' in el_str:
121
121
  res_list.append(" {")
122
122
  res_list.append(Tools.indent_string(4, el_str))
@@ -133,9 +133,10 @@ class Tools(object):
133
133
  # logger.print(f"+++++ Tools.__represent_object: {str(type(obj))} is object with {attributes=}")
134
134
  if attributes:
135
135
  res_list = [f"{str(type(obj))}({id_obj})"] if full_details else [f"{str(type(obj))}"]
136
- for name, value in attributes:
137
- # logger.print(f"+++++ Tools.__represent_object: attribute '{name}'")
138
- res_list.append(f" {name}: {cls.__represent_object(value, 4, False, full_details, access_type, _internal)}")
136
+ if max_level > 0:
137
+ for name, value in attributes:
138
+ # logger.print(f"+++++ Tools.__represent_object: attribute '{name}'")
139
+ res_list.append(f" {name}: {cls.__represent_object(value, 4, False, full_details, access_type, max_level-1, _internal)}")
139
140
  res = "\n".join(res_list)
140
141
  else:
141
142
  res = f"{obj} [{str(type(obj))}({id_obj})]" if full_details else f"{obj}"
@@ -23,15 +23,17 @@ from holado_core.common.tables.table import Table
23
23
  from holado_db.tools.db.query.base.query_builder import QueryBuilder
24
24
  from holado_data.data.generator.base import BaseGenerator
25
25
  from holado_python.standard_library.typing import Typing
26
+ from holado.common.handlers.object import Object
26
27
 
27
28
  logger = logging.getLogger(__name__)
28
29
 
29
30
 
30
- class DBClient(object):
31
+ class DBClient(Object):
31
32
  __metaclass__ = abc.ABCMeta
32
33
 
33
34
  def __init__(self, name, connect_kwargs, with_cursor=True, auto_commit=True):
34
- self.__name = name
35
+ super().__init__(name)
36
+
35
37
  self.__connect_kwargs = connect_kwargs
36
38
  self.__with_cursor = with_cursor
37
39
  self.__auto_commit = auto_commit
@@ -41,10 +43,6 @@ class DBClient(object):
41
43
  self.__audit_manager = None
42
44
  self.__column_names_by_table = {}
43
45
 
44
- @property
45
- def name(self):
46
- return self.__name
47
-
48
46
  @property
49
47
  def query_builder(self) -> QueryBuilder:
50
48
  return self.__query_builder
@@ -48,7 +48,7 @@ class SQLite3Client(DBClient):
48
48
  database = connect_kwargs.pop("database")
49
49
  return sqlite3.connect(database, **connect_kwargs)
50
50
  except Exception as exc:
51
- raise FunctionalException(f"Failed to connect with kwargs={kwargs}.\nUsage:\n{Tools.indent_string(4, sqlite3.connect.__doc__)}") from exc
51
+ raise FunctionalException(f"Failed to connect with kwargs={kwargs}.\nUsage:\n{Tools.indent_string(4, sqlite3.connect.__doc__)}") from exc # @UndefinedVariable
52
52
 
53
53
  def _get_sql_placeholder(self):
54
54
  return "?"
@@ -18,6 +18,8 @@ from holado_value.common.tables.converters.value_table_converter import ValueTab
18
18
  from holado_core.common.tools.tools import Tools
19
19
  import time
20
20
  from holado.holado_config import Config
21
+ from holado.common.handlers.object import Object
22
+ from holado.common.handlers.undefined import undefined_argument, undefined_value
21
23
 
22
24
  logger = logging.getLogger(__name__)
23
25
 
@@ -36,7 +38,7 @@ except Exception as exc:
36
38
  # os.environ["GRPC_TRACE"] = "all"
37
39
 
38
40
 
39
- class GRpcClient(object):
41
+ class GRpcClient(Object):
40
42
  """
41
43
  gRPC client
42
44
 
@@ -49,7 +51,7 @@ class GRpcClient(object):
49
51
 
50
52
  if with_grpc_requests:
51
53
  def __init__(self, name, endpoint, **kwargs):
52
- self.__name = name
54
+ super().__init__(name)
53
55
  self.__endpoint = endpoint
54
56
  self.__kwargs = kwargs
55
57
  self.__client = grpc_requests.client.get_by_endpoint(endpoint, **kwargs)
@@ -57,6 +59,8 @@ class GRpcClient(object):
57
59
  self.__func_grpc_services = None
58
60
  self.__func_protobuf_converter = None
59
61
  self.__func_protobuf_messages = None
62
+
63
+ self.__request_log_level = Config.log_level_grpc_request
60
64
 
61
65
  def initialize(self, func_grpc_services, func_protobuf_converter, func_protobuf_messages):
62
66
  self.__func_grpc_services = func_grpc_services
@@ -75,22 +79,28 @@ class GRpcClient(object):
75
79
  def __protobuf_messages(self):
76
80
  return self.__func_protobuf_messages()
77
81
 
78
- @property
79
- def name(self):
80
- return self.__name
81
-
82
82
  @property
83
83
  def internal_client(self) -> grpc_requests.client.Client:
84
84
  return self.__client
85
85
 
86
- def request(self, service, method, request, raw_output=False, **kwargs):
86
+ @property
87
+ def request_log_level(self):
88
+ return self.__request_log_level
89
+
90
+ @request_log_level.setter
91
+ def request_log_level(self, log_level):
92
+ self.__request_log_level = log_level
93
+
94
+ def request(self, service, method, request, raw_output=False, result_on_statuses=undefined_argument, **kwargs):
87
95
  """
88
96
  :param request: request data in json or proto format
89
97
  :param raw_output: if method should return a proto object or a json oject (default: False)
90
98
  :param kwargs: other arguments for underlying grpc_requests method, or further underlying grpc method (ex: 'timeout')
91
99
  :returns: if raw_output==True, returns a proto object, else returns a json object with proto data
92
100
  """
93
- logger.info(f"Requesting {service}.{method} with data [{request}] (raw_output: {raw_output} ; kwargs:{kwargs})")
101
+ if Tools.do_log(logger, logging.DEBUG):
102
+ logger.debug(f"Requesting {service}.{method} with data [{request}] (raw_output: {raw_output} ; kwargs:{kwargs})")
103
+ res = undefined_value
94
104
 
95
105
  # Set a default timeout
96
106
  raise_on_timeout = False
@@ -110,6 +120,17 @@ class GRpcClient(object):
110
120
  except Exception as exc:
111
121
  last_exc = exc
112
122
  exc_str = str(exc)
123
+
124
+ # Manage result on statuses
125
+ if result_on_statuses is not undefined_argument:
126
+ for status, status_result in result_on_statuses.items():
127
+ if f"status = StatusCode.{status.name}" in exc_str:
128
+ res = status_result
129
+ break
130
+ if res is not undefined_value:
131
+ success = True
132
+ break
133
+
113
134
  msg_list = [
114
135
  f"Request failed (try {try_nb}):",
115
136
  f" method: {service}.{method}",
@@ -139,6 +160,7 @@ class GRpcClient(object):
139
160
  success = True
140
161
  break
141
162
 
163
+ # If still in error after all tries, raise an exception with last exception message
142
164
  if not success:
143
165
  if "status = " in exc_msg:
144
166
  raise FunctionalException(exc_msg) from last_exc
@@ -149,17 +171,20 @@ class GRpcClient(object):
149
171
  # Note: this step is done manually since grpc_requests has some limitations when raw_output=False:
150
172
  # - Field with default values are not set in json result
151
173
  # - Some field types are badly managed (ex: uint64 fields appear as string in json)
152
- if raw_output == True:
153
- if isinstance(res_proto, grpc._channel._MultiThreadedRendezvous):
154
- return list(res_proto)
155
- else:
156
- return res_proto
157
- else:
158
- if isinstance(res_proto, grpc._channel._MultiThreadedRendezvous):
159
- res = [self.__protobuf_converter.convert_protobuf_object_to_json_object(cur_res) for cur_res in res_proto]
174
+ if res is undefined_value:
175
+ if raw_output == True:
176
+ if isinstance(res_proto, grpc._channel._MultiThreadedRendezvous):
177
+ res = list(res_proto)
178
+ else:
179
+ res = res_proto
160
180
  else:
161
- res = self.__protobuf_converter.convert_protobuf_object_to_json_object(res_proto)
162
- return res
181
+ if isinstance(res_proto, grpc._channel._MultiThreadedRendezvous):
182
+ res = [self.__protobuf_converter.convert_protobuf_object_to_json_object(cur_res) for cur_res in res_proto]
183
+ else:
184
+ res = self.__protobuf_converter.convert_protobuf_object_to_json_object(res_proto)
185
+ if Tools.do_log(logger, self.request_log_level):
186
+ logger.log(self.request_log_level, f"Request {service}.{method} with data [{request}] (raw_output: {raw_output} ; kwargs:{kwargs}) => {res}")
187
+ return res
163
188
 
164
189
  def get_request_data_type_fullname(self, service, method):
165
190
  method_descriptor = self.__grpc_services.get_method_descriptor(service, method)
holado_json/ipc/json.py CHANGED
@@ -29,7 +29,7 @@ def create_name_value_table_from_json(json_value, recursive=False, uncollapse_li
29
29
  converter = JsonConverter()
30
30
  json_value = converter.to_json(json_value)
31
31
 
32
- name_values = __convert_json_value_2_name_values(json_value, recursive=recursive, uncollapse_list=uncollapse_list)
32
+ name_values = convert_json_value_2_name_values(json_value, recursive=recursive, uncollapse_list=uncollapse_list)
33
33
  for name, value in name_values:
34
34
  res.add_row(cells_content=(name, value))
35
35
 
@@ -51,7 +51,7 @@ def create_table_with_header_from_json(json_value, recursive=False, uncollapse_l
51
51
  for json_val in json_list:
52
52
  json_val = converter.to_json(json_val)
53
53
 
54
- name_values = __convert_json_value_2_name_values(json_val, recursive=recursive, uncollapse_list=uncollapse_list)
54
+ name_values = convert_json_value_2_name_values(json_val, recursive=recursive, uncollapse_list=uncollapse_list)
55
55
 
56
56
  # Add new columns if needed
57
57
  for name, value in name_values:
@@ -68,9 +68,17 @@ def create_table_with_header_from_json(json_value, recursive=False, uncollapse_l
68
68
 
69
69
  return res
70
70
 
71
- def __convert_json_value_2_name_values(json_value, recursive=False, uncollapse_list=False):
71
+ def convert_json_value_2_name_values(json_value, recursive=False, uncollapse_list=False, as_dict=False, sorted_=False):
72
+ """Convert json object as a list of (name, value).
73
+ If as_dict is True, the result is a dict of {name:value}
74
+ """
72
75
  res = []
73
76
  __fill_name_values_with_json_value(res, None, json_value, recursive=recursive, uncollapse_list=uncollapse_list)
77
+
78
+ if sorted_:
79
+ res = sorted(res)
80
+ if as_dict:
81
+ res = {e[0]:e[1] for e in res}
74
82
  return res
75
83
 
76
84
  def __fill_name_values_with_json_value(res, name_prefix, json_value, recursive=False, uncollapse_list=False):
@@ -123,3 +131,16 @@ def set_object_attributes_with_json_dict(obj, json_value):
123
131
  else:
124
132
  raise FunctionalException(f"Object doesn't have attribute '{attr_name}' (object type: {Typing.get_object_class_fullname(obj)})")
125
133
 
134
+
135
+ def update_json_object_with_missing_attributes(json_obj, json_ref, recursive=False):
136
+ if not isinstance(json_obj, dict):
137
+ raise TechnicalException(f"json object is expected to be a dict (obtained: {Typing.get_object_class_fullname(json_obj)}")
138
+ if not isinstance(json_ref, dict):
139
+ raise TechnicalException(f"json reference is expected to be a dict (obtained: {Typing.get_object_class_fullname(json_ref)}")
140
+
141
+ for key, value in json_ref.items():
142
+ if key not in json_obj:
143
+ json_obj[key] = value
144
+ elif recursive and isinstance(json_obj[key], dict) and isinstance(value, dict):
145
+ update_json_object_with_missing_attributes(json_obj[key], value, recursive=recursive)
146
+
@@ -18,6 +18,8 @@ from holado_core.common.tools.tools import Tools
18
18
  import json
19
19
  from holado_core.common.tools.converters.converter import Converter
20
20
  from holado_json.ipc.json_converter import JsonConverter
21
+ from holado.common.handlers.object import Object
22
+ from holado.holado_config import Config
21
23
 
22
24
  logger = logging.getLogger(__name__)
23
25
 
@@ -31,7 +33,7 @@ except Exception as exc:
31
33
  with_requests = False
32
34
 
33
35
 
34
- class RestClient(object):
36
+ class RestClient(Object):
35
37
  """
36
38
  REST client
37
39
  """
@@ -41,14 +43,20 @@ class RestClient(object):
41
43
  return with_requests
42
44
 
43
45
  def __init__(self, name, url, headers=None):
44
- self.__name = name
46
+ super().__init__(name)
45
47
  self.__url = url.rstrip('/')
46
48
  self.__headers = headers if headers is not None else {}
47
49
  self.__kwargs = {}
48
-
50
+
51
+ self.__request_log_level = Config.log_level_rest_request
52
+
49
53
  @property
50
- def name(self):
51
- return self.__name
54
+ def request_log_level(self):
55
+ return self.__request_log_level
56
+
57
+ @request_log_level.setter
58
+ def request_log_level(self, log_level):
59
+ self.__request_log_level = log_level
52
60
 
53
61
  def authenticate_by_user(self, user, pwd):
54
62
  if Tools.do_log(logger, logging.DEBUG):
@@ -66,7 +74,14 @@ class RestClient(object):
66
74
  raise TechnicalException(f"Unmanaged SSL arguments: {unexpected_keys}")
67
75
 
68
76
  self.__kwargs.update(ssl_kwargs)
69
-
77
+
78
+ def add_parameters_to_path(self, path, parameters:dict):
79
+ res = path
80
+ if parameters:
81
+ res += "&" if '?' in res else "?"
82
+ res += "&".join([f"{k}={v}" for k,v in parameters.items()])
83
+ return res
84
+
70
85
  def response_result(self, response, status_ok=200):
71
86
  # Get result
72
87
  if response.status_code == 204:
@@ -98,27 +113,32 @@ class RestClient(object):
98
113
  except Exception as exc:
99
114
  raise TechnicalException(f"[{self.name}] Failed to process {method} '{url}' with arguments {r_kwargs}") from exc
100
115
 
101
- if Tools.do_log(logger, logging.DEBUG):
102
- logger.debug(f"[{self.name}] {method} on url '{url}' => {res}")
103
116
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
104
117
  logger.trace(f"[{self.name}] {method} on url '{url}' => {Tools.represent_object(res, 4)}")
118
+ elif Tools.do_log(logger, self.request_log_level):
119
+ logger.log(self.request_log_level, f"[{self.name}] {method} on url '{url}' => {Tools.represent_object(res, 4, max_level=1)}")
105
120
  return res
106
121
 
107
- def delete(self, path, data=None, **kwargs):
122
+ def delete(self, path, data=None, path_parameters=None, **kwargs):
123
+ path = self.add_parameters_to_path(path, path_parameters)
108
124
  return self.request("DELETE", path, data=data, **kwargs)
109
125
 
110
- def get(self, path, data=None, **kwargs):
126
+ def get(self, path, data=None, path_parameters=None, **kwargs):
127
+ path = self.add_parameters_to_path(path, path_parameters)
111
128
  return self.request("GET", path, data=data, **kwargs)
112
129
 
113
- def patch(self, path, data=None, **kwargs):
130
+ def patch(self, path, data=None, path_parameters=None, **kwargs):
131
+ path = self.add_parameters_to_path(path, path_parameters)
114
132
  return self.request("PATCH", path, data=data, **kwargs)
115
133
 
116
- def post(self, path, data=None, json=None, **kwargs):
134
+ def post(self, path, data=None, json=None, path_parameters=None, **kwargs):
135
+ path = self.add_parameters_to_path(path, path_parameters)
117
136
  return self.request("POST", path, data=data, json=json, **kwargs)
118
137
 
119
- def put(self, path, data=None, **kwargs):
138
+ def put(self, path, data=None, path_parameters=None, **kwargs):
139
+ path = self.add_parameters_to_path(path, path_parameters)
120
140
  return self.request("PUT", path, data=data, **kwargs)
121
-
141
+
122
142
  def __build_url(self, path):
123
143
  return f"{self.__url}/{path.lstrip('/')}"
124
144
 
@@ -32,9 +32,9 @@ class RestManager(object):
32
32
  self.__default_client_class = default_client_class
33
33
 
34
34
  def new_client(self, name, **kwargs):
35
- if name is None:
36
- name = f"RestClient({kwargs})"
37
35
  url = kwargs.pop("url")
36
+ if name is None:
37
+ name = f"RestClient({url})"
38
38
  headers = Tools.pop_sub_kwargs(kwargs, "headers.")
39
39
  authentication = Tools.pop_sub_kwargs(kwargs, "authentication.")
40
40
  ssl_kwargs = Tools.pop_sub_kwargs(kwargs, "ssl.")
@@ -241,7 +241,7 @@ class StepTools(object):
241
241
  if ValueTableManager.is_value_table(value):
242
242
  res = value
243
243
  elif isinstance(value, TableWithHeader):
244
- res = ValueTableConverter.convert_table_with_header_2_value_table_with_header(value, do_eval_once=do_eval_once)
244
+ res = ValueTableConverter.convert_table_2_value_table(value, do_eval_once=do_eval_once)
245
245
  elif isinstance(value, Table):
246
246
  raise FunctionalException(f"The table in variable '{cell_content}' is expected to be with header")
247
247
  elif isinstance(table, Table):
@@ -48,6 +48,8 @@ class ValueTableConverter(TableConverter):
48
48
 
49
49
  @classmethod
50
50
  def convert_value_table_2_table(cls, table):
51
+ ValueTableManager.verify_is_value_table(table)
52
+
51
53
  if isinstance(table, ValueTableWithHeader):
52
54
  res = TableWithHeader()
53
55
  res.header = copy.copy(table.header)
@@ -58,15 +60,6 @@ class ValueTableConverter(TableConverter):
58
60
  res.add_row(cells_content=cells_content)
59
61
  return res
60
62
 
61
- @classmethod
62
- def convert_table_with_header_2_value_table_with_header(cls, table, do_eval_once=True):
63
- res = ValueTableWithHeader()
64
- res.header = TableRow(cells_content=table.header.cells_content)
65
- for row in table:
66
- cells_content = [f"'{cc}'" if isinstance(cc, str) else f"{cc}" for cc in row.cells_content]
67
- res.add_row(cells_content=cells_content, do_eval_once=do_eval_once)
68
- return res
69
-
70
63
  @classmethod
71
64
  def convert_table_with_header_to_dict_list(cls, table, as_generator=False):
72
65
  if not ValueTableManager.is_value_table(table):
@@ -123,36 +116,43 @@ class ValueTableConverter(TableConverter):
123
116
 
124
117
  @classmethod
125
118
  def convert_name_value_table_2_dict(cls, table, with_original_value_content = False):
119
+ if not ValueTableManager.is_value_table(table):
120
+ return TableConverter.convert_name_value_table_2_dict(table)
121
+
126
122
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
127
123
  logger.trace(f"Converting Name/Value table to dict (table = {table})")
128
-
129
- # Verify table structure
130
- ValueTableManager.verify_table_is_name_value_table(table)
131
- ValueTableManager.verify_is_value_table(table)
132
124
 
133
125
  res = {}
134
- for row in table.rows:
135
- if row.get_cell(1).value_type not in [ValueTypes.NotApplicable]:
136
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
137
- logger.trace("Converting row (%s)", row)
138
-
139
- name = row.get_cell(0).value
140
- if with_original_value_content:
141
- value = row.get_cell(1).content
142
- else:
143
- value = row.get_cell(1).value
144
-
145
- if name in res:
146
- raise FunctionalException("Name '{}' appears several times in table".format(name))
147
- else:
148
- res[name] = value
149
-
126
+ if table is not None:
127
+ # Verify table structure
128
+ ValueTableManager.verify_table_is_name_value_table(table)
129
+ ValueTableManager.verify_is_value_table(table)
130
+
131
+ for row in table.rows:
132
+ if row.get_cell(1).value_type not in [ValueTypes.NotApplicable]:
133
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
134
+ logger.trace("Converting row (%s)", row)
135
+
136
+ name = row.get_cell(0).value
137
+ if with_original_value_content:
138
+ value = row.get_cell(1).content
139
+ else:
140
+ value = row.get_cell(1).value
141
+
142
+ if name in res:
143
+ raise FunctionalException("Name '{}' appears several times in table".format(name))
144
+ else:
145
+ res[name] = value
146
+
150
147
  if Tools.do_log(logger, logging.DEBUG):
151
148
  logger.debug(f"Converting Name/Value table to dict (table = {table}) => {res}")
152
149
  return res
153
150
 
154
151
  @classmethod
155
152
  def convert_name_value_table_2_list_and_dict(cls, table, with_original_value_content = False):
153
+ # if not ValueTableManager.is_value_table(table):
154
+ # return TableConverter.convert_name_value_table_2_list_and_dict(table)
155
+
156
156
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
157
157
  logger.trace(f"Converting Name/Value table to list and dict (table = {table})")
158
158
 
@@ -186,6 +186,9 @@ class ValueTableConverter(TableConverter):
186
186
 
187
187
  @classmethod
188
188
  def convert_name_value_table_2_json_object(cls, table, converter=None):
189
+ if not ValueTableManager.is_value_table(table):
190
+ return TableConverter.convert_name_value_table_2_json_object(table, converter=converter)
191
+
189
192
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
190
193
  logger.trace(f"Converting Name/Value table to json object (table = {table})")
191
194
  if converter is None:
@@ -226,6 +229,9 @@ class ValueTableConverter(TableConverter):
226
229
 
227
230
  @classmethod
228
231
  def convert_x_name_value_table_2_list_x_values(cls, table, x_name, with_original_value_content = False):
232
+ # if not ValueTableManager.is_value_table(table):
233
+ # return TableConverter.convert_x_name_value_table_2_list_x_values(table, x_name)
234
+
229
235
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
230
236
  logger.trace(f"Converting {x_name}/Name/Value table to list of {x_name} and values dict (table = {table})")
231
237
 
File without changes