orionis 0.293.0__py3-none-any.whl → 0.295.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.
@@ -145,6 +145,15 @@ class Testing:
145
145
  }
146
146
  )
147
147
 
148
+ web_report: bool = field(
149
+ default=False,
150
+ metadata={
151
+ "description": "Whether to generate a web report for the test results. Default is False.",
152
+ "required": True,
153
+ "default": False
154
+ }
155
+ )
156
+
148
157
  def __post_init__(self):
149
158
  """
150
159
  Post-initialization validation for the testing configuration entity.
@@ -245,14 +254,19 @@ class Testing:
245
254
  f"Invalid type for 'persistent': {type(self.persistent).__name__}. It must be a boolean (True or False)."
246
255
  )
247
256
 
248
- if not isinstance(self.persistent_driver, str):
249
- raise OrionisIntegrityException(
250
- f"Invalid type for 'persistent_driver': {type(self.persistent_driver).__name__}. It must be a string."
251
- )
257
+ if self.persistent:
258
+ if not isinstance(self.persistent_driver, str):
259
+ raise OrionisIntegrityException(
260
+ f"Invalid type for 'persistent_driver': {type(self.persistent_driver).__name__}. It must be a string."
261
+ )
262
+ if self.persistent_driver not in ['sqlite', 'json']:
263
+ raise OrionisIntegrityException(
264
+ f"Invalid value for 'persistent_driver': {self.persistent_driver}. It must be one of: ['sqlite', 'json']."
265
+ )
252
266
 
253
- if self.persistent_driver not in ['sqlite', 'json']:
267
+ if not isinstance(self.web_report, bool):
254
268
  raise OrionisIntegrityException(
255
- f"Invalid value for 'persistent_driver': {self.persistent_driver}. It must be one of: ['sqlite', 'json']."
269
+ f"Invalid type for 'web_report': {type(self.web_report).__name__}. It must be a boolean (True or False)."
256
270
  )
257
271
 
258
272
  def toDict(self) -> dict:
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.293.0"
8
+ VERSION = "0.295.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -80,6 +80,7 @@ class TestSuite(ITestSuite):
80
80
  throw_exception=config.throw_exception,
81
81
  persistent=config.persistent,
82
82
  persistent_driver=config.persistent_driver,
83
+ web_report=config.web_report
83
84
  )
84
85
 
85
86
  # Extract configuration values
@@ -16,17 +16,17 @@ from rich.live import Live
16
16
  from rich.panel import Panel
17
17
  from rich.syntax import Syntax
18
18
  from rich.table import Table
19
+ from rich.text import Text
19
20
  from orionis.console.output.console import Console
20
21
  from orionis.test.entities.test_result import TestResult
21
22
  from orionis.test.enums.test_mode import ExecutionMode
22
23
  from orionis.test.enums.test_status import TestStatus
23
- from orionis.test.exceptions.test_persistence_error import OrionisTestPersistenceError
24
24
  from orionis.test.exceptions.test_failure_exception import OrionisTestFailureException
25
+ from orionis.test.exceptions.test_persistence_error import OrionisTestPersistenceError
25
26
  from orionis.test.exceptions.test_value_error import OrionisTestValueError
26
27
  from orionis.test.logs.history import TestHistory
27
28
  from orionis.test.suites.contracts.test_unit import IUnitTest
28
29
  from orionis.test.view.render import TestingResultRender
29
- from rich.text import Text
30
30
 
31
31
  class UnitTest(IUnitTest):
32
32
  """
@@ -131,7 +131,9 @@ class UnitTest(IUnitTest):
131
131
  self.throw_exception: bool = False
132
132
  self.persistent: bool = False
133
133
  self.persistent_driver: str = 'sqlite'
134
+ self.web_report: bool = False
134
135
  self.base_path: str = "tests"
136
+ self.withliveconsole: bool = True
135
137
 
