orionis 0.283.0__py3-none-any.whl → 0.285.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/foundation/config/testing/entities/testing.py +25 -0
- orionis/metadata/framework.py +1 -1
- orionis/services/asynchrony/{async_io.py → coroutines.py} +2 -1
- orionis/services/asynchrony/exceptions/__init__.py +0 -0
- orionis/services/asynchrony/exceptions/coroutine_exception.py +26 -0
- orionis/services/environment/dot_env.py +7 -7
- orionis/services/environment/env.py +56 -8
- orionis/services/environment/exceptions/__init__.py +0 -0
- orionis/services/environment/exceptions/value_exception.py +27 -0
- orionis/services/introspection/exceptions/__init__.py +0 -0
- orionis/services/introspection/exceptions/types.py +0 -0
- orionis/services/introspection/helpers/__init__.py +0 -0
- orionis/services/introspection/helpers/functions.py +285 -0
- orionis/services/introspection/reflection.py +216 -0
- orionis/services/parsers/exceptions/__init__.py +0 -0
- orionis/services/parsers/serializer.py +1 -1
- orionis/services/paths/exceptions/__init__.py +0 -0
- orionis/services/paths/exceptions/not_found_exceptions.py +28 -0
- orionis/services/paths/exceptions/path_value_exceptions.py +28 -0
- orionis/services/paths/resolver.py +6 -4
- orionis/services/standard/exceptions/__init__.py +0 -0
- orionis/services/standard/exceptions/path_value_exceptions.py +28 -0
- orionis/services/standard/std.py +4 -3
- orionis/test/entities/test_result.py +14 -1
- orionis/test/exceptions/test_persistence_error.py +34 -0
- orionis/test/exceptions/test_runtime_error.py +26 -0
- orionis/test/exceptions/test_value_error.py +26 -0
- orionis/test/logs/contracts/history.py +29 -56
- orionis/test/logs/history.py +309 -188
- orionis/test/output/contracts/dumper.py +24 -8
- orionis/test/output/dumper.py +52 -21
- orionis/test/suites/contracts/test_suite.py +27 -13
- orionis/test/suites/contracts/test_unit.py +101 -61
- orionis/test/suites/test_suite.py +45 -24
- orionis/test/suites/test_unit.py +559 -290
- orionis/unittesting.py +8 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/METADATA +1 -1
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/RECORD +44 -26
- tests/services/asynchrony/test_async_io.py +3 -2
- /orionis/services/parsers/{exception.py → exceptions/exception_parser.py} +0 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/WHEEL +0 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/top_level.txt +0 -0
- {orionis-0.283.0.dist-info → orionis-0.285.0.dist-info}/zip-safe +0 -0
@@ -136,6 +136,15 @@ class Testing:
|
|
136
136
|
}
|
137
137
|
)
|
138
138
|
|
139
|
+
persistent_driver: str = field(
|
140
|
+
default='sqlite',
|
141
|
+
metadata={
|
142
|
+
"description": "Specifies the driver to use for persisting test results. Supported values: 'sqlite', 'json'. Default is 'sqlite'.",
|
143
|
+
"required": False,
|
144
|
+
"default": 'sqlite'
|
145
|
+
}
|
146
|
+
)
|
147
|
+
|
139
148
|
def __post_init__(self):
|
140
149
|
"""
|
141
150
|
Post-initialization validation for the testing configuration entity.
|
@@ -202,6 +211,7 @@ class Testing:
|
|
202
211
|
raise OrionisIntegrityException(
|
203
212
|
f"Invalid type for 'folder_path': {type(self.folder_path).__name__}. It must be a string or a list of strings representing the folder path pattern."
|
204
213
|
)
|
214
|
+
|
205
215
|
if isinstance(self.folder_path, list):
|
206
216
|
for i, folder in enumerate(self.folder_path):
|
207
217
|
if not isinstance(folder, str):
|
@@ -230,6 +240,21 @@ class Testing:
|
|
230
240
|
f"Invalid type for tag at index {i} in 'tags': {type(tag).__name__}. Each tag must be a string."
|
231
241
|
)
|
232
242
|
|
243
|
+
if not isinstance(self.persistent, bool):
|
244
|
+
raise OrionisIntegrityException(
|
245
|
+
f"Invalid type for 'persistent': {type(self.persistent).__name__}. It must be a boolean (True or False)."
|
246
|
+
)
|
247
|
+
|
248
|
+
if not isinstance(self.persistent_driver, str):
|
249
|
+
raise OrionisIntegrityException(
|
250
|
+
f"Invalid type for 'persistent_driver': {type(self.persistent_driver).__name__}. It must be a string."
|
251
|
+
)
|
252
|
+
|
253
|
+
if self.persistent_driver not in ['sqlite', 'json']:
|
254
|
+
raise OrionisIntegrityException(
|
255
|
+
f"Invalid value for 'persistent_driver': {self.persistent_driver}. It must be one of: ['sqlite', 'json']."
|
256
|
+
)
|
257
|
+
|
233
258
|
def toDict(self) -> dict:
|
234
259
|
"""
|
235
260
|
Convert the object to a dictionary representation.
|
orionis/metadata/framework.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import asyncio
|
2
2
|
from typing import Any, Coroutine, TypeVar, Union
|
3
|
+
from orionis.services.asynchrony.exceptions.coroutine_exception import OrionisCoroutineException
|
3
4
|
|
4
5
|
T = TypeVar("T")
|
5
6
|
|
@@ -18,7 +19,7 @@ def run_coroutine(coro: Coroutine[Any, Any, T]) -> Union[T, asyncio.Future]:
|
|
18
19
|
from inspect import iscoroutine
|
19
20
|
|
20
21
|
if not iscoroutine(coro):
|
21
|
-
raise
|
22
|
+
raise OrionisCoroutineException("Expected a coroutine object.")
|
22
23
|
|
23
24
|
try:
|
24
25
|
loop = asyncio.get_running_loop()
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class OrionisCoroutineException(Exception):
|
2
|
+
"""
|
3
|
+
Exception raised for errors related to coroutine operations in the Orionis framework.
|
4
|
+
This exception is intended to signal issues encountered during asynchronous
|
5
|
+
operations, providing a clear and descriptive error message to facilitate debugging.
|
6
|
+
msg (str): A detailed message describing the cause of the exception.
|
7
|
+
Example:
|
8
|
+
raise OrionisCoroutineException("Coroutine execution failed due to timeout.")
|
9
|
+
"""
|
10
|
+
|
11
|
+
def __init__(self, msg: str):
|
12
|
+
"""
|
13
|
+
Initialize the exception with a custom error message.
|
14
|
+
Args:
|
15
|
+
msg (str): The error message describing the exception.
|
16
|
+
"""
|
17
|
+
super().__init__(msg)
|
18
|
+
|
19
|
+
def __str__(self) -> str:
|
20
|
+
"""
|
21
|
+
Return a string representation of the exception, including the class name and the first argument.
|
22
|
+
|
23
|
+
Returns:
|
24
|
+
str: A formatted string with the exception class name and its first argument.
|
25
|
+
"""
|
26
|
+
return f"{self.__class__.__name__}: {self.args[0]}"
|
@@ -5,6 +5,7 @@ from pathlib import Path
|
|
5
5
|
from typing import Any, Optional, Union
|
6
6
|
from dotenv import dotenv_values, load_dotenv, set_key, unset_key
|
7
7
|
from orionis.patterns.singleton.meta_class import Singleton
|
8
|
+
from orionis.services.environment.exceptions.value_exception import OrionisEnvironmentValueException
|
8
9
|
|
9
10
|
class DotEnv(metaclass=Singleton):
|
10
11
|
"""
|
@@ -206,8 +207,7 @@ class DotEnv(metaclass=Singleton):
|
|
206
207
|
str: The serialized string representation of the value.
|
207
208
|
|
208
209
|
Raises:
|
209
|
-
|
210
|
-
TypeError: If the value's type is not serializable for .env files.
|
210
|
+
OrionisEnvironmentValueException: If a float value is in scientific notation or If the value's type is not serializable for .env files.
|
211
211
|
"""
|
212
212
|
if is_path:
|
213
213
|
return str(value).replace("\\", "/")
|
@@ -227,21 +227,21 @@ class DotEnv(metaclass=Singleton):
|
|
227
227
|
if isinstance(value, float):
|
228
228
|
value = str(value)
|
229
229
|
if 'e' in value or 'E' in value:
|
230
|
-
raise
|
230
|
+
raise OrionisEnvironmentValueException('scientific notation is not supported, use a string instead')
|
231
231
|
return value
|
232
232
|
|
233
233
|
if isinstance(value, (list, dict)):
|
234
234
|
return repr(value)
|
235
235
|
|
236
236
|
if hasattr(value, '__dict__'):
|
237
|
-
raise
|
237
|
+
raise OrionisEnvironmentValueException(f"Type {type(value).__name__} is not serializable for .env")
|
238
238
|
|
239
239
|
if not isinstance(value, (list, dict, bool, int, float, str)):
|
240
|
-
raise
|
240
|
+
raise OrionisEnvironmentValueException(f"Type {type(value).__name__} is not serializable for .env")
|
241
241
|
|
242
242
|
if isinstance(value, (list, dict, bool, int, float, str)):
|
243
243
|
if type(value).__module__ != "builtins" and not isinstance(value, str):
|
244
|
-
raise
|
244
|
+
raise OrionisEnvironmentValueException(f"Type {type(value).__name__} is not serializable for .env")
|
245
245
|
return repr(value) if not isinstance(value, str) else value
|
246
246
|
|
247
|
-
raise
|
247
|
+
raise OrionisEnvironmentValueException(f"Type {type(value).__name__} is not serializable for .env")
|
@@ -2,11 +2,19 @@ from orionis.services.environment.contracts.env import IEnv
|
|
2
2
|
from orionis.services.environment.dot_env import DotEnv
|
3
3
|
from typing import Any, Optional, Dict
|
4
4
|
|
5
|
-
def env(key: str, default: Any = None) -> Any:
|
5
|
+
def env(key: str, default: Any = None, is_path: bool = False) -> Any:
|
6
6
|
"""
|
7
|
-
|
7
|
+
Retrieve the value of an environment variable by key.
|
8
|
+
|
9
|
+
Args:
|
10
|
+
key (str): The name of the environment variable to retrieve.
|
11
|
+
default (Any, optional): The value to return if the key is not found. Defaults to None.
|
12
|
+
is_path (bool, optional): If True, the value will be treated as a file path. Defaults to False.
|
13
|
+
|
14
|
+
Returns:
|
15
|
+
Any: The value of the environment variable if found, otherwise the default value.
|
8
16
|
"""
|
9
|
-
return DotEnv().get(key, default)
|
17
|
+
return DotEnv().get(key, default, is_path)
|
10
18
|
|
11
19
|
class Env(IEnv):
|
12
20
|
"""
|
@@ -19,6 +27,15 @@ class Env(IEnv):
|
|
19
27
|
|
20
28
|
@classmethod
|
21
29
|
def _dotenv(cls) -> DotEnv:
|
30
|
+
"""
|
31
|
+
Returns a singleton instance of the DotEnv class.
|
32
|
+
|
33
|
+
If the instance does not exist, it creates a new one and stores it in the class attribute.
|
34
|
+
Subsequent calls will return the same instance.
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
DotEnv: The singleton instance of the DotEnv class.
|
38
|
+
"""
|
22
39
|
if cls._dotenv_instance is None:
|
23
40
|
cls._dotenv_instance = DotEnv()
|
24
41
|
return cls._dotenv_instance
|
@@ -26,14 +43,30 @@ class Env(IEnv):
|
|
26
43
|
@staticmethod
|
27
44
|
def get(key: str, default: Any = None, is_path: bool = False) -> Any:
|
28
45
|
"""
|
29
|
-
Retrieve the value of an environment variable
|
46
|
+
Retrieve the value of an environment variable.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
key (str): The name of the environment variable to retrieve.
|
50
|
+
default (Any, optional): The value to return if the environment variable is not found. Defaults to None.
|
51
|
+
is_path (bool, optional): If True, treat the value as a filesystem path. Defaults to False.
|
52
|
+
|
53
|
+
Returns:
|
54
|
+
Any: The value of the environment variable if found, otherwise the default value.
|
30
55
|
"""
|
31
56
|
return Env._dotenv().get(key, default, is_path)
|
32
57
|
|
33
58
|
@staticmethod
|
34
59
|
def set(key: str, value: str, is_path: bool = False) -> bool:
|
35
60
|
"""
|
36
|
-
Sets the
|
61
|
+
Sets an environment variable with the specified key and value.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
key (str): The name of the environment variable to set.
|
65
|
+
value (str): The value to assign to the environment variable.
|
66
|
+
is_path (bool, optional): If True, treats the value as a file system path. Defaults to False.
|
67
|
+
|
68
|
+
Returns:
|
69
|
+
bool: True if the environment variable was set successfully, False otherwise.
|
37
70
|
"""
|
38
71
|
return Env._dotenv().set(key, value, is_path)
|
39
72
|
|
@@ -41,26 +74,41 @@ class Env(IEnv):
|
|
41
74
|
def unset(key: str) -> bool:
|
42
75
|
"""
|
43
76
|
Removes the specified environment variable from the environment.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
key (str): The name of the environment variable to remove.
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
bool: True if the variable was successfully removed, False otherwise.
|
44
83
|
"""
|
45
84
|
return Env._dotenv().unset(key)
|
46
85
|
|
47
86
|
@staticmethod
|
48
87
|
def all() -> Dict[str, Any]:
|
49
88
|
"""
|
50
|
-
Retrieve all environment variables
|
89
|
+
Retrieve all environment variables as a dictionary.
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
Dict[str, Any]: A dictionary containing all environment variables loaded by the dotenv configuration.
|
51
93
|
"""
|
52
94
|
return Env._dotenv().all()
|
53
95
|
|
54
96
|
@staticmethod
|
55
97
|
def toJson() -> str:
|
56
98
|
"""
|
57
|
-
Serializes the
|
99
|
+
Serializes the environment variables managed by the Env class into a JSON-formatted string.
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
str: A JSON string representation of the environment variables.
|
58
103
|
"""
|
59
104
|
return Env._dotenv().toJson()
|
60
105
|
|
61
106
|
@staticmethod
|
62
107
|
def toBase64() -> str:
|
63
108
|
"""
|
64
|
-
Converts the
|
109
|
+
Converts the environment variables loaded by the dotenv instance to a Base64-encoded string.
|
110
|
+
|
111
|
+
Returns:
|
112
|
+
str: The Base64-encoded representation of the environment variables.
|
65
113
|
"""
|
66
114
|
return Env._dotenv().toBase64()
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class OrionisEnvironmentValueException(Exception):
|
2
|
+
"""
|
3
|
+
Exception raised for invalid or unexpected environment values within the Orionis framework.
|
4
|
+
This exception is intended to signal issues encountered when an environment variable,
|
5
|
+
configuration value, or similar parameter does not meet the expected criteria or format.
|
6
|
+
It provides a clear and descriptive error message to facilitate debugging and error handling.
|
7
|
+
Attributes:
|
8
|
+
raise OrionisEnvironmentValueException("Invalid value for ORIONIS_MODE: expected 'production' or 'development'.")
|
9
|
+
msg (str): The error message describing the specific value-related exception.
|
10
|
+
"""
|
11
|
+
|
12
|
+
def __init__(self, msg: str):
|
13
|
+
"""
|
14
|
+
Initializes the exception with a custom error message.
|
15
|
+
Args:
|
16
|
+
msg (str): The error message describing the exception.
|
17
|
+
"""
|
18
|
+
super().__init__(msg)
|
19
|
+
|
20
|
+
def __str__(self) -> str:
|
21
|
+
"""
|
22
|
+
Return a string representation of the exception, including the class name and the first argument.
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
str: A formatted string with the exception class name and its first argument.
|
26
|
+
"""
|
27
|
+
return f"{self.__class__.__name__}: {self.args[0]}"
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,285 @@
|
|
1
|
+
import importlib
|
2
|
+
import inspect
|
3
|
+
from typing import Any, Type
|
4
|
+
|
5
|
+
class HelpersReflection:
|
6
|
+
"""
|
7
|
+
A collection of helper functions for reflection and inspection.
|
8
|
+
"""
|
9
|
+
|
10
|
+
@staticmethod
|
11
|
+
def isValidModule(module_name: str) -> bool:
|
12
|
+
"""Check if a module name is valid and can be imported.
|
13
|
+
|
14
|
+
Parameters
|
15
|
+
----------
|
16
|
+
module_name : str
|
17
|
+
The name of the module to check
|
18
|
+
|
19
|
+
Returns
|
20
|
+
-------
|
21
|
+
bool
|
22
|
+
True if the module is valid and can be imported, False otherwise
|
23
|
+
"""
|
24
|
+
try:
|
25
|
+
importlib.import_module(module_name)
|
26
|
+
return True
|
27
|
+
except ImportError:
|
28
|
+
return False
|
29
|
+
|
30
|
+
@staticmethod
|
31
|
+
def ensureValidModule(module_name: str) -> None:
|
32
|
+
"""Ensure a module name is valid and can be imported.
|
33
|
+
|
34
|
+
Parameters
|
35
|
+
----------
|
36
|
+
module_name : str
|
37
|
+
The name of the module to check
|
38
|
+
|
39
|
+
Raises
|
40
|
+
------
|
41
|
+
ValueError
|
42
|
+
If the module cannot be imported or is invalid
|
43
|
+
"""
|
44
|
+
if not isinstance(module_name, str):
|
45
|
+
raise TypeError(f"Module name must be a string, got {type(module_name)}")
|
46
|
+
if not HelpersReflection.isValidModule(module_name):
|
47
|
+
raise ValueError(f"Invalid or non-importable module: {module_name}")
|
48
|
+
|
49
|
+
@staticmethod
|
50
|
+
def isInstantiableClass(cls: Type) -> bool:
|
51
|
+
"""Check if a class is concrete and can be instantiated.
|
52
|
+
|
53
|
+
Parameters
|
54
|
+
----------
|
55
|
+
cls : Type
|
56
|
+
The class to check
|
57
|
+
|
58
|
+
Returns
|
59
|
+
--
|
60
|
+
bool
|
61
|
+
True if the class is concrete and can be instantiated, False otherwise
|
62
|
+
"""
|
63
|
+
if not isinstance(cls, type):
|
64
|
+
return False
|
65
|
+
if HelpersReflection.isAbstractClass(cls):
|
66
|
+
return False
|
67
|
+
|
68
|
+
# Try to create an instance to verify it's truly concrete
|
69
|
+
try:
|
70
|
+
cls()
|
71
|
+
return True
|
72
|
+
except TypeError:
|
73
|
+
return False
|
74
|
+
|
75
|
+
@staticmethod
|
76
|
+
def ensureNotBuiltinType(cls: Type) -> None:
|
77
|
+
"""Ensure a class is not a built-in or primitive type.
|
78
|
+
|
79
|
+
Parameters
|
80
|
+
----------
|
81
|
+
cls : Type
|
82
|
+
The class to check
|
83
|
+
|
84
|
+
Raises
|
85
|
+
------
|
86
|
+
TypeError
|
87
|
+
If the input is not a class
|
88
|
+
ValueError
|
89
|
+
If the class is a built-in or primitive type
|
90
|
+
"""
|
91
|
+
if not isinstance(cls, type):
|
92
|
+
raise TypeError(f"Expected a class, got {type(cls)}")
|
93
|
+
|
94
|
+
builtin_types = {
|
95
|
+
int, float, str, bool, bytes, type(None), complex,
|
96
|
+
list, tuple, dict, set, frozenset
|
97
|
+
}
|
98
|
+
|
99
|
+
if cls in builtin_types:
|
100
|
+
raise ValueError(f"Class '{cls.__name__}' is a built-in or primitive type and cannot be used.")
|
101
|
+
|
102
|
+
@staticmethod
|
103
|
+
def ensureInstantiableClass(cls: Type) -> None:
|
104
|
+
"""Ensure a class is concrete and can be instantiated.
|
105
|
+
|
106
|
+
Parameters
|
107
|
+
----------
|
108
|
+
cls : Type
|
109
|
+
The class to check
|
110
|
+
|
111
|
+
Raises
|
112
|
+
------
|
113
|
+
TypeError
|
114
|
+
If the input is not a class
|
115
|
+
ValueError
|
116
|
+
If the class is abstract or cannot be instantiated
|
117
|
+
"""
|
118
|
+
if HelpersReflection.ensureNotBuiltinType(cls):
|
119
|
+
raise TypeError(f"Invalid class: {cls!r}")
|
120
|
+
|
121
|
+
if not isinstance(cls, type):
|
122
|
+
raise TypeError(f"Expected a class, got {type(cls)}")
|
123
|
+
|
124
|
+
if HelpersReflection.isAbstractClass(cls):
|
125
|
+
raise ValueError(f"Class '{cls.__name__}' is abstract")
|
126
|
+
|
127
|
+
try:
|
128
|
+
cls()
|
129
|
+
except TypeError as e:
|
130
|
+
raise ValueError(f"Class '{cls.__name__}' cannot be instantiated: {str(e)}")
|
131
|
+
|
132
|
+
@staticmethod
|
133
|
+
def isValidClassName(module_name: str, class_name: str) -> bool:
|
134
|
+
"""Check if a class exists in a given module.
|
135
|
+
|
136
|
+
Parameters
|
137
|
+
----------
|
138
|
+
module_name : str
|
139
|
+
The name of the module to check
|
140
|
+
class_name : str
|
141
|
+
The name of the class to look for
|
142
|
+
|
143
|
+
Returns
|
144
|
+
-------
|
145
|
+
bool
|
146
|
+
True if the class exists in the module, False otherwise
|
147
|
+
"""
|
148
|
+
try:
|
149
|
+
module = importlib.import_module(module_name)
|
150
|
+
return hasattr(module, class_name) and inspect.isclass(getattr(module, class_name))
|
151
|
+
except ImportError:
|
152
|
+
return False
|
153
|
+
|
154
|
+
@staticmethod
|
155
|
+
def ensureValidClassName(module_name: str, class_name: str) -> None:
|
156
|
+
"""Ensure a class exists in a given module.
|
157
|
+
|
158
|
+
Parameters
|
159
|
+
----------
|
160
|
+
module_name : str
|
161
|
+
The name of the module to check
|
162
|
+
class_name : str
|
163
|
+
The name of the class to look for
|
164
|
+
|
165
|
+
Raises
|
166
|
+
------
|
167
|
+
ValueError
|
168
|
+
If the class doesn't exist in the module
|
169
|
+
"""
|
170
|
+
if not HelpersReflection.isValidClassName(module_name, class_name):
|
171
|
+
raise ValueError(f"Class '{class_name}' not found in module '{module_name}'")
|
172
|
+
|
173
|
+
@staticmethod
|
174
|
+
def isUserDefinedClassInstance(instance: Any) -> bool:
|
175
|
+
"""Check if an object is an instance of a user-defined class.
|
176
|
+
|
177
|
+
Parameters
|
178
|
+
----------
|
179
|
+
instance : Any
|
180
|
+
The object to check
|
181
|
+
|
182
|
+
Returns
|
183
|
+
-------
|
184
|
+
bool
|
185
|
+
True if the object is an instance of a user-defined class, False otherwise
|
186
|
+
"""
|
187
|
+
return isinstance(instance, object) and type(instance).__module__ not in {'builtins', 'abc', '__main__'}
|
188
|
+
|
189
|
+
@staticmethod
|
190
|
+
def ensureUserDefinedClassInstance(instance: Any) -> None:
|
191
|
+
"""Ensure an object is an instance of a user-defined class.
|
192
|
+
|
193
|
+
Parameters
|
194
|
+
----------
|
195
|
+
instance : Any
|
196
|
+
The object to check
|
197
|
+
|
198
|
+
Raises
|
199
|
+
------
|
200
|
+
TypeError
|
201
|
+
If the input is not an object instance
|
202
|
+
ValueError
|
203
|
+
If the instance is from builtins, abc, or __main__
|
204
|
+
"""
|
205
|
+
if not isinstance(instance, object):
|
206
|
+
raise TypeError(f"Invalid object: {instance!r}")
|
207
|
+
module = type(instance).__module__
|
208
|
+
if module in {'builtins', 'abc'}:
|
209
|
+
raise ValueError(f"'{instance!r}' is not a user-defined class instance, belongs to '{module}'.")
|
210
|
+
if module == '__main__':
|
211
|
+
raise ValueError("Instance originates from '__main__', origin indeterminate.")
|
212
|
+
|
213
|
+
@staticmethod
|
214
|
+
def isAbstractClass(cls: Type) -> bool:
|
215
|
+
"""Check if a class is abstract.
|
216
|
+
|
217
|
+
Parameters
|
218
|
+
----------
|
219
|
+
cls : Type
|
220
|
+
The class to check
|
221
|
+
|
222
|
+
Returns
|
223
|
+
-------
|
224
|
+
bool
|
225
|
+
True if the class is abstract, False otherwise
|
226
|
+
"""
|
227
|
+
return isinstance(cls, type) and bool(getattr(cls, '__abstractmethods__', False))
|
228
|
+
|
229
|
+
@staticmethod
|
230
|
+
def ensureAbstractClass(cls: Type) -> None:
|
231
|
+
"""Ensure a class is abstract.
|
232
|
+
|
233
|
+
Parameters
|
234
|
+
----------
|
235
|
+
cls : Type
|
236
|
+
The class to check
|
237
|
+
|
238
|
+
Raises
|
239
|
+
------
|
240
|
+
TypeError
|
241
|
+
If the input is not a class
|
242
|
+
ValueError
|
243
|
+
If the class is not abstract
|
244
|
+
"""
|
245
|
+
if not isinstance(cls, type):
|
246
|
+
raise TypeError(f"Invalid class: {cls!r}")
|
247
|
+
if not HelpersReflection.isAbstractClass(cls):
|
248
|
+
raise ValueError(f"Class '{cls.__name__}' is not abstract.")
|
249
|
+
|
250
|
+
@staticmethod
|
251
|
+
def isConcreteClass(cls: Type) -> bool:
|
252
|
+
"""Check if a class is concrete.
|
253
|
+
|
254
|
+
Parameters
|
255
|
+
----------
|
256
|
+
cls : Type
|
257
|
+
The class to check
|
258
|
+
|
259
|
+
Returns
|
260
|
+
-------
|
261
|
+
bool
|
262
|
+
True if the class is concrete, False otherwise
|
263
|
+
"""
|
264
|
+
return isinstance(cls, type) and not HelpersReflection.isAbstractClass(cls)
|
265
|
+
|
266
|
+
@staticmethod
|
267
|
+
def ensureConcreteClass(cls: Type) -> None:
|
268
|
+
"""Ensure a class is concrete.
|
269
|
+
|
270
|
+
Parameters
|
271
|
+
----------
|
272
|
+
cls : Type
|
273
|
+
The class to check
|
274
|
+
|
275
|
+
Raises
|
276
|
+
------
|
277
|
+
TypeError
|
278
|
+
If the input is not a class
|
279
|
+
ValueError
|
280
|
+
If the class is not concrete
|
281
|
+
"""
|
282
|
+
if not isinstance(cls, type):
|
283
|
+
raise TypeError(f"Invalid class: {cls!r}")
|
284
|
+
if not HelpersReflection.isConcreteClass(cls):
|
285
|
+
raise ValueError(f"Class '{cls.__name__}' is not concrete.")
|