orionis 0.286.0__py3-none-any.whl → 0.288.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/metadata/framework.py +1 -1
- orionis/services/environment/contracts/env.py +45 -50
- orionis/services/environment/contracts/types.py +70 -0
- orionis/services/environment/dot_env.py +204 -182
- orionis/services/environment/env.py +68 -85
- orionis/services/{standard/exceptions/path_value_exceptions.py → environment/exceptions/environment_value_error.py} +2 -12
- orionis/services/environment/exceptions/environment_value_exception.py +23 -0
- orionis/services/environment/types.py +578 -0
- orionis/services/paths/exceptions/not_found_exceptions.py +15 -12
- orionis/services/paths/exceptions/path_value_exceptions.py +13 -10
- orionis/services/standard/contracts/std.py +1 -1
- orionis/services/standard/exceptions/std_value_exception.py +23 -0
- orionis/services/standard/std.py +2 -2
- orionis/services/system/contracts/imports.py +27 -7
- orionis/services/system/contracts/workers.py +8 -3
- orionis/services/system/imports.py +31 -12
- orionis/services/system/runtime_imports.py +33 -23
- orionis/services/system/workers.py +6 -8
- orionis/services/wrapper/dicts/dot_dict.py +82 -41
- orionis/test/logs/history.py +3 -5
- orionis/unittesting.py +12 -12
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/METADATA +1 -1
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/RECORD +76 -70
- tests/example/test_example.py +5 -2
- tests/foundation/config/app/{test_app.py → test_foundation_config_app.py} +14 -4
- tests/foundation/config/auth/{test_auth.py → test_foundation_config_auth.py} +10 -5
- tests/foundation/config/cache/{test_cache.py → test_foundation_config_cache.py} +61 -16
- tests/foundation/config/cache/test_foundation_config_cache_file.py +126 -0
- tests/foundation/config/cache/test_foundation_config_cache_stores.py +148 -0
- tests/foundation/config/cors/test_foundation_config_cors.py +190 -0
- tests/foundation/config/database/{test_database.py → test_foundation_config_database.py} +39 -15
- tests/foundation/config/database/{test_database_connections.py → test_foundation_config_database_connections.py} +80 -6
- tests/foundation/config/database/{test_database_mysql.py → test_foundation_config_database_mysql.py} +139 -16
- tests/foundation/config/database/{test_database_oracle.py → test_foundation_config_database_oracle.py} +111 -27
- tests/foundation/config/database/{test_database_pgsql.py → test_foundation_config_database_pgsql.py} +97 -27
- tests/foundation/config/database/{test_database_sqlite.py → test_foundation_config_database_sqlite.py} +57 -3
- tests/foundation/config/exceptions/{test_exceptions_integrity.py → test_foundation_config_exceptions.py} +45 -11
- tests/foundation/config/filesystems/{test_filesystems.py → test_foundation_config_filesystems.py} +65 -15
- tests/foundation/config/filesystems/{test_filesystems_aws.py → test_foundation_config_filesystems_aws.py} +46 -8
- tests/foundation/config/filesystems/{test_filesystems_disks.py → test_foundation_config_filesystems_disks.py} +79 -9
- tests/foundation/config/filesystems/{test_filesystems_local.py → test_foundation_config_filesystems_local.py} +67 -19
- tests/foundation/config/filesystems/{test_filesystems_public.py → test_foundation_config_filesystems_public.py} +38 -1
- tests/foundation/config/logging/test_foundation_config_logging.py +112 -0
- tests/foundation/config/logging/{test_logging_channels.py → test_foundation_config_logging_channels.py} +80 -3
- tests/foundation/config/logging/{test_logging_chunked.py → test_foundation_config_logging_chunked.py} +86 -13
- tests/foundation/config/logging/{test_logging_daily.py → test_foundation_config_logging_daily.py} +80 -13
- tests/foundation/config/logging/{test_logging_hourly.py → test_foundation_config_logging_hourly.py} +69 -3
- tests/foundation/config/logging/{test_logging_monthly.py → test_foundation_config_logging_monthly.py} +49 -3
- tests/foundation/config/logging/{test_logging_stack.py → test_foundation_config_logging_stack.py} +50 -15
- tests/foundation/config/logging/{test_logging_weekly.py → test_foundation_config_logging_weekly.py} +93 -3
- tests/foundation/config/mail/test_foundation_config_mail.py +145 -0
- tests/foundation/config/mail/{test_mail_file.py → test_foundation_config_mail_file.py} +41 -5
- tests/foundation/config/mail/test_foundation_config_mail_mailers.py +106 -0
- tests/foundation/config/mail/{test_mail_smtp.py → test_foundation_config_mail_smtp.py} +59 -15
- tests/foundation/config/queue/test_foundation_config_queue.py +111 -0
- tests/foundation/config/queue/{test_queue_brokers.py → test_foundation_config_queue_brokers.py} +28 -11
- tests/foundation/config/queue/{test_queue_database.py → test_foundation_config_queue_database.py} +54 -16
- tests/foundation/config/root/{test_root_paths.py → test_foundation_config_root_paths.py} +70 -3
- tests/foundation/config/session/{test_session.py → test_foundation_config_session.py} +31 -2
- tests/foundation/config/startup/{test_config_startup.py → test_foundation_config_startup.py} +91 -21
- tests/foundation/config/testing/{test_testing.py → test_foundation_config_testing.py} +69 -1
- tests/patterns/singleton/test_patterns_singleton.py +27 -0
- tests/services/asynchrony/{test_async_io.py → test_services_asynchrony_coroutine.py} +1 -1
- tests/services/environment/test_services_environment.py +93 -0
- tests/services/path/{test_resolver.py → test_services_resolver.py} +51 -12
- tests/services/standard/{test_std.py → test_services_std.py} +45 -22
- tests/services/system/__init__.py +0 -0
- tests/services/system/test_services_system_imports.py +101 -0
- tests/services/system/test_services_system_workers.py +89 -0
- tests/services/wrapper/{test_wrapper_doc_dict.py → test_services_wrapper_docdict.py} +28 -16
- tests/testing/test_testing_result.py +57 -20
- tests/testing/test_testing_unit.py +110 -41
- orionis/services/environment/exceptions/value_exception.py +0 -27
- tests/foundation/config/cache/test_cache_file.py +0 -78
- tests/foundation/config/cache/test_cache_stores.py +0 -88
- tests/foundation/config/cors/test_cors.py +0 -121
- tests/foundation/config/logging/test_logging.py +0 -48
- tests/foundation/config/mail/test_mail.py +0 -73
- tests/foundation/config/mail/test_mail_mailers.py +0 -58
- tests/foundation/config/queue/test_queue.py +0 -58
- tests/patterns/singleton/test_singleton.py +0 -18
- tests/services/environment/test_env.py +0 -155
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/WHEEL +0 -0
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/top_level.txt +0 -0
- {orionis-0.286.0.dist-info → orionis-0.288.0.dist-info}/zip-safe +0 -0
orionis/services/standard/std.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from orionis.services.standard.contracts.std import IStdClass
|
2
|
-
from orionis.services.standard.exceptions.
|
2
|
+
from orionis.services.standard.exceptions.std_value_exception import OrionisStdValueException
|
3
3
|
|
4
4
|
class StdClass(IStdClass):
|
5
5
|
"""
|
@@ -112,7 +112,7 @@ class StdClass(IStdClass):
|
|
112
112
|
delattr(self, attr)
|
113
113
|
|
114
114
|
@classmethod
|
115
|
-
def
|
115
|
+
def fromDict(cls, dictionary):
|
116
116
|
"""
|
117
117
|
Creates a StdClass instance from a dictionary.
|
118
118
|
|
@@ -3,29 +3,49 @@ from abc import ABC, abstractmethod
|
|
3
3
|
class IImports(ABC):
|
4
4
|
"""
|
5
5
|
Interface for a utility to collect and display information about currently loaded Python modules.
|
6
|
+
|
7
|
+
Methods
|
8
|
+
-------
|
9
|
+
collect()
|
10
|
+
Collects information about user-defined Python modules currently loaded in sys.modules.
|
11
|
+
|
12
|
+
display()
|
13
|
+
Displays a formatted table of collected import statements.
|
14
|
+
|
15
|
+
clear()
|
16
|
+
Clears the collected imports list.
|
6
17
|
"""
|
7
18
|
|
8
19
|
@abstractmethod
|
9
20
|
def collect(self):
|
10
21
|
"""
|
11
|
-
|
12
|
-
|
13
|
-
|
22
|
+
Collect information about user-defined Python modules currently loaded in sys.modules.
|
23
|
+
|
24
|
+
Returns
|
25
|
+
-------
|
26
|
+
IImports
|
27
|
+
The current instance with updated imports information.
|
14
28
|
"""
|
15
29
|
pass
|
16
30
|
|
17
31
|
@abstractmethod
|
18
32
|
def display(self) -> None:
|
19
33
|
"""
|
20
|
-
|
21
|
-
|
22
|
-
|
34
|
+
Display a formatted table of collected import statements.
|
35
|
+
|
36
|
+
Returns
|
37
|
+
-------
|
38
|
+
None
|
23
39
|
"""
|
24
40
|
pass
|
25
41
|
|
26
42
|
@abstractmethod
|
27
43
|
def clear(self) -> None:
|
28
44
|
"""
|
29
|
-
|
45
|
+
Clear the collected imports list.
|
46
|
+
|
47
|
+
Returns
|
48
|
+
-------
|
49
|
+
None
|
30
50
|
"""
|
31
51
|
pass
|
@@ -2,17 +2,22 @@ from abc import ABC, abstractmethod
|
|
2
2
|
|
3
3
|
class IWorkers(ABC):
|
4
4
|
"""
|
5
|
-
Interface
|
5
|
+
Interface for calculating the optimal number of workers a machine can handle based on CPU and memory resources.
|
6
|
+
|
7
|
+
Notes
|
8
|
+
-----
|
9
|
+
Implementations should provide logic to determine the recommended number of worker processes
|
10
|
+
according to the available CPU and memory resources of the current machine.
|
6
11
|
"""
|
7
12
|
|
8
13
|
@abstractmethod
|
9
14
|
def calculate(self) -> int:
|
10
15
|
"""
|
11
|
-
|
16
|
+
Compute the maximum number of workers supported by the current machine.
|
12
17
|
|
13
18
|
Returns
|
14
19
|
-------
|
15
20
|
int
|
16
|
-
|
21
|
+
Recommended number of worker processes based on CPU and memory limits.
|
17
22
|
"""
|
18
23
|
pass
|
@@ -3,30 +3,42 @@ from orionis.services.system.contracts.imports import IImports
|
|
3
3
|
|
4
4
|
class Imports(IImports):
|
5
5
|
"""
|
6
|
-
|
6
|
+
Utility class to collect and display information about currently loaded Python modules.
|
7
|
+
|
8
|
+
This class provides methods to gather details about user-defined Python modules
|
9
|
+
currently loaded in `sys.modules`, excluding standard library and virtual environment modules.
|
10
|
+
It can display the collected information in a formatted table using the Rich library.
|
7
11
|
"""
|
8
12
|
|
9
13
|
def __init__(self):
|
10
14
|
"""
|
11
|
-
|
15
|
+
Initialize the Imports object.
|
16
|
+
|
17
|
+
Initializes an empty list to store module information.
|
12
18
|
"""
|
13
19
|
self.imports: List[Dict[str, Any]] = []
|
14
20
|
|
15
21
|
def collect(self) -> 'Imports':
|
16
22
|
"""
|
17
|
-
|
23
|
+
Collect information about user-defined Python modules currently loaded.
|
24
|
+
|
18
25
|
For each qualifying module, gathers:
|
19
26
|
- The module's name.
|
20
27
|
- The relative file path to the module from the current working directory.
|
21
28
|
- A list of symbols (functions, classes, or submodules) defined in the module.
|
29
|
+
|
22
30
|
Excludes:
|
23
31
|
- Modules from the standard library.
|
24
32
|
- Modules from the active virtual environment (if any).
|
25
33
|
- Binary extension modules (.pyd, .dll, .so).
|
26
34
|
- Special modules like "__main__", "__mp_main__", and modules starting with "_distutils".
|
27
|
-
|
28
|
-
|
29
|
-
|
35
|
+
|
36
|
+
The collected information is stored in `self.imports` as a list of dictionaries.
|
37
|
+
|
38
|
+
Returns
|
39
|
+
-------
|
40
|
+
Imports
|
41
|
+
The current instance with updated imports information.
|
30
42
|
"""
|
31
43
|
|
32
44
|
import sys
|
@@ -39,7 +51,7 @@ class Imports(IImports):
|
|
39
51
|
if venv_path:
|
40
52
|
venv_path = os.path.abspath(venv_path)
|
41
53
|
|
42
|
-
for name, module in sys.modules.items():
|
54
|
+
for name, module in list(sys.modules.items()):
|
43
55
|
file:str = getattr(module, '__file__', None)
|
44
56
|
|
45
57
|
if (
|
@@ -73,12 +85,15 @@ class Imports(IImports):
|
|
73
85
|
|
74
86
|
def display(self) -> None:
|
75
87
|
"""
|
76
|
-
|
77
|
-
|
88
|
+
Display a formatted table of collected import statements using the Rich library.
|
89
|
+
|
90
|
+
If the imports have not been collected yet, it calls `self.collect()` to gather them.
|
78
91
|
The table includes columns for the import name, file, and imported symbols, and is
|
79
92
|
rendered inside a styled panel in the console.
|
80
|
-
|
81
|
-
|
93
|
+
|
94
|
+
Returns
|
95
|
+
-------
|
96
|
+
None
|
82
97
|
"""
|
83
98
|
|
84
99
|
if not self.imports:
|
@@ -119,6 +134,10 @@ class Imports(IImports):
|
|
119
134
|
|
120
135
|
def clear(self) -> None:
|
121
136
|
"""
|
122
|
-
|
137
|
+
Clear the collected imports list.
|
138
|
+
|
139
|
+
Returns
|
140
|
+
-------
|
141
|
+
None
|
123
142
|
"""
|
124
143
|
self.imports.clear()
|
@@ -1,27 +1,29 @@
|
|
1
1
|
"""
|
2
|
-
|
3
|
-
|
4
|
-
This module overrides Python's built-in import mechanism to monitor and log
|
5
|
-
the number of times modules from the 'orionis' package are imported.
|
2
|
+
Overrides Python's built-in import mechanism to monitor and log the number of times
|
3
|
+
modules from the 'orionis' package are imported.
|
6
4
|
|
7
5
|
Each time a module whose name starts with 'orionis' is imported, a message is printed
|
8
|
-
showing
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
showing the module name, the number of times it has been imported, and the fromlist
|
7
|
+
used in the import. Thread safety is ensured using a lock.
|
8
|
+
|
9
|
+
.. warning::
|
10
|
+
This affects the global import system for the current Python process.
|
11
|
+
To disable, restore ``builtins.__import__`` to its original value.
|
12
12
|
|
13
|
-
|
13
|
+
Examples
|
14
|
+
--------
|
15
|
+
Import this module at the very beginning of your application to enable import tracking
|
16
|
+
for 'orionis' modules. No further configuration is required.
|
14
17
|
|
15
|
-
|
16
|
-
Import this module at the very beginning of your application to enable import tracking
|
17
|
-
for 'orionis' modules. No further configuration is required.
|
18
|
+
Example output::
|
18
19
|
|
19
|
-
Example output:
|
20
20
|
Module: orionis.example | Imported: 2 | FromList: ('submodule',)
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
Notes
|
23
|
+
-----
|
24
|
+
- This module should be imported before any other 'orionis' modules to ensure all imports are tracked.
|
25
|
+
- Thread safety is provided via a threading.Lock.
|
26
|
+
|
25
27
|
"""
|
26
28
|
import builtins
|
27
29
|
from collections import defaultdict
|
@@ -40,14 +42,22 @@ def custom_import(name, globals=None, locals=None, fromlist=(), level=0):
|
|
40
42
|
"""
|
41
43
|
Custom import function that tracks imports of 'orionis' modules.
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
Parameters
|
46
|
+
----------
|
47
|
+
name : str
|
48
|
+
The name of the module to import.
|
49
|
+
globals : dict, optional
|
50
|
+
The global namespace.
|
51
|
+
locals : dict, optional
|
52
|
+
The local namespace.
|
53
|
+
fromlist : tuple, optional
|
54
|
+
Names to import from the module.
|
55
|
+
level : int, optional
|
56
|
+
Relative import level.
|
49
57
|
|
50
|
-
Returns
|
58
|
+
Returns
|
59
|
+
-------
|
60
|
+
module
|
51
61
|
The imported module.
|
52
62
|
"""
|
53
63
|
# Check if the module name starts with 'orionis'
|
@@ -5,17 +5,15 @@ from orionis.services.system.contracts.workers import IWorkers
|
|
5
5
|
|
6
6
|
class Workers(IWorkers):
|
7
7
|
"""
|
8
|
-
|
8
|
+
Estimate the optimal number of worker processes based on system CPU and memory resources.
|
9
9
|
|
10
|
-
This class
|
11
|
-
|
12
|
-
- The total system memory (RAM).
|
13
|
-
- The estimated memory usage per worker (configurable).
|
10
|
+
This class calculates the recommended number of Uvicorn (or similar) workers by considering:
|
11
|
+
the number of available CPU cores, total system memory (RAM), and the estimated memory usage per worker.
|
14
12
|
|
15
13
|
Parameters
|
16
14
|
----------
|
17
15
|
ram_per_worker : float, optional
|
18
|
-
Estimated amount of RAM
|
16
|
+
Estimated amount of RAM in gigabytes (GB) that each worker will consume. Default is 0.5.
|
19
17
|
"""
|
20
18
|
|
21
19
|
def __init__(self, ram_per_worker: float = 0.5):
|
@@ -25,12 +23,12 @@ class Workers(IWorkers):
|
|
25
23
|
|
26
24
|
def calculate(self) -> int:
|
27
25
|
"""
|
28
|
-
|
26
|
+
Compute the maximum number of workers supported by the current machine.
|
29
27
|
|
30
28
|
Returns
|
31
29
|
-------
|
32
30
|
int
|
33
|
-
The recommended number of worker processes based on CPU and memory
|
31
|
+
The recommended number of worker processes based on CPU and memory constraints.
|
34
32
|
"""
|
35
33
|
max_workers_by_cpu = self._cpu_count
|
36
34
|
max_workers_by_ram = math.floor(self._ram_total_gb / self._ram_per_worker)
|
@@ -2,9 +2,11 @@ from typing import Any, Optional, Dict
|
|
2
2
|
|
3
3
|
class DotDict(dict):
|
4
4
|
"""
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
Dictionary subclass with attribute-style access and recursive dot notation.
|
6
|
+
|
7
|
+
This class allows accessing dictionary keys as attributes, with automatic
|
8
|
+
conversion of nested dictionaries to DotDict instances. Missing keys return
|
9
|
+
None instead of raising AttributeError or KeyError.
|
8
10
|
"""
|
9
11
|
|
10
12
|
__slots__ = ()
|
@@ -12,14 +14,21 @@ class DotDict(dict):
|
|
12
14
|
def __getattr__(self, key: str) -> Optional[Any]:
|
13
15
|
"""
|
14
16
|
Retrieve the value associated with the given key as an attribute.
|
15
|
-
If the value is a dictionary (but not already a DotDict), it is converted to a DotDict and updated in-place.
|
16
|
-
Returns None if the key does not exist.
|
17
|
-
Args:
|
18
|
-
key (str): The attribute name to retrieve.
|
19
|
-
Returns:
|
20
|
-
Optional[Any]: The value associated with the key, converted to DotDict if applicable, or None if the key is not found.
|
21
|
-
"""
|
22
17
|
|
18
|
+
If the value is a dictionary (but not already a DotDict), it is converted
|
19
|
+
to a DotDict and updated in-place. Returns None if the key does not exist.
|
20
|
+
|
21
|
+
Parameters
|
22
|
+
----------
|
23
|
+
key : str
|
24
|
+
The attribute name to retrieve.
|
25
|
+
|
26
|
+
Returns
|
27
|
+
-------
|
28
|
+
value : Any or None
|
29
|
+
The value associated with the key, converted to DotDict if applicable,
|
30
|
+
or None if the key is not found.
|
31
|
+
"""
|
23
32
|
try:
|
24
33
|
value = self[key]
|
25
34
|
if isinstance(value, dict) and not isinstance(value, DotDict):
|
@@ -31,15 +40,19 @@ class DotDict(dict):
|
|
31
40
|
|
32
41
|
def __setattr__(self, key: str, value: Any) -> None:
|
33
42
|
"""
|
34
|
-
|
35
|
-
|
36
|
-
If the value assigned is a dictionary (but not already a DotDict), it is
|
37
|
-
The attribute is stored as a
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
Set an attribute on the DotDict instance.
|
44
|
+
|
45
|
+
If the value assigned is a dictionary (but not already a DotDict), it is
|
46
|
+
automatically converted into a DotDict. The attribute is stored as a
|
47
|
+
key-value pair in the underlying dictionary.
|
48
|
+
|
49
|
+
Parameters
|
50
|
+
----------
|
51
|
+
key : str
|
52
|
+
The attribute name to set.
|
53
|
+
value : Any
|
54
|
+
The value to assign to the attribute. If it's a dict, it will be
|
55
|
+
converted to a DotDict.
|
43
56
|
"""
|
44
57
|
if isinstance(value, dict) and not isinstance(value, DotDict):
|
45
58
|
value = DotDict(value)
|
@@ -47,13 +60,17 @@ class DotDict(dict):
|
|
47
60
|
|
48
61
|
def __delattr__(self, key: str) -> None:
|
49
62
|
"""
|
50
|
-
|
63
|
+
Delete the attribute with the specified key from the dictionary.
|
51
64
|
|
52
|
-
|
53
|
-
|
65
|
+
Parameters
|
66
|
+
----------
|
67
|
+
key : str
|
68
|
+
The name of the attribute to delete.
|
54
69
|
|
55
|
-
Raises
|
56
|
-
|
70
|
+
Raises
|
71
|
+
------
|
72
|
+
AttributeError
|
73
|
+
If the attribute does not exist.
|
57
74
|
"""
|
58
75
|
try:
|
59
76
|
del self[key]
|
@@ -67,12 +84,17 @@ class DotDict(dict):
|
|
67
84
|
If the retrieved value is a plain dictionary (not a DotDict), it is converted to a DotDict,
|
68
85
|
stored back in the dictionary, and then returned.
|
69
86
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
87
|
+
Parameters
|
88
|
+
----------
|
89
|
+
key : str
|
90
|
+
The key to look up in the dictionary.
|
91
|
+
default : Any, optional
|
92
|
+
The value to return if the key is not found. Defaults to None.
|
93
|
+
|
94
|
+
Returns
|
95
|
+
-------
|
96
|
+
value : Any or None
|
97
|
+
The value associated with the key, converted to a DotDict if it is a dict,
|
76
98
|
or the default value if the key is not present.
|
77
99
|
"""
|
78
100
|
value = super().get(key, default)
|
@@ -83,24 +105,41 @@ class DotDict(dict):
|
|
83
105
|
|
84
106
|
def export(self) -> Dict[str, Any]:
|
85
107
|
"""
|
86
|
-
Recursively
|
108
|
+
Recursively export the contents of the DotDict as a standard dictionary.
|
87
109
|
|
88
|
-
Returns
|
89
|
-
|
110
|
+
Returns
|
111
|
+
-------
|
112
|
+
result : dict
|
113
|
+
A dictionary representation of the DotDict, where any nested DotDict instances
|
90
114
|
are also converted to dictionaries via their own export method.
|
91
115
|
"""
|
92
|
-
|
116
|
+
result = {}
|
117
|
+
for k, v in self.items():
|
118
|
+
if isinstance(v, DotDict):
|
119
|
+
result[k] = v.export()
|
120
|
+
else:
|
121
|
+
result[k] = v
|
122
|
+
return result
|
93
123
|
|
94
124
|
def copy(self) -> 'DotDict':
|
95
125
|
"""
|
96
126
|
Create a deep copy of the DotDict instance.
|
97
127
|
|
98
|
-
Returns
|
99
|
-
|
128
|
+
Returns
|
129
|
+
-------
|
130
|
+
copied : DotDict
|
131
|
+
A new DotDict object with recursively copied contents.
|
100
132
|
Nested DotDict and dict instances are also copied to ensure no shared references.
|
101
133
|
"""
|
102
|
-
|
103
|
-
|
134
|
+
copied = {}
|
135
|
+
for k, v in self.items():
|
136
|
+
if isinstance(v, DotDict):
|
137
|
+
copied[k] = v.copy()
|
138
|
+
elif isinstance(v, dict):
|
139
|
+
copied[k] = DotDict(v).copy()
|
140
|
+
else:
|
141
|
+
copied[k] = v
|
142
|
+
return DotDict(copied)
|
104
143
|
|
105
144
|
def __repr__(self) -> str:
|
106
145
|
"""
|
@@ -109,7 +148,9 @@ class DotDict(dict):
|
|
109
148
|
This method overrides the default __repr__ implementation to provide a more informative
|
110
149
|
string that includes the class name 'DotDict' and the representation of the underlying dictionary.
|
111
150
|
|
112
|
-
Returns
|
113
|
-
|
151
|
+
Returns
|
152
|
+
-------
|
153
|
+
repr_str : str
|
154
|
+
A string representation of the DotDict object.
|
114
155
|
"""
|
115
|
-
return
|
156
|
+
return super().__repr__()
|
orionis/test/logs/history.py
CHANGED
@@ -54,7 +54,7 @@ class TestHistory(ITestHistory):
|
|
54
54
|
if db_path.is_dir():
|
55
55
|
db_path = db_path / self.__db_name
|
56
56
|
else:
|
57
|
-
env_path = Env.get(
|
57
|
+
env_path = Env.get("TEST_DB_PATH", None)
|
58
58
|
if env_path:
|
59
59
|
db_path = Path(env_path).expanduser().resolve()
|
60
60
|
if db_path.is_dir():
|
@@ -66,7 +66,7 @@ class TestHistory(ITestHistory):
|
|
66
66
|
db_path.parent.mkdir(parents=True, exist_ok=True)
|
67
67
|
|
68
68
|
# Store path in environment
|
69
|
-
Env.set(
|
69
|
+
Env.set("TEST_DB_PATH", str(db_path), 'path')
|
70
70
|
self.__db_path = db_path
|
71
71
|
|
72
72
|
# Create a connection to the database, initially set to None
|
@@ -89,8 +89,6 @@ class TestHistory(ITestHistory):
|
|
89
89
|
self._conn = sqlite3.connect(str(self.__db_path))
|
90
90
|
except (sqlite3.Error, Exception) as e:
|
91
91
|
raise OrionisTestPersistenceError(f"Database connection error: {e}")
|
92
|
-
finally:
|
93
|
-
self._conn = None
|
94
92
|
|
95
93
|
def __createTableIfNotExists(self) -> bool:
|
96
94
|
"""
|
@@ -177,7 +175,7 @@ class TestHistory(ITestHistory):
|
|
177
175
|
# Validate report structure
|
178
176
|
missing = []
|
179
177
|
for key in fields:
|
180
|
-
if key not in report:
|
178
|
+
if key not in report and key != "json":
|
181
179
|
missing.append(key)
|
182
180
|
if missing:
|
183
181
|
raise OrionisTestValueError(f"Missing report fields: {missing}")
|
orionis/unittesting.py
CHANGED
@@ -26,16 +26,16 @@ from orionis.test.suites.test_unit import UnitTest
|
|
26
26
|
|
27
27
|
# Import standard unittest components for compatibility
|
28
28
|
from unittest import (
|
29
|
-
TestLoader
|
30
|
-
TestSuite as
|
31
|
-
TestResult as
|
29
|
+
TestLoader,
|
30
|
+
TestSuite as StandardTestSuite,
|
31
|
+
TestResult as StandardTestResult
|
32
32
|
)
|
33
33
|
|
34
34
|
# Import mock classes for creating test doubles
|
35
35
|
from unittest.mock import (
|
36
|
-
Mock
|
37
|
-
MagicMock
|
38
|
-
patch
|
36
|
+
Mock,
|
37
|
+
MagicMock,
|
38
|
+
patch
|
39
39
|
)
|
40
40
|
|
41
41
|
# Define the public API of this module
|
@@ -54,11 +54,11 @@ __all__ = [
|
|
54
54
|
"Configuration",
|
55
55
|
"TestSuite",
|
56
56
|
"UnitTest",
|
57
|
-
"
|
58
|
-
"
|
59
|
-
"
|
60
|
-
"
|
61
|
-
"
|
57
|
+
"TestLoader",
|
58
|
+
"StandardTestSuite",
|
59
|
+
"StandardTestResult",
|
60
|
+
"Mock",
|
61
|
+
"MagicMock",
|
62
62
|
"TestHistory",
|
63
|
-
"
|
63
|
+
"patch",
|
64
64
|
]
|