orionis 0.575.0__py3-none-any.whl → 0.576.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.
@@ -11,7 +11,17 @@ from orionis.container.contracts.container import IContainer
11
11
  from orionis.container.entities.binding import Binding
12
12
  from orionis.container.enums.lifetimes import Lifetime
13
13
  from orionis.container.exceptions import OrionisContainerException
14
- from orionis.container.validators import *
14
+ from orionis.container.validators import (
15
+ ImplementsAbstractMethods,
16
+ IsAbstractClass,
17
+ IsConcreteClass,
18
+ IsInstance,
19
+ IsCallable,
20
+ IsSubclass,
21
+ IsNotSubclass,
22
+ IsValidAlias,
23
+ LifetimeValidator
24
+ )
15
25
  from orionis.services.introspection.abstract.reflection import ReflectionAbstract
16
26
  from orionis.services.introspection.callables.reflection import ReflectionCallable
17
27
  from orionis.services.introspection.concretes.reflection import ReflectionConcrete
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.575.0"
8
+ VERSION = "0.576.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -1090,6 +1090,7 @@ class UnitTest(IUnitTest):
1090
1090
  module=ReflectionInstance(test).getModuleName(),
1091
1091
  file_path=ReflectionInstance(test).getFile(),
1092
1092
  doc_string=ReflectionInstance(test).getMethodDocstring(test._testMethodName),
1093
+ exception=err[1]
1093
1094
  )
1094
1095
  )
1095
1096
 
@@ -1112,6 +1113,7 @@ class UnitTest(IUnitTest):
1112
1113
  module=ReflectionInstance(test).getModuleName(),
1113
1114
  file_path=ReflectionInstance(test).getFile(),
1114
1115
  doc_string=ReflectionInstance(test).getMethodDocstring(test._testMethodName),
1116
+ exception=err[1]
1115
1117
  )
1116
1118
  )
1117
1119
 
@@ -1225,6 +1227,19 @@ class UnitTest(IUnitTest):
1225
1227
  test_details = []
1226
1228
  for test_result in result.test_results:
1227
1229
  rst: TestResult = test_result
1230
+
1231
+ # Extraer información solo del último frame del traceback si existe
1232
+ traceback_frames = []
1233
+ if rst.exception and rst.exception.__traceback__:
1234
+ tb = traceback.extract_tb(rst.exception.__traceback__)
1235
+ for frame in tb:
1236
+ traceback_frames.append({
1237
+ 'file': frame.filename,
1238
+ 'line': frame.lineno,
1239
+ 'function': frame.name,
1240
+ 'code': frame.line
1241
+ })
1242
+
1228
1243
  test_details.append({
1229
1244
  'id': rst.id,
1230
1245
  'class': rst.class_name,
@@ -1234,7 +1249,8 @@ class UnitTest(IUnitTest):
1234
1249
  'error_message': rst.error_message,
1235
1250
  'traceback': rst.traceback,
1236
1251
  'file_path': rst.file_path,
1237
- 'doc_string': rst.doc_string
1252
+ 'doc_string': rst.doc_string,
1253
+ 'traceback_frames': traceback_frames
1238
1254
  })
1239
1255
 
1240
1256
  # Calculate the number of passed tests
@@ -140,4 +140,12 @@ class TestResult:
140
140
  metadata={
141
141
  "description": "Docstring of the test, if applicable."
142
142
  }
143
+ )
144
+
145
+ # The exception instance if an error occurred, otherwise None
146
+ exception: Optional[BaseException] = field(
147
+ default=None,
148
+ metadata={
149
+ "description": "The exception instance if an error occurred, otherwise None."
150
+ }
143
151
  )
@@ -1,6 +1,6 @@
1
1
  import re
2
2
  from datetime import datetime
3
- from typing import Any, Dict
3
+ from typing import Any, Dict, List
4
4
  from rich.console import Console
5
5
  from rich.live import Live
6
6
  from rich.panel import Panel
@@ -361,60 +361,100 @@ class TestPrinter(ITestPrinter):
361
361
  # Print the summary table of test results
362
362
  self.summaryTable(summary)
363
363
 
