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.
- orionis/__init__.py +4 -2
- orionis/container/facades/facade.py +10 -8
- orionis/container/resolver/resolver.py +3 -3
- orionis/foundation/application.py +25 -0
- orionis/metadata/framework.py +1 -1
- orionis/services/introspection/dependencies/entities/callable_dependencies.py +6 -6
- orionis/services/introspection/dependencies/entities/class_dependencies.py +7 -7
- orionis/services/introspection/dependencies/entities/{resolved_dependencies.py → known_dependencies.py} +1 -1
- orionis/services/introspection/dependencies/entities/method_dependencies.py +6 -6
- orionis/services/introspection/dependencies/reflection.py +4 -4
- orionis/test/arguments/parser.py +187 -0
- orionis/test/cases/asynchronous.py +145 -0
- orionis/test/cases/synchronous.py +135 -0
- orionis/test/contracts/kernel.py +134 -0
- orionis/test/contracts/logs.py +125 -0
- orionis/test/contracts/parser.py +43 -0
- orionis/test/contracts/render.py +30 -0
- orionis/test/contracts/unit_test.py +21 -0
- orionis/test/core/unit_test.py +104 -23
- orionis/test/entities/arguments.py +38 -0
- orionis/test/kernel.py +336 -0
- orionis/test/output/dumper.py +3 -4
- orionis/test/output/printer.py +22 -0
- orionis/test/{logs → record}/history.py +25 -9
- orionis/test/records/__init__.py +0 -0
- orionis/test/records/logs.py +385 -0
- orionis/test/view/render.py +8 -5
- {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/METADATA +1 -1
- {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/RECORD +93 -88
- tests/example/test_example.py +4 -3
- tests/foundation/config/app/test_foundation_config_app.py +2 -2
- tests/foundation/config/auth/test_foundation_config_auth.py +2 -2
- tests/foundation/config/cache/test_foundation_config_cache.py +2 -2
- tests/foundation/config/cache/test_foundation_config_cache_file.py +2 -2
- tests/foundation/config/cache/test_foundation_config_cache_stores.py +2 -2
- tests/foundation/config/cors/test_foundation_config_cors.py +2 -2
- tests/foundation/config/database/test_foundation_config_database.py +2 -2
- tests/foundation/config/database/test_foundation_config_database_connections.py +2 -2
- tests/foundation/config/database/test_foundation_config_database_mysql.py +2 -2
- tests/foundation/config/database/test_foundation_config_database_oracle.py +2 -2
- tests/foundation/config/database/test_foundation_config_database_pgsql.py +2 -2
- tests/foundation/config/database/test_foundation_config_database_sqlite.py +2 -2
- tests/foundation/config/filesystems/test_foundation_config_filesystems.py +2 -2
- tests/foundation/config/filesystems/test_foundation_config_filesystems_aws.py +2 -2
- tests/foundation/config/filesystems/test_foundation_config_filesystems_disks.py +2 -2
- tests/foundation/config/filesystems/test_foundation_config_filesystems_local.py +2 -2
- tests/foundation/config/filesystems/test_foundation_config_filesystems_public.py +2 -2
- tests/foundation/config/logging/test_foundation_config_logging.py +2 -2
- tests/foundation/config/logging/test_foundation_config_logging_channels.py +2 -2
- tests/foundation/config/logging/test_foundation_config_logging_chunked.py +2 -2
- tests/foundation/config/logging/test_foundation_config_logging_daily.py +2 -2
- tests/foundation/config/logging/test_foundation_config_logging_hourly.py +2 -2
- tests/foundation/config/logging/test_foundation_config_logging_monthly.py +2 -2
- tests/foundation/config/logging/test_foundation_config_logging_stack.py +2 -2
- tests/foundation/config/logging/test_foundation_config_logging_weekly.py +2 -2
- tests/foundation/config/mail/test_foundation_config_mail.py +2 -2
- tests/foundation/config/mail/test_foundation_config_mail_file.py +2 -2
- tests/foundation/config/mail/test_foundation_config_mail_mailers.py +2 -2
- tests/foundation/config/mail/test_foundation_config_mail_smtp.py +2 -2
- tests/foundation/config/queue/test_foundation_config_queue.py +2 -5
- tests/foundation/config/queue/test_foundation_config_queue_brokers.py +2 -2
- tests/foundation/config/queue/test_foundation_config_queue_database.py +3 -2
- tests/foundation/config/root/test_foundation_config_root_paths.py +3 -3
- tests/foundation/config/session/test_foundation_config_session.py +4 -3
- tests/foundation/config/startup/test_foundation_config_startup.py +4 -3
- tests/foundation/config/testing/test_foundation_config_testing.py +3 -3
- tests/foundation/exceptions/test_foundation_config_exceptions.py +3 -3
- tests/metadata/test_metadata_framework.py +2 -2
- tests/metadata/test_metadata_package.py +3 -2
- tests/services/asynchrony/test_services_asynchrony_coroutine.py +2 -2
- tests/services/environment/test_services_environment.py +2 -2
- tests/services/inspection/dependencies/test_reflect_dependencies.py +22 -22
- tests/services/inspection/reflection/test_reflection_abstract.py +2 -2
- tests/services/inspection/reflection/test_reflection_callable.py +2 -2
- tests/services/inspection/reflection/test_reflection_concrete.py +2 -2
- tests/services/inspection/reflection/test_reflection_instance.py +2 -2
- tests/services/inspection/reflection/test_reflection_module.py +2 -2
- tests/services/inspection/test_reflection.py +2 -2
- tests/services/path/test_services_resolver.py +2 -2
- tests/services/system/test_services_system_imports.py +2 -2
- tests/services/system/test_services_system_workers.py +3 -2
- tests/support/parsers/test_services_parser_exceptions.py +2 -2
- tests/support/patterns/singleton/test_patterns_singleton.py +2 -2
- tests/support/standard/test_services_std.py +2 -2
- tests/support/wrapper/test_services_wrapper_docdict.py +2 -2
- tests/testing/test_testing_result.py +4 -6
- tests/testing/test_testing_unit.py +9 -10
- orionis/test/cases/test_async.py +0 -55
- orionis/test/cases/test_case.py +0 -42
- orionis/test/cases/test_sync.py +0 -33
- orionis/test/contracts/history.py +0 -54
- orionis/test/test_suite.py +0 -142
- orionis/unittesting.py +0 -64
- /orionis/test/{logs → arguments}/__init__.py +0 -0
- /orionis/test/entities/{test_result.py → result.py} +0 -0
- {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/WHEEL +0 -0
- {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.372.0.dist-info → orionis-0.374.0.dist-info}/top_level.txt +0 -0
- {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
|
|
2
|
-
|
|
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) ->
|
|
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
|
-
#
|
|
34
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
371
|
-
if isinstance(dep,
|
|
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]
|
orionis/metadata/framework.py
CHANGED
|
@@ -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.
|
|
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[
|
|
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
|
|
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[
|
|
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[
|
|
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[
|
|
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.
|
|
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[
|
|
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
|
|
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[
|
|
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[
|
|
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[
|
|
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
|
|
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
|
|
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.
|
|
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[
|
|
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
|
|
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[
|
|
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[
|
|
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[
|
|
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.
|
|
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] =
|
|
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] =
|
|
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] =
|
|
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
|