rpa-suite 1.6.1__py3-none-any.whl → 1.6.3__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.
- rpa_suite/__init__.py +1 -1
- rpa_suite/core/__init__.py +5 -1
- rpa_suite/core/artemis.py +445 -0
- rpa_suite/core/asyncrun.py +15 -8
- rpa_suite/core/browser.py +44 -41
- rpa_suite/core/clock.py +46 -13
- rpa_suite/core/date.py +41 -16
- rpa_suite/core/dir.py +29 -72
- rpa_suite/core/email.py +26 -15
- rpa_suite/core/file.py +46 -43
- rpa_suite/core/iris.py +146 -70
- rpa_suite/core/log.py +134 -46
- rpa_suite/core/parallel.py +185 -182
- rpa_suite/core/print.py +119 -96
- rpa_suite/core/regex.py +26 -26
- rpa_suite/core/validate.py +20 -76
- rpa_suite/functions/__init__.py +1 -1
- rpa_suite/suite.py +13 -1
- rpa_suite/utils/__init__.py +1 -1
- rpa_suite/utils/system.py +64 -61
- {rpa_suite-1.6.1.dist-info → rpa_suite-1.6.3.dist-info}/METADATA +8 -18
- rpa_suite-1.6.3.dist-info/RECORD +27 -0
- rpa_suite-1.6.1.dist-info/RECORD +0 -26
- {rpa_suite-1.6.1.dist-info → rpa_suite-1.6.3.dist-info}/WHEEL +0 -0
- {rpa_suite-1.6.1.dist-info → rpa_suite-1.6.3.dist-info}/licenses/LICENSE +0 -0
- {rpa_suite-1.6.1.dist-info → rpa_suite-1.6.3.dist-info}/top_level.txt +0 -0
rpa_suite/core/log.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# rpa_suite/core/log.py
|
2
2
|
|
3
3
|
# imports internal
|
4
|
-
from rpa_suite.functions._printer import
|
4
|
+
from rpa_suite.functions._printer import alert_print, success_print
|
5
5
|
|
6
6
|
# imports third party
|
7
7
|
from loguru import logger
|
@@ -11,49 +11,91 @@ from typing import Optional as Op
|
|
11
11
|
import sys
|
12
12
|
import os
|
13
13
|
import inspect
|
14
|
-
|
14
|
+
import traceback
|
15
|
+
|
16
|
+
class LogFiltersError(Exception):
|
17
|
+
"""Custom exception for LogFilters errors."""
|
18
|
+
def __init__(self, message):
|
19
|
+
clean_message = message.replace("LogFilters Error:", "").strip()
|
20
|
+
super().__init__(f'LogFilters Error: {clean_message}')
|
21
|
+
|
22
|
+
class LogCustomHandlerError(Exception):
|
23
|
+
"""Custom exception for LogCustomHandler errors."""
|
24
|
+
def __init__(self, message):
|
25
|
+
clean_message = message.replace("LogCustomHandler Error:", "").strip()
|
26
|
+
super().__init__(f'LogCustomHandler Error: {clean_message}')
|
27
|
+
|
28
|
+
class LogCustomFormatterError(Exception):
|
29
|
+
"""Custom exception for LogCustomFormatter errors."""
|
30
|
+
def __init__(self, message):
|
31
|
+
clean_message = message.replace("LogCustomFormatter Error:", "").strip()
|
32
|
+
super().__init__(f'LogCustomFormatter Error: {clean_message}')
|
33
|
+
|
34
|
+
class LogError(Exception):
|
35
|
+
"""Custom exception for Log errors."""
|
36
|
+
def __init__(self, message):
|
37
|
+
clean_message = message.replace("Log Error:", "").strip()
|
38
|
+
super().__init__(f'Log Error: {clean_message}')
|
15
39
|
|
16
40
|
class Filters:
|
41
|
+
"""
|
42
|
+
Filter class for log messages based on word filtering.
|
43
|
+
"""
|
17
44
|
word_filter: Op[list[str]]
|
18
45
|
|
19
|
-
def __call__(self, record):
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
for
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
46
|
+
def __call__(self, record: dict[str, str]):
|
47
|
+
try:
|
48
|
+
if self.word_filter and len(self.word_filter) > 0:
|
49
|
+
message = record["message"]
|
50
|
+
for words in self.word_filter:
|
51
|
+
string_words: list[str] = [str(word) for word in words]
|
52
|
+
for word in string_words:
|
53
|
+
if word in message:
|
54
|
+
record["message"] = message.replace(word, "***")
|
55
|
+
return True
|
56
|
+
return True
|
57
|
+
except Exception as e:
|
58
|
+
raise LogFiltersError(f"Error trying execute: {self.__call__.__name__}! {str(e)}.")
|
29
59
|
|
30
60
|
class CustomHandler:
|
61
|
+
"""
|
62
|
+
Custom handler for log messages with formatting capabilities.
|
63
|
+
"""
|
31
64
|
def __init__(self, formatter):
|
32
65
|
self.formatter = formatter
|
33
66
|
|
34
67
|
def write(self, message):
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
68
|
+
try:
|
69
|
+
frame = inspect.currentframe().f_back.f_back
|
70
|
+
log_msg = self.formatter.format(message, frame)
|
71
|
+
sys.stderr.write(log_msg)
|
72
|
+
except Exception as e:
|
73
|
+
raise LogCustomHandlerError(f"Error trying execute: {self.write.__name__}! {str(e)}.")
|
39
74
|
|
40
75
|
class CustomFormatter:
|
76
|
+
"""
|
77
|
+
Custom formatter for log messages with specific formatting rules.
|
78
|
+
"""
|
41
79
|
def format(self, record):
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
80
|
+
try:
|
81
|
+
filename = record["extra"].get("filename", "")
|
82
|
+
lineno = record["extra"].get("lineno", "")
|
83
|
+
format_string = "<green>{time:DD.MM.YY.HH:mm}</green> <level>{level: <8}</level> <green>{filename}</green>:<cyan>{lineno: <4}</cyan> <level>{message}</level>\n"
|
84
|
+
log_msg = format_string.format(
|
85
|
+
time=record["time"],
|
86
|
+
level=record["level"].name,
|
87
|
+
filename=filename,
|
88
|
+
lineno=lineno,
|
89
|
+
message=record["message"],
|
90
|
+
)
|
91
|
+
return log_msg
|
92
|
+
except Exception as e:
|
93
|
+
raise LogCustomFormatterError(f"Error trying execute: {self.format.__name__}! {str(e)}.")
|
55
94
|
|
56
95
|
class Log:
|
96
|
+
"""
|
97
|
+
Main logging class providing comprehensive logging functionality.
|
98
|
+
"""
|
57
99
|
filters: Filters
|
58
100
|
custom_handler: CustomHandler
|
59
101
|
custom_formatter: CustomFormatter
|
@@ -61,9 +103,16 @@ class Log:
|
|
61
103
|
name_file_log: str | None = None
|
62
104
|
full_path: str | None = None
|
63
105
|
file_handler = None
|
106
|
+
enable_traceback: bool = False # NEW PROPERTY
|
64
107
|
|
65
108
|
def __init__(self):
|
66
|
-
|
109
|
+
"""
|
110
|
+
Initialize the Log class with default loguru logger.
|
111
|
+
"""
|
112
|
+
try:
|
113
|
+
self.logger = logger
|
114
|
+
except Exception as e:
|
115
|
+
raise LogError(f"Error trying execute: {self.__init__.__name__}! {str(e)}.")
|
67
116
|
|
68
117
|
def config_logger(
|
69
118
|
self,
|
@@ -72,10 +121,23 @@ class Log:
|
|
72
121
|
name_file_log: str = "log",
|
73
122
|
filter_words: list[str] = None,
|
74
123
|
display_message: bool = False,
|
124
|
+
enable_traceback: bool = False, # NEW PARAMETER
|
75
125
|
):
|
126
|
+
"""
|
127
|
+
Configure the logger with specified parameters.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
path_dir: Directory path for log files
|
131
|
+
name_log_dir: Name of the log directory
|
132
|
+
name_file_log: Name of the log file
|
133
|
+
filter_words: List of words to filter from logs
|
134
|
+
display_message: Whether to display configuration messages
|
135
|
+
enable_traceback: Whether to include traceback in error logs
|
136
|
+
"""
|
76
137
|
try:
|
77
138
|
self.path_dir = path_dir
|
78
139
|
self.name_file_log = name_file_log
|
140
|
+
self.enable_traceback = enable_traceback # CONFIGURE THE PROPERTY
|
79
141
|
|
80
142
|
if self.path_dir == "default":
|
81
143
|
self.path_dir = os.getcwd()
|
@@ -86,12 +148,12 @@ class Log:
|
|
86
148
|
try:
|
87
149
|
os.makedirs(self.full_path, exist_ok=True)
|
88
150
|
if display_message:
|
89
|
-
success_print(f"
|
151
|
+
success_print(f"Directory:'{self.full_path}' was created successfully.")
|
90
152
|
except FileExistsError:
|
91
153
|
if display_message:
|
92
|
-
alert_print(f"
|
154
|
+
alert_print(f"Directory:'{self.full_path}' already exists.")
|
93
155
|
except PermissionError:
|
94
|
-
|
156
|
+
LogError(f"Permission denied: cannot create directory '{self.full_path}'.")
|
95
157
|
|
96
158
|
new_filter = None
|
97
159
|
if filter_words is not None:
|
@@ -115,12 +177,22 @@ class Log:
|
|
115
177
|
return file_handler
|
116
178
|
|
117
179
|
except Exception as e:
|
118
|
-
|
119
|
-
return None
|
180
|
+
raise LogError(f"Error trying execute: {self.config_logger.__name__}! {str(e)}.")
|
120
181
|
|
182
|
+
def _escape_traceback(self, tb_string: str) -> str:
|
183
|
+
"""
|
184
|
+
Escape special characters in traceback to avoid conflicts with Loguru colorizer.
|
185
|
+
"""
|
186
|
+
try:
|
187
|
+
# Escape characters that might be interpreted as color tags
|
188
|
+
escaped = tb_string.replace('<', '\\<').replace('>', '\\>')
|
189
|
+
return escaped
|
190
|
+
except Exception as e:
|
191
|
+
raise LogError(f"Error trying execute: {self._escape_traceback.__name__}! {str(e)}.")
|
192
|
+
|
121
193
|
def _log(self, level: str, msg: str):
|
122
194
|
"""
|
123
|
-
Method to
|
195
|
+
Method to generate logs used from self.
|
124
196
|
"""
|
125
197
|
try:
|
126
198
|
# Find the first frame that's not from this log.py file
|
@@ -137,42 +209,58 @@ class Log:
|
|
137
209
|
frame = inspect.currentframe().f_back.f_back
|
138
210
|
|
139
211
|
full_path_filename = frame.f_code.co_filename
|
140
|
-
|
141
|
-
# Normalize path to use os.sep
|
142
212
|
full_path_filename = os.path.normpath(full_path_filename)
|
143
|
-
|
144
|
-
# Get the last two components: parent folder and filename
|
145
213
|
parent_folder = os.path.basename(os.path.dirname(full_path_filename))
|
146
214
|
file_name = os.path.basename(full_path_filename)
|
147
215
|
display_filename = f"{parent_folder}/{file_name}"
|
148
|
-
|
149
216
|
lineno = frame.f_lineno
|
150
217
|
|
218
|
+
# IF TRACEBACK IS ENABLED AND IT'S ERROR LEVEL, ADD TRACEBACK
|
219
|
+
if self.enable_traceback and level in ["ERROR", "CRITICAL"]:
|
220
|
+
try:
|
221
|
+
# Capture current traceback if there's an active exception
|
222
|
+
tb_string = traceback.format_exc()
|
223
|
+
if tb_string != "NoneType: None\n": # Check if there's real traceback
|
224
|
+
# ESCAPE SPECIAL CHARACTERS IN TRACEBACK
|
225
|
+
escaped_traceback = self._escape_traceback(tb_string)
|
226
|
+
msg = f"{msg}\n{escaped_traceback}"
|
227
|
+
except Exception:
|
228
|
+
# If can't capture traceback, continue normally
|
229
|
+
pass
|
230
|
+
|
151
231
|
self.logger.bind(filename=display_filename, lineno=lineno).log(level, msg)
|
152
232
|
except Exception as e:
|
153
|
-
|
233
|
+
raise LogError(f"Error trying execute: {self._log.__name__}! {str(e)}.")
|
154
234
|
|
155
235
|
def log_start_run_debug(self, msg_start_loggin: str) -> None:
|
236
|
+
"""
|
237
|
+
Log a debug message to start a new run session.
|
238
|
+
"""
|
156
239
|
try:
|
157
240
|
with open(self.file_handler, "a") as log_file:
|
158
|
-
log_file.write("\n")
|
241
|
+
log_file.write("\n")
|
159
242
|
self._log("DEBUG", msg_start_loggin)
|
160
243
|
except Exception as e:
|
161
|
-
|
162
|
-
f"
|
244
|
+
raise LogError(
|
245
|
+
f"Error trying execute: {self.log_start_run_debug.__name__}! see log directory and configuration to config_logger: {str(e)}."
|
163
246
|
)
|
164
247
|
|
165
248
|
def log_debug(self, msg: str) -> None:
|
249
|
+
"""Log a debug level message."""
|
166
250
|
self._log("DEBUG", msg)
|
167
251
|
|
168
252
|
def log_info(self, msg: str) -> None:
|
253
|
+
"""Log an info level message."""
|
169
254
|
self._log("INFO", msg)
|
170
255
|
|
171
256
|
def log_warning(self, msg: str) -> None:
|
257
|
+
"""Log a warning level message."""
|
172
258
|
self._log("WARNING", msg)
|
173
259
|
|
174
260
|
def log_error(self, msg: str) -> None:
|
261
|
+
"""Log an error level message."""
|
175
262
|
self._log("ERROR", msg)
|
176
263
|
|
177
264
|
def log_critical(self, msg: str) -> None:
|
178
|
-
|
265
|
+
"""Log a critical level message."""
|
266
|
+
self._log("CRITICAL", msg)
|