364
- # Group failed and errored tests by their test class
365
- failures_by_class = {}
366
- for test in summary["test_details"]:
364
+ # Print failed and errored tests
365
+ test_details: List[Dict] = summary.get("test_details", [])
366
+ for test in test_details:
367
+
368
+ # If there are no failures or errors, skip to the next test
367
369
  if test["status"] in (TestStatus.FAILED.name, TestStatus.ERRORED.name):
368
- class_name = test["class"]
369
- if class_name not in failures_by_class:
370
- failures_by_class[class_name] = []
371
- failures_by_class[class_name].append(test)
372
-
373
- # Display grouped failures and errors for each test class
374
- for class_name, tests in failures_by_class.items():
375
-
376
- # Print a panel with the class name as the header
377
- class_panel = Panel.fit(
378
- f"[bold]{class_name}[/bold]",
379
- border_style="red",
380
- padding=(0, 2)
381
- )
382
- self.__rich_console.print(class_panel)
383
-
384
- for test in tests:
385
- # Sanitize the traceback to show only relevant parts
386
- traceback_str = self.__sanitizeTraceback(test['file_path'], test['traceback'])
387
-
388
- # Create a syntax-highlighted panel for the traceback
389
- syntax = Syntax(
390
- traceback_str,
391
- lexer="python",
392
- line_numbers=False,
393
- background_color="default",
394
- word_wrap=True,
395
- theme="monokai"
396
- )
397
-
398
- # Choose icon and border color based on test status
399
- icon = "❌" if test["status"] == TestStatus.FAILED.name else "💥"
400
- border_color = "yellow" if test["status"] == TestStatus.FAILED.name else "red"
401
-
402
- # Ensure execution time is never zero for display purposes
403
- if not test['execution_time'] or test['execution_time'] == 0:
404
- test['execution_time'] = 0.001
405
-
406
- # Print the panel with traceback and test metadata
407
- panel = Panel(
408
- syntax,
409
- title=f"{icon} {test['method']}",
410
- subtitle=f"Duration: {test['execution_time']:.3f}s",
411
- border_style=border_color,
412
- title_align="left",
413
- padding=(1, 1),
414
- subtitle_align="right",
415
- width=self.__panel_width
416
- )
417
- self.__rich_console.print(panel)
370
+
371
+ # Print separator line before each test result with class name and method name
372
+ self.__rich_console.rule(title=f'🧪 {test["class"]}.{test["method"]}()', align="left")
373
+
374
+ # Add clickable file:line info if available
375
+ last_trace_frame = test.get('traceback_frames')
376
+ if last_trace_frame and last_trace_frame is not None:
377
+
378
+ # Get the last frame details
379
+ last_trace_frame: dict = last_trace_frame[-1]
380
+ _file = last_trace_frame.get('file')
381
+ _line = last_trace_frame.get('line')
382
+ _code = last_trace_frame.get('code')
383
+ _function = last_trace_frame.get('function')
384
+
385
+ # Print the file and line number if available
386
+ text = Text("📂 ")
387
+ text.append(f'{_file}:{_line}', style="underline blue")
388
+ self.__rich_console.print(text)
389
+
390
+ # Print the error message with better formatting
391
+ text = Text("Error in ", style="bold red")
392
+ text.append(f'{_function}()', style="bold cyan")
393
+ text.append(": ", style="bold red")
394
+
395
+ # Extract just the first line of the error message for cleaner display
396
+ error_msg = test["error_message"] if test["error_message"] else "Unknown error"
397
+ text.append(error_msg, style="red")
398
+ self.__rich_console.print(text)
399
+
400
+ # Print the code context (3 lines before and after the error)
401
+ try:
402
+
403
+ # Open the file and read its lines
404
+ with open(_file, 'r', encoding='utf-8') as f:
405
+ file_lines = f.readlines()
406
+
407
+ # Convert to 0-based index
408
+ error_line_num = int(_line) - 1
409
+ start_line = max(0, error_line_num - 1)
410
+ end_line = min(len(file_lines), error_line_num + 3)
411
+
412
+ # Create a code block with syntax highlighting
413
+ code_lines = []
414
+ for i in range(start_line, end_line):
415
+ line_num = i + 1
416
+ line_content = file_lines[i].rstrip()
417
+ if line_num == int(_line):
418
+ # Highlight the error line
419
+ code_lines.append(f"* {line_num:3d} | {line_content}")
420
+ else:
421
+ code_lines.append(f" {line_num:3d} | {line_content}")
422
+
423
+ code_block = '\n'.join(code_lines)
424
+ syntax = Syntax(code_block, "python", theme="monokai", line_numbers=False)
425
+ self.__rich_console.print(syntax)
426
+
427
+ except (FileNotFoundError, ValueError, IndexError):
428
+
429
+ # Fallback to original behavior if file cannot be read
430
+ text = Text(f"{_line} | {_code}", style="dim")
431
+ self.__rich_console.print(text)
432
+
433
+ else:
434
+
435
+ # Print the file and line number if available
436
+ text = Text("📂 ")
437
+ text.append(f'{test["file_path"]}', style="underline blue")
438
+ self.__rich_console.print(text)
439
+
440
+ # Print the error message with better formatting
441
+ text = Text("Error: ", style="bold red")
442
+ text.append(f'{test["error_message"]}', style="red")
443
+ self.__rich_console.print(text)
444
+
445
+ # Print traceback if available
446
+ if test["traceback"]:
447
+ sanitized_traceback = self.__sanitizeTraceback(
448
+ test_path=test["file_path"],
449
+ traceback_test=test["traceback"]
450
+ )
451
+ syntax = Syntax(sanitized_traceback, "python", theme="monokai", line_numbers=False)
452
+ self.__rich_console.print(syntax)
453
+
454
+ # Print a separator line after each test result
455
+ self.__rich_console.rule()
456
+
457
+ # Print one blank line after the results
418
458
  self.__rich_console.line(1)