136
138
  def configure(
137
139
  self,
@@ -142,7 +144,8 @@ class UnitTest(IUnitTest):
142
144
  print_result: bool = None,
143
145
  throw_exception: bool = False,
144
146
  persistent: bool = False,
145
- persistent_driver: str = 'sqlite'
147
+ persistent_driver: str = 'sqlite',
148
+ web_report: bool = False
146
149
  ) -> 'UnitTest':
147
150
  """
148
151
  Configures the UnitTest instance with the specified parameters.
@@ -197,6 +200,9 @@ class UnitTest(IUnitTest):
197
200
  if persistent_driver is not None:
198
201
  self.persistent_driver = persistent_driver
199
202
 
203
+ if web_report is not None:
204
+ self.web_report = web_report
205
+
200
206
  return self
201
207
 
202
208
  def discoverTestsInFolder(
@@ -387,17 +393,27 @@ class UnitTest(IUnitTest):
387
393
  OrionisTestFailureException
388
394
  If `throw_exception` is True and there are test failures or errors.
389
395
  """
396
+
397
+ # Check if required print_result and throw_exception
390
398
  if print_result is not None:
391
399
  self.print_result = print_result
392
400
  if throw_exception is not None:
393
401
  self.throw_exception = throw_exception
394
402
 
403
+ # Dynamically determine if live console should be enabled based on test code usage
404
+ self._withLiveConsole()
405
+
406
+ # Start the timer and print the start message
395
407
  self.start_time = time.time()
396
408
  self._startMessage()
397
409
 
398
- # Elegant "running" message using Rich Panel
410
+ # Prepare the running message based on whether live console is enabled
411
+ message = "[bold yellow]⏳ Running tests...[/bold yellow]\n"
412
+ message += "[dim]This may take a few seconds. Please wait...[/dim]" if self.withliveconsole else "[dim]Please wait, results will appear below...[/dim]"
413
+
414
+ # Panel for running message
399
415
  running_panel = Panel(
400
- "[bold yellow]⏳ Running tests...[/bold yellow]\n[dim]This may take a few seconds. Please wait...[/dim]",
416
+ message,
401
417
  border_style="yellow",
402
418
  title="In Progress",
403
419
  title_align="left",
@@ -405,18 +421,18 @@ class UnitTest(IUnitTest):
405
421
  padding=(1, 2)
406
422
  )
407
423
 
408
- # Print the panel and keep a reference to the live display
409
- with Live(running_panel, console=self.rich_console, refresh_per_second=4, transient=True):
410
-
411
- # Setup output capture
412
- output_buffer = io.StringIO()
413
- error_buffer = io.StringIO()
424
+ # Elegant "running" message using Rich Panel
425
+ if self.withliveconsole:
426
+ with Live(running_panel, console=self.rich_console, refresh_per_second=4, transient=True):
427
+ result, output_buffer, error_buffer = self._runSuite()
428
+ else:
429
+ self.rich_console.print(running_panel)
430
+ result, output_buffer, error_buffer = self._runSuite()
414
431
 
415
- # Execute tests based on selected mode
416
- if self.execution_mode == ExecutionMode.PARALLEL.value:
417
- result = self._runTestsInParallel(output_buffer, error_buffer)
418
- else:
419
- result = self._runTestsSequentially(output_buffer, error_buffer)
432
+ # Capture and display the output and error buffers only if not empty
433
+ output_content = output_buffer.getvalue()
434
+ if output_content.strip():
435
+ print(output_buffer.getvalue())
420
436
 
421
437
  # Process results
422
438
  execution_time = time.time() - self.start_time
@@ -433,6 +449,80 @@ class UnitTest(IUnitTest):
433
449
  # Return the summary of the test results
434
450
  return summary
435
451
 
