-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathexception.py
More file actions
101 lines (84 loc) · 3.19 KB
/
Copy pathexception.py
File metadata and controls
101 lines (84 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""Base exception class for UiPath runtime errors with structured error information."""
import sys
import traceback
from typing import Any
from uipath.runtime.errors.codes import UiPathErrorCode
from uipath.runtime.errors.contract import UiPathErrorCategory, UiPathErrorContract
class UiPathBaseRuntimeError(Exception):
"""Base exception class for UiPath runtime errors with structured error information."""
def __init__(
self,
code: str,
title: str,
detail: str,
category: UiPathErrorCategory = UiPathErrorCategory.UNKNOWN,
status: int | None = None,
prefix: str = "Python",
include_traceback: bool = True,
):
"""Initialize the UiPathBaseRuntimeError with structured error information."""
# Get the current traceback as a string
if include_traceback:
tb = traceback.format_exc()
if (
tb and tb.strip() != "NoneType: None"
): # Ensure there's an actual traceback
detail = f"{detail}\n\n{tb}"
if status is None:
status = self._extract_http_status()
self.error_info = UiPathErrorContract(
code=f"{prefix}.{code}",
title=title,
detail=detail,
category=category,
status=status,
)
super().__init__(detail)
def _extract_http_status(self) -> int | None:
"""Extract HTTP status code from the exception chain if present."""
exc_info = sys.exc_info()
if not exc_info or len(exc_info) < 2 or exc_info[1] is None:
return None
exc: BaseException | None = exc_info[1] # Current exception being handled
while exc is not None:
if hasattr(exc, "status_code"):
return exc.status_code
if hasattr(exc, "response") and hasattr(exc.response, "status_code"):
return exc.response.status_code
# Move to the next exception in the chain
next_exc = getattr(exc, "__cause__", None) or getattr(
exc, "__context__", None
)
# Ensure next_exc is a BaseException or None
exc = (
next_exc
if isinstance(next_exc, BaseException) or next_exc is None
else None
)
return None
@property
def as_dict(self) -> dict[str, Any]:
"""Get the error information as a dictionary."""
return self.error_info.model_dump()
class UiPathRuntimeError(UiPathBaseRuntimeError):
"""Exception class for UiPath runtime errors."""
def __init__(
self,
code: UiPathErrorCode,
title: str,
detail: str,
category: UiPathErrorCategory = UiPathErrorCategory.UNKNOWN,
status: int | None = None,
prefix: str = "Python",
include_traceback: bool = True,
):
"""Initialize the UiPathRuntimeError with structured error information."""
super().__init__(
code=code.value,
title=title,
detail=detail,
category=category,
status=status,
prefix=prefix,
include_traceback=include_traceback,
)