419
459
 
420
460
  def unittestResult(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orionis
3
- Version: 0.575.0
3
+ Version: 0.576.0
4
4
  Summary: Orionis Framework – Elegant, Fast, and Powerful.
5
5
  Home-page: https://github.com/orionis-framework/framework
6
6
  Author: Raul Mauricio Uñate Castro
@@ -67,7 +67,7 @@ orionis/console/stub/listener.stub,sha256=DbX-ghx2-vb73kzQ6L20lyg5vSKn58jSLTwFuw
67
67
  orionis/console/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
68
  orionis/console/tasks/schedule.py,sha256=g7eX4uuxT1EK8-uBulx2Xzies98-5FEGdc_20O8ORn8,83392
69
69
  orionis/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
- orionis/container/container.py,sha256=9beW1IQzgZkgVIMo0ePBAkTz7bnNz3GNZZDRogMp8AI,96902
70
+ orionis/container/container.py,sha256=jmxCyuPTwnw_PF4eS66mvBnnSW5VHS5gkx2LOPIwB-w,97094
71
71
  orionis/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
72
  orionis/container/context/manager.py,sha256=I08K_jKXSKmrq18Pv33qYyMKIlAovVOwIgmfiVm-J7c,2971
73
73
  orionis/container/context/scope.py,sha256=p_oCzR7dDz-5ZAd16ab4vfLc3gBf34CaN0f4iR9D0bQ,1155
@@ -224,7 +224,7 @@ orionis/foundation/providers/scheduler_provider.py,sha256=1do4B09bU_6xbFHHVYYTGM
224
224
  orionis/foundation/providers/testing_provider.py,sha256=SrJRpdvcblx9WvX7x9Y3zc7OQfiTf7la0HAJrm2ESlE,3725
225
225
  orionis/foundation/providers/workers_provider.py,sha256=oa_2NIDH6UxZrtuGkkoo_zEoNIMGgJ46vg5CCgAm7wI,3926
226
226
  orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
227
- orionis/metadata/framework.py,sha256=gnEfurGNKW-giyGDg_uSRVZa6GbC283iXZdrcozLLi8,4109
227
+ orionis/metadata/framework.py,sha256=7M797sulQ9ulnsFSzcaLmlDX2fD3kCPUl4IzUUqdYWg,4109
228
228
  orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
229
229
  orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
230
230
  orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -382,9 +382,9 @@ orionis/test/contracts/render.py,sha256=wpDQzUtT0r8KFZ7zPcxWHXQ1EVNKxzA_rZ6ZKUcZ
382
382
  orionis/test/contracts/test_result.py,sha256=SNXJ2UerkweYn7uCT0i0HmMGP0XBrL_9KJs-0ZvIYU4,4002
383
383
  orionis/test/contracts/unit_test.py,sha256=getqaBoadQT_wh_V6aTQvm0yx9IgbVrE9EEOD8b031g,8031
384
384
  orionis/test/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
385
- orionis/test/core/unit_test.py,sha256=nOb5UIeMHu16K3vaB0GF9-QtdEKE6F8OghvXd9tP80s,64748
385
+ orionis/test/core/unit_test.py,sha256=c4eT9PT1PDhWHndsNl7mN45olTAysMx79q4WP1wHVkI,65438
386
386
  orionis/test/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
387
- orionis/test/entities/result.py,sha256=IMAd1AiwOf2z8krTDBFMpQe_1PG4YJ5Z0qpbr9xZwjg,4507
387
+ orionis/test/entities/result.py,sha256=eZ6UIqGmFW8FZ9x8PB_MZbLAc-SAuUyi4FUcMYIZzGo,4777
388
388
  orionis/test/enums/__init__.py,sha256=M3imAgMvKFTKg55FbtVoY3zxj7QRY9AfaUWxiSZVvn4,66
389
389
  orionis/test/enums/status.py,sha256=5SXvDQEFOT4Jkzdndw6hV8Tc2k4gm9XGjyZp0Qa55Zk,757
390
390
  orionis/test/exceptions/__init__.py,sha256=HcFudBMqi86hzgxEyNhh29hNMOle4KZmKosJRqX5ayc,424
@@ -395,7 +395,7 @@ orionis/test/exceptions/runtime.py,sha256=h9gQ0pS8tJTmuXNG-GHky8tTqpdz-cNqkntOOl
395
395
  orionis/test/exceptions/value.py,sha256=CoqYOkViU_RaKCMNpB82tgEsR3XhI1pw6YQ8sH8CJh4,588
396
396
  orionis/test/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
397
397
  orionis/test/output/dumper.py,sha256=qJDyVvl3MO0Uinr6z9TYYdDTqHNwwM0PcoDNNkTpAnA,5908
398
- orionis/test/output/printer.py,sha256=lW29hkrpPQLW0Q0AF39vBXRsQrUgYDru-SA2QyQ9Qqs,20820
398
+ orionis/test/output/printer.py,sha256=PGyLurOzatYjKXpeaAEWlTmZlCzRj-UI5_MN2Zrz5u4,23138
399
399
  orionis/test/records/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
400
400
  orionis/test/records/logs.py,sha256=7XIdzDmQpb2HLUoAUWVj8UKiQDOnCkLD7ttro-Lv5UY,14223
401
401
  orionis/test/validators/__init__.py,sha256=RpuZFsrmxzLjRERyJ2fcZIQ27xuq2DedDlao2zmFE_U,991
@@ -417,8 +417,8 @@ orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnI
417
417
  orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
418
418
  orionis/test/view/render.py,sha256=f-zNhtKSg9R5Njqujbg2l2amAs2-mRVESneLIkWOZjU,4082
419
419
  orionis/test/view/report.stub,sha256=QLqqCdRoENr3ECiritRB3DO_MOjRQvgBh5jxZ3Hs1r0,28189
420
- orionis-0.575.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
421
- orionis-0.575.0.dist-info/METADATA,sha256=ENBomJW_ksIaRdyyGkDAZvlc-87LUmAdLOS6ehImORQ,4801
422
- orionis-0.575.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
423
- orionis-0.575.0.dist-info/top_level.txt,sha256=lyXi6jArpqJ-0zzNqd_uwsH-z9TCEBVBL-pC3Ekv7hU,8
424
- orionis-0.575.0.dist-info/RECORD,,
420
+ orionis-0.576.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
421
+ orionis-0.576.0.dist-info/METADATA,sha256=g1iB9F4BJGeNafA-0d_iLz-tjGz4bM9m2GJ4gUjji68,4801
422
+ orionis-0.576.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
423
+ orionis-0.576.0.dist-info/top_level.txt,sha256=lyXi6jArpqJ-0zzNqd_uwsH-z9TCEBVBL-pC3Ekv7hU,8
424
+ orionis-0.576.0.dist-info/RECORD,,