testit-python-commons 5.2.0__py3-none-any.whl → 5.2.1__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.
- testit_python_commons/client/api_client.py +4 -0
- testit_python_commons/client/helpers/bulk_autotest_helper.py +3 -3
- testit_python_commons/models/test_result.py +1 -1
- testit_python_commons/utils/html_escape_utils.py +63 -35
- {testit_python_commons-5.2.0.dist-info → testit_python_commons-5.2.1.dist-info}/METADATA +1 -1
- {testit_python_commons-5.2.0.dist-info → testit_python_commons-5.2.1.dist-info}/RECORD +8 -8
- {testit_python_commons-5.2.0.dist-info → testit_python_commons-5.2.1.dist-info}/WHEEL +0 -0
- {testit_python_commons-5.2.0.dist-info → testit_python_commons-5.2.1.dist-info}/top_level.txt +0 -0
|
@@ -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:
|
|
@@ -469,6 +470,7 @@ class ApiClientWorker:
|
|
|
469
470
|
test_result,
|
|
470
471
|
self.__config.get_project_id())
|
|
471
472
|
|
|
473
|
+
HtmlEscapeUtils.escape_html_in_object(model)
|
|
472
474
|
autotest_response = self.__autotest_api.adapters_auto_tests_post(
|
|
473
475
|
adapters_auto_tests_post_request=model)
|
|
474
476
|
|
|
@@ -496,6 +498,7 @@ class ApiClientWorker:
|
|
|
496
498
|
model = Converter.prepare_to_update_autotest(test_result, autotest, self.__config.get_project_id())
|
|
497
499
|
|
|
498
500
|
try:
|
|
501
|
+
HtmlEscapeUtils.escape_html_in_object(model)
|
|
499
502
|
self.__autotest_api.adapters_auto_tests_put(adapters_auto_tests_put_request=model)
|
|
500
503
|
except Exception as exc:
|
|
501
504
|
if is_retriable_connection_error(exc):
|
|
@@ -562,6 +565,7 @@ class ApiClientWorker:
|
|
|
562
565
|
self.__config.get_configuration_id(),
|
|
563
566
|
self.__status_codes)
|
|
564
567
|
|
|
568
|
+
HtmlEscapeUtils.escape_html_in_object(model)
|
|
565
569
|
response = self.__test_run_api.adapters_test_runs_id_test_results_post(
|
|
566
570
|
id=self.__config.get_test_run_id(),
|
|
567
571
|
auto_test_results_for_test_run_model=[model])
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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)
|
|
@@ -80,7 +80,12 @@ class HtmlEscapeUtils:
|
|
|
80
80
|
return obj
|
|
81
81
|
|
|
82
82
|
try:
|
|
83
|
-
|
|
83
|
+
if isinstance(obj, list):
|
|
84
|
+
HtmlEscapeUtils._process_list(obj)
|
|
85
|
+
elif isinstance(obj, dict):
|
|
86
|
+
HtmlEscapeUtils._process_dict(obj)
|
|
87
|
+
else:
|
|
88
|
+
HtmlEscapeUtils._process_object_attributes(obj)
|
|
84
89
|
except Exception as e:
|
|
85
90
|
# Silently ignore reflection errors
|
|
86
91
|
logging.debug(f"Error processing object attributes: {e}")
|
|
@@ -90,7 +95,7 @@ class HtmlEscapeUtils:
|
|
|
90
95
|
@staticmethod
|
|
91
96
|
def escape_html_in_object_list(obj_list: Optional[List[Any]]) -> Optional[List[Any]]:
|
|
92
97
|
"""
|
|
93
|
-
Escapes HTML tags in
|
|
98
|
+
Escapes HTML tags in list items: strings in-place, objects via reflection.
|
|
94
99
|
Can be disabled by setting NO_ESCAPE_HTML environment variable to "true".
|
|
95
100
|
|
|
96
101
|
Args:
|
|
@@ -106,47 +111,68 @@ class HtmlEscapeUtils:
|
|
|
106
111
|
no_escape_html = os.environ.get(HtmlEscapeUtils.NO_ESCAPE_HTML_ENV_VAR, "").lower()
|
|
107
112
|
if no_escape_html == "true":
|
|
108
113
|
return obj_list
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
HtmlEscapeUtils.escape_html_in_object(obj)
|
|
112
|
-
|
|
114
|
+
|
|
115
|
+
HtmlEscapeUtils._process_list(obj_list)
|
|
113
116
|
return obj_list
|
|
114
117
|
|
|
118
|
+
@staticmethod
|
|
119
|
+
def _process_dict(obj: dict) -> None:
|
|
120
|
+
for key, value in obj.items():
|
|
121
|
+
if isinstance(value, str):
|
|
122
|
+
obj[key] = HtmlEscapeUtils.escape_html_tags(value)
|
|
123
|
+
elif isinstance(value, list):
|
|
124
|
+
HtmlEscapeUtils._process_list(value)
|
|
125
|
+
elif isinstance(value, dict):
|
|
126
|
+
HtmlEscapeUtils._process_dict(value)
|
|
127
|
+
elif value is not None and not HtmlEscapeUtils._is_simple_type(type(value)):
|
|
128
|
+
HtmlEscapeUtils.escape_html_in_object(value)
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def _iter_object_attr_names(obj: Any):
|
|
132
|
+
"""
|
|
133
|
+
OpenAPI models store fields in attribute_map/_data_store; they are not listed by dir().
|
|
134
|
+
Prefer those maps, fall back to public dir() attributes for plain objects.
|
|
135
|
+
"""
|
|
136
|
+
attribute_map = getattr(obj, 'attribute_map', None)
|
|
137
|
+
if isinstance(attribute_map, dict) and attribute_map:
|
|
138
|
+
return attribute_map.keys()
|
|
139
|
+
|
|
140
|
+
data_store = getattr(obj, '_data_store', None)
|
|
141
|
+
if isinstance(data_store, dict) and data_store:
|
|
142
|
+
return data_store.keys()
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
attr_name for attr_name in dir(obj)
|
|
146
|
+
if not attr_name.startswith('_') and not callable(getattr(obj, attr_name, None))
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def _should_skip_attr(attr_name: str) -> bool:
|
|
151
|
+
return (
|
|
152
|
+
attr_name.startswith('_')
|
|
153
|
+
or attr_name.startswith("external_id")
|
|
154
|
+
or attr_name.startswith("externalId")
|
|
155
|
+
or attr_name.startswith("auto_test_external_id")
|
|
156
|
+
or attr_name.startswith("autoTestExternalId")
|
|
157
|
+
)
|
|
158
|
+
|
|
115
159
|
@staticmethod
|
|
116
160
|
def _process_object_attributes(obj: Any) -> None:
|
|
117
161
|
"""
|
|
118
162
|
Process all attributes of an object for HTML escaping.
|
|
119
163
|
"""
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
):
|
|
164
|
+
for attr_name in HtmlEscapeUtils._iter_object_attr_names(obj):
|
|
165
|
+
if HtmlEscapeUtils._should_skip_attr(attr_name):
|
|
166
|
+
continue
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
value = getattr(obj, attr_name, None)
|
|
170
|
+
if callable(value):
|
|
132
171
|
continue
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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)
|
|
172
|
+
HtmlEscapeUtils._process_attribute_value(obj, attr_name, value)
|
|
173
|
+
except Exception as e:
|
|
174
|
+
# Silently ignore attribute errors
|
|
175
|
+
logging.debug(f"Error processing attribute {attr_name}: {e}")
|
|
150
176
|
|
|
151
177
|
@staticmethod
|
|
152
178
|
def _process_attribute_value(obj: Any, attr_name: str, value: Any) -> None:
|
|
@@ -162,6 +188,8 @@ class HtmlEscapeUtils:
|
|
|
162
188
|
pass
|
|
163
189
|
elif isinstance(value, list):
|
|
164
190
|
HtmlEscapeUtils._process_list(value)
|
|
191
|
+
elif isinstance(value, dict):
|
|
192
|
+
HtmlEscapeUtils._process_dict(value)
|
|
165
193
|
elif value is not None and not HtmlEscapeUtils._is_simple_type(type(value)):
|
|
166
194
|
# Process nested objects (but not simple types)
|
|
167
195
|
HtmlEscapeUtils.escape_html_in_object(value)
|
|
@@ -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=
|
|
230
|
+
testit_python_commons/client/api_client.py,sha256=fuQnwyYPktWA-LkDv7FOBe1wXBPa2epR83PLpOcBSkw,25511
|
|
231
231
|
testit_python_commons/client/client_configuration.py,sha256=1M-OrROU3Xj0YGsUX4venG-l6Ewr43LNvUcyFfY57ys,2776
|
|
232
232
|
testit_python_commons/client/converter.py,sha256=QJ-zRG7-DuXx6c_ujLIjlOT6kfBRqLh196Xt9_eo8RU,28147
|
|
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=
|
|
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,7 +248,7 @@ 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=
|
|
251
|
+
testit_python_commons/models/test_result.py,sha256=guf0RD2FjLY5sNFuyucXY07xg01yG_sKKdoASYpJ3rc,7815
|
|
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
254
|
testit_python_commons/services/adapter_manager.py,sha256=UJK0c8aj4X2UI8rFNR2wYtPnHWDOA8c5K0dAQeDOIRU,11849
|
|
@@ -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=
|
|
269
|
-
testit_python_commons-5.2.
|
|
270
|
-
testit_python_commons-5.2.
|
|
271
|
-
testit_python_commons-5.2.
|
|
272
|
-
testit_python_commons-5.2.
|
|
268
|
+
testit_python_commons/utils/html_escape_utils.py,sha256=H03t3mYaUMAS-MR9lH00ld2Pe8mW6ebB6OLGIw9x72c,9057
|
|
269
|
+
testit_python_commons-5.2.1.dist-info/METADATA,sha256=4c-5lwTDE6mGM9cgccJw2RDZxvIf5uODJXU_rU5lJwU,1766
|
|
270
|
+
testit_python_commons-5.2.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
271
|
+
testit_python_commons-5.2.1.dist-info/top_level.txt,sha256=TuyfRneOyFuvNz83bbn-pWaAR1fY7FINrrJRTW9Lyqg,65
|
|
272
|
+
testit_python_commons-5.2.1.dist-info/RECORD,,
|
|
File without changes
|
{testit_python_commons-5.2.0.dist-info → testit_python_commons-5.2.1.dist-info}/top_level.txt
RENAMED
|
File without changes
|