-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathexception.py
More file actions
115 lines (96 loc) · 3.65 KB
/
Copy pathexception.py
File metadata and controls
115 lines (96 loc) · 3.65 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""Base exception class for UiPath runtime errors with structured error information."""
import sys
import traceback
from typing import Any
from uipath.core.errors import UiPathFaultedTriggerError
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,
)
@classmethod
def from_resume_trigger_error(
cls, exc: UiPathFaultedTriggerError
) -> "UiPathRuntimeError":
"""Create UiPathRuntimeError from UiPathFaultedTriggerError."""
return cls(
code=UiPathErrorCode.RESUME_TRIGGER_ERROR,
title="Resume trigger error",
detail=exc.message,
category=UiPathErrorCategory(exc.category),
)