452
+ def _withLiveConsole(self) -> None:
453
+ """
454
+ Determines if the live console should be used based on the presence of debug or dump calls in the test code.
455
+
456
+ Returns
457
+ -------
458
+ bool
459
+ True if the live console should be used, False otherwise.
460
+ """
461
+ if self.withliveconsole:
462
+
463
+ try:
464
+
465
+ # Flatten the test suite to get all test cases
466
+ for test_case in self._flattenTestSuite(self.suite):
467
+
468
+ # Get the source code of the test case class
469
+ source = inspect.getsource(test_case.__class__)
470
+
471
+ # Only match if the keyword is not inside a comment
472
+ for keyword in ('self.dd', 'self.dump'):
473
+
474
+ # Find all lines containing the keyword
475
+ for line in source.splitlines():
476
+ if keyword in line:
477
+
478
+ # Remove leading/trailing whitespace
479
+ stripped = line.strip()
480
+
481
+ # Ignore lines that start with '#' (comments)
482
+ if not stripped.startswith('#') and not re.match(r'^\s*#', line):
483
+ self.withliveconsole = False
484
+ break
485
+
486
+ # If we found a keyword, no need to check further
487
+ if not self.withliveconsole:
488
+ break
489
+
490
+ # If we found a keyword in any test case, no need to check further
491
+ if not self.withliveconsole:
492
+ break
493
+
494
+ except Exception:
495
+ pass
496
+
497
+ def _runSuite(self):
498
+ """
499
+ Run the test suite according to the selected execution mode (parallel or sequential),
500
+ capturing standard output and error streams during execution.
501
+
502
+ Returns
503
+ -------
504
+ tuple
505
+ result : unittest.TestResult
506
+ The result object from the test execution.
507
+ output_buffer : io.StringIO
508
+ Captured standard output during test execution.
509
+ error_buffer : io.StringIO
510
+ Captured standard error during test execution.
511
+ """
512
+
513
+ # Setup output capture
514
+ output_buffer = io.StringIO()
515
+ error_buffer = io.StringIO()
516
+
517
+ # Execute tests based on selected mode
518
+ if self.execution_mode == ExecutionMode.PARALLEL.value:
519
+ result = self._runTestsInParallel(output_buffer, error_buffer)
520
+ else:
521
+ result = self._runTestsSequentially(output_buffer, error_buffer)
522
+
523
+ # Return the result along with captured output and error streams
524
+ return result, output_buffer, error_buffer
525
+
436
526
  def _runTestsSequentially(self, output_buffer: io.StringIO, error_buffer: io.StringIO) -> unittest.TestResult:
