orionis 0.405.0__py3-none-any.whl → 0.406.0__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.
- orionis/console/base/command.py +57 -50
- orionis/console/base/contracts/command.py +68 -0
- orionis/console/dynamic/contracts/progress_bar.py +3 -3
- orionis/console/dynamic/progress_bar.py +8 -8
- orionis/console/output/console.py +8 -2
- orionis/console/output/contracts/console.py +1 -1
- orionis/container/container.py +2 -2
- orionis/container/context/scope.py +4 -1
- orionis/container/contracts/service_provider.py +2 -2
- orionis/container/entities/binding.py +31 -44
- orionis/container/enums/lifetimes.py +22 -1
- orionis/container/facades/facade.py +1 -2
- orionis/container/providers/service_provider.py +2 -2
- orionis/foundation/application.py +542 -248
- orionis/foundation/config/app/entities/app.py +107 -90
- orionis/foundation/config/auth/entities/auth.py +4 -33
- orionis/foundation/config/cache/entities/cache.py +18 -41
- orionis/foundation/config/cache/entities/file.py +8 -35
- orionis/foundation/config/cache/entities/stores.py +17 -38
- orionis/foundation/config/cors/entities/cors.py +41 -54
- orionis/foundation/config/database/entities/connections.py +40 -56
- orionis/foundation/config/database/entities/database.py +11 -38
- orionis/foundation/config/database/entities/mysql.py +48 -76
- orionis/foundation/config/database/entities/oracle.py +30 -57
- orionis/foundation/config/database/entities/pgsql.py +45 -61
- orionis/foundation/config/database/entities/sqlite.py +26 -53
- orionis/foundation/config/filesystems/entitites/aws.py +28 -49
- orionis/foundation/config/filesystems/entitites/disks.py +27 -47
- orionis/foundation/config/filesystems/entitites/filesystems.py +15 -37
- orionis/foundation/config/filesystems/entitites/local.py +9 -35
- orionis/foundation/config/filesystems/entitites/public.py +14 -41
- orionis/foundation/config/logging/entities/channels.py +56 -86
- orionis/foundation/config/logging/entities/chunked.py +9 -9
- orionis/foundation/config/logging/entities/daily.py +8 -8
- orionis/foundation/config/logging/entities/hourly.py +6 -6
- orionis/foundation/config/logging/entities/logging.py +12 -18
- orionis/foundation/config/logging/entities/monthly.py +7 -7
- orionis/foundation/config/logging/entities/stack.py +5 -5
- orionis/foundation/config/logging/entities/weekly.py +6 -6
- orionis/foundation/config/mail/entities/file.py +9 -36
- orionis/foundation/config/mail/entities/mail.py +22 -40
- orionis/foundation/config/mail/entities/mailers.py +29 -44
- orionis/foundation/config/mail/entities/smtp.py +47 -48
- orionis/foundation/config/queue/entities/brokers.py +19 -41
- orionis/foundation/config/queue/entities/database.py +24 -46
- orionis/foundation/config/queue/entities/queue.py +28 -40
- orionis/foundation/config/roots/paths.py +272 -468
- orionis/foundation/config/session/entities/session.py +23 -53
- orionis/foundation/config/startup.py +165 -135
- orionis/foundation/config/testing/entities/testing.py +137 -122
- orionis/foundation/config/testing/enums/__init__.py +6 -2
- orionis/foundation/config/testing/enums/drivers.py +16 -0
- orionis/foundation/config/testing/enums/verbosity.py +18 -0
- orionis/foundation/contracts/application.py +152 -362
- orionis/foundation/providers/console_provider.py +24 -2
- orionis/foundation/providers/dumper_provider.py +24 -2
- orionis/foundation/providers/logger_provider.py +24 -2
- orionis/foundation/providers/path_resolver_provider.py +25 -2
- orionis/foundation/providers/progress_bar_provider.py +24 -2
- orionis/foundation/providers/testing_provider.py +39 -0
- orionis/foundation/providers/workers_provider.py +24 -2
- orionis/metadata/framework.py +1 -1
- orionis/services/environment/helpers/functions.py +1 -2
- orionis/services/environment/key/__init__.py +0 -0
- orionis/services/environment/key/key_generator.py +37 -0
- orionis/support/entities/__init__.py +0 -0
- orionis/support/entities/base.py +104 -0
- orionis/support/facades/testing.py +15 -0
- orionis/support/facades/workers.py +1 -1
- orionis/test/cases/asynchronous.py +0 -11
- orionis/test/cases/synchronous.py +0 -9
- orionis/test/contracts/dumper.py +11 -4
- orionis/test/contracts/kernel.py +5 -110
- orionis/test/contracts/logs.py +27 -65
- orionis/test/contracts/printer.py +16 -128
- orionis/test/contracts/test_result.py +100 -0
- orionis/test/contracts/unit_test.py +87 -150
- orionis/test/core/unit_test.py +608 -554
- orionis/test/entities/result.py +22 -2
- orionis/test/enums/__init__.py +0 -2
- orionis/test/enums/status.py +14 -9
- orionis/test/exceptions/config.py +9 -1
- orionis/test/exceptions/failure.py +34 -11
- orionis/test/exceptions/persistence.py +10 -2
- orionis/test/exceptions/runtime.py +9 -1
- orionis/test/exceptions/value.py +13 -1
- orionis/test/kernel.py +87 -289
- orionis/test/output/dumper.py +82 -18
- orionis/test/output/printer.py +399 -156
- orionis/test/records/logs.py +203 -82
- orionis/test/validators/__init__.py +33 -0
- orionis/test/validators/base_path.py +45 -0
- orionis/test/validators/execution_mode.py +45 -0
- orionis/test/validators/fail_fast.py +37 -0
- orionis/test/validators/folder_path.py +34 -0
- orionis/test/validators/module_name.py +31 -0
- orionis/test/validators/name_pattern.py +40 -0
- orionis/test/validators/pattern.py +36 -0
- orionis/test/validators/persistent.py +42 -0
- orionis/test/validators/persistent_driver.py +43 -0
- orionis/test/validators/print_result.py +37 -0
- orionis/test/validators/tags.py +37 -0
- orionis/test/validators/throw_exception.py +39 -0
- orionis/test/validators/verbosity.py +37 -0
- orionis/test/validators/web_report.py +35 -0
- orionis/test/validators/workers.py +31 -0
- orionis/test/view/render.py +48 -54
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/METADATA +1 -1
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/RECORD +149 -98
- tests/container/__init__.py +0 -0
- tests/container/context/__init__.py +0 -0
- tests/container/context/test_manager.py +27 -0
- tests/container/context/test_scope.py +23 -0
- tests/container/entities/__init__.py +0 -0
- tests/container/entities/test_binding.py +133 -0
- tests/container/enums/__init__.py +0 -0
- tests/container/enums/test_lifetimes.py +63 -0
- tests/container/facades/__init__.py +0 -0
- tests/container/facades/test_facade.py +61 -0
- tests/container/mocks/__init__.py +0 -0
- tests/container/mocks/mock_complex_classes.py +482 -0
- tests/container/mocks/mock_simple_classes.py +32 -0
- tests/container/providers/__init__.py +0 -0
- tests/container/providers/test_providers.py +48 -0
- tests/container/resolver/__init__.py +0 -0
- tests/container/resolver/test_resolver.py +55 -0
- tests/container/test_container.py +254 -0
- tests/container/test_singleton.py +98 -0
- tests/container/test_thread_safety.py +217 -0
- tests/container/validators/__init__.py +0 -0
- tests/container/validators/test_implements.py +140 -0
- tests/container/validators/test_is_abstract_class.py +99 -0
- tests/container/validators/test_is_callable.py +73 -0
- tests/container/validators/test_is_concrete_class.py +97 -0
- tests/container/validators/test_is_instance.py +105 -0
- tests/container/validators/test_is_not_subclass.py +117 -0
- tests/container/validators/test_is_subclass.py +115 -0
- tests/container/validators/test_is_valid_alias.py +113 -0
- tests/container/validators/test_lifetime.py +75 -0
- tests/foundation/config/testing/test_foundation_config_testing.py +1 -1
- tests/metadata/test_metadata_framework.py +18 -18
- tests/testing/test_testing_result.py +117 -117
- tests/testing/test_testing_unit.py +209 -209
- orionis/foundation/config/base.py +0 -112
- orionis/test/arguments/parser.py +0 -187
- orionis/test/contracts/parser.py +0 -43
- orionis/test/entities/arguments.py +0 -38
- orionis/test/enums/execution_mode.py +0 -16
- /orionis/{test/arguments → console/base/contracts}/__init__.py +0 -0
- /orionis/foundation/config/testing/enums/{test_mode.py → mode.py} +0 -0
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/WHEEL +0 -0
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/top_level.txt +0 -0
- {orionis-0.405.0.dist-info → orionis-0.406.0.dist-info}/zip-safe +0 -0
orionis/test/output/printer.py
CHANGED
|
@@ -9,211 +9,299 @@ from rich.table import Table
|
|
|
9
9
|
from rich.text import Text
|
|
10
10
|
from orionis.services.introspection.instances.reflection import ReflectionInstance
|
|
11
11
|
from orionis.test.contracts.printer import ITestPrinter
|
|
12
|
+
from orionis.test.entities.result import TestResult
|
|
12
13
|
from orionis.test.enums import TestStatus
|
|
13
14
|
|
|
14
15
|
class TestPrinter(ITestPrinter):
|
|
15
16
|
|
|
16
17
|
def __init__(
|
|
17
|
-
self
|
|
18
|
+
self,
|
|
19
|
+
print_result: bool = True,
|
|
20
|
+
title: str = "🧪 Orionis Framework - Component Test Suite",
|
|
21
|
+
width: int = 75
|
|
18
22
|
) -> None:
|
|
19
23
|
"""
|
|
20
|
-
Initialize
|
|
24
|
+
Initialize a TestPrinter instance for formatted test output.
|
|
21
25
|
|
|
22
|
-
This
|
|
23
|
-
|
|
26
|
+
This constructor sets up the Rich Console for rendering output, configures
|
|
27
|
+
the panel title and width for display, and defines keywords used to detect
|
|
28
|
+
debugging calls in test code.
|
|
24
29
|
|
|
25
30
|
Parameters
|
|
26
31
|
----------
|
|
27
|
-
|
|
32
|
+
print_result : bool, optional
|
|
33
|
+
Whether to print test results to the console (default is True).
|
|
34
|
+
title : str, optional
|
|
35
|
+
The title to display in the output panel (default is "🧪 Orionis Framework - Component Test Suite").
|
|
36
|
+
width : int, optional
|
|
37
|
+
The width of the output panel as a percentage of the console width (default is 75).
|
|
28
38
|
|
|
29
39
|
Returns
|
|
30
40
|
-------
|
|
31
41
|
None
|
|
42
|
+
This method does not return a value. It initializes instance attributes for output formatting.
|
|
32
43
|
|
|
33
44
|
Notes
|
|
34
45
|
-----
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
- Initializes the following attributes:
|
|
47
|
+
- __rich_console: Rich Console instance for formatted terminal output.
|
|
48
|
+
- __panel_title: Title string for the output panel.
|
|
49
|
+
- __panel_width: Width of the output panel, calculated as a percentage of the console width.
|
|
50
|
+
- __debbug_keywords: List of keywords for identifying debug calls in test code.
|
|
51
|
+
- __print_result: Flag indicating whether to print results.
|
|
40
52
|
"""
|
|
53
|
+
# Create a Rich Console instance for output rendering
|
|
41
54
|
self.__rich_console = Console()
|
|
42
|
-
|
|
43
|
-
|
|
55
|
+
|
|
56
|
+
# Set the panel title for display
|
|
57
|
+
self.__panel_title: str = title
|
|
58
|
+
|
|
59
|
+
# Calculate the panel width as a percentage of the console width
|
|
60
|
+
self.__panel_width: int = int(self.__rich_console.width * (width / 100))
|
|
61
|
+
|
|
62
|
+
# Define keywords to detect debugging or dump calls in test code
|
|
44
63
|
self.__debbug_keywords: list = ['self.dd', 'self.dump']
|
|
45
64
|
|
|
65
|
+
# Store the flag indicating whether to print results
|
|
66
|
+
self.__print_result: bool = print_result
|
|
67
|
+
|
|
46
68
|
def print(
|
|
47
69
|
self,
|
|
48
70
|
value: Any
|
|
49
71
|
) -> None:
|
|
50
72
|
"""
|
|
51
|
-
|
|
73
|
+
Print a value to the console using the Rich library's console.
|
|
74
|
+
|
|
75
|
+
This method provides a unified way to output various types of values to the console,
|
|
76
|
+
leveraging Rich's formatting capabilities. It handles strings, objects, and lists,
|
|
77
|
+
ensuring each is displayed appropriately.
|
|
78
|
+
|
|
52
79
|
Parameters
|
|
53
80
|
----------
|
|
54
81
|
value : Any
|
|
55
|
-
The value to be printed.
|
|
82
|
+
The value to be printed. Can be a string, object, or list.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
None
|
|
87
|
+
This method does not return any value. It outputs the provided value(s) to the console.
|
|
88
|
+
|
|
56
89
|
Notes
|
|
57
90
|
-----
|
|
58
91
|
- If the value is a string, it is printed directly.
|
|
59
|
-
- If the value is
|
|
60
|
-
-
|
|
92
|
+
- If the value is a list, each item in the list is printed on a new line.
|
|
93
|
+
- For any other object, its string representation is printed.
|
|
61
94
|
"""
|
|
95
|
+
|
|
96
|
+
# If not printing results, return early
|
|
97
|
+
if self.__print_result is False:
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
# If the value is a string, print it directly
|
|
62
101
|
if isinstance(value, str):
|
|
63
102
|
self.__rich_console.print(value)
|
|
64
|
-
|
|
65
|
-
|
|
103
|
+
|
|
104
|
+
# If the value is a list, print each item on a new line
|
|
66
105
|
elif isinstance(value, list):
|
|
67
106
|
for item in value:
|
|
68
107
|
self.__rich_console.print(item)
|
|
108
|
+
|
|
109
|
+
# For any other object, print its string representation
|
|
69
110
|
else:
|
|
70
111
|
self.__rich_console.print(str(value))
|
|
71
112
|
|
|
72
113
|
def startMessage(
|
|
73
114
|
self,
|
|
74
115
|
*,
|
|
75
|
-
print_result: bool,
|
|
76
116
|
length_tests: int,
|
|
77
117
|
execution_mode: str,
|
|
78
118
|
max_workers: int
|
|
79
119
|
):
|
|
80
120
|
"""
|
|
81
|
-
|
|
121
|
+
Display a formatted start message for the test execution session.
|
|
122
|
+
|
|
123
|
+
This method prints a styled panel to the console at the beginning of a test run,
|
|
124
|
+
providing key information about the test session such as the total number of tests,
|
|
125
|
+
the execution mode (parallel or sequential), and the start time. The output is
|
|
126
|
+
rendered using the Rich library for enhanced readability.
|
|
82
127
|
|
|
83
128
|
Parameters
|
|
84
129
|
----------
|
|
85
|
-
print_result : bool
|
|
86
|
-
Whether to print the start message.
|
|
87
130
|
length_tests : int
|
|
88
|
-
The total number of tests to be executed.
|
|
131
|
+
The total number of tests to be executed in the session.
|
|
89
132
|
execution_mode : str
|
|
90
|
-
The mode of execution
|
|
133
|
+
The mode of execution for the tests. Accepts "parallel" or "sequential".
|
|
91
134
|
max_workers : int
|
|
92
|
-
The number of worker threads
|
|
135
|
+
The number of worker threads or processes to use if running in parallel mode.
|
|
93
136
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
None
|
|
140
|
+
This method does not return any value. It only prints formatted output to the console.
|
|
141
|
+
|
|
142
|
+
Notes
|
|
143
|
+
-----
|
|
144
|
+
- The message is only printed if the `print_result` flag is set to True.
|
|
145
|
+
- The panel includes the total number of tests, execution mode, and the current timestamp.
|
|
97
146
|
"""
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
147
|
+
|
|
148
|
+
# If not printing results, return early
|
|
149
|
+
if self.__print_result is False:
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
# Determine the execution mode text for display
|
|
153
|
+
mode_text = f"[stat]Parallel with {max_workers} workers[/stat]" if execution_mode == "parallel" else "Sequential"
|
|
154
|
+
|
|
155
|
+
# Prepare the lines of information to display in the panel
|
|
156
|
+
textlines = [
|
|
157
|
+
f"[bold]Total Tests:[/bold] [dim]{length_tests}[/dim]",
|
|
158
|
+
f"[bold]Mode:[/bold] [dim]{mode_text}[/dim]",
|
|
159
|
+
f"[bold]Started at:[/bold] [dim]{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}[/dim]"
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
# Add a blank line before the panel
|
|
163
|
+
self.__rich_console.line(1)
|
|
164
|
+
|
|
165
|
+
# Print the panel with the formatted text lines
|
|
166
|
+
self.__rich_console.print(
|
|
167
|
+
Panel(
|
|
168
|
+
str('\n').join(textlines),
|
|
169
|
+
border_style="blue",
|
|
170
|
+
title=self.__panel_title,
|
|
171
|
+
title_align="center",
|
|
172
|
+
width=self.__panel_width,
|
|
173
|
+
padding=(0, 1)
|
|
116
174
|
)
|
|
117
|
-
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Add a blank line after the panel
|
|
178
|
+
self.__rich_console.line(1)
|
|
118
179
|
|
|
119
180
|
def finishMessage(
|
|
120
181
|
self,
|
|
121
182
|
*,
|
|
122
|
-
print_result: bool,
|
|
123
183
|
summary: Dict[str, Any]
|
|
124
184
|
) -> None:
|
|
125
185
|
"""
|
|
126
|
-
Display a summary message for the test suite execution.
|
|
186
|
+
Display a final summary message for the test suite execution in a styled panel.
|
|
187
|
+
|
|
188
|
+
This method prints a completion message at the end of the test run, summarizing the overall
|
|
189
|
+
status and total execution time. The message includes a status icon (✅ for success, ❌ for failure)
|
|
190
|
+
based on whether any tests failed or errored. The output is formatted using the Rich library
|
|
191
|
+
for enhanced readability.
|
|
127
192
|
|
|
128
193
|
Parameters
|
|
129
194
|
----------
|
|
130
195
|
summary : dict
|
|
131
|
-
Dictionary containing the test suite summary
|
|
132
|
-
|
|
196
|
+
Dictionary containing the test suite summary. Must include the following keys:
|
|
197
|
+
- 'failed': int, number of failed tests
|
|
198
|
+
- 'errors': int, number of errored tests
|
|
199
|
+
- 'total_time': float, total duration of the test suite execution in seconds
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
None
|
|
204
|
+
This method does not return any value. It outputs a formatted completion message to the console.
|
|
133
205
|
|
|
134
206
|
Notes
|
|
135
207
|
-----
|
|
136
|
-
- If `self.
|
|
137
|
-
-
|
|
138
|
-
|
|
139
|
-
- Formats and prints the message within a styled panel using the `rich` library.
|
|
208
|
+
- If `self.__print_result` is False, the method returns without displaying anything.
|
|
209
|
+
- The status icon reflects the presence of failures or errors in the test suite.
|
|
210
|
+
- The message is displayed within a styled Rich panel for clarity.
|
|
140
211
|
"""
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
212
|
+
|
|
213
|
+
# If not printing results, return early
|
|
214
|
+
if self.__print_result is False:
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
# Determine status icon based on failures and errors
|
|
218
|
+
status_icon = "✅" if (summary['failed'] + summary['errors']) == 0 else "❌"
|
|
219
|
+
|
|
220
|
+
# Prepare the completion message with total execution time
|
|
221
|
+
msg = f"Test suite completed in {summary['total_time']:.2f} seconds"
|
|
222
|
+
|
|
223
|
+
# Print the message inside a styled Rich panel
|
|
224
|
+
self.__rich_console.print(
|
|
225
|
+
Panel(
|
|
226
|
+
msg,
|
|
227
|
+
border_style="blue",
|
|
228
|
+
title=f"{status_icon} Test Suite Finished",
|
|
229
|
+
title_align='left',
|
|
230
|
+
width=self.__panel_width,
|
|
231
|
+
padding=(0, 1)
|
|
153
232
|
)
|
|
154
|
-
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Add a blank line after the panel for spacing
|
|
236
|
+
self.__rich_console.line(1)
|
|
155
237
|
|
|
156
238
|
def executePanel(
|
|
157
239
|
self,
|
|
158
240
|
*,
|
|
159
|
-
print_result: bool,
|
|
160
241
|
flatten_test_suite: list,
|
|
161
242
|
callable: callable
|
|
162
243
|
):
|
|
163
244
|
"""
|
|
164
|
-
|
|
245
|
+
Execute a test suite panel with optional live console output and debugging detection.
|
|
246
|
+
|
|
247
|
+
This method manages the display of a running message panel using the Rich library,
|
|
248
|
+
adapting its behavior based on whether debugging or dump calls are detected in the test suite
|
|
249
|
+
and whether result printing is enabled. If debugging or dump calls are present in the test code,
|
|
250
|
+
a static panel is shown before executing the test suite. Otherwise, a live panel is displayed
|
|
251
|
+
during execution for a more dynamic user experience.
|
|
165
252
|
|
|
166
253
|
Parameters
|
|
167
254
|
----------
|
|
168
|
-
print_result : bool
|
|
169
|
-
If True, displays a running message panel while executing the test suite.
|
|
170
255
|
flatten_test_suite : list
|
|
171
|
-
The flattened list of test
|
|
256
|
+
The flattened list of test case instances or test suite items to be executed.
|
|
172
257
|
callable : callable
|
|
173
258
|
The function or method to execute the test suite.
|
|
174
259
|
|
|
175
260
|
Returns
|
|
176
261
|
-------
|
|
177
262
|
Any
|
|
178
|
-
|
|
263
|
+
Returns the result produced by the provided callable after execution, which typically
|
|
264
|
+
contains the outcome of the test suite run (such as a summary or result object).
|
|
179
265
|
|
|
180
266
|
Notes
|
|
181
267
|
-----
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
If
|
|
185
|
-
real-time updates. Otherwise, a static panel is shown before executing the test suite.
|
|
268
|
+
- If debugging or dump calls are detected in the test code, a static panel is displayed.
|
|
269
|
+
- If no debugging or dump calls are found and result printing is enabled, a live panel is shown.
|
|
270
|
+
- If result printing is disabled, the test suite is executed without any panel display.
|
|
186
271
|
"""
|
|
187
272
|
|
|
188
|
-
#
|
|
273
|
+
# Determine if the test suite contains active debugging or dump calls
|
|
189
274
|
use_debugger = self.__withDebugger(
|
|
190
275
|
flatten_test_suite=flatten_test_suite
|
|
191
276
|
)
|
|
192
277
|
|
|
193
|
-
#
|
|
194
|
-
if
|
|
195
|
-
message = "[bold yellow]⏳ Running tests...[/bold yellow]\n"
|
|
196
|
-
message += "[dim]This may take a few seconds. Please wait...[/dim]" if use_debugger else "[dim]Please wait, results will appear below...[/dim]"
|
|
278
|
+
# Only display output if printing results is enabled
|
|
279
|
+
if self.__print_result:
|
|
197
280
|
|
|
198
|
-
#
|
|
281
|
+
# Prepare a minimal running message as a single line, using the configured panel width
|
|
199
282
|
running_panel = Panel(
|
|
200
|
-
|
|
283
|
+
"[yellow]⏳ Running...[/yellow]",
|
|
201
284
|
border_style="yellow",
|
|
202
|
-
title="In Progress",
|
|
203
|
-
title_align="left",
|
|
204
285
|
width=self.__panel_width,
|
|
205
|
-
padding=(
|
|
286
|
+
padding=(0, 1)
|
|
206
287
|
)
|
|
207
288
|
|
|
208
|
-
#
|
|
209
|
-
if use_debugger:
|
|
289
|
+
# If no debugger/dump calls, use a live panel for dynamic updates
|
|
290
|
+
if not use_debugger:
|
|
291
|
+
|
|
292
|
+
# Execute the test suite and return its result
|
|
210
293
|
with Live(running_panel, console=self.__rich_console, refresh_per_second=4, transient=True):
|
|
211
294
|
return callable()
|
|
295
|
+
|
|
212
296
|
else:
|
|
297
|
+
|
|
298
|
+
# If debugger/dump calls are present, print a static panel before running
|
|
213
299
|
self.__rich_console.print(running_panel)
|
|
214
300
|
return callable()
|
|
301
|
+
|
|
215
302
|
else:
|
|
216
|
-
|
|
303
|
+
|
|
304
|
+
# If result printing is disabled, execute the test suite without any panel
|
|
217
305
|
return callable()
|
|
218
306
|
|
|
219
307
|
def linkWebReport(
|
|
@@ -221,16 +309,42 @@ class TestPrinter(ITestPrinter):
|
|
|
221
309
|
path: str
|
|
222
310
|
):
|
|
223
311
|
"""
|
|
224
|
-
|
|
312
|
+
Display a styled message inviting the user to view the test results report.
|
|
313
|
+
|
|
314
|
+
This method prints an elegant invitation to the console, indicating that the test results
|
|
315
|
+
have been saved and providing a clickable or visually distinct path to the report. The output
|
|
316
|
+
uses Rich's Text styling to highlight the message and underline the report path for emphasis.
|
|
225
317
|
|
|
226
318
|
Parameters
|
|
227
319
|
----------
|
|
228
|
-
path : str
|
|
229
|
-
The path to the test results report.
|
|
320
|
+
path : str
|
|
321
|
+
The file system path or URL to the test results report.
|
|
322
|
+
|
|
323
|
+
Returns
|
|
324
|
+
-------
|
|
325
|
+
None
|
|
326
|
+
This method does not return any value. It outputs a formatted message to the console.
|
|
327
|
+
|
|
328
|
+
Notes
|
|
329
|
+
-----
|
|
330
|
+
- The invitation message is styled with green text for success and an underlined blue path for visibility.
|
|
331
|
+
- Intended to be called after test execution to direct users to the generated report.
|
|
230
332
|
"""
|
|
333
|
+
|
|
334
|
+
# If not printing results, do not display the link
|
|
335
|
+
if self.__print_result is False:
|
|
336
|
+
return
|
|
337
|
+
|
|
338
|
+
# Create the base invitation text with a green style
|
|
231
339
|
invite_text = Text("Test results saved. ", style="green")
|
|
340
|
+
|
|
341
|
+
# Append a bold green prompt to view the report
|
|
232
342
|
invite_text.append("View report: ", style="bold green")
|
|
343
|
+
|
|
344
|
+
# Append the report path, styled as underlined blue for emphasis
|
|
233
345
|
invite_text.append(str(path), style="underline blue")
|
|
346
|
+
|
|
347
|
+
# Print the composed invitation message to the console
|
|
234
348
|
self.__rich_console.print(invite_text)
|
|
235
349
|
|
|
236
350
|
def summaryTable(
|
|
@@ -238,37 +352,49 @@ class TestPrinter(ITestPrinter):
|
|
|
238
352
|
summary: Dict[str, Any]
|
|
239
353
|
) -> None:
|
|
240
354
|
"""
|
|
241
|
-
|
|
355
|
+
Display a summary table of test results using the Rich library.
|
|
356
|
+
|
|
357
|
+
This method prints a formatted table summarizing the results of a test suite execution.
|
|
358
|
+
The table includes the total number of tests, counts of passed, failed, errored, and skipped tests,
|
|
359
|
+
the total execution duration, and the overall success rate. The output is styled for readability
|
|
360
|
+
and is only displayed if result printing is enabled.
|
|
242
361
|
|
|
243
362
|
Parameters
|
|
244
363
|
----------
|
|
245
364
|
summary : dict
|
|
246
|
-
Dictionary
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
Number of tests that
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
Number of tests that had errors.
|
|
255
|
-
skipped : int
|
|
256
|
-
Number of tests that were skipped.
|
|
257
|
-
total_time : float
|
|
258
|
-
Total duration of the test execution in seconds.
|
|
259
|
-
success_rate : float
|
|
260
|
-
Percentage of tests that passed.
|
|
365
|
+
Dictionary containing the test summary data. Must include the following keys:
|
|
366
|
+
- total_tests (int): Total number of tests executed.
|
|
367
|
+
- passed (int): Number of tests that passed.
|
|
368
|
+
- failed (int): Number of tests that failed.
|
|
369
|
+
- errors (int): Number of tests that had errors.
|
|
370
|
+
- skipped (int): Number of tests that were skipped.
|
|
371
|
+
- total_time (float): Total duration of the test execution in seconds.
|
|
372
|
+
- success_rate (float): Percentage of tests that passed.
|
|
261
373
|
|
|
262
374
|
Returns
|
|
263
375
|
-------
|
|
264
376
|
None
|
|
377
|
+
This method does not return any value. It outputs a formatted summary table to the console
|
|
378
|
+
if result printing is enabled.
|
|
379
|
+
|
|
380
|
+
Notes
|
|
381
|
+
-----
|
|
382
|
+
- The table is only displayed if the `print_result` flag is set to True.
|
|
383
|
+
- The table uses Rich's styling features for enhanced readability.
|
|
265
384
|
"""
|
|
385
|
+
|
|
386
|
+
# If result printing is disabled, do not display the summary table
|
|
387
|
+
if self.__print_result is False:
|
|
388
|
+
return
|
|
389
|
+
|
|
390
|
+
# Create a Rich Table with headers and styling
|
|
266
391
|
table = Table(
|
|
267
392
|
show_header=True,
|
|
268
393
|
header_style="bold white",
|
|
269
394
|
width=self.__panel_width,
|
|
270
395
|
border_style="blue"
|
|
271
396
|
)
|
|
397
|
+
# Add columns for each summary metric
|
|
272
398
|
table.add_column("Total", justify="center")
|
|
273
399
|
table.add_column("Passed", justify="center")
|
|
274
400
|
table.add_column("Failed", justify="center")
|
|
@@ -276,6 +402,8 @@ class TestPrinter(ITestPrinter):
|
|
|
276
402
|
table.add_column("Skipped", justify="center")
|
|
277
403
|
table.add_column("Duration", justify="center")
|
|
278
404
|
table.add_column("Success Rate", justify="center")
|
|
405
|
+
|
|
406
|
+
# Add a row with the summary values, formatting duration and success rate
|
|
279
407
|
table.add_row(
|
|
280
408
|
str(summary["total_tests"]),
|
|
281
409
|
str(summary["passed"]),
|
|
@@ -285,44 +413,63 @@ class TestPrinter(ITestPrinter):
|
|
|
285
413
|
f"{summary['total_time']:.2f}s",
|
|
286
414
|
f"{summary['success_rate']:.2f}%"
|
|
287
415
|
)
|
|
416
|
+
|
|
417
|
+
# Print the summary table to the console
|
|
288
418
|
self.__rich_console.print(table)
|
|
419
|
+
|
|
420
|
+
# Add a blank line after the table for spacing
|
|
289
421
|
self.__rich_console.line(1)
|
|
290
422
|
|
|
291
423
|
def displayResults(
|
|
292
424
|
self,
|
|
293
425
|
*,
|
|
294
|
-
print_result: bool,
|
|
295
426
|
summary: Dict[str, Any]
|
|
296
427
|
) -> None:
|
|
297
428
|
"""
|
|
298
|
-
Display
|
|
299
|
-
|
|
429
|
+
Display a detailed summary of test execution results, including a summary table and
|
|
430
|
+
grouped panels for failed or errored tests.
|
|
431
|
+
|
|
432
|
+
This method prints a summary table of the test results and, if there are any failed or
|
|
433
|
+
errored tests, displays them grouped by their test class. For each failed or errored test,
|
|
434
|
+
a syntax-highlighted traceback panel is shown, along with metadata such as the test method
|
|
435
|
+
name and execution time. Different icons and border colors are used to distinguish between
|
|
436
|
+
failed and errored tests.
|
|
300
437
|
|
|
301
438
|
Parameters
|
|
302
439
|
----------
|
|
303
440
|
summary : dict
|
|
304
|
-
Dictionary containing the summary of the test execution
|
|
305
|
-
|
|
441
|
+
Dictionary containing the overall summary and details of the test execution. It must
|
|
442
|
+
include keys such as 'test_details' (list of test result dicts), 'total_tests',
|
|
443
|
+
'passed', 'failed', 'errors', 'skipped', 'total_time', and 'success_rate'.
|
|
444
|
+
|
|
445
|
+
Returns
|
|
446
|
+
-------
|
|
447
|
+
None
|
|
448
|
+
This method does not return any value. It outputs the formatted summary table and
|
|
449
|
+
detailed panels for failed or errored tests to the console.
|
|
306
450
|
|
|
307
451
|
Notes
|
|
308
452
|
-----
|
|
309
|
-
-
|
|
310
|
-
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
-
|
|
453
|
+
- The summary table provides an overview of the test results.
|
|
454
|
+
- Failed and errored tests are grouped and displayed by their test class.
|
|
455
|
+
- Each failed or errored test is shown in a panel with a syntax-highlighted traceback,
|
|
456
|
+
test method name, and execution time.
|
|
457
|
+
- Icons and border colors visually distinguish between failed (❌, yellow) and errored
|
|
458
|
+
(💥, red) tests.
|
|
459
|
+
- No output is produced if result printing is disabled.
|
|
316
460
|
"""
|
|
317
461
|
|
|
318
|
-
# If
|
|
319
|
-
if not
|
|
462
|
+
# If result printing is disabled, do not display results
|
|
463
|
+
if not self.__print_result:
|
|
320
464
|
return
|
|
321
465
|
|
|
322
|
-
# Print summary
|
|
466
|
+
# Print one blank line before the summary
|
|
467
|
+
self.__rich_console.line(1)
|
|
468
|
+
|
|
469
|
+
# Print the summary table of test results
|
|
323
470
|
self.summaryTable(summary)
|
|
324
471
|
|
|
325
|
-
# Group
|
|
472
|
+
# Group failed and errored tests by their test class
|
|
326
473
|
failures_by_class = {}
|
|
327
474
|
for test in summary["test_details"]:
|
|
328
475
|
if test["status"] in (TestStatus.FAILED.name, TestStatus.ERRORED.name):
|
|
@@ -331,14 +478,22 @@ class TestPrinter(ITestPrinter):
|
|
|
331
478
|
failures_by_class[class_name] = []
|
|
332
479
|
failures_by_class[class_name].append(test)
|
|
333
480
|
|
|
334
|
-
# Display grouped failures
|
|
481
|
+
# Display grouped failures and errors for each test class
|
|
335
482
|
for class_name, tests in failures_by_class.items():
|
|
336
483
|
|
|
337
|
-
|
|
484
|
+
# Print a panel with the class name as the header
|
|
485
|
+
class_panel = Panel.fit(
|
|
486
|
+
f"[bold]{class_name}[/bold]",
|
|
487
|
+
border_style="red",
|
|
488
|
+
padding=(0, 2)
|
|
489
|
+
)
|
|
338
490
|
self.__rich_console.print(class_panel)
|
|
339
491
|
|
|
340
492
|
for test in tests:
|
|
493
|
+
# Sanitize the traceback to show only relevant parts
|
|
341
494
|
traceback_str = self.__sanitizeTraceback(test['file_path'], test['traceback'])
|
|
495
|
+
|
|
496
|
+
# Create a syntax-highlighted panel for the traceback
|
|
342
497
|
syntax = Syntax(
|
|
343
498
|
traceback_str,
|
|
344
499
|
lexer="python",
|
|
@@ -348,6 +503,7 @@ class TestPrinter(ITestPrinter):
|
|
|
348
503
|
theme="monokai"
|
|
349
504
|
)
|
|
350
505
|
|
|
506
|
+
# Choose icon and border color based on test status
|
|
351
507
|
icon = "❌" if test["status"] == TestStatus.FAILED.name else "💥"
|
|
352
508
|
border_color = "yellow" if test["status"] == TestStatus.FAILED.name else "red"
|
|
353
509
|
|
|
@@ -355,6 +511,7 @@ class TestPrinter(ITestPrinter):
|
|
|
355
511
|
if not test['execution_time'] or test['execution_time'] == 0:
|
|
356
512
|
test['execution_time'] = 0.001
|
|
357
513
|
|
|
514
|
+
# Print the panel with traceback and test metadata
|
|
358
515
|
panel = Panel(
|
|
359
516
|
syntax,
|
|
360
517
|
title=f"{icon} {test['method']}",
|
|
@@ -368,47 +525,121 @@ class TestPrinter(ITestPrinter):
|
|
|
368
525
|
self.__rich_console.print(panel)
|
|
369
526
|
self.__rich_console.line(1)
|
|
370
527
|
|
|
528
|
+
def unittestResult(
|
|
529
|
+
self,
|
|
530
|
+
test_result: TestResult
|
|
531
|
+
) -> None:
|
|
532
|
+
"""
|
|
533
|
+
Display the result of a single unit test in a formatted manner using the Rich library.
|
|
534
|
+
|
|
535
|
+
This method prints the outcome of an individual unit test to the console, showing a status icon
|
|
536
|
+
(✅ for passed, ❌ for failed) along with the test name. If the test failed, the first line of the
|
|
537
|
+
error message is also displayed for quick reference. The output is styled for clarity and does not
|
|
538
|
+
use syntax highlighting.
|
|
539
|
+
|
|
540
|
+
Parameters
|
|
541
|
+
----------
|
|
542
|
+
test_result : Any
|
|
543
|
+
An object representing the result of a unit test. It must have the following attributes:
|
|
544
|
+
- status: An enum or object with a 'name' attribute indicating the test status (e.g., "PASSED", "FAILED").
|
|
545
|
+
- name: The name of the test.
|
|
546
|
+
- error_message: The error message string (present if the test failed).
|
|
547
|
+
|
|
548
|
+
Returns
|
|
549
|
+
-------
|
|
550
|
+
None
|
|
551
|
+
This method does not return any value. It outputs the formatted test result to the console.
|
|
552
|
+
|
|
553
|
+
Notes
|
|
554
|
+
-----
|
|
555
|
+
- If the test passed, only the status and test name are displayed.
|
|
556
|
+
- If the test failed, the status, test name, and the first line of the error message are shown.
|
|
557
|
+
- Output is printed using the Rich console without syntax highlighting.
|
|
558
|
+
"""
|
|
559
|
+
|
|
560
|
+
# If result printing is disabled, do not display results
|
|
561
|
+
if not self.__print_result:
|
|
562
|
+
return
|
|
563
|
+
|
|
564
|
+
# Determine the status icon and label based on the test result
|
|
565
|
+
if test_result.status.name == "PASSED":
|
|
566
|
+
status = "✅ PASSED"
|
|
567
|
+
elif test_result.status.name == "FAILED":
|
|
568
|
+
status = "❌ FAILED"
|
|
569
|
+
elif test_result.status.name == "SKIPPED":
|
|
570
|
+
status = "⏩ SKIPPED"
|
|
571
|
+
elif test_result.status.name == "ERRORED":
|
|
572
|
+
status = "💥 ERRORED"
|
|
573
|
+
else:
|
|
574
|
+
status = f"🔸 {test_result.status.name}"
|
|
575
|
+
|
|
576
|
+
msg = f"[{status}] {test_result.name}"
|
|
577
|
+
|
|
578
|
+
if test_result.status.name == "FAILED":
|
|
579
|
+
msg += f" | Error: {test_result.error_message.splitlines()[0].strip()}"
|
|
580
|
+
|
|
581
|
+
max_width = self.__rich_console.width - 2
|
|
582
|
+
display_msg = msg if len(msg) <= max_width else msg[:max_width - 3] + "..."
|
|
583
|
+
self.__rich_console.print(display_msg, highlight=False)
|
|
584
|
+
|
|
371
585
|
def __withDebugger(
|
|
372
586
|
self,
|
|
373
587
|
flatten_test_suite: list
|
|
374
588
|
) -> bool:
|
|
375
589
|
"""
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
590
|
+
Determine if any test case in the provided flattened test suite contains active debugging or dumping calls.
|
|
591
|
+
|
|
592
|
+
This method inspects the source code of each test case instance in the given list to check for the presence
|
|
593
|
+
of specific debugging or dumping method calls (such as 'self.dd' or 'self.dump'). Only lines that are not
|
|
594
|
+
commented out are considered. If any such call is found in the source code, the method immediately returns True,
|
|
595
|
+
indicating that a debugger or dump method is actively used in the test suite.
|
|
380
596
|
|
|
381
597
|
Parameters
|
|
382
598
|
----------
|
|
383
599
|
flatten_test_suite : list
|
|
384
|
-
A list of test case instances
|
|
600
|
+
A list of test case instances whose source code will be inspected for debugging or dumping calls.
|
|
385
601
|
|
|
386
602
|
Returns
|
|
387
603
|
-------
|
|
388
604
|
bool
|
|
389
|
-
True if any test case
|
|
390
|
-
False
|
|
605
|
+
Returns True if any test case contains an active (non-commented) call to a debugging or dumping method
|
|
606
|
+
(e.g., 'self.dd' or 'self.dump'). Returns False if no such calls are found or if an exception occurs
|
|
607
|
+
during inspection.
|
|
391
608
|
|
|
392
609
|
Notes
|
|
393
610
|
-----
|
|
394
|
-
Lines that
|
|
395
|
-
If an exception occurs
|
|
611
|
+
- Lines that are commented out (i.e., start with '#') are ignored during inspection.
|
|
612
|
+
- If an exception occurs while retrieving or processing the source code, the method returns False.
|
|
396
613
|
"""
|
|
397
614
|
|
|
398
615
|
try:
|
|
616
|
+
|
|
617
|
+
# Iterate through each test case in the flattened test suite
|
|
399
618
|
for test_case in flatten_test_suite:
|
|
619
|
+
|
|
620
|
+
# Retrieve the source code of the test case using reflection
|
|
400
621
|
source = ReflectionInstance(test_case).getSourceCode()
|
|
622
|
+
|
|
623
|
+
# Check each line of the source code
|
|
401
624
|
for line in source.splitlines():
|
|
625
|
+
|
|
626
|
+
# Strip leading and trailing whitespace from the line
|
|
402
627
|
stripped = line.strip()
|
|
403
|
-
|
|
628
|
+
|
|
629
|
+
# Skip lines that are commented out
|
|
404
630
|
if stripped.startswith('#') or re.match(r'^\s*#', line):
|
|
405
631
|
continue
|
|
406
|
-
|
|
632
|
+
|
|
633
|
+
# If any debug keyword is present in the line, return True
|
|
407
634
|
if any(keyword in line for keyword in self.__debbug_keywords):
|
|
408
|
-
return
|
|
409
|
-
|
|
635
|
+
return True
|
|
636
|
+
|
|
637
|
+
# No debug or dump calls found in any test case
|
|
638
|
+
return False
|
|
639
|
+
|
|
410
640
|
except Exception:
|
|
411
|
-
|
|
641
|
+
|
|
642
|
+
# If any error occurs during inspection, return False
|
|
412
643
|
return False
|
|
413
644
|
|
|
414
645
|
def __sanitizeTraceback(
|
|
@@ -417,54 +648,66 @@ class TestPrinter(ITestPrinter):
|
|
|
417
648
|
traceback_test: str
|
|
418
649
|
) -> str:
|
|
419
650
|
"""
|
|
420
|
-
|
|
421
|
-
|
|
651
|
+
Extract and return the most relevant portion of a traceback string that pertains to a specific test file.
|
|
652
|
+
|
|
653
|
+
This method processes a full Python traceback and attempts to isolate the lines that are directly related
|
|
654
|
+
to the provided test file. It does so by searching for the test file's name within the traceback and collecting
|
|
655
|
+
all subsequent lines that are relevant, such as those containing 'File' or non-empty lines. If the test file's
|
|
656
|
+
name cannot be determined or no relevant lines are found, the original traceback is returned. If the traceback
|
|
657
|
+
is empty, a default message is returned.
|
|
422
658
|
|
|
423
659
|
Parameters
|
|
424
660
|
----------
|
|
425
661
|
test_path : str
|
|
426
|
-
The file path of the test file
|
|
662
|
+
The file path of the test file whose related traceback lines should be extracted.
|
|
427
663
|
traceback_test : str
|
|
428
|
-
The
|
|
664
|
+
The complete traceback string to be sanitized.
|
|
429
665
|
|
|
430
666
|
Returns
|
|
431
667
|
-------
|
|
432
668
|
str
|
|
433
|
-
|
|
434
|
-
If no relevant
|
|
435
|
-
If the traceback is empty,
|
|
669
|
+
Returns a string containing only the relevant traceback lines associated with the test file.
|
|
670
|
+
If no relevant lines are found or the file name cannot be determined, the full traceback is returned.
|
|
671
|
+
If the traceback is empty, returns "No traceback available for this test."
|
|
436
672
|
"""
|
|
437
673
|
|
|
438
|
-
#
|
|
674
|
+
# Return a default message if the traceback is empty
|
|
439
675
|
if not traceback_test:
|
|
440
676
|
return "No traceback available for this test."
|
|
441
677
|
|
|
442
|
-
#
|
|
678
|
+
# Attempt to extract the test file's name (without extension) from the provided path
|
|
443
679
|
file_match = re.search(r'([^/\\]+)\.py', test_path)
|
|
444
680
|
file_name = file_match.group(1) if file_match else None
|
|
445
681
|
|
|
446
|
-
# If
|
|
682
|
+
# If the file name cannot be determined, return the full traceback
|
|
447
683
|
if not file_name:
|
|
448
684
|
return traceback_test
|
|
449
685
|
|
|
450
|
-
#
|
|
686
|
+
# Split the traceback into individual lines for processing
|
|
451
687
|
lines = traceback_test.splitlines()
|
|
452
688
|
relevant_lines = []
|
|
689
|
+
|
|
690
|
+
# Determine if the test file is present in the traceback
|
|
691
|
+
# If not found, set found_test_file to True to include all lines
|
|
453
692
|
found_test_file = False if file_name in traceback_test else True
|
|
454
693
|
|
|
455
|
-
# Iterate through
|
|
694
|
+
# Iterate through each line of the traceback
|
|
456
695
|
for line in lines:
|
|
696
|
+
|
|
697
|
+
# Mark when the test file is first encountered in the traceback
|
|
457
698
|
if file_name in line and not found_test_file:
|
|
458
699
|
found_test_file = True
|
|
700
|
+
|
|
701
|
+
# Once the test file is found, collect relevant lines
|
|
459
702
|
if found_test_file:
|
|
460
703
|
if 'File' in line:
|
|
461
704
|
relevant_lines.append(line.strip())
|
|
462
705
|
elif line.strip() != '':
|
|
463
706
|
relevant_lines.append(line)
|
|
464
707
|
|
|
465
|
-
# If
|
|
708
|
+
# If no relevant lines were found, return the full traceback
|
|
466
709
|
if not relevant_lines:
|
|
467
710
|
return traceback_test
|
|
468
711
|
|
|
469
|
-
#
|
|
712
|
+
# Join and return only the relevant lines as a single string
|
|
470
713
|
return str('\n').join(relevant_lines)
|