testit-python-commons 5.2.0__py3-none-any.whl → 5.2.2__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.
@@ -41,6 +41,7 @@ from testit_python_commons.services.retry import (
41
41
  retry,
42
42
  retry_on_connection_error,
43
43
  )
44
+ from testit_python_commons.utils.html_escape_utils import HtmlEscapeUtils
44
45
 
45
46
 
46
47
  class ApiClientWorker:
@@ -265,9 +266,9 @@ class ApiClientWorker:
265
266
  self,
266
267
  test_results: List[TestResult],
267
268
  fixture_containers: dict,
268
- finalized_external_ids: set = None) -> None:
269
+ finalized_result_keys: set = None) -> None:
269
270
  logging.debug("call __write_tests")
270
- finalized_external_ids = finalized_external_ids or set()
271
+ finalized_result_keys = finalized_result_keys or set()
271
272
  bulk_autotest_helper = BulkAutotestHelper(self.__autotest_api, self.__test_run_api, self.__config)
272
273
  create_count = 0
273
274
  update_count = 0
@@ -277,8 +278,11 @@ class ApiClientWorker:
277
278
  for test_result in test_results:
278
279
  test_result = self.__add_fixtures_to_test_result(test_result, fixture_containers)
279
280
  external_id = test_result.get_external_id()
281
+ finalize_key = test_result.get_finalize_key()
280
282
 
281
- if external_id in finalized_external_ids:
283
+ # Skip only the same invocation (Java: by UUID). Bare externalId would
284
+ # drop other parametrize iterations that share one autotest id.
285
+ if finalize_key in finalized_result_keys:
282
286
  skip_count += 1
283
287
  logging.info(
284
288
  'Bulk import: skip sendTestResults for %s (already finalized at test finish)',
@@ -469,6 +473,7 @@ class ApiClientWorker:
469
473
  test_result,
470
474
  self.__config.get_project_id())
471
475
 
476
+ HtmlEscapeUtils.escape_html_in_object(model)
472
477
  autotest_response = self.__autotest_api.adapters_auto_tests_post(
473
478
  adapters_auto_tests_post_request=model)
474
479
 
@@ -496,6 +501,7 @@ class ApiClientWorker:
496
501
  model = Converter.prepare_to_update_autotest(test_result, autotest, self.__config.get_project_id())
497
502
 
498
503
  try:
504
+ HtmlEscapeUtils.escape_html_in_object(model)
499
505
  self.__autotest_api.adapters_auto_tests_put(adapters_auto_tests_put_request=model)
500
506
  except Exception as exc:
501
507
  if is_retriable_connection_error(exc):
@@ -562,6 +568,7 @@ class ApiClientWorker:
562
568
  self.__config.get_configuration_id(),
563
569
  self.__status_codes)
564
570
 
571
+ HtmlEscapeUtils.escape_html_in_object(model)
565
572
  response = self.__test_run_api.adapters_test_runs_id_test_results_post(
566
573
  id=self.__config.get_test_run_id(),
567
574
  auto_test_results_for_test_run_model=[model])
@@ -45,9 +45,19 @@ from testit_python_commons.models.step_result import StepResult
45
45
  from testit_python_commons.models.test_result import TestResult
46
46
  from testit_python_commons.models.test_result_with_all_fixture_step_results_model import TestResultWithAllFixtureStepResults
47
47
  from testit_python_commons.services.logger import adapter_logger
48
+ from testit_python_commons.utils.html_escape_utils import HtmlEscapeUtils
48
49
 
49
50
 
50
51
  class Converter:
52
+ @staticmethod
53
+ def _escape_string_map(values: Optional[dict]) -> Optional[dict]:
54
+ if not values:
55
+ return values
56
+ return {
57
+ str(key): HtmlEscapeUtils.escape_html_tags(str(value)) if value is not None else value
58
+ for key, value in values.items()
59
+ }
60
+
51
61
  @staticmethod
52
62
  @adapter_logger
53
63
  def test_run_to_test_run_short_model(
@@ -402,8 +412,8 @@ class Converter:
402
412
  test_result.get_teardown_results()),
403
413
  traces=test_result.get_traces(),
404
414
  attachments=test_result.get_attachments(),
