t-bug-catcher 0.5.1__tar.gz → 0.5.3__tar.gz
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.
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/PKG-INFO +1 -1
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/setup.cfg +1 -1
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/setup.py +1 -1
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/__init__.py +1 -1
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/bug_catcher.py +5 -2
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/config.py +13 -4
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/jira.py +137 -14
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/stack_saver.py +0 -2
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/utils/common.py +15 -4
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher.egg-info/PKG-INFO +1 -1
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/tests/test_t_bug_catcher.py +2 -2
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/MANIFEST.in +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/README.rst +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/pyproject.toml +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/requirements.txt +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/bug_snag.py +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/exceptions.py +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/resources/whispers_config.yml +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/utils/__init__.py +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/utils/logger.py +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/validation.py +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher/workitems.py +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher.egg-info/SOURCES.txt +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher.egg-info/dependency_links.txt +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher.egg-info/not-zip-safe +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher.egg-info/requires.txt +0 -0
- {t_bug_catcher-0.5.1 → t_bug_catcher-0.5.3}/t_bug_catcher.egg-info/top_level.txt +0 -0
|
@@ -26,7 +26,7 @@ setup(
|
|
|
26
26
|
packages=find_packages(include=["t_bug_catcher", "t_bug_catcher.*"]),
|
|
27
27
|
test_suite="tests",
|
|
28
28
|
url="https://www.thoughtful.ai/",
|
|
29
|
-
version="0.5.
|
|
29
|
+
version="0.5.3",
|
|
30
30
|
zip_safe=False,
|
|
31
31
|
install_requires=install_requirements,
|
|
32
32
|
include_package_data=True,
|
|
@@ -334,5 +334,8 @@ report_error_to_bugsnag = __bug_catcher.report_error_to_bugsnag
|
|
|
334
334
|
install_sys_hook = __bug_catcher.install_sys_hook
|
|
335
335
|
uninstall_sys_hook = __bug_catcher.uninstall_sys_hook
|
|
336
336
|
|
|
337
|
-
if CONFIG.STAGE
|
|
338
|
-
|
|
337
|
+
if not CONFIG.STAGE:
|
|
338
|
+
logger.warning("Implementation Stage is not configured. Please configure it before running.")
|
|
339
|
+
else:
|
|
340
|
+
if CONFIG.STAGE.lower() == "delivery":
|
|
341
|
+
pre_run_validation = PRE_RUN_VALIDATION
|
|
@@ -14,6 +14,8 @@ class Config:
|
|
|
14
14
|
MAX_DESCRIPTION_LENGTH: int = 250
|
|
15
15
|
SUMMARY_LENGTH: int = 120
|
|
16
16
|
STACK_SCOPE: int = 3
|
|
17
|
+
STACK_ITEM_LENGTH: int = 100
|
|
18
|
+
STACK_TEXT_LENGTH: int = 10000
|
|
17
19
|
|
|
18
20
|
class TICKET_PRIORITIES:
|
|
19
21
|
"""Priorities class for configuring the application."""
|
|
@@ -25,6 +27,7 @@ class Config:
|
|
|
25
27
|
LOWEST: str = "5"
|
|
26
28
|
|
|
27
29
|
SUPPORT_BOARD = "AB"
|
|
30
|
+
BC_BOARD = "BC"
|
|
28
31
|
|
|
29
32
|
KEYS_TO_REMOVE = ["credential", "password"]
|
|
30
33
|
BUILD_INFO_FILE = "commit_info.json"
|
|
@@ -42,10 +45,16 @@ class Config:
|
|
|
42
45
|
else variables.get("environment", "local")
|
|
43
46
|
)
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
if ENVIRONMENT != "local":
|
|
49
|
+
STAGE = metadata.get("process", dict()).get("implementationStage", "")
|
|
50
|
+
ADMIN_CODE = metadata.get("process", dict()).get("adminCode", "")
|
|
51
|
+
WORKER_NAME = metadata.get("process", dict()).get("name", "")
|
|
52
|
+
EMPOWER_URL = metadata.get("process", dict()).get("processRunUrl") or variables.get("processRunUrl")
|
|
53
|
+
else:
|
|
54
|
+
STAGE = "test"
|
|
55
|
+
ADMIN_CODE = ""
|
|
56
|
+
WORKER_NAME = ""
|
|
57
|
+
EMPOWER_URL = ""
|
|
49
58
|
|
|
50
59
|
|
|
51
60
|
CONFIG = Config()
|
|
@@ -150,13 +150,14 @@ class Jira:
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
@retry_if_bad_request
|
|
153
|
-
def get_issues(self) -> dict:
|
|
153
|
+
def get_issues(self, project_key: Optional[str] = None) -> dict:
|
|
154
154
|
"""A function to get the issues using a Jira API.
|
|
155
155
|
|
|
156
156
|
It updates the headers, sets up a JQL query, specifies additional query parameters,
|
|
157
157
|
makes a GET request to the Jira API, and returns the JSON response.
|
|
158
158
|
"""
|
|
159
|
-
|
|
159
|
+
project_key = project_key or self._project_key
|
|
160
|
+
jql_query = f'project = "{project_key}"'
|
|
160
161
|
|
|
161
162
|
# Specify additional query parameters if needed
|
|
162
163
|
query_params = {"jql": jql_query, "maxResults": 100} # Adjust as needed
|
|
@@ -210,6 +211,7 @@ class Jira:
|
|
|
210
211
|
summary: str,
|
|
211
212
|
description: dict,
|
|
212
213
|
issue_type: str,
|
|
214
|
+
project_key: Optional[str] = None,
|
|
213
215
|
assignee: Optional[str] = None,
|
|
214
216
|
labels: Optional[list] = None,
|
|
215
217
|
priority: Optional[str] = None,
|
|
@@ -227,18 +229,19 @@ class Jira:
|
|
|
227
229
|
Returns:
|
|
228
230
|
The JSON payload for creating a new issue.
|
|
229
231
|
"""
|
|
232
|
+
project_key = project_key or self._project_key
|
|
230
233
|
fields = {
|
|
231
234
|
"fields": {
|
|
232
235
|
"assignee": {"id": assignee if assignee else "-1"},
|
|
233
236
|
"description": description,
|
|
234
237
|
"issuetype": {"id": issue_type},
|
|
235
|
-
"project": {"key":
|
|
238
|
+
"project": {"key": project_key},
|
|
236
239
|
"summary": summary,
|
|
237
240
|
},
|
|
238
241
|
}
|
|
239
242
|
if labels:
|
|
240
243
|
fields["fields"]["labels"] = labels
|
|
241
|
-
if
|
|
244
|
+
if project_key == CONFIG.SUPPORT_BOARD and CONFIG.ADMIN_CODE:
|
|
242
245
|
fields["fields"]["customfield_10077"] = [CONFIG.ADMIN_CODE]
|
|
243
246
|
if priority:
|
|
244
247
|
fields["fields"]["priority"] = {"id": priority}
|
|
@@ -264,7 +267,7 @@ class Jira:
|
|
|
264
267
|
)
|
|
265
268
|
|
|
266
269
|
@retry_if_bad_request
|
|
267
|
-
def __get_issue_types(self) -> dict:
|
|
270
|
+
def __get_issue_types(self, project_key: Optional[str] = None) -> dict:
|
|
268
271
|
"""Get the board information.
|
|
269
272
|
|
|
270
273
|
Args:
|
|
@@ -273,9 +276,10 @@ class Jira:
|
|
|
273
276
|
Returns:
|
|
274
277
|
dict: The board information
|
|
275
278
|
"""
|
|
279
|
+
project_key = project_key or self._project_key
|
|
276
280
|
response = requests.request(
|
|
277
281
|
"GET",
|
|
278
|
-
url=self._base_url + f"/rest/api/3/project/{
|
|
282
|
+
url=self._base_url + f"/rest/api/3/project/{project_key}",
|
|
279
283
|
headers=self.__get_headers(),
|
|
280
284
|
auth=self._auth,
|
|
281
285
|
)
|
|
@@ -850,6 +854,54 @@ class Jira:
|
|
|
850
854
|
+ self.__error_markup(warning_id),
|
|
851
855
|
}
|
|
852
856
|
|
|
857
|
+
def __create_internal_error_markup(
|
|
858
|
+
self,
|
|
859
|
+
exc_type: type,
|
|
860
|
+
exc_value: Union[Exception, str],
|
|
861
|
+
exc_traceback: TracebackType,
|
|
862
|
+
error_id: str,
|
|
863
|
+
additional_info: Optional[str] = None,
|
|
864
|
+
metadata: Optional[dict] = None,
|
|
865
|
+
) -> dict:
|
|
866
|
+
"""Create a description with the given trace_back and additional_info.
|
|
867
|
+
|
|
868
|
+
Args:
|
|
869
|
+
exc_type (type): The type of the exception.
|
|
870
|
+
exc_value (Exception): The exception.
|
|
871
|
+
exc_traceback (TracebackType): The trace_back.
|
|
872
|
+
error_id (str): The error ID.
|
|
873
|
+
additional_info (str, optional): Additional information. Defaults to "".
|
|
874
|
+
metadata (dict, optional): Additional metadata. Defaults to None.
|
|
875
|
+
|
|
876
|
+
Returns:
|
|
877
|
+
dict: A dictionary containing the version, type, and content.
|
|
878
|
+
"""
|
|
879
|
+
exc_info = f"{exc_type.__name__}: {exc_value}"
|
|
880
|
+
frames = get_frames(exc_traceback)
|
|
881
|
+
error_string: str = frames[-1].line
|
|
882
|
+
exc_traceback_info: str = (
|
|
883
|
+
f"Traceback (most recent call last):\n{''.join(traceback.format_tb(exc_traceback))}{exc_info}"
|
|
884
|
+
)
|
|
885
|
+
if len(exc_traceback_info) > 30000:
|
|
886
|
+
exc_traceback_info: str = (
|
|
887
|
+
f"Traceback (most recent call last):\n{''.join(traceback.format_tb(exc_traceback)[-1])}{exc_info}"
|
|
888
|
+
)
|
|
889
|
+
|
|
890
|
+
return {
|
|
891
|
+
"version": 1,
|
|
892
|
+
"type": "doc",
|
|
893
|
+
"content": []
|
|
894
|
+
+ (self.__error_string_markup(error_string, exc_info) if error_string else [])
|
|
895
|
+
+ self.__bot_name_markup()
|
|
896
|
+
+ self.__date_markup()
|
|
897
|
+
+ self.__runlink_markup()
|
|
898
|
+
+ self.__environment_markup()
|
|
899
|
+
+ (self.__description_markup(additional_info) if additional_info else [])
|
|
900
|
+
+ self.__traceback_markup(exc_traceback_info)
|
|
901
|
+
+ (self.__metadata_markup(metadata) if metadata else [])
|
|
902
|
+
+ self.__error_markup(error_id),
|
|
903
|
+
}
|
|
904
|
+
|
|
853
905
|
def __create_transtion_markup(self, issue_status: str) -> dict:
|
|
854
906
|
"""Create a transition markup.
|
|
855
907
|
|
|
@@ -1070,6 +1122,7 @@ class Jira:
|
|
|
1070
1122
|
self,
|
|
1071
1123
|
summary: str,
|
|
1072
1124
|
description: dict,
|
|
1125
|
+
project_key: Optional[str] = None,
|
|
1073
1126
|
assignee_id: Optional[str] = None,
|
|
1074
1127
|
attachments: Optional[List] = None,
|
|
1075
1128
|
labels: Optional[list] = None,
|
|
@@ -1088,11 +1141,14 @@ class Jira:
|
|
|
1088
1141
|
Returns:
|
|
1089
1142
|
The response from creating the ticket.
|
|
1090
1143
|
"""
|
|
1091
|
-
|
|
1144
|
+
project_key = project_key or self._project_key
|
|
1145
|
+
if project_key == CONFIG.BC_BOARD:
|
|
1146
|
+
issue_type = self.__get_issue_types(project_key=project_key).get("task")
|
|
1147
|
+
elif CONFIG.STAGE and CONFIG.STAGE.lower() == "hypercare":
|
|
1092
1148
|
issue_type = self._issue_types.get("hypercare") or self._issue_types.get("epic")
|
|
1093
|
-
elif CONFIG.STAGE.lower() == "support":
|
|
1149
|
+
elif CONFIG.STAGE and CONFIG.STAGE.lower() == "support":
|
|
1094
1150
|
issue_type = self._issue_types.get("support") or self._issue_types.get("epic")
|
|
1095
|
-
elif CONFIG.STAGE.lower() == "delivery" and
|
|
1151
|
+
elif CONFIG.STAGE and CONFIG.STAGE.lower() == "delivery" and project_key == CONFIG.SUPPORT_BOARD:
|
|
1096
1152
|
issue_type = self._issue_types.get("development") or self._issue_types.get("epic")
|
|
1097
1153
|
else:
|
|
1098
1154
|
issue_type = (
|
|
@@ -1107,6 +1163,7 @@ class Jira:
|
|
|
1107
1163
|
description=description,
|
|
1108
1164
|
assignee=assignee_id,
|
|
1109
1165
|
issue_type=issue_type,
|
|
1166
|
+
project_key=project_key,
|
|
1110
1167
|
labels=labels,
|
|
1111
1168
|
priority=priority,
|
|
1112
1169
|
)
|
|
@@ -1118,6 +1175,7 @@ class Jira:
|
|
|
1118
1175
|
description=description,
|
|
1119
1176
|
assignee=assignee_id,
|
|
1120
1177
|
issue_type=issue_type,
|
|
1178
|
+
project_key=project_key,
|
|
1121
1179
|
priority=priority,
|
|
1122
1180
|
)
|
|
1123
1181
|
response = self.post_ticket(issue=issue)
|
|
@@ -1137,7 +1195,7 @@ class Jira:
|
|
|
1137
1195
|
for attachment in attachments:
|
|
1138
1196
|
if os.path.exists(str(attachment)):
|
|
1139
1197
|
self.add_attachment(attachment, ticket_id)
|
|
1140
|
-
if self._webhook_url and
|
|
1198
|
+
if self._webhook_url and project_key != CONFIG.SUPPORT_BOARD:
|
|
1141
1199
|
self.move_ticket_to_board(ticket_id)
|
|
1142
1200
|
return response
|
|
1143
1201
|
|
|
@@ -1248,6 +1306,8 @@ class Jira:
|
|
|
1248
1306
|
additional_info=additional_info,
|
|
1249
1307
|
metadata=metadata,
|
|
1250
1308
|
)
|
|
1309
|
+
if stack_trace and os.path.exists(stack_trace):
|
|
1310
|
+
os.remove(stack_trace)
|
|
1251
1311
|
return existing_ticket
|
|
1252
1312
|
|
|
1253
1313
|
if stack_trace:
|
|
@@ -1270,7 +1330,7 @@ class Jira:
|
|
|
1270
1330
|
metadata=metadata,
|
|
1271
1331
|
)
|
|
1272
1332
|
|
|
1273
|
-
priority = CONFIG.TICKET_PRIORITIES.HIGH if CONFIG.STAGE.lower() == "hypercare" else None
|
|
1333
|
+
priority = CONFIG.TICKET_PRIORITIES.HIGH if CONFIG.STAGE and CONFIG.STAGE.lower() == "hypercare" else None
|
|
1274
1334
|
|
|
1275
1335
|
response = self.__create_new_ticket(
|
|
1276
1336
|
summary=summary,
|
|
@@ -1284,7 +1344,8 @@ class Jira:
|
|
|
1284
1344
|
os.remove(stack_trace)
|
|
1285
1345
|
return response
|
|
1286
1346
|
except Exception as ex:
|
|
1287
|
-
logger.warning(f"Failed to create Jira issue due to: {ex
|
|
1347
|
+
logger.warning(f"Failed to create Jira issue due to: {type(ex)}: {ex}")
|
|
1348
|
+
self.report_internal_error(exception=ex, additional_info="Failed to report error.")
|
|
1288
1349
|
return False
|
|
1289
1350
|
|
|
1290
1351
|
def report_unhandled_error(
|
|
@@ -1314,6 +1375,8 @@ class Jira:
|
|
|
1314
1375
|
existing_ticket=existing_ticket,
|
|
1315
1376
|
summary=summary,
|
|
1316
1377
|
)
|
|
1378
|
+
if os.path.exists(stack_trace):
|
|
1379
|
+
os.remove(stack_trace)
|
|
1317
1380
|
return existing_ticket
|
|
1318
1381
|
|
|
1319
1382
|
assignee_id = None
|
|
@@ -1330,7 +1393,9 @@ class Jira:
|
|
|
1330
1393
|
error_id=error_id,
|
|
1331
1394
|
)
|
|
1332
1395
|
|
|
1333
|
-
priority =
|
|
1396
|
+
priority = (
|
|
1397
|
+
CONFIG.TICKET_PRIORITIES.HIGHEST if CONFIG.STAGE and CONFIG.STAGE.lower() == "hypercare" else None
|
|
1398
|
+
)
|
|
1334
1399
|
|
|
1335
1400
|
response = self.__create_new_ticket(
|
|
1336
1401
|
summary=summary,
|
|
@@ -1344,9 +1409,67 @@ class Jira:
|
|
|
1344
1409
|
os.remove(stack_trace)
|
|
1345
1410
|
return response
|
|
1346
1411
|
except Exception as ex:
|
|
1347
|
-
logger.warning(f"Failed to create Jira issue due to: {ex
|
|
1412
|
+
logger.warning(f"Failed to create Jira issue due to: {type(ex)}: {ex}")
|
|
1413
|
+
self.report_internal_error(exception=ex, additional_info="Failed to report unhandled error.")
|
|
1348
1414
|
return False
|
|
1349
1415
|
|
|
1416
|
+
def report_internal_error(self, exception: Exception, metadata: dict = None, additional_info: str = None):
|
|
1417
|
+
"""Report an internal error to Jira.
|
|
1418
|
+
|
|
1419
|
+
Args:
|
|
1420
|
+
exception (Exception): The exception to be added to the Jira issue.
|
|
1421
|
+
|
|
1422
|
+
Returns:
|
|
1423
|
+
The response from creating the Jira issue.
|
|
1424
|
+
"""
|
|
1425
|
+
try:
|
|
1426
|
+
if not exception:
|
|
1427
|
+
_, exception, _ = sys.exc_info()
|
|
1428
|
+
|
|
1429
|
+
attachments = [str(file) for file in Path().cwd().glob("stack_details_*.json")]
|
|
1430
|
+
|
|
1431
|
+
summary = self.__create_summary(type(exception), exception, exception.__traceback__)
|
|
1432
|
+
error_id = self.__generate_error_id(exc_type=type(exception), exc_traceback=exception.__traceback__)
|
|
1433
|
+
|
|
1434
|
+
existing_ticket = self.filter_tickets(
|
|
1435
|
+
all_tickets=self.get_issues(project_key=CONFIG.BC_BOARD)["issues"],
|
|
1436
|
+
error_id=error_id,
|
|
1437
|
+
)
|
|
1438
|
+
if existing_ticket:
|
|
1439
|
+
self.__update_existing_ticket(
|
|
1440
|
+
existing_ticket=existing_ticket,
|
|
1441
|
+
attachments=attachments,
|
|
1442
|
+
summary=summary,
|
|
1443
|
+
additional_info=additional_info,
|
|
1444
|
+
metadata=metadata,
|
|
1445
|
+
)
|
|
1446
|
+
for file in attachments:
|
|
1447
|
+
os.remove(file)
|
|
1448
|
+
return existing_ticket
|
|
1449
|
+
|
|
1450
|
+
description = self.__create_internal_error_markup(
|
|
1451
|
+
exc_type=type(exception),
|
|
1452
|
+
exc_value=exception,
|
|
1453
|
+
exc_traceback=exception.__traceback__,
|
|
1454
|
+
error_id=error_id,
|
|
1455
|
+
additional_info=additional_info,
|
|
1456
|
+
metadata=metadata,
|
|
1457
|
+
)
|
|
1458
|
+
|
|
1459
|
+
response = self.__create_new_ticket(
|
|
1460
|
+
summary=summary,
|
|
1461
|
+
description=description,
|
|
1462
|
+
project_key=CONFIG.BC_BOARD,
|
|
1463
|
+
attachments=attachments,
|
|
1464
|
+
labels=["bug_catcher"],
|
|
1465
|
+
)
|
|
1466
|
+
for file in attachments:
|
|
1467
|
+
os.remove(file)
|
|
1468
|
+
logger.info("Created Bug Catcher issue.")
|
|
1469
|
+
return response
|
|
1470
|
+
except Exception as ex:
|
|
1471
|
+
logger.warning(f"Failed to report Bug Catcher issue due to: {type(ex)}: {ex}")
|
|
1472
|
+
|
|
1350
1473
|
@retry_if_bad_request
|
|
1351
1474
|
def add_attachment(self, attachment: str, ticket_id: str) -> Optional[dict]:
|
|
1352
1475
|
"""Uploads an attachment to a Jira ticket.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import json
|
|
3
3
|
import linecache
|
|
4
|
-
import os
|
|
5
4
|
import re
|
|
6
5
|
import sys
|
|
7
6
|
from datetime import datetime
|
|
@@ -99,7 +98,6 @@ class StackSaver:
|
|
|
99
98
|
|
|
100
99
|
if secrets:
|
|
101
100
|
logger.warning("Failed to mask credentials")
|
|
102
|
-
os.remove(file_path)
|
|
103
101
|
raise Exception("Failed to mask credentials")
|
|
104
102
|
|
|
105
103
|
with open(file_path, "w") as file:
|
|
@@ -26,7 +26,7 @@ class Encoder(json.JSONEncoder):
|
|
|
26
26
|
try:
|
|
27
27
|
object_copy = copy.deepcopy(o)
|
|
28
28
|
except (TypeError, AttributeError):
|
|
29
|
-
return str(o)
|
|
29
|
+
return str(o)[: CONFIG.LIMITS.STACK_TEXT_LENGTH]
|
|
30
30
|
try:
|
|
31
31
|
if hasattr(object_copy, "__dict__"):
|
|
32
32
|
keys_to_remove = [
|
|
@@ -36,14 +36,17 @@ class Encoder(json.JSONEncoder):
|
|
|
36
36
|
]
|
|
37
37
|
for key in keys_to_remove:
|
|
38
38
|
del object_copy.__dict__[key]
|
|
39
|
-
return {
|
|
39
|
+
return {
|
|
40
|
+
str(key): str(value)[: CONFIG.LIMITS.STACK_TEXT_LENGTH]
|
|
41
|
+
for key, value in object_copy.__dict__.items()
|
|
42
|
+
}
|
|
40
43
|
if isinstance(object_copy, (datetime, date)):
|
|
41
44
|
return object_copy.isoformat()
|
|
42
45
|
if isinstance(object_copy, Path):
|
|
43
46
|
return str(object_copy)
|
|
44
47
|
return super().default(self, object_copy)
|
|
45
48
|
except TypeError:
|
|
46
|
-
return str(object_copy)
|
|
49
|
+
return str(object_copy)[: CONFIG.LIMITS.STACK_TEXT_LENGTH]
|
|
47
50
|
|
|
48
51
|
|
|
49
52
|
def get_frames(exc_traceback: TracebackType) -> List:
|
|
@@ -55,9 +58,12 @@ def get_frames(exc_traceback: TracebackType) -> List:
|
|
|
55
58
|
Returns:
|
|
56
59
|
List: The frames of the exception.
|
|
57
60
|
"""
|
|
58
|
-
|
|
61
|
+
frames = [
|
|
59
62
|
frame for frame in traceback.extract_tb(exc_traceback) if "site-packages" not in str(frame.filename).lower()
|
|
60
63
|
]
|
|
64
|
+
if not frames:
|
|
65
|
+
frames = [frame for frame in traceback.extract_tb(exc_traceback)]
|
|
66
|
+
return frames
|
|
61
67
|
|
|
62
68
|
|
|
63
69
|
def convert_keys_to_primitives(data: dict) -> dict:
|
|
@@ -71,7 +77,12 @@ def convert_keys_to_primitives(data: dict) -> dict:
|
|
|
71
77
|
"""
|
|
72
78
|
new_dict = {}
|
|
73
79
|
for key, value in data.items():
|
|
80
|
+
if isinstance(value, list) or isinstance(value, tuple):
|
|
81
|
+
value = value[: CONFIG.LIMITS.STACK_ITEM_LENGTH]
|
|
74
82
|
if isinstance(value, dict):
|
|
83
|
+
items_list = list(value.items())
|
|
84
|
+
sliced_list = items_list[: CONFIG.LIMITS.STACK_ITEM_LENGTH]
|
|
85
|
+
value = dict(sliced_list)
|
|
75
86
|
new_dict[str(key)] = convert_keys_to_primitives(value)
|
|
76
87
|
else:
|
|
77
88
|
new_dict[str(key)] = value
|
|
@@ -64,8 +64,8 @@ class TestBugCatcher(unittest.TestCase):
|
|
|
64
64
|
self.bug_catcher.report_error(exception=ex)
|
|
65
65
|
actual_call = mock_warning.call_args
|
|
66
66
|
warning_message = actual_call[0][0]
|
|
67
|
-
self.assertTrue(warning_message.startswith("Failed to
|
|
68
|
-
self.assertEqual(mock_warning.call_count,
|
|
67
|
+
self.assertTrue(warning_message.startswith("Failed to report Bug Catcher issue due to"))
|
|
68
|
+
self.assertEqual(mock_warning.call_count, 2)
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
if __name__ == "__main__":
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|