orionis 0.372.0__py3-none-any.whl → 0.374.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.
Files changed (99) hide show
  1. orionis/__init__.py +4 -2
  2. orionis/container/facades/facade.py +10 -8
  3. orionis/container/resolver/resolver.py +3 -3
  4. orionis/foundation/application.py +25 -0
  5. orionis/metadata/framework.py +1 -1
  6. orionis/services/introspection/dependencies/entities/callable_dependencies.py +6 -6
  7. orionis/services/introspection/dependencies/entities/class_dependencies.py +7 -7
  8. orionis/services/introspection/dependencies/entities/{resolved_dependencies.py → known_dependencies.py} +1 -1
  9. orionis/services/introspection/dependencies/entities/method_dependencies.py +6 -6
  10. orionis/services/introspection/dependencies/reflection.py +4 -4
  11. orionis/test/arguments/parser.py +187 -0
  12. orionis/test/cases/asynchronous.py +145 -0
  13. orionis/test/cases/synchronous.py +135 -0
  14. orionis/test/contracts/kernel.py +134 -0
  15. orionis/test/contracts/logs.py +125 -0
  16. orionis/test/contracts/parser.py +43 -0
  17. orionis/test/contracts/render.py +30 -0
  18. orionis/test/contracts/unit_test.py +21 -0
  19. orionis/test/core/unit_test.py +104 -23
  20. orionis/test/entities/arguments.py +38 -0
  21. orionis/test/kernel.py +336 -0
  22. orionis/test/output/dumper.py +3 -4
  23. orionis/test/output/printer.py +22 -0
  24. orionis/test/{logs → record}/history.py +25 -9
  25. orionis/test/records/__init__.py +0 -0
  26. orionis/test/records/logs.py +385 -0
  27. orionis/test/view/render.py +8 -5
  28. {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/METADATA +1 -1
  29. {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/RECORD +93 -88
  30. tests/example/test_example.py +4 -3
  31. tests/foundation/config/app/test_foundation_config_app.py +2 -2
  32. tests/foundation/config/auth/test_foundation_config_auth.py +2 -2
  33. tests/foundation/config/cache/test_foundation_config_cache.py +2 -2
  34. tests/foundation/config/cache/test_foundation_config_cache_file.py +2 -2
  35. tests/foundation/config/cache/test_foundation_config_cache_stores.py +2 -2
  36. tests/foundation/config/cors/test_foundation_config_cors.py +2 -2
  37. tests/foundation/config/database/test_foundation_config_database.py +2 -2
  38. tests/foundation/config/database/test_foundation_config_database_connections.py +2 -2
  39. tests/foundation/config/database/test_foundation_config_database_mysql.py +2 -2
  40. tests/foundation/config/database/test_foundation_config_database_oracle.py +2 -2
  41. tests/foundation/config/database/test_foundation_config_database_pgsql.py +2 -2
  42. tests/foundation/config/database/test_foundation_config_database_sqlite.py +2 -2
  43. tests/foundation/config/filesystems/test_foundation_config_filesystems.py +2 -2
  44. tests/foundation/config/filesystems/test_foundation_config_filesystems_aws.py +2 -2
  45. tests/foundation/config/filesystems/test_foundation_config_filesystems_disks.py +2 -2
  46. tests/foundation/config/filesystems/test_foundation_config_filesystems_local.py +2 -2
  47. tests/foundation/config/filesystems/test_foundation_config_filesystems_public.py +2 -2
  48. tests/foundation/config/logging/test_foundation_config_logging.py +2 -2
  49. tests/foundation/config/logging/test_foundation_config_logging_channels.py +2 -2
  50. tests/foundation/config/logging/test_foundation_config_logging_chunked.py +2 -2
  51. tests/foundation/config/logging/test_foundation_config_logging_daily.py +2 -2
  52. tests/foundation/config/logging/test_foundation_config_logging_hourly.py +2 -2
  53. tests/foundation/config/logging/test_foundation_config_logging_monthly.py +2 -2
  54. tests/foundation/config/logging/test_foundation_config_logging_stack.py +2 -2
  55. tests/foundation/config/logging/test_foundation_config_logging_weekly.py +2 -2
  56. tests/foundation/config/mail/test_foundation_config_mail.py +2 -2
  57. tests/foundation/config/mail/test_foundation_config_mail_file.py +2 -2
  58. tests/foundation/config/mail/test_foundation_config_mail_mailers.py +2 -2
  59. tests/foundation/config/mail/test_foundation_config_mail_smtp.py +2 -2
  60. tests/foundation/config/queue/test_foundation_config_queue.py +2 -5
  61. tests/foundation/config/queue/test_foundation_config_queue_brokers.py +2 -2
  62. tests/foundation/config/queue/test_foundation_config_queue_database.py +3 -2
  63. tests/foundation/config/root/test_foundation_config_root_paths.py +3 -3
  64. tests/foundation/config/session/test_foundation_config_session.py +4 -3
  65. tests/foundation/config/startup/test_foundation_config_startup.py +4 -3
  66. tests/foundation/config/testing/test_foundation_config_testing.py +3 -3
  67. tests/foundation/exceptions/test_foundation_config_exceptions.py +3 -3
  68. tests/metadata/test_metadata_framework.py +2 -2
  69. tests/metadata/test_metadata_package.py +3 -2
  70. tests/services/asynchrony/test_services_asynchrony_coroutine.py +2 -2
  71. tests/services/environment/test_services_environment.py +2 -2
  72. tests/services/inspection/dependencies/test_reflect_dependencies.py +22 -22
  73. tests/services/inspection/reflection/test_reflection_abstract.py +2 -2
  74. tests/services/inspection/reflection/test_reflection_callable.py +2 -2
  75. tests/services/inspection/reflection/test_reflection_concrete.py +2 -2
  76. tests/services/inspection/reflection/test_reflection_instance.py +2 -2
  77. tests/services/inspection/reflection/test_reflection_module.py +2 -2
  78. tests/services/inspection/test_reflection.py +2 -2
  79. tests/services/path/test_services_resolver.py +2 -2
  80. tests/services/system/test_services_system_imports.py +2 -2
  81. tests/services/system/test_services_system_workers.py +3 -2
  82. tests/support/parsers/test_services_parser_exceptions.py +2 -2
  83. tests/support/patterns/singleton/test_patterns_singleton.py +2 -2
  84. tests/support/standard/test_services_std.py +2 -2
  85. tests/support/wrapper/test_services_wrapper_docdict.py +2 -2
  86. tests/testing/test_testing_result.py +4 -6
  87. tests/testing/test_testing_unit.py +9 -10
  88. orionis/test/cases/test_async.py +0 -55
  89. orionis/test/cases/test_case.py +0 -42
  90. orionis/test/cases/test_sync.py +0 -33
  91. orionis/test/contracts/history.py +0 -54
  92. orionis/test/test_suite.py +0 -142
  93. orionis/unittesting.py +0 -64
  94. /orionis/test/{logs → arguments}/__init__.py +0 -0
  95. /orionis/test/entities/{test_result.py → result.py} +0 -0
  96. {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/WHEEL +0 -0
  97. {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/licenses/LICENCE +0 -0
  98. {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/top_level.txt +0 -0
  99. {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/zip-safe +0 -0
orionis/__init__.py CHANGED
@@ -1,5 +1,7 @@
1
- from orionis.foundation.application import Application as Orionis
2
- from orionis.foundation.contracts.application import IApplication as IOrionis
1
+ from orionis.foundation.application import (
2
+ Application as Orionis,
3
+ IApplication as IOrionis
4
+ )
3
5
 
4
6
  __all__ = [
5
7
  "Orionis",
@@ -1,10 +1,13 @@
1
1
  from typing import Any
2
- from orionis.container.container import Container
3
2
  from orionis.container.exceptions import OrionisContainerAttributeError, OrionisContainerException
3
+ from orionis.foundation.application import Application
4
+ from typing import TypeVar, Any
5
+
6
+ T = TypeVar('T')
4
7
 
5
8
  class FacadeMeta(type):
6
9
 
7
- def __getattr__(cls, name: str) -> Any:
10
+ def __getattr__(cls, name: str) -> T:
8
11
  """
9
12
  When an undefined attribute is accessed, this method resolves the service and delegates the call.
10
13
 
@@ -30,8 +33,8 @@ class FacadeMeta(type):
30
33
 
31
34
  class Facade(metaclass=FacadeMeta):
32
35
 
33
- # Container instance to resolve services
34
- _container = Container()
36
+ # Application instance to resolve services
37
+ _app = Application()
35
38
 
36
39
  @classmethod
37
40
  def getFacadeAccessor(cls) -> str:
@@ -79,13 +82,12 @@ class Facade(metaclass=FacadeMeta):
79
82
  service_name = cls.getFacadeAccessor()
80
83
 
81
84
  # Check if the service is bound in the container
82
- if not cls._container.bound(service_name):
85
+ if not cls._app.bound(service_name):
83
86
  raise OrionisContainerException(
84
87
  f"Service '{service_name}' not bound in the container. "
85
- f"Please ensure '{service_name}' is registered in the container before using the {cls.__name__} facade. "
86
- "You can register services in a service provider using the 'register' method."
88
+ f"Please ensure '{service_name}' is registered in the container before using the {cls.__name__} facade."
87
89
  )
88
90
 
89
91
  # Resolve the service instance from the container
90
- service_instance = cls._container.make(service_name, *args, **kwargs)
92
+ service_instance = cls._app.make(service_name, *args, **kwargs)
91
93
  return service_instance
@@ -7,7 +7,7 @@ from orionis.container.enums.lifetimes import Lifetime
7
7
  from orionis.container.exceptions import OrionisContainerException
8
8
  from orionis.services.introspection.callables.reflection import ReflectionCallable
9
9
  from orionis.services.introspection.concretes.reflection import ReflectionConcrete
10
- from orionis.services.introspection.dependencies.entities.resolved_dependencies import ResolvedDependency
10
+ from orionis.services.introspection.dependencies.entities.known_dependencies import KnownDependency
11
11
 
12
12
  class Resolver(IResolver):
13
13
  """
@@ -367,8 +367,8 @@ class Resolver(IResolver):
367
367
  params = {}
368
368
  for param_name, dep in dependencies.resolved.items():
369
369
 
370
- # If the dependency is a ResolvedDependency, resolve it
371
- if isinstance(dep, ResolvedDependency):
370
+ # If the dependency is a KnownDependency, resolve it
371
+ if isinstance(dep, KnownDependency):
372
372
 
373
373
  # If the dependency is a built-in type, raise an exception
374
374
  if dep.module_name == 'builtins':
@@ -64,6 +64,7 @@ class Application(Container, IApplication):
64
64
  """
65
65
  if not self.__booted:
66
66
  self.__loadFrameworkProviders()
67
+ self.__loadFrameworksKernel()
67
68
 
68
69
  def __loadFrameworkProviders(self) -> None:
69
70
  """
@@ -72,12 +73,15 @@ class Application(Container, IApplication):
72
73
  This method should register core services required by the framework
73
74
  before user-defined providers are loaded.
74
75
  """
76
+
77
+ # Import core provider classes
75
78
  from orionis.foundation.providers.console_provider import ConsoleProvider
76
79
  from orionis.foundation.providers.dumper_provider import DumperProvider
77
80
  from orionis.foundation.providers.path_resolver_provider import PathResolverProvider
78
81
  from orionis.foundation.providers.progress_bar_provider import ProgressBarProvider
79
82
  from orionis.foundation.providers.workers_provider import WorkersProvider
80
83
 
84
+ # List of core providers to register
81
85
  core_providers = [
82
86
  ConsoleProvider,
83
87
  DumperProvider,
@@ -86,9 +90,30 @@ class Application(Container, IApplication):
86
90
  WorkersProvider
87
91
  ]
88
92
 
93
+ # Register each core provider with the application
89
94
  for provider_cls in core_providers:
90
95
  self.__registerProvider(provider_cls)
91
96
 
97
+ def __loadFrameworksKernel(self) -> None:
98
+ """
99
+ Load the core framework kernel.
100
+
101
+ This method is responsible for loading the core kernel of the framework,
102
+ which is essential for the application to function correctly.
103
+ """
104
+
105
+ # Import Kernel classes
106
+ from orionis.test.kernel import TestKernel, ITestKernel
107
+
108
+ # List of core kernels to register
109
+ core_kernels = {
110
+ ITestKernel: TestKernel
111
+ }
112
+
113
+ # Register each core kernel with the application
114
+ for kernel_name, kernel_cls in core_kernels.items():
115
+ self.instance(kernel_name, kernel_cls(self))
116
+
92
117
  def __registerProvider(
93
118
  self,
94
119
  provider_cls: Type[IServiceProvider]
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.372.0"
8
+ VERSION = "0.374.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Any, Dict, List
3
- from orionis.services.introspection.dependencies.entities.resolved_dependencies import ResolvedDependency
3
+ from orionis.services.introspection.dependencies.entities.known_dependencies import KnownDependency
4
4
  from orionis.services.introspection.exceptions import ReflectionTypeError
5
5
 
6
6
  @dataclass(frozen=True, kw_only=True)
@@ -10,9 +10,9 @@ class CallableDependency:
10
10
 
11
11
  Parameters
12
12
  ----------
13
- resolved : Dict[ResolvedDependency, Any]
13
+ resolved : Dict[KnownDependency, Any]
14
14
  A dictionary mapping resolved dependency descriptors to their corresponding
15
- resolved instances or values for the method. All keys must be ResolvedDependency instances.
15
+ resolved instances or values for the method. All keys must be KnownDependency instances.
16
16
  unresolved : List[str]
17
17
  A list of method parameter names or dependency identifiers that could not be resolved.
18
18
  Must contain only non-empty strings.
@@ -21,12 +21,12 @@ class CallableDependency:
21
21
  ------
22
22
  ReflectionTypeError
23
23
  If types don't match the expected:
24
- - resolved: Dict[ResolvedDependency, Any]
24
+ - resolved: Dict[KnownDependency, Any]
25
25
  - unresolved: List[str]
26
26
  ValueError
27
27
  If resolved contains None keys or unresolved contains empty strings
28
28
  """
29
- resolved: Dict[ResolvedDependency, Any]
29
+ resolved: Dict[KnownDependency, Any]
30
30
  unresolved: List[str]
31
31
 
32
32
  def __post_init__(self):
@@ -37,7 +37,7 @@ class CallableDependency:
37
37
  ------
38
38
  ReflectionTypeError
39
39
  If types don't match the expected:
40
- - resolved: Dict[ResolvedDependency, Any]
40
+ - resolved: Dict[KnownDependency, Any]
41
41
  - unresolved: List[str]
42
42
  ValueError
43
43
  If resolved contains None keys or unresolved contains empty strings
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Any, Dict, List
3
- from orionis.services.introspection.dependencies.entities.resolved_dependencies import ResolvedDependency
3
+ from orionis.services.introspection.dependencies.entities.known_dependencies import KnownDependency
4
4
  from orionis.services.introspection.exceptions import ReflectionTypeError
5
5
 
6
6
  @dataclass(frozen=True, kw_only=True)
@@ -10,21 +10,21 @@ class ClassDependency:
10
10
 
11
11
  Parameters
12
12
  ----------
13
- resolved : Dict[ResolvedDependency, Any]
13
+ resolved : Dict[KnownDependency, Any]
14
14
  A dictionary mapping resolved dependency descriptors to their corresponding resolved instances or values.
15
- All keys must be ResolvedDependency instances.
15
+ All keys must be KnownDependency instances.
16
16
  unresolved : List[str]
17
17
  A list of dependency names or identifiers that could not be resolved.
18
18
  Must contain only strings.
19
19
 
20
20
  Attributes
21
21
  ----------
22
- resolved : Dict[ResolvedDependency, Any]
22
+ resolved : Dict[KnownDependency, Any]
23
23
  Dictionary of resolved dependencies.
24
24
  unresolved : List[str]
25
25
  List of unresolved dependency names.
26
26
  """
27
- resolved: Dict[ResolvedDependency, Any]
27
+ resolved: Dict[KnownDependency, Any]
28
28
  unresolved: List[str]
29
29
 
30
30
  def __post_init__(self):
@@ -35,12 +35,12 @@ class ClassDependency:
35
35
  ------
36
36
  ReflectionTypeError
37
37
  If types don't match the expected:
38
- - resolved: Dict[ResolvedDependency, Any]
38
+ - resolved: Dict[KnownDependency, Any]
39
39
  - unresolved: List[str]
40
40
  ValueError
41
41
  If resolved contains None keys or unresolved contains empty strings.
42
42
  """
43
- # Validate 'resolved' is a dict with ResolvedDependency keys
43
+ # Validate 'resolved' is a dict with KnownDependency keys
44
44
  if not isinstance(self.resolved, dict):
45
45
  raise ReflectionTypeError(
46
46
  f"'resolved' must be a dict, got {type(self.resolved).__name__}"
@@ -3,7 +3,7 @@ from typing import Type, Any
3
3
  from orionis.services.introspection.exceptions import ReflectionTypeError
4
4
 
5
5
  @dataclass(frozen=True, kw_only=True)
6
- class ResolvedDependency:
6
+ class KnownDependency:
7
7
  """
8
8
  Represents a fully resolved dependency with complete type information.
9
9
 
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Any, Dict, List
3
- from orionis.services.introspection.dependencies.entities.resolved_dependencies import ResolvedDependency
3
+ from orionis.services.introspection.dependencies.entities.known_dependencies import KnownDependency
4
4
  from orionis.services.introspection.exceptions import ReflectionTypeError
5
5
 
6
6
  @dataclass(frozen=True, kw_only=True)
@@ -10,9 +10,9 @@ class MethodDependency:
10
10
 
11
11
  Parameters
12
12
  ----------
13
- resolved : Dict[ResolvedDependency, Any]
13
+ resolved : Dict[KnownDependency, Any]
14
14
  A dictionary mapping resolved dependency descriptors to their corresponding
15
- resolved instances or values for the method. All keys must be ResolvedDependency instances.
15
+ resolved instances or values for the method. All keys must be KnownDependency instances.
16
16
  unresolved : List[str]
17
17
  A list of method parameter names or dependency identifiers that could not be resolved.
18
18
  Must contain only non-empty strings.
@@ -21,12 +21,12 @@ class MethodDependency:
21
21
  ------
22
22
  ReflectionTypeError
23
23
  If types don't match the expected:
24
- - resolved: Dict[ResolvedDependency, Any]
24
+ - resolved: Dict[KnownDependency, Any]
25
25
  - unresolved: List[str]
26
26
  ValueError
27
27
  If resolved contains None keys or unresolved contains empty strings
28
28
  """
29
- resolved: Dict[ResolvedDependency, Any]
29
+ resolved: Dict[KnownDependency, Any]
30
30
  unresolved: List[str]
31
31
 
32
32
  def __post_init__(self):
@@ -37,7 +37,7 @@ class MethodDependency:
37
37
  ------
38
38
  ReflectionTypeError
39
39
  If types don't match the expected:
40
- - resolved: Dict[ResolvedDependency, Any]
40
+ - resolved: Dict[KnownDependency, Any]
41
41
  - unresolved: List[str]
42
42
  ValueError
43
43
  If resolved contains None keys or unresolved contains empty strings
@@ -4,7 +4,7 @@ from orionis.services.introspection.dependencies.contracts.reflection import IRe
4
4
  from orionis.services.introspection.dependencies.entities.callable_dependencies import CallableDependency
5
5
  from orionis.services.introspection.dependencies.entities.class_dependencies import ClassDependency
6
6
  from orionis.services.introspection.dependencies.entities.method_dependencies import MethodDependency
7
- from orionis.services.introspection.dependencies.entities.resolved_dependencies import ResolvedDependency
7
+ from orionis.services.introspection.dependencies.entities.known_dependencies import KnownDependency
8
8
  from orionis.services.introspection.exceptions import ReflectionValueError
9
9
 
10
10
  class ReflectDependencies(IReflectDependencies):
@@ -114,7 +114,7 @@ class ReflectDependencies(IReflectDependencies):
114
114
  # If the parameter has an annotation, it is added to the list of resolved dependencies
115
115
  if param.annotation is not param.empty:
116
116
  module_path = param.annotation.__module__
117
- resolved_dependencies[param_name] = ResolvedDependency(
117
+ resolved_dependencies[param_name] = KnownDependency(
118
118
  module_name=module_path,
119
119
  class_name=param.annotation.__name__,
120
120
  type=param.annotation,
@@ -165,7 +165,7 @@ class ReflectDependencies(IReflectDependencies):
165
165
  # If the parameter has an annotation, it is added to the list of resolved dependencies
166
166
  if param.annotation is not param.empty:
167
167
  module_path = param.annotation.__module__
168
- resolved_dependencies[param_name] = ResolvedDependency(
168
+ resolved_dependencies[param_name] = KnownDependency(
169
169
  module_name=module_path,
170
170
  class_name=param.annotation.__name__,
171
171
  type=param.annotation,
@@ -216,7 +216,7 @@ class ReflectDependencies(IReflectDependencies):
216
216
  # If the parameter has an annotation, it is added to the list of resolved dependencies
217
217
  if param.annotation is not param.empty:
218
218
  module_path = param.annotation.__module__
219
- resolved_dependencies[param_name] = ResolvedDependency(
219
+ resolved_dependencies[param_name] = KnownDependency(
220
220
  module_name=module_path,
221
221
  class_name=param.annotation.__name__,
222
222
  type=param.annotation,
@@ -0,0 +1,187 @@
1
+ import argparse
2
+ from orionis.test.contracts.parser import ITestArgumentParser
3
+ from orionis.test.entities.arguments import TestArguments
4
+
5
+ class TestArgumentParser(ITestArgumentParser):
6
+ """
7
+ A parser class for handling test command-line arguments.
8
+
9
+ This class encapsulates the logic for creating and configuring the argument parser
10
+ for the Orionis test runner, providing a clean interface for parsing test arguments.
11
+ """
12
+
13
+ def __init__(
14
+ self
15
+ ) -> None:
16
+ """Initialize the argument parser with all required arguments."""
17
+ self.parser = self.__create()
18
+
19
+ def __create(
20
+ self
21
+ ) -> argparse.ArgumentParser:
22
+ """
23
+ Create and configure the argument parser with all test-related arguments.
24
+
25
+ Returns
26
+ -------
27
+ argparse.ArgumentParser
28
+ The configured argument parser instance.
29
+ """
30
+ parser = argparse.ArgumentParser(description="Run Orionis tests.")
31
+
32
+ # Basic test configuration
33
+ parser.add_argument(
34
+ '--verbosity',
35
+ type=int,
36
+ default=2,
37
+ help='Verbosity level (default: 2)'
38
+ )
39
+
40
+ parser.add_argument(
41
+ '--mode',
42
+ choices=['parallel', 'sequential'],
43
+ default='parallel',
44
+ help='Execution mode for tests (default: parallel)'
45
+ )
46
+
47
+ # Fail fast configuration
48
+ parser.add_argument(
49
+ '--fail_fast',
50
+ dest='fail_fast',
51
+ action='store_true',
52
+ help='Stop on first failure'
53
+ )
54
+ parser.add_argument(
55
+ '--no_fail_fast',
56
+ dest='fail_fast',
57
+ action='store_false',
58
+ help='Do not stop on first failure (default)'
59
+ )
60
+ parser.set_defaults(fail_fast=False)
61
+
62
+ # Print result configuration
63
+ parser.add_argument(
64
+ '--print_result',
65
+ dest='print_result',
66
+ action='store_true',
67
+ help='Print test results to console (default)'
68
+ )
69
+ parser.add_argument(
70
+ '--no_print_result',
71
+ dest='print_result',
72
+ action='store_false',
73
+ help='Do not print test results to console'
74
+ )
75
+ parser.set_defaults(print_result=True)
76
+
77
+ # Exception handling configuration
78
+ parser.add_argument(
79
+ '--throw_exception',
80
+ dest='throw_exception',
81
+ action='store_true',
82
+ help='Throw exception on test failure'
83
+ )
84
+ parser.add_argument(
85
+ '--no_throw_exception',
86
+ dest='throw_exception',
87
+ action='store_false',
88
+ help='Do not throw exception on test failure (default)'
89
+ )
90
+ parser.set_defaults(throw_exception=False)
91
+
92
+ # Persistent mode configuration
93
+ parser.add_argument(
94
+ '--persistent',
95
+ dest='persistent',
96
+ action='store_true',
97
+ help='Run tests in persistent mode'
98
+ )
99
+ parser.add_argument(
100
+ '--no_persistent',
101
+ dest='persistent',
102
+ action='store_false',
103
+ help='Do not run tests in persistent mode (default)'
104
+ )
105
+ parser.set_defaults(persistent=False)
106
+
107
+ parser.add_argument(
108
+ '--persistent_driver',
109
+ type=str,
110
+ default=None,
111
+ help='Persistent driver to use (default: None)'
112
+ )
113
+
114
+ # Web report configuration
115
+ parser.add_argument(
116
+ '--web_report',
117
+ dest='web_report',
118
+ action='store_true',
119
+ help='Generate web report'
120
+ )
121
+ parser.add_argument(
122
+ '--no_web_report',
123
+ dest='web_report',
124
+ action='store_false',
125
+ help='Do not generate web report (default)'
126
+ )
127
+ parser.set_defaults(web_report=False)
128
+
129
+ # Output buffer configuration
130
+ parser.add_argument(
131
+ '--print_output_buffer',
132
+ dest='print_output_buffer',
133
+ action='store_true',
134
+ help='Print output buffer (for CI integrations)'
135
+ )
136
+ parser.add_argument(
137
+ '--no_print_output_buffer',
138
+ dest='print_output_buffer',
139
+ action='store_false',
140
+ help='Do not print output buffer (default)'
141
+ )
142
+ parser.set_defaults(print_output_buffer=False)
143
+
144
+ return parser
145
+
146
+ def parse(
147
+ self,
148
+ sys_argv: list[str]
149
+ ) -> TestArguments:
150
+ """
151
+ Parse command line arguments from sys.argv and return TestArguments object.
152
+
153
+ Parameters
154
+ ----------
155
+ sys_argv : list[str]
156
+ Command line arguments including script name. The script name (first element)
157
+ will be automatically removed before parsing.
158
+
159
+ Returns
160
+ -------
161
+ TestArguments
162
+ Parsed test arguments object.
163
+ """
164
+ # Remove script name from sys.argv (first element)
165
+ args_only = sys_argv[1:] if len(sys_argv) > 0 else []
166
+
167
+ # Parse arguments and convert to TestArguments object
168
+ parsed_args = self.parser.parse_args(args_only)
169
+
170
+ # Create TestArguments instance from parsed arguments
171
+ return TestArguments(
172
+ verbosity=parsed_args.verbosity,
173
+ mode=parsed_args.mode,
174
+ fail_fast=parsed_args.fail_fast,
175
+ print_result=parsed_args.print_result,
176
+ throw_exception=parsed_args.throw_exception,
177
+ persistent=parsed_args.persistent,
178
+ persistent_driver=parsed_args.persistent_driver,
179
+ web_report=parsed_args.web_report,
180
+ print_output_buffer=parsed_args.print_output_buffer
181
+ )
182
+
183
+ def help(
184
+ self
185
+ ) -> None:
186
+ """Print help message for the test runner."""
187
+ self.parser.print_help()
@@ -0,0 +1,145 @@
1
+ import unittest
2
+ from orionis.test.output.dumper import TestDumper
3
+
4
+ class AsyncTestCase(unittest.IsolatedAsyncioTestCase, TestDumper):
5
+ """
6
+ Base test case class for asynchronous unit testing.
7
+
8
+ This class provides a foundation for writing asynchronous unit tests within
9
+ the Orionis framework. It extends unittest.IsolatedAsyncioTestCase and includes
10
+ TestDumper functionality for enhanced test output and debugging capabilities.
11
+
12
+ The class provides hooks for custom async setup and teardown logic through the
13
+ onAsyncSetup() and onAsyncTeardown() methods, which can be overridden by subclasses
14
+ to implement test-specific asynchronous initialization and cleanup procedures.
15
+
16
+ Each test method runs in its own isolated asyncio event loop, ensuring proper
17
+ isolation and preventing side effects between tests.
18
+
19
+ Attributes
20
+ ----------
21
+ None
22
+
23
+ Methods
24
+ -------
25
+ asyncSetUp()
26
+ Initialize test environment before each async test method execution.
27
+ asyncTearDown()
28
+ Clean up test environment after each async test method execution.
29
+ onAsyncSetup()
30
+ Hook method for subclass-specific async setup logic.
31
+ onAsyncTeardown()
32
+ Hook method for subclass-specific async teardown logic.
33
+
34
+ Examples
35
+ --------
36
+ >>> class MyAsyncTest(AsyncTestCase):
37
+ ... async def onAsyncSetup(self):
38
+ ... self.client = AsyncHttpClient()
39
+ ... await self.client.connect()
40
+ ...
41
+ ... async def testAsyncOperation(self):
42
+ ... result = await self.client.get('/api/data')
43
+ ... self.assertEqual(result.status, 200)
44
+ """
45
+
46
+ async def asyncSetUp(self):
47
+ """
48
+ Initialize the test environment before each async test method.
49
+
50
+ This method is automatically called by the unittest framework before
51
+ each async test method execution. It performs the standard unittest
52
+ async setup and then calls the onAsyncSetup() hook for custom
53
+ asynchronous initialization.
54
+
55
+ Parameters
56
+ ----------
57
+ None
58
+
59
+ Returns
60
+ -------
61
+ None
62
+
63
+ Notes
64
+ -----
65
+ This method should not be overridden directly. Use onAsyncSetup() instead
66
+ for custom async setup logic. The method runs in the isolated event loop
67
+ created for each test.
68
+ """
69
+ await super().asyncSetUp()
70
+ await self.onAsyncSetup()
71
+
72
+ async def asyncTearDown(self):
73
+ """
74
+ Clean up the test environment after each async test method.
75
+
76
+ This method is automatically called by the unittest framework after
77
+ each async test method execution. It calls the onAsyncTeardown() hook
78
+ for custom cleanup and then performs the standard unittest async teardown.
79
+
80
+ Parameters
81
+ ----------
82
+ None
83
+
84
+ Returns
85
+ -------
86
+ None
87
+
88
+ Notes
89
+ -----
90
+ This method should not be overridden directly. Use onAsyncTeardown() instead
91
+ for custom async teardown logic. The method runs in the same isolated event
92
+ loop as the test.
93
+ """
94
+ await self.onAsyncTeardown()
95
+ await super().asyncTearDown()
96
+
97
+ async def onAsyncSetup(self):
98
+ """
99
+ Hook method for subclass-specific async setup logic.
100
+
101
+ This method is called during the asyncSetUp() phase and is intended to be
102
+ overridden by subclasses that need to perform custom asynchronous
103
+ initialization before each test method execution.
104
+
105
+ Parameters
106
+ ----------
107
+ None
108
+
109
+ Returns
110
+ -------
111
+ None
112
+
113
+ Examples
114
+ --------
115
+ >>> async def onAsyncSetup(self):
116
+ ... self.db_connection = await create_async_connection()
117
+ ... self.mock_service = AsyncMockService()
118
+ ... await self.mock_service.initialize()
119
+ """
120
+ pass
121
+
122
+ async def onAsyncTeardown(self):
123
+ """
124
+ Hook method for subclass-specific async teardown logic.
125
+
126
+ This method is called during the asyncTearDown() phase and is intended to be
127
+ overridden by subclasses that need to perform custom asynchronous cleanup
128
+ after each test method execution.
129
+
130
+ Parameters
131
+ ----------
132
+ None
133
+
134
+ Returns
135
+ -------
136
+ None
137
+
138
+ Examples
139
+ --------
140
+ >>> async def onAsyncTeardown(self):
141
+ ... await self.db_connection.close()
142
+ ... await self.mock_service.cleanup()
143
+ ... del self.test_data
144
+ """
145
+ pass