405
- parameters=test_result.get_parameters(),
406
- properties=test_result.get_properties(),
415
+ parameters=cls._escape_string_map(test_result.get_parameters()),
416
+ properties=cls._escape_string_map(test_result.get_properties()),
407
417
  links=cls.links_to_links_post_model(
408
418
  test_result.get_result_links()),
409
419
  duration=round(test_result.get_duration()),
@@ -156,7 +156,7 @@ class BulkAutotestHelper:
156
156
  def __create_tests(self, autotests_for_create: List[AutoTestCreateApiModel]):
157
157
  # logging.debug(f'Creating autotests: "{autotests_for_create}')
158
158
 
159
- autotests_for_create = HtmlEscapeUtils.escape_html_in_object(autotests_for_create)
159
+ autotests_for_create = HtmlEscapeUtils.escape_html_in_object_list(autotests_for_create)
160
160
  self.__autotests_api.adapters_auto_tests_bulk_post(auto_test_create_api_model=autotests_for_create)
161
161
 
162
162
  logging.debug(f'Autotests were created')
@@ -165,7 +165,7 @@ class BulkAutotestHelper:
165
165
  def __update_tests(self, autotests_for_update: List[AutoTestUpdateApiModel]):
166
166
  # logging.debug(f'Updating autotests: {autotests_for_update}')
167
167
 
168
- autotests_for_update = HtmlEscapeUtils.escape_html_in_object(autotests_for_update)
168
+ autotests_for_update = HtmlEscapeUtils.escape_html_in_object_list(autotests_for_update)
169
169
  self.__autotests_api.adapters_auto_tests_bulk_put(auto_test_update_api_model=autotests_for_update)
170
170
 
171
171
  logging.debug(f'Autotests were updated')
@@ -174,7 +174,7 @@ class BulkAutotestHelper:
174
174
  def __load_test_results(self, test_results: List[AutoTestResultsForTestRunModel]):
175
175
  # logging.debug(f'Loading test results: {test_results}')
176
176
 
177
- test_results = HtmlEscapeUtils.escape_html_in_object(test_results)
177
+ test_results = HtmlEscapeUtils.escape_html_in_object_list(test_results)
178
178
  self.__test_runs_api.adapters_test_runs_id_test_results_post(
179
179
  id=self.__test_run_id,
180
180
  auto_test_results_for_test_run_model=test_results)
@@ -1,3 +1,4 @@
1
+ import json
1
2
  from typing import List
2
3
 
3
4
  from testit_python_commons.models.link import Link
@@ -289,7 +290,7 @@ class TestResult:
289
290
 
290
291
  @adapter_logger
291
292
  def set_external_key(self, external_key: str):
292
- self.__external_key = external_key
293
+ self.__external_key = HtmlEscapeUtils.escape_html_tags(external_key)
293
294
 
294
295
  return self
295
296
 
@@ -297,6 +298,19 @@ class TestResult:
297
298
  def get_external_key(self) -> str:
298
299
  return self.__external_key
299
300
 
301
+ def get_finalize_key(self) -> str:
302
+ """
303
+ Identity of one test invocation for bulk dedupe (parametrize-safe).
304
+ Prefer externalKey (e.g. pytest node id); else externalId + parameters.
305
+ """
306
+ if self.__external_key:
307
+ return self.__external_key
308
+ params = self.__parameters or {}
309
+ return '{0}\n{1}'.format(
310
+ self.__external_id,
311
+ json.dumps(params, sort_keys=True, default=str, ensure_ascii=False),
312
+ )
313
+
300
314
  @adapter_logger
301
315
  def set_layer(self, layer: str):
302
316
  self.__layer = HtmlEscapeUtils.escape_html_tags(layer) if layer else None
@@ -5,6 +5,7 @@ import uuid
5
5
  from testit_python_commons.client.api_client import ApiClientWorker
6
6
  from testit_python_commons.client.client_configuration import ClientConfiguration
7
7
  from testit_python_commons.models.adapter_mode import AdapterMode
8
+ from testit_python_commons.models.status_type import StatusType
8
9
  from testit_python_commons.models.test_result import TestResult
