orionis 0.432.0__py3-none-any.whl → 0.435.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/app.py +17 -0
- orionis/metadata/framework.py +1 -1
- orionis/support/entities/base.py +18 -37
- orionis/support/facades/console.py +3 -9
- orionis/support/facades/dumper.py +3 -9
- orionis/support/facades/logger.py +3 -9
- orionis/support/facades/path_resolver.py +3 -10
- orionis/support/facades/progress_bar.py +3 -10
- orionis/support/facades/testing.py +4 -10
- orionis/support/facades/workers.py +4 -9
- orionis/support/formatter/exceptions/contracts/parser.py +10 -7
- orionis/support/formatter/exceptions/parser.py +28 -26
- orionis/support/formatter/serializer.py +12 -5
- orionis/support/patterns/singleton/meta.py +17 -21
- orionis/support/standard/contracts/std.py +25 -24
- orionis/support/standard/exceptions/value.py +2 -2
- orionis/support/standard/std.py +26 -24
- orionis/support/wrapper/dot_dict.py +16 -51
- orionis/test/cases/asynchronous.py +17 -81
- orionis/test/cases/synchronous.py +17 -73
- orionis/test/contracts/dumper.py +17 -21
- orionis/test/contracts/kernel.py +5 -12
- orionis/test/contracts/logs.py +16 -21
- orionis/test/contracts/printer.py +70 -8
- orionis/test/contracts/render.py +7 -13
- orionis/test/contracts/test_result.py +58 -27
- orionis/test/contracts/unit_test.py +18 -18
- orionis/test/core/unit_test.py +325 -445
- orionis/test/entities/result.py +49 -21
- orionis/test/enums/status.py +11 -17
- orionis/test/exceptions/config.py +4 -8
- orionis/test/exceptions/failure.py +2 -18
- orionis/test/exceptions/persistence.py +4 -8
- orionis/test/exceptions/runtime.py +4 -8
- orionis/test/exceptions/value.py +5 -13
- orionis/test/kernel.py +14 -42
- orionis/test/output/dumper.py +21 -43
- orionis/test/output/printer.py +6 -146
- orionis/test/records/logs.py +57 -121
- orionis/test/validators/base_path.py +8 -6
- orionis/test/validators/execution_mode.py +2 -3
- orionis/test/validators/fail_fast.py +4 -8
- orionis/test/validators/folder_path.py +5 -7
- orionis/test/validators/module_name.py +3 -3
- orionis/test/validators/name_pattern.py +4 -9
- orionis/test/validators/pattern.py +4 -9
- orionis/test/validators/persistent.py +4 -14
- orionis/test/validators/persistent_driver.py +7 -12
- orionis/test/validators/print_result.py +4 -9
- orionis/test/validators/tags.py +6 -7
- orionis/test/validators/throw_exception.py +7 -14
- orionis/test/validators/verbosity.py +15 -5
- orionis/test/validators/web_report.py +6 -10
- orionis/test/validators/workers.py +9 -4
- orionis/test/view/render.py +9 -26
- {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/METADATA +1 -1
- {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/RECORD +76 -75
- tests/support/entities/mock_dataclass.py +16 -10
- tests/support/entities/test_base.py +6 -14
- tests/support/patterns/singleton/test_patterns_singleton.py +7 -8
- tests/support/standard/test_services_std.py +113 -37
- tests/support/wrapper/test_services_wrapper_docdict.py +25 -40
- tests/testing/cases/test_testing_asynchronous.py +14 -14
- tests/testing/cases/test_testing_synchronous.py +12 -14
- tests/testing/entities/test_testing_result.py +12 -51
- tests/testing/enums/test_testing_status.py +8 -13
- tests/testing/output/test_testing_dumper.py +3 -6
- tests/testing/output/test_testing_printer.py +5 -5
- tests/testing/records/test_testing_records.py +16 -26
- tests/testing/test_testing_unit.py +8 -94
- tests/testing/validators/test_testing_validators.py +55 -112
- tests/testing/view/test_render.py +4 -5
- {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/WHEEL +0 -0
- {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/top_level.txt +0 -0
- {orionis-0.432.0.dist-info → orionis-0.435.0.dist-info}/zip-safe +0 -0
orionis/app.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from orionis.foundation.application import Application, IApplication
|
|
2
|
+
|
|
3
|
+
def Orionis() -> IApplication:
|
|
4
|
+
"""
|
|
5
|
+
Initialize and return the main Orionis application instance.
|
|
6
|
+
|
|
7
|
+
Initializes the core application object that implements the `IApplication` interface.
|
|
8
|
+
This function acts as the entry point for creating and accessing the main application instance.
|
|
9
|
+
|
|
10
|
+
Returns
|
|
11
|
+
-------
|
|
12
|
+
IApplication
|
|
13
|
+
The initialized application instance implementing the `IApplication` interface.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
# Instantiate and return the main application object
|
|
17
|
+
return Application()
|
orionis/metadata/framework.py
CHANGED
orionis/support/entities/base.py
CHANGED
|
@@ -5,11 +5,10 @@ class BaseEntity:
|
|
|
5
5
|
|
|
6
6
|
def __post_init__(self):
|
|
7
7
|
"""
|
|
8
|
-
|
|
8
|
+
Called automatically after the dataclass instance is initialized.
|
|
9
9
|
|
|
10
|
-
This method is
|
|
11
|
-
|
|
12
|
-
or validation logic after all fields have been set.
|
|
10
|
+
This method is intended to be overridden by subclasses to perform additional
|
|
11
|
+
initialization or validation after all fields have been set.
|
|
13
12
|
|
|
14
13
|
Parameters
|
|
15
14
|
----------
|
|
@@ -18,60 +17,42 @@ class BaseEntity:
|
|
|
18
17
|
Returns
|
|
19
18
|
-------
|
|
20
19
|
None
|
|
21
|
-
This method does not return any value.
|
|
22
|
-
|
|
23
|
-
Notes
|
|
24
|
-
-----
|
|
25
|
-
By default, this method does nothing. Subclasses can override it to implement
|
|
26
|
-
custom post-initialization behavior.
|
|
27
20
|
"""
|
|
28
|
-
|
|
29
21
|
pass
|
|
30
22
|
|
|
31
23
|
def toDict(self) -> dict:
|
|
32
24
|
"""
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Parameters
|
|
36
|
-
----------
|
|
37
|
-
None
|
|
25
|
+
Convert the dataclass instance to a dictionary.
|
|
38
26
|
|
|
39
27
|
Returns
|
|
40
28
|
-------
|
|
41
29
|
dict
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Notes
|
|
45
|
-
-----
|
|
46
|
-
This method uses `dataclasses.asdict` to recursively convert the dataclass instance and any nested dataclasses into dictionaries.
|
|
47
|
-
Enum values are preserved as their actual values.
|
|
30
|
+
Dictionary representation of the dataclass instance, including nested dataclasses.
|
|
48
31
|
"""
|
|
49
|
-
|
|
50
|
-
# Use asdict to convert the dataclass instance to a dictionary, including nested dataclasses
|
|
51
32
|
return asdict(self)
|
|
52
33
|
|
|
53
34
|
def getFields(self):
|
|
54
35
|
"""
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
Parameters
|
|
58
|
-
----------
|
|
59
|
-
None
|
|
36
|
+
Get detailed information about each field in the dataclass instance.
|
|
60
37
|
|
|
61
38
|
Returns
|
|
62
39
|
-------
|
|
63
40
|
list of dict
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
41
|
+
A list where each element is a dictionary containing:
|
|
42
|
+
- name : str
|
|
43
|
+
The name of the field.
|
|
44
|
+
- types : list of str
|
|
45
|
+
The type(s) of the field as a list of type names.
|
|
46
|
+
- default : Any
|
|
47
|
+
The default value of the field, resolved from the field definition, default factory, or metadata.
|
|
48
|
+
- metadata : dict
|
|
49
|
+
The metadata associated with the field.
|
|
69
50
|
|
|
70
51
|
Notes
|
|
71
52
|
-----
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
53
|
+
Handles complex field types, including unions and generics, by representing them as lists of type names.
|
|
54
|
+
Resolves default values from direct assignment, default factories, or metadata, and normalizes dataclass and Enum values.
|
|
55
|
+
Metadata defaults are normalized if present and callable or dataclass/Enum types.
|
|
75
56
|
"""
|
|
76
57
|
|
|
77
58
|
# List to hold field information dictionaries
|
|
@@ -5,17 +5,11 @@ class Console(Facade):
|
|
|
5
5
|
@classmethod
|
|
6
6
|
def getFacadeAccessor(cls) -> str:
|
|
7
7
|
"""
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
This method provides the unique string identifier that the service container uses
|
|
11
|
-
to locate and instantiate the console service. It is typically used internally
|
|
12
|
-
by the Facade base class to delegate calls to the underlying implementation.
|
|
8
|
+
Get the service container binding key for the console component.
|
|
13
9
|
|
|
14
10
|
Returns
|
|
15
11
|
-------
|
|
16
12
|
str
|
|
17
|
-
The
|
|
13
|
+
The binding key used to resolve the console service from the container.
|
|
18
14
|
"""
|
|
19
|
-
|
|
20
|
-
# Return the binding key for the console service in the container
|
|
21
|
-
return "core.orionis.console"
|
|
15
|
+
return "core.orionis.console"
|
|
@@ -5,17 +5,11 @@ class Dumper(Facade):
|
|
|
5
5
|
@classmethod
|
|
6
6
|
def getFacadeAccessor(cls) -> str:
|
|
7
7
|
"""
|
|
8
|
-
Returns the binding key
|
|
9
|
-
|
|
10
|
-
This method provides the unique string identifier that the service container uses to resolve
|
|
11
|
-
and return the dumper service instance. It is typically used internally by the Facade base class
|
|
12
|
-
to access the underlying implementation.
|
|
8
|
+
Returns the service container binding key for the dumper component.
|
|
13
9
|
|
|
14
10
|
Returns
|
|
15
11
|
-------
|
|
16
12
|
str
|
|
17
|
-
The
|
|
13
|
+
The binding key "core.orionis.dumper" used to resolve the dumper service from the container.
|
|
18
14
|
"""
|
|
19
|
-
|
|
20
|
-
# Return the service container binding key for the dumper component
|
|
21
|
-
return "core.orionis.dumper"
|
|
15
|
+
return "core.orionis.dumper"
|
|
@@ -5,18 +5,12 @@ class Log(Facade):
|
|
|
5
5
|
@classmethod
|
|
6
6
|
def getFacadeAccessor(cls) -> str:
|
|
7
7
|
"""
|
|
8
|
-
Returns the binding key
|
|
9
|
-
|
|
10
|
-
This method provides the unique identifier required by the service container to retrieve
|
|
11
|
-
the logger component. It is used internally by the Facade base class to delegate calls
|
|
12
|
-
to the appropriate service implementation.
|
|
8
|
+
Returns the binding key for the logger service in the service container.
|
|
13
9
|
|
|
14
10
|
Returns
|
|
15
11
|
-------
|
|
16
12
|
str
|
|
17
|
-
The
|
|
13
|
+
The unique identifier used to resolve the logger service, specifically
|
|
18
14
|
"core.orionis.logger".
|
|
19
15
|
"""
|
|
20
|
-
|
|
21
|
-
# Return the service container binding key for the logger component
|
|
22
|
-
return "core.orionis.logger"
|
|
16
|
+
return "core.orionis.logger"
|
|
@@ -5,18 +5,11 @@ class PathResolver(Facade):
|
|
|
5
5
|
@classmethod
|
|
6
6
|
def getFacadeAccessor(cls):
|
|
7
7
|
"""
|
|
8
|
-
Returns the
|
|
9
|
-
|
|
10
|
-
This method provides the unique string identifier that the service container uses
|
|
11
|
-
to locate and retrieve the path resolver service. It is typically used internally
|
|
12
|
-
by the facade mechanism to delegate calls to the appropriate underlying implementation.
|
|
8
|
+
Returns the binding key for the path resolver service in the container.
|
|
13
9
|
|
|
14
10
|
Returns
|
|
15
11
|
-------
|
|
16
12
|
str
|
|
17
|
-
The string
|
|
18
|
-
service in the container.
|
|
13
|
+
The unique string identifier for the path resolver service, used by the service container.
|
|
19
14
|
"""
|
|
20
|
-
|
|
21
|
-
# Return the binding key for the path resolver service in the container
|
|
22
|
-
return "core.orionis.path_resolver"
|
|
15
|
+
return "core.orionis.path_resolver"
|
|
@@ -5,18 +5,11 @@ class ProgressBar(Facade):
|
|
|
5
5
|
@classmethod
|
|
6
6
|
def getFacadeAccessor(cls):
|
|
7
7
|
"""
|
|
8
|
-
Returns the binding key
|
|
9
|
-
|
|
10
|
-
This method provides the unique string identifier that the service container uses to resolve
|
|
11
|
-
the progress bar component. It is typically used internally by the Facade system to access
|
|
12
|
-
the underlying implementation.
|
|
8
|
+
Returns the binding key for the progress bar service.
|
|
13
9
|
|
|
14
10
|
Returns
|
|
15
11
|
-------
|
|
16
12
|
str
|
|
17
|
-
The
|
|
18
|
-
"core.orionis.progress_bar".
|
|
13
|
+
The unique identifier used to retrieve the progress bar service from the service container.
|
|
19
14
|
"""
|
|
20
|
-
|
|
21
|
-
# Return the service container binding key for the progress bar component
|
|
22
|
-
return "core.orionis.progress_bar"
|
|
15
|
+
return "core.orionis.progress_bar"
|
|
@@ -5,18 +5,12 @@ class Test(Facade):
|
|
|
5
5
|
@classmethod
|
|
6
6
|
def getFacadeAccessor(cls) -> str:
|
|
7
7
|
"""
|
|
8
|
-
Returns the
|
|
9
|
-
|
|
10
|
-
This method provides the unique string identifier used by the service container
|
|
11
|
-
to resolve the testing component. It is typically used internally by the Facade
|
|
12
|
-
system to retrieve the correct implementation from the container.
|
|
8
|
+
Returns the binding key for the testing component in the service container.
|
|
13
9
|
|
|
14
10
|
Returns
|
|
15
11
|
-------
|
|
16
12
|
str
|
|
17
|
-
The string
|
|
18
|
-
|
|
13
|
+
The unique string identifier for the testing component, used by the service
|
|
14
|
+
container to resolve the appropriate implementation.
|
|
19
15
|
"""
|
|
20
|
-
|
|
21
|
-
# Return the binding key for the testing component in the service container
|
|
22
|
-
return "core.orionis.testing"
|
|
16
|
+
return "core.orionis.testing"
|
|
@@ -5,18 +5,13 @@ class Workers(Facade):
|
|
|
5
5
|
@classmethod
|
|
6
6
|
def getFacadeAccessor(cls):
|
|
7
7
|
"""
|
|
8
|
-
Returns the
|
|
9
|
-
|
|
10
|
-
This method provides the unique string identifier used by the service container
|
|
11
|
-
to resolve the workers service. It is typically used internally by the Facade
|
|
12
|
-
mechanism to access the underlying implementation.
|
|
8
|
+
Returns the binding key for the workers service in the service container.
|
|
13
9
|
|
|
14
10
|
Returns
|
|
15
11
|
-------
|
|
16
12
|
str
|
|
17
|
-
The string
|
|
18
|
-
|
|
13
|
+
The identifier string for the workers service, used by the service container
|
|
14
|
+
to resolve the corresponding implementation.
|
|
19
15
|
"""
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
return "core.orionis.workers"
|
|
17
|
+
return "core.orionis.workers"
|
|
@@ -3,36 +3,39 @@ from typing import Any, Dict
|
|
|
3
3
|
|
|
4
4
|
class IExceptionParser(ABC):
|
|
5
5
|
"""
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
Interface for parsing exceptions into structured dictionary representations.
|
|
7
|
+
|
|
8
|
+
This abstract base class defines the contract for classes that convert
|
|
9
|
+
exception objects into a standardized dictionary format, which may include
|
|
10
|
+
details such as error type, message, code, stack trace, and cause.
|
|
8
11
|
"""
|
|
9
12
|
|
|
10
13
|
@property
|
|
11
14
|
@abstractmethod
|
|
12
15
|
def raw_exception(self) -> Exception:
|
|
13
16
|
"""
|
|
14
|
-
|
|
17
|
+
Returns the original exception instance.
|
|
15
18
|
|
|
16
19
|
Returns
|
|
17
20
|
-------
|
|
18
21
|
Exception
|
|
19
|
-
The
|
|
22
|
+
The exception object to be parsed.
|
|
20
23
|
"""
|
|
21
24
|
pass
|
|
22
25
|
|
|
23
26
|
@abstractmethod
|
|
24
27
|
def toDict(self) -> Dict[str, Any]:
|
|
25
28
|
"""
|
|
26
|
-
|
|
29
|
+
Converts the exception into a structured dictionary.
|
|
27
30
|
|
|
28
31
|
Returns
|
|
29
32
|
-------
|
|
30
33
|
dict
|
|
31
|
-
A
|
|
34
|
+
A dictionary containing details about the exception, such as:
|
|
32
35
|
- error_type
|
|
33
36
|
- error_message
|
|
34
37
|
- error_code
|
|
35
38
|
- stack_trace
|
|
36
|
-
- cause (if
|
|
39
|
+
- cause (if present)
|
|
37
40
|
"""
|
|
38
41
|
pass
|
|
@@ -4,24 +4,21 @@ from orionis.support.formatter.exceptions.contracts.parser import IExceptionPars
|
|
|
4
4
|
|
|
5
5
|
class ExceptionParser(IExceptionParser):
|
|
6
6
|
"""
|
|
7
|
-
|
|
7
|
+
Parses an exception and converts it into a structured dictionary representation.
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
exception : Exception
|
|
12
|
+
The exception instance to be parsed.
|
|
8
13
|
"""
|
|
9
14
|
|
|
10
15
|
def __init__(self, exception: Exception) -> None:
|
|
11
|
-
"""
|
|
12
|
-
Initialize the ExceptionParser with the given exception.
|
|
13
|
-
|
|
14
|
-
Parameters
|
|
15
|
-
----------
|
|
16
|
-
exception : Exception
|
|
17
|
-
The exception to be parsed.
|
|
18
|
-
"""
|
|
19
16
|
self.__exception = exception
|
|
20
17
|
|
|
21
18
|
@property
|
|
22
19
|
def raw_exception(self) -> Exception:
|
|
23
20
|
"""
|
|
24
|
-
|
|
21
|
+
Returns the original exception object.
|
|
25
22
|
|
|
26
23
|
Returns
|
|
27
24
|
-------
|
|
@@ -32,21 +29,21 @@ class ExceptionParser(IExceptionParser):
|
|
|
32
29
|
|
|
33
30
|
def toDict(self) -> Dict[str, Any]:
|
|
34
31
|
"""
|
|
35
|
-
|
|
32
|
+
Serializes the exception into a dictionary containing detailed error information.
|
|
36
33
|
|
|
37
34
|
Returns
|
|
38
35
|
-------
|
|
39
36
|
dict
|
|
40
|
-
|
|
41
|
-
- 'error_type':
|
|
42
|
-
- 'error_message':
|
|
43
|
-
- 'error_code':
|
|
44
|
-
- 'stack_trace':
|
|
45
|
-
- 'filename':
|
|
46
|
-
- 'lineno':
|
|
47
|
-
- 'name':
|
|
48
|
-
- 'line':
|
|
49
|
-
- 'cause':
|
|
37
|
+
Dictionary with the following keys:
|
|
38
|
+
- 'error_type': str, the type of the exception.
|
|
39
|
+
- 'error_message': str, the formatted traceback string.
|
|
40
|
+
- 'error_code': Any, custom error code if present on the exception.
|
|
41
|
+
- 'stack_trace': list of dict, each dict contains frame details:
|
|
42
|
+
- 'filename': str, file where the error occurred.
|
|
43
|
+
- 'lineno': int, line number in the file.
|
|
44
|
+
- 'name': str, function or method name.
|
|
45
|
+
- 'line': str or None, source line of code.
|
|
46
|
+
- 'cause': dict or None, nested dictionary for the original cause if present.
|
|
50
47
|
"""
|
|
51
48
|
tb = traceback.TracebackException.from_exception(self.__exception, capture_locals=False)
|
|
52
49
|
|
|
@@ -60,17 +57,21 @@ class ExceptionParser(IExceptionParser):
|
|
|
60
57
|
|
|
61
58
|
def __parse_stack(self, stack: traceback.StackSummary) -> List[Dict[str, Union[str, int, None]]]:
|
|
62
59
|
"""
|
|
63
|
-
|
|
60
|
+
Parses the stack trace summary into a list of frame dictionaries.
|
|
64
61
|
|
|
65
62
|
Parameters
|
|
66
63
|
----------
|
|
67
64
|
stack : traceback.StackSummary
|
|
68
|
-
The summary of the stack.
|
|
65
|
+
The summary of the stack trace.
|
|
69
66
|
|
|
70
67
|
Returns
|
|
71
68
|
-------
|
|
72
69
|
list of dict
|
|
73
|
-
|
|
70
|
+
Each dictionary contains:
|
|
71
|
+
- 'filename': str, file where the frame is located.
|
|
72
|
+
- 'lineno': int, line number in the file.
|
|
73
|
+
- 'name': str, function or method name.
|
|
74
|
+
- 'line': str or None, source line of code.
|
|
74
75
|
"""
|
|
75
76
|
return [
|
|
76
77
|
{
|
|
@@ -84,7 +85,7 @@ class ExceptionParser(IExceptionParser):
|
|
|
84
85
|
|
|
85
86
|
def __parse_cause(self, cause: Optional[BaseException]) -> Optional[Dict[str, Any]]:
|
|
86
87
|
"""
|
|
87
|
-
Recursively
|
|
88
|
+
Recursively parses the cause of an exception, if present.
|
|
88
89
|
|
|
89
90
|
Parameters
|
|
90
91
|
----------
|
|
@@ -94,7 +95,8 @@ class ExceptionParser(IExceptionParser):
|
|
|
94
95
|
Returns
|
|
95
96
|
-------
|
|
96
97
|
dict or None
|
|
97
|
-
|
|
98
|
+
Dictionary with the cause's error type, message, and stack trace,
|
|
99
|
+
or None if no cause exists.
|
|
98
100
|
"""
|
|
99
101
|
if not isinstance(cause, BaseException):
|
|
100
102
|
return None
|
|
@@ -5,11 +5,18 @@ class Parser:
|
|
|
5
5
|
@staticmethod
|
|
6
6
|
def exception(exception: Exception) -> ExceptionParser:
|
|
7
7
|
"""
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
Create and return an ExceptionParser instance for the given exception.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
exception : Exception
|
|
13
|
+
The exception object to be parsed.
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
ExceptionParser
|
|
18
|
+
An ExceptionParser instance initialized with the provided exception.
|
|
13
19
|
"""
|
|
14
20
|
|
|
21
|
+
# Instantiate and return an ExceptionParser for the given exception
|
|
15
22
|
return ExceptionParser(exception)
|
|
@@ -6,25 +6,21 @@ T = TypeVar('T')
|
|
|
6
6
|
|
|
7
7
|
class Singleton(type):
|
|
8
8
|
"""
|
|
9
|
-
|
|
9
|
+
Metaclass for implementing thread-safe and async-safe singleton pattern.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
This metaclass ensures that only one instance of a class exists, regardless of
|
|
12
|
+
whether the code is running in a synchronous or asynchronous context. It provides
|
|
13
|
+
both synchronous and asynchronous mechanisms for instance creation, using appropriate
|
|
14
|
+
locking to prevent race conditions in multi-threaded or async environments.
|
|
12
15
|
|
|
13
16
|
Attributes
|
|
14
17
|
----------
|
|
15
18
|
_instances : Dict[Type[T], T]
|
|
16
|
-
|
|
19
|
+
Dictionary storing singleton instances for each class using this metaclass.
|
|
17
20
|
_lock : threading.Lock
|
|
18
21
|
Thread lock for synchronizing instance creation in synchronous contexts.
|
|
19
22
|
_async_lock : asyncio.Lock
|
|
20
23
|
Async lock for synchronizing instance creation in asynchronous contexts.
|
|
21
|
-
|
|
22
|
-
Methods
|
|
23
|
-
-------
|
|
24
|
-
__call__(cls, *args, **kwargs)
|
|
25
|
-
Synchronously creates or retrieves the singleton instance.
|
|
26
|
-
__acall__(cls, *args, **kwargs)
|
|
27
|
-
Asynchronously creates or retrieves the singleton instance.
|
|
28
24
|
"""
|
|
29
25
|
|
|
30
26
|
_instances: Dict[Type[T], T] = {}
|
|
@@ -33,12 +29,12 @@ class Singleton(type):
|
|
|
33
29
|
|
|
34
30
|
def __call__(cls: Type[T], *args: Any, **kwargs: Any) -> T:
|
|
35
31
|
"""
|
|
36
|
-
Synchronously
|
|
32
|
+
Synchronously create or retrieve the singleton instance.
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
If the instance does not exist,
|
|
40
|
-
and stores it in the class-level `_instances` dictionary.
|
|
41
|
-
the existing instance.
|
|
34
|
+
Ensures that only one instance of the class is created in a thread-safe manner.
|
|
35
|
+
If the instance does not exist, acquires a thread lock to prevent race conditions,
|
|
36
|
+
creates the instance, and stores it in the class-level `_instances` dictionary.
|
|
37
|
+
If the instance already exists, returns the existing instance.
|
|
42
38
|
|
|
43
39
|
Parameters
|
|
44
40
|
----------
|
|
@@ -70,12 +66,12 @@ class Singleton(type):
|
|
|
70
66
|
|
|
71
67
|
async def __acall__(cls: Type[T], *args: Any, **kwargs: Any) -> T:
|
|
72
68
|
"""
|
|
73
|
-
Asynchronously
|
|
69
|
+
Asynchronously create or retrieve the singleton instance.
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
If the instance does not exist,
|
|
77
|
-
creates the instance, and stores it in the class-level `_instances`
|
|
78
|
-
already exists,
|
|
71
|
+
Ensures that only one instance of the class is created in an async-safe manner.
|
|
72
|
+
If the instance does not exist, acquires an asynchronous lock to prevent race
|
|
73
|
+
conditions, creates the instance, and stores it in the class-level `_instances`
|
|
74
|
+
dictionary. If the instance already exists, returns the existing instance.
|
|
79
75
|
|
|
80
76
|
Parameters
|
|
81
77
|
----------
|
|
@@ -103,4 +99,4 @@ class Singleton(type):
|
|
|
103
99
|
cls._instances[cls] = super().__call__(*args, **kwargs)
|
|
104
100
|
|
|
105
101
|
# Return the singleton instance
|
|
106
|
-
return cls._instances[cls]
|
|
102
|
+
return cls._instances[cls]
|