437
527
  """
438
528
  Executes the test suite sequentially, capturing the output and error streams.
@@ -760,13 +850,16 @@ class UnitTest(IUnitTest):
760
850
  self._persistTestResults(report)
761
851
 
762
852
  # Handle Web Report Rendering
763
- path = self._webReport(report)
853
+ if self.web_report:
854
+
855
+ # Generate the web report and get the path
856
+ path = self._webReport(report)
764
857
 
765
- # Elegant invitation to view the results, with underlined path
766
- invite_text = Text("Test results saved. ", style="green")
767
- invite_text.append("View report: ", style="bold green")
768
- invite_text.append(str(path), style="underline blue")
769
- self.rich_console.print(invite_text)
858
+ # Elegant invitation to view the results, with underlined path
859
+ invite_text = Text("Test results saved. ", style="green")
860
+ invite_text.append("View report: ", style="bold green")
861
+ invite_text.append(str(path), style="underline blue")
862
+ self.rich_console.print(invite_text)
770
863
 
771
864
  # Return the summary
772
865
  return {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orionis
3
- Version: 0.293.0
3
+ Version: 0.295.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
@@ -222,11 +222,11 @@ orionis/foundation/config/session/enums/same_site_policy.py,sha256=Oo05CJ-5keJWz
222
222
  orionis/foundation/config/session/helpers/secret_key.py,sha256=yafjzQ9KVQdXzCQCMthpgizlNCo5F5UTLtAnInipUMk,447
223
223
  orionis/foundation/config/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
224
224
  orionis/foundation/config/testing/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
225
- orionis/foundation/config/testing/entities/testing.py,sha256=m_i9jZlOXs_AzNKNNf0a3ByS7jDGaRz_2FO1ScV577Q,11293
225
+ orionis/foundation/config/testing/entities/testing.py,sha256=AuhPU9O15Aeqs8jQVHWJwamgrrcvmC4ThsJ31jyrWic,11849
226
226
  orionis/foundation/config/testing/enums/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
227
227
  orionis/foundation/config/testing/enums/test_mode.py,sha256=IbFpauu7J-iSAfmC8jDbmTEYl8eZr-AexL-lyOh8_74,337
228
228
  orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
229
- orionis/metadata/framework.py,sha256=QmC-g5i6UhTE0QWIF78bMyfW6Dm4d4521_PuYknYoGQ,4960
229
+ orionis/metadata/framework.py,sha256=klmDRFqvLc8HnxhUeqOIpWsQhC1a4vZm3oDq2LUAxQs,4960
230
230
  orionis/metadata/package.py,sha256=tqLfBRo-w1j_GN4xvzUNFyweWYFS-qhSgAEc-AmCH1M,5452
231
231
  orionis/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
232
232
  orionis/patterns/singleton/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -344,14 +344,14 @@ orionis/test/output/dumper.py,sha256=y-6du3n1IU2Cd2MFbMuEiLcpMqEOqENkuAXwMMhcsEI
344
344
  orionis/test/output/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
345
345
  orionis/test/output/contracts/dumper.py,sha256=5OqGc4GEXCXX76sCX185giQMyKwwZvlOv3I7tTwV2fQ,1324
346
346
  orionis/test/suites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
347
- orionis/test/suites/test_suite.py,sha256=fdVmC56PJfWDuYeekY7oN-04AEHMqxwLI5mZNJAuOZI,5261
348
- orionis/test/suites/test_unit.py,sha256=JAla82Uc2OEvvBTE8oI8BT0hxeb03FJB1bdKU7G2xlA,51293
347
+ orionis/test/suites/test_suite.py,sha256=nJhToYdvHFETSNqunk-_i6Pe716842eaFKDBhChjigA,5303
348
+ orionis/test/suites/test_unit.py,sha256=dnLEEeBnGkE7DRM2XXJPtxHw25JLzP9ZtcGImmBNBM4,54916
349
349
  orionis/test/suites/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
350
350
  orionis/test/suites/contracts/test_suite.py,sha256=eluzYwkNBbKjxYStj_tHN_Fm3YDPpGQdqMu5eiluh-E,1059
351
351
  orionis/test/suites/contracts/test_unit.py,sha256=l1LQllODyvcSByXMl1lGrUkoLsXbBHZZLWZI4A-mlQg,5881
352
352
  orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
353
353
  orionis/test/view/render.py,sha256=jXZkbITBknbUwm_mD8bcTiwLDvsFkrO9qrf0ZgPwqxc,4903
354
- orionis-0.293.0.dist-info/licenses/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
354
+ orionis-0.295.0.dist-info/licenses/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
355
355
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
356
356
  tests/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
357
357
  tests/example/test_example.py,sha256=byd_lI6tVDgGPEIrr7PLZbBu0UoZOymmdmyA_4u-QUw,601
@@ -455,8 +455,8 @@ tests/support/inspection/fakes/fake_reflection_instance_with_abstract.py,sha256=
455
455
  tests/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
456
456
  tests/testing/test_testing_result.py,sha256=MrGK3ZimedL0b5Ydu69Dg8Iul017AzLTm7VPxpXlpfU,4315
457
457
  tests/testing/test_testing_unit.py,sha256=A6QkiOkP7GPC1Szh_GqsrV7GxjWjK8cIwFez6YfrzmM,7683
458
- orionis-0.293.0.dist-info/METADATA,sha256=VYamMjDShBXxI6Quu-380uo1bp772T2nDaTlWcmJdwI,4772
459
- orionis-0.293.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
460
- orionis-0.293.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
461
- orionis-0.293.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
462
- orionis-0.293.0.dist-info/RECORD,,
458
+ orionis-0.295.0.dist-info/METADATA,sha256=fPQLKOQTJqwhW2rscOTMOoRqQjcIAfMW3fKU2w1e5Wc,4772
459
+ orionis-0.295.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
460
+ orionis-0.295.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
461
+ orionis-0.295.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
462
+ orionis-0.295.0.dist-info/RECORD,,