9
10
  from testit_python_commons.services.adapter_manager_configuration import (
10
11
  AdapterManagerConfiguration,
@@ -18,6 +19,7 @@ from testit_python_commons.services.sync_storage.sync_storage_runner import (
18
19
  )
19
20
 
20
21
  SYNC_STORAGE_AVAILABLE = True
22
+ IN_PROGRESS_LITERAL = "InProgress"
21
23
 
22
24
 
23
25
  class AdapterManager:
@@ -33,6 +35,9 @@ class AdapterManager:
33
35
  self.__api_client = ApiClientWorker(client_configuration)
34
36
  self.__fixture_manager = fixture_manager
35
37
  self.__test_result_map = {}
38
+ # Keys of results already sent at test finish (externalKey or externalId+params).
39
+ # Must not be bare externalId — parametrize shares one externalId.
40
+ self.__finalized_result_keys = set()
36
41
  self.__test_results = []
37
42
  self.__test_run_metadata_applied = False
38
43
 
@@ -146,23 +151,32 @@ class AdapterManager:
146
151
 
147
152
  @adapter_logger
148
153
  def write_test(self, test_result: TestResult) -> None:
149
- if self.__config.should_import_realtime():
150
- self.__write_test_realtime(test_result)
151
- return
152
-
153
- # for realtime false
154
- # if
155
- logging.debug("Is already in progress: " + str(self.__is_already_in_progress()))
156
- # Handle Sync Storage integration if available
157
- # Check if current worker is master and no test is in progress
158
- if self.__is_active_syncstorage_instance() and self.__is_master_and_no_in_progress():
159
- logging.debug(f"Outcome: {test_result.get_outcome()}")
160
- is_ok = self.on_master_no_already_in_progress(test_result)
161
- if is_ok:
154
+ try:
155
+ if self.__config.should_import_realtime():
156
+ self.__write_test_realtime(test_result)
162
157
  return
163
- # else continue normal processing
164
158
 
165
- self.__test_results.append(test_result)
159
+ # for realtime false
160
+ # if
161
+ logging.debug("Is already in progress: " + str(self.__is_already_in_progress()))
162
+ # Handle Sync Storage integration if available
163
+ # Check if current worker is master and no test is in progress
164
+ if self.__is_active_syncstorage_instance() and self.__is_master_and_no_in_progress():
165
+ logging.debug(f"Outcome: {test_result.get_outcome()}")
166
+ is_ok = self.on_master_no_already_in_progress(test_result)
167
+ if is_ok:
168
+ return
169
+ # else continue normal processing
170
+
171
+ self.__test_results.append(test_result)
172
+ except Exception as exc:
173
+ # Do not abort the pytest/session run if TMS rejects one result (e.g. XSS validation)
174
+ logging.error(
175
+ 'Failed to write test result for external_id="%s", parameters=%s: %s',
176
+ test_result.get_external_id(),
177
+ test_result.get_parameters(),
178
+ exc,
179
+ )
166
180
 
167
181
 
168
182
  @adapter_logger
@@ -189,12 +203,31 @@ class AdapterManager:
189
203
  self.__sync_storage_runner.set_is_already_in_progress(True)
190
204
 
191
205
  try:
192
- # Final status via sendTestResults (create); never change status via PUT.
206
+ # Mode 0: finalize in TMS now (TP-bound InProgress / orphan fix).
207
+ # Modes 1/2: post InProgress to TMS; Work X finalizes from the cut.
208
+ if self.__config.get_mode() == AdapterMode.USE_FILTER:
209
+ logging.debug(
210
+ "SyncStorage accepted %s; sendTestResults with final status (mode 0)",
211
+ test_result.get_external_id(),
212
+ )
213
+ self._write_test_realtime_internal(test_result)
214
+ return True
215
+
216
+ final_outcome = test_result.get_outcome()
217
+ final_status_type = test_result.get_status_type()
193
218
  logging.debug(
194
- "SyncStorage accepted %s; sendTestResults with final status",
219
+ "SyncStorage accepted %s; sendTestResults InProgress (Work X will finalize)",
195
220
  test_result.get_external_id(),
196
221
  )
197
- self._write_test_realtime_internal(test_result)
222
+ try:
223
+ test_result.set_outcome(IN_PROGRESS_LITERAL)
224
+ test_result.set_status_type(StatusType.INPROGRESS)
225
+ self._write_test_realtime_internal(test_result)
226
+ finally:
227
+ if final_outcome is not None:
228
+ test_result.set_outcome(final_outcome)
229
+ if final_status_type is not None:
230
+ test_result.set_status_type(final_status_type)
198
231
  return True
199
232
  except Exception as e:
200
233
  logging.warning(
@@ -233,7 +266,9 @@ class AdapterManager:
233
266
  logging.warning(test_result)
234
267
  return
235
268
 
269
+ # Fixture attach (realtime) still indexes by externalId.
236
270
  self.__test_result_map[ext_id] = test_result_id
271
+ self.__finalized_result_keys.add(test_result.get_finalize_key())
237
272
 
238
273
  @adapter_logger
239
274
  def write_tests(self) -> None:
@@ -265,7 +300,7 @@ class AdapterManager:
265
300
  self.__api_client.write_tests(
266
301
  self.__test_results,
267
302
  fixtures,
268
- finalized_external_ids=set(self.__test_result_map.keys()),
303
+ finalized_result_keys=set(self.__finalized_result_keys),
269
304
  )
270
305
 
271
306
  @adapter_logger
@@ -15,23 +15,18 @@ class HtmlEscapeUtils:
15
15
 
16
16
  NO_ESCAPE_HTML_ENV_VAR = "NO_ESCAPE_HTML"
17
17
 
18
- # Regex pattern to detect HTML tags (requires at least one non-whitespace character after <)
19
- # This ensures empty <> brackets are not considered HTML tags
20
- _HTML_TAG_PATTERN = re.compile(r'<\S.*?(?:>|/>)')
21
-
22
- # Regex patterns to escape only non-escaped characters
23
- # Using negative lookbehind to avoid double escaping
24
- _LESS_THAN_PATTERN = re.compile('<')
25
- _GREATER_THAN_PATTERN = re.compile('>')
26
-
18
+ # Align with Java adapters: tag must start with letter, '!' or '/'
19
+ _HTML_TAG_PATTERN = re.compile(
20
+ r'''<[a-zA-Z!/][^<>"']*(?:"[^"]*"[^<>"']*|'[^']*'[^<>"']*)*>'''
21
+ )
22
+
27
23
  @staticmethod
28
24
  def escape_html_tags(text: Optional[str]) -> Optional[str]:
29
25
  """
30
26
  Escapes HTML tags to prevent XSS attacks.
31
27
  First checks if the string contains HTML tags using regex pattern.
32
28
  Only performs escaping if HTML tags are detected.
33
- Escapes all < as \\< and > as \\> only if they are not already escaped.
34
- Uses regex with negative lookbehind to avoid double escaping.
29
+ Escapes < as &lt; and > as &gt; (idempotent for already-escaped text).
35
30
 
36
31
  Args:
37
32
  text: The text to escape
@@ -51,11 +46,7 @@ class HtmlEscapeUtils:
51
46
  if not HtmlEscapeUtils._HTML_TAG_PATTERN.search(text):
52
47
  return text # No HTML tags found, return original string
53
48
 
54
- # Use regex with negative lookbehind to escape only non-escaped characters
55
- result = HtmlEscapeUtils._LESS_THAN_PATTERN.sub('&lt;', text)
56
- result = HtmlEscapeUtils._GREATER_THAN_PATTERN.sub('&gt;', result)
57
-
58
- return result
49
+ return text.replace('<', '&lt;').replace('>', '&gt;')
59
50
 
60
51
  @staticmethod
61
52
  def escape_html_in_object(obj: Any) -> Any:
@@ -80,7 +71,12 @@ class HtmlEscapeUtils:
80
71
  return obj
81
72
 
82
73
  try:
83
- HtmlEscapeUtils._process_object_attributes(obj)
74
+ if isinstance(obj, list):
75
+ HtmlEscapeUtils._process_list(obj)
76
+ elif isinstance(obj, dict):
77
+ HtmlEscapeUtils._process_dict(obj)
78
+ else:
79
+ HtmlEscapeUtils._process_object_attributes(obj)
84
80
  except Exception as e:
85
81
  # Silently ignore reflection errors
86
82
  logging.debug(f"Error processing object attributes: {e}")
@@ -90,7 +86,7 @@ class HtmlEscapeUtils:
90
86
  @staticmethod
91
87
  def escape_html_in_object_list(obj_list: Optional[List[Any]]) -> Optional[List[Any]]:
92
88
  """
93
- Escapes HTML tags in all string attributes of objects in a list using reflection.
89
+ Escapes HTML tags in list items: strings in-place, objects via reflection.
94
90
  Can be disabled by setting NO_ESCAPE_HTML environment variable to "true".
95
91
 
96
92
  Args:
@@ -106,47 +102,68 @@ class HtmlEscapeUtils:
106
102
  no_escape_html = os.environ.get(HtmlEscapeUtils.NO_ESCAPE_HTML_ENV_VAR, "").lower()
107
103
  if no_escape_html == "true":
108
104
  return obj_list
109
-
110
- for obj in obj_list:
111
- HtmlEscapeUtils.escape_html_in_object(obj)
112
-
105
+
106
+ HtmlEscapeUtils._process_list(obj_list)
113
107
  return obj_list
114
108
 
109
+ @staticmethod
110
+ def _process_dict(obj: dict) -> None:
111
+ for key, value in obj.items():
112
+ if isinstance(value, str):
113
+ obj[key] = HtmlEscapeUtils.escape_html_tags(value)
114
+ elif isinstance(value, list):
115
+ HtmlEscapeUtils._process_list(value)
116
+ elif isinstance(value, dict):
117
+ HtmlEscapeUtils._process_dict(value)
118
+ elif value is not None and not HtmlEscapeUtils._is_simple_type(type(value)):
119
+ HtmlEscapeUtils.escape_html_in_object(value)
120
+
121
+ @staticmethod
122
+ def _iter_object_attr_names(obj: Any):
123
+ """
124
+ OpenAPI models store fields in attribute_map/_data_store; they are not listed by dir().
125
+ Prefer those maps, fall back to public dir() attributes for plain objects.
126
+ """
127
+ attribute_map = getattr(obj, 'attribute_map', None)
128
+ if isinstance(attribute_map, dict) and attribute_map:
129
+ return attribute_map.keys()
130
+
131
+ data_store = getattr(obj, '_data_store', None)
132
+ if isinstance(data_store, dict) and data_store:
133
+ return data_store.keys()
134
+
135
+ return (
136
+ attr_name for attr_name in dir(obj)
137
+ if not attr_name.startswith('_') and not callable(getattr(obj, attr_name, None))
138
+ )
139
+
140
+ @staticmethod
141
+ def _should_skip_attr(attr_name: str) -> bool:
142
+ return (
143
+ attr_name.startswith('_')
144
+ or attr_name.startswith("external_id")
145
+ or attr_name.startswith("externalId")
146
+ or attr_name.startswith("auto_test_external_id")
147
+ or attr_name.startswith("autoTestExternalId")
148
+ )
149
+
115
150
  @staticmethod
116
151
  def _process_object_attributes(obj: Any) -> None:
117
152
  """
118
153
  Process all attributes of an object for HTML escaping.
119
154
  """
120
- # Handle dictionary-like objects (common in API models)
121
- if hasattr(obj, '__dict__'):
122
- for attr_name in dir(obj):
123
- # Skip private/protected attributes and methods
124
- if attr_name.startswith('_') or callable(getattr(obj, attr_name, None)):
125
- continue
126
- if (
127
- attr_name.startswith("external_id")
128
- or attr_name.startswith("externalId")
129
- or attr_name.startswith("auto_test_external_id")
130
- or attr_name.startswith("autoTestExternalId")
131
- ):
155
+ for attr_name in HtmlEscapeUtils._iter_object_attr_names(obj):
156
+ if HtmlEscapeUtils._should_skip_attr(attr_name):
157
+ continue
158
+
159
+ try:
160
+ value = getattr(obj, attr_name, None)
161
+ if callable(value):
132
162
  continue
133
-
134
- try:
135
- value = getattr(obj, attr_name)
136
- HtmlEscapeUtils._process_attribute_value(obj, attr_name, value)
137
- except Exception as e:
138
- # Silently ignore attribute errors
139
- logging.debug(f"Error processing attribute {attr_name}: {e}")
140
-
141
- # Handle dictionary objects
142
- elif isinstance(obj, dict):
143
- for key, value in obj.items():
144
- if isinstance(value, str):
145
- obj[key] = HtmlEscapeUtils.escape_html_tags(value)
146
- elif isinstance(value, list):
147
- HtmlEscapeUtils._process_list(value)
148
- elif not HtmlEscapeUtils._is_simple_type(type(value)):
149
- HtmlEscapeUtils.escape_html_in_object(value)
163
+ HtmlEscapeUtils._process_attribute_value(obj, attr_name, value)
164
+ except Exception as e:
165
+ # Silently ignore attribute errors
166
+ logging.debug(f"Error processing attribute {attr_name}: {e}")
150
167
 
151
168
  @staticmethod
152
169
  def _process_attribute_value(obj: Any, attr_name: str, value: Any) -> None:
@@ -162,6 +179,13 @@ class HtmlEscapeUtils:
162
179
  pass
163
180
  elif isinstance(value, list):
164
181
  HtmlEscapeUtils._process_list(value)
182
+ elif isinstance(value, dict):
183
+ HtmlEscapeUtils._process_dict(value)
184
+ try:
185
+ # Write back so OpenAPI models that return dict copies keep escaped values
186
+ setattr(obj, attr_name, value)
187
+ except AttributeError:
188
+ pass
165
189
  elif value is not None and not HtmlEscapeUtils._is_simple_type(type(value)):
166
190
  # Process nested objects (but not simple types)
167
191
  HtmlEscapeUtils.escape_html_in_object(value)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testit-python-commons
3
- Version: 5.2.0
3
+ Version: 5.2.2
4
4
  Summary: Python commons for Test IT
5
5
  Home-page: https://github.com/testit-tms/adapters-python/
6
6
  Author: Integration team
@@ -227,11 +227,11 @@ testit_python_commons/decorators.py,sha256=5P0VF1z0rncMiB-G_eeuj536vizYj2UQVDroX
227
227
  testit_python_commons/dynamic_methods.py,sha256=WKHHA6Uj61tWXI3DphALYOi2BV6TnQKvQy0-Vt2JR2I,8816
228
228
  testit_python_commons/step.py,sha256=CYUs_S8opmRg1tsTY1dVJOPzzt-HYR3_uLTBpYtHSfQ,3244
229
229
  testit_python_commons/client/__init__.py,sha256=zSJhxDHzWWTFHJ0s8bqCaBtM5FK2GcPgZxaKdI8zf-o,165
230
- testit_python_commons/client/api_client.py,sha256=SgIPi9AG8o5jAATggZeiUvK7Hffuir_Z7727AJT3OEs,25274
230
+ testit_python_commons/client/api_client.py,sha256=j6omqfCR_FI0OvTlW-li291BwL96U7e8agdbG4Fs7k0,25725
231
231
  testit_python_commons/client/client_configuration.py,sha256=1M-OrROU3Xj0YGsUX4venG-l6Ewr43LNvUcyFfY57ys,2776
232
- testit_python_commons/client/converter.py,sha256=QJ-zRG7-DuXx6c_ujLIjlOT6kfBRqLh196Xt9_eo8RU,28147
232
+ testit_python_commons/client/converter.py,sha256=-TfQsLI9ezPwngbXwTrRKJenNmuyNdYRHX__xFQvxaE,28578
233
233
  testit_python_commons/client/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
234
- testit_python_commons/client/helpers/bulk_autotest_helper.py,sha256=k_5sK3tVz0fCZw_Eh2mk9diHF_bLin0P4016E2gWQQI,10888
234
+ testit_python_commons/client/helpers/bulk_autotest_helper.py,sha256=I8kIetucvjN5Zws8q99GRd8Rjy7I7MrmduBSjG7vTgQ,10903
235
235
  testit_python_commons/client/helpers/test_result_matching.py,sha256=XSGzzESs-vg41MrvcijD91snpczL3fiVTywOe2j2WZg,1373
236
236
  testit_python_commons/client/helpers/threads_manager.py,sha256=PVDQytuNrGs95JfQ03QeUV_447Yn4Oig-ZmQaA6vo6w,3505
237
237
  testit_python_commons/client/models/__init__.py,sha256=4c3yNkadtebFF1eEZw7JmfwcLtOim2zHkwbZIHvCK0A,284
@@ -248,10 +248,10 @@ testit_python_commons/models/outcome_type.py,sha256=WAAuPRTopmYPczd-Gd0IrE7SGDZO
248
248
  testit_python_commons/models/status_type.py,sha256=lm4Hp02Z5Wo1mOaaMDjzBD1W0BE6gtwjBMPdhxuO_5U,152
249
249
  testit_python_commons/models/step_result.py,sha256=T9BbcPB6BCz3ZkrWXy2Z2Guj2wecvKJX1oIrG-yJH4I,2209
250
250
  testit_python_commons/models/test_layers.py,sha256=XACHq-r3bf35ktU9_HUputiBYKXwOXJmeqMJTnrB460,168
251
- testit_python_commons/models/test_result.py,sha256=R2CaQFnHVH_grf0LIvat7Dq1PlPCJm_-kbAkot8ANwg,7781
251
+ testit_python_commons/models/test_result.py,sha256=jgdYtg2d56wNXBAMh7qJVjgpSIPVycBibTY_Cp9bxgM,8316
252
252
  testit_python_commons/models/test_result_with_all_fixture_step_results_model.py,sha256=aI5nfJ_4EAhzZg7eIV1JhSf9i3EENiRiuQuqJvSUs3M,866
253
253
  testit_python_commons/services/__init__.py,sha256=yVVmiCgMyike_8OoNPiHLNoMqKhCDlWYhvmGW0IRHJM,1197
254
- testit_python_commons/services/adapter_manager.py,sha256=UJK0c8aj4X2UI8rFNR2wYtPnHWDOA8c5K0dAQeDOIRU,11849
254
+ testit_python_commons/services/adapter_manager.py,sha256=c47V4oFAm2tMC6GZSZCQ-svHcNu9YZI1HlF-zqMapLY,13689
255
255
  testit_python_commons/services/adapter_manager_configuration.py,sha256=ZPgSRUskSh8sJNAtlpOSAXqGWWTdYNsDb3jaiuTFEc8,2228
256
256
  testit_python_commons/services/fixture_manager.py,sha256=PCSLBEPa3yJVbCPsMt_Y5badWLAhKrJsZTaUesq7oNI,2006
257
257
  testit_python_commons/services/fixture_storage.py,sha256=nAIW0p9lVvVWtiVdFNqaD7-gCBislY8DLrfdlh8OqFw,1205
@@ -265,8 +265,8 @@ testit_python_commons/services/utils.py,sha256=5LBymIxEC1AKtGQz-S1-ipo3OYR-JzRUA
265
265
  testit_python_commons/services/sync_storage/__init__.py,sha256=Qmjs6Xk5l-i5FFItk0-XPrlVK_HkDuX6FD8FID1iKu0,154
266
266
  testit_python_commons/services/sync_storage/sync_storage_runner.py,sha256=DPOHJZ57otKlmAHHD7JV1rfYAgSTm0fYTvlp1QFtR4I,20539
267
267
  testit_python_commons/utils/__init__.py,sha256=CUHziylwvFAuKyUM1tCp13ik5Z2Mw-VK8n7c92aVy-I,78
268
- testit_python_commons/utils/html_escape_utils.py,sha256=wx20lAVrMvhNiQ7bEu_f-SGqDBp85D-EBL2sgTmnJPY,8135
269
- testit_python_commons-5.2.0.dist-info/METADATA,sha256=_bZbHygVpktiVYN0yafMebpPJudr0lBMzx9x1Vdo9ZQ,1766
270
- testit_python_commons-5.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
271
- testit_python_commons-5.2.0.dist-info/top_level.txt,sha256=TuyfRneOyFuvNz83bbn-pWaAR1fY7FINrrJRTW9Lyqg,65
272
- testit_python_commons-5.2.0.dist-info/RECORD,,
268
+ testit_python_commons/utils/html_escape_utils.py,sha256=xizAyxl0eQa1joW0pLgAhe1E8KYxPpEDxSkKcswlDR4,8758
269
+ testit_python_commons-5.2.2.dist-info/METADATA,sha256=dx7oKINtc3VyVVeO0Zu-Y2UEJn9EZrNFuEqd-XBgI-Y,1766
270
+ testit_python_commons-5.2.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
271
+ testit_python_commons-5.2.2.dist-info/top_level.txt,sha256=TuyfRneOyFuvNz83bbn-pWaAR1fY7FINrrJRTW9Lyqg,65
272
+ testit_python_commons-5.2.2.dist-info/RECORD,,