orionis 0.246.0__py3-none-any.whl → 0.247.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/framework.py +1 -1
- orionis/luminate/config/app/__init__.py +10 -0
- orionis/luminate/config/app/entities/app.py +205 -0
- orionis/luminate/config/app/enums/ciphers.py +34 -0
- orionis/luminate/config/app/enums/environments.py +15 -0
- orionis/luminate/config/auth/__init__.py +7 -0
- orionis/luminate/config/auth/entities/auth.py +11 -0
- orionis/luminate/config/cache/__init__.py +9 -0
- orionis/luminate/config/cache/entities/cache.py +58 -0
- orionis/luminate/config/cache/entities/file.py +29 -0
- orionis/luminate/config/cache/entities/stores.py +35 -0
- orionis/luminate/config/cache/enums/drivers.py +12 -0
- orionis/luminate/config/entities/testing.py +192 -14
- orionis/luminate/config/exceptions/integrity_exception.py +30 -0
- orionis/luminate/console/dumper/dump_die.py +418 -0
- orionis/luminate/contracts/facades/commands/scheduler_facade.py +1 -1
- orionis/luminate/facades/files/path_facade.py +1 -1
- orionis/luminate/patterns/__init__.py +4 -0
- orionis/luminate/patterns/singleton/__init__.py +10 -0
- orionis/luminate/patterns/singleton/meta_class.py +56 -0
- orionis/luminate/providers/commands/reactor_commands_service_provider.py +3 -3
- orionis/luminate/providers/commands/scheduler_provider.py +1 -1
- orionis/luminate/providers/config/config_service_provider.py +1 -1
- orionis/luminate/providers/environment/environment__service_provider.py +2 -2
- orionis/luminate/providers/files/paths_provider.py +1 -1
- orionis/luminate/providers/log/log_service_provider.py +2 -2
- orionis/luminate/services/environment/__init__.py +10 -0
- orionis/luminate/services/environment/contracts/__init__.py +5 -0
- orionis/luminate/services/environment/contracts/env.py +93 -0
- orionis/luminate/services/environment/dot_env.py +293 -0
- orionis/luminate/services/environment/env.py +77 -0
- orionis/luminate/services/paths/__init__.py +9 -0
- orionis/luminate/services/paths/contracts/resolver.py +67 -0
- orionis/luminate/services/paths/resolver.py +83 -0
- orionis/luminate/services/workers/__init__.py +10 -0
- orionis/luminate/services/workers/maximum_workers.py +36 -0
- orionis/luminate/services_/commands/__init__.py +0 -0
- orionis/luminate/services_/config/__init__.py +0 -0
- orionis/luminate/services_/log/__init__.py +0 -0
- orionis/luminate/test/__init__.py +11 -1
- orionis/luminate/test/cases/test_async.py +1 -10
- orionis/luminate/test/cases/test_case.py +8 -3
- orionis/luminate/test/cases/test_sync.py +1 -0
- orionis/luminate/test/core/contracts/test_suite.py +19 -31
- orionis/luminate/test/core/contracts/test_unit.py +4 -0
- orionis/luminate/test/core/test_suite.py +27 -26
- orionis/luminate/test/core/test_unit.py +28 -45
- orionis/luminate/test/entities/test_result.py +13 -16
- orionis/luminate/test/exceptions/test_exception.py +1 -1
- orionis/luminate/test/output/contracts/test_std_out.py +22 -11
- orionis/luminate/test/output/test_std_out.py +69 -80
- {orionis-0.246.0.dist-info → orionis-0.247.0.dist-info}/METADATA +4 -1
- {orionis-0.246.0.dist-info → orionis-0.247.0.dist-info}/RECORD +80 -51
- tests/config/__init__.py +0 -0
- tests/config/test_app.py +122 -0
- tests/config/test_auth.py +21 -0
- tests/config/test_cache.py +20 -0
- tests/patterns/__init__.py +0 -0
- tests/patterns/singleton/__init__.py +0 -0
- tests/patterns/singleton/test_singleton.py +18 -0
- tests/services/__init__.py +0 -0
- tests/services/environment/__init__.py +0 -0
- tests/services/environment/test_env.py +33 -0
- orionis/luminate/config/entities/app.py +0 -47
- orionis/luminate/config/entities/auth.py +0 -15
- orionis/luminate/config/entities/cache.py +0 -51
- orionis/luminate/support/environment/contracts/env.py +0 -68
- orionis/luminate/support/environment/env.py +0 -139
- orionis/luminate/support/environment/functions.py +0 -49
- orionis/luminate/support/environment/helper.py +0 -26
- orionis/luminate/support/patterns/singleton.py +0 -44
- tests/support/environment/test_env.py +0 -91
- tests/support/patterns/test_singleton.py +0 -18
- /orionis/luminate/config/{entities → app/entities}/__init__.py +0 -0
- /orionis/luminate/{services/commands → config/app/enums}/__init__.py +0 -0
- /orionis/luminate/{services/config → config/auth/entities}/__init__.py +0 -0
- /orionis/luminate/{services/log → config/cache/entities}/__init__.py +0 -0
- /orionis/luminate/{support/environment → config/cache/enums}/__init__.py +0 -0
- /orionis/luminate/{support/environment/contracts → config/exceptions}/__init__.py +0 -0
- /orionis/luminate/{support/patterns → console/dumper}/__init__.py +0 -0
- {tests/support/environment → orionis/luminate/services/paths/contracts}/__init__.py +0 -0
- {tests/support/patterns → orionis/luminate/services_}/__init__.py +0 -0
- /orionis/luminate/{services → services_}/commands/reactor_commands_service.py +0 -0
- /orionis/luminate/{services → services_}/commands/scheduler_service.py +0 -0
- /orionis/luminate/{services → services_}/config/config_service.py +0 -0
- /orionis/luminate/{services → services_}/log/log_service.py +0 -0
- {orionis-0.246.0.dist-info → orionis-0.247.0.dist-info}/LICENCE +0 -0
- {orionis-0.246.0.dist-info → orionis-0.247.0.dist-info}/WHEEL +0 -0
- {orionis-0.246.0.dist-info → orionis-0.247.0.dist-info}/entry_points.txt +0 -0
- {orionis-0.246.0.dist-info → orionis-0.247.0.dist-info}/top_level.txt +0 -0
orionis/framework.py
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
from orionis.luminate.config.app.entities.app import App
|
2
|
+
|
3
|
+
__all__ = [
|
4
|
+
"app"
|
5
|
+
]
|
6
|
+
__author__ = "Raúl Mauricio Uñate Castro"
|
7
|
+
__description__ = (
|
8
|
+
"This dataclass defines the main configuration of the Orionis Framework application. "
|
9
|
+
"Its design aims to provide a flexible and adaptable structure for Python projects."
|
10
|
+
)
|
@@ -0,0 +1,205 @@
|
|
1
|
+
from dataclasses import dataclass, field
|
2
|
+
from orionis.luminate.config.app.enums.ciphers import Cipher
|
3
|
+
from orionis.luminate.config.app.enums.environments import Environments
|
4
|
+
from orionis.luminate.config.exceptions.integrity_exception import OrionisIntegrityException
|
5
|
+
from orionis.luminate.services.environment.env import Env
|
6
|
+
from orionis.luminate.services.workers.maximum_workers import MaximumWorkers
|
7
|
+
|
8
|
+
@dataclass(unsafe_hash=True, kw_only=True)
|
9
|
+
class App:
|
10
|
+
"""
|
11
|
+
Represents the configuration settings for the application.
|
12
|
+
Attributes:
|
13
|
+
name (str): The name of the application. Defaults to 'Orionis Application'.
|
14
|
+
env (Environments): The environment in which the application is running. Defaults to 'DEVELOPMENT'.
|
15
|
+
debug (bool): Flag indicating whether debug mode is enabled. Defaults to True.
|
16
|
+
url (str): The base URL of the application. Defaults to 'http://127.0.0.1'.
|
17
|
+
port (int): The port on which the application will run. Defaults to 8000.
|
18
|
+
workers (int): The number of worker processes to handle requests. Defaults to the maximum available workers.
|
19
|
+
reload (bool): Flag indicating whether the application should reload on code changes. Defaults to True.
|
20
|
+
timezone (str): The timezone of the application. Defaults to 'UTC'.
|
21
|
+
locale (str): The locale for the application. Defaults to 'en'.
|
22
|
+
fallback_locale (str): The fallback locale for the application. Defaults to 'en'.
|
23
|
+
cipher (Cipher): The cipher used for encryption. Defaults to 'AES_256_CBC'.
|
24
|
+
key (str or None): The encryption key for the application. Defaults to None.
|
25
|
+
maintenance (Maintenance): The maintenance configuration for the application. Defaults to '/maintenance'.
|
26
|
+
Methods:
|
27
|
+
__post_init__():
|
28
|
+
"""
|
29
|
+
|
30
|
+
name: str = field(
|
31
|
+
default_factory=lambda: Env.get('APP_NAME', 'Orionis Application'),
|
32
|
+
metadata={
|
33
|
+
"description": "The name of the application. Defaults to 'Orionis Application'.",
|
34
|
+
"required": True,
|
35
|
+
"default": "Orionis Application"
|
36
|
+
}
|
37
|
+
)
|
38
|
+
|
39
|
+
env: Environments = field(
|
40
|
+
default_factory=lambda: Env.get('APP_ENV', Environments.DEVELOPMENT),
|
41
|
+
metadata={
|
42
|
+
"description": "The environment in which the application is running. Defaults to 'DEVELOPMENT'.",
|
43
|
+
"required": True,
|
44
|
+
"default": "Environments.DEVELOPMENT"
|
45
|
+
}
|
46
|
+
)
|
47
|
+
|
48
|
+
debug: bool = field(
|
49
|
+
default_factory=lambda: Env.get('APP_DEBUG', True),
|
50
|
+
metadata={
|
51
|
+
"description": "Flag indicating whether debug mode is enabled. Defaults to False.",
|
52
|
+
"required": True,
|
53
|
+
"default": True
|
54
|
+
}
|
55
|
+
)
|
56
|
+
|
57
|
+
url: str = field(
|
58
|
+
default_factory=lambda: Env.get('APP_URL', 'http://127.0.0.1'),
|
59
|
+
metadata={
|
60
|
+
"description": "The base URL of the application. Defaults to 'http://127.0.0.1'.",
|
61
|
+
"required": True,
|
62
|
+
"default": "http://127.0.0.1"
|
63
|
+
}
|
64
|
+
)
|
65
|
+
|
66
|
+
port: int = field(
|
67
|
+
default_factory=lambda: Env.get('APP_PORT', 8000),
|
68
|
+
metadata={
|
69
|
+
"description": "The port on which the application will run. Defaults to 8000.",
|
70
|
+
"required": True,
|
71
|
+
"default": 8000
|
72
|
+
}
|
73
|
+
)
|
74
|
+
|
75
|
+
workers: int = field(
|
76
|
+
default_factory=lambda: Env.get('APP_WORKERS', MaximumWorkers().calculate()),
|
77
|
+
metadata={
|
78
|
+
"description": "The number of worker processes to handle requests. Defaults to the maximum available workers.",
|
79
|
+
"required": True,
|
80
|
+
"default": "MaximumWorkers.calculate()"
|
81
|
+
}
|
82
|
+
)
|
83
|
+
|
84
|
+
reload: bool = field(
|
85
|
+
default_factory=lambda: Env.get('APP_RELOAD', True),
|
86
|
+
metadata={
|
87
|
+
"description": "Flag indicating whether the application should reload on code changes. Defaults to True.",
|
88
|
+
"required": True,
|
89
|
+
"default": True
|
90
|
+
}
|
91
|
+
)
|
92
|
+
|
93
|
+
timezone: str = field(
|
94
|
+
default_factory=lambda: Env.get('APP_TIMEZONE', 'UTC'),
|
95
|
+
metadata={
|
96
|
+
"description": "The timezone of the application. Defaults to 'UTC'.",
|
97
|
+
"required": True,
|
98
|
+
"default": "UTC"
|
99
|
+
}
|
100
|
+
)
|
101
|
+
|
102
|
+
locale: str = field(
|
103
|
+
default_factory=lambda: Env.get('APP_LOCALE', 'en'),
|
104
|
+
metadata={
|
105
|
+
"description": "The locale for the application. Defaults to 'en'.",
|
106
|
+
"required": True,
|
107
|
+
"default": "en"
|
108
|
+
}
|
109
|
+
)
|
110
|
+
|
111
|
+
fallback_locale: str = field(
|
112
|
+
default_factory=lambda: Env.get('APP_FALLBACK_LOCALE', 'en'),
|
113
|
+
metadata={
|
114
|
+
"description": "The fallback locale for the application. Defaults to 'en'.",
|
115
|
+
"required": True,
|
116
|
+
"default": "en"
|
117
|
+
}
|
118
|
+
)
|
119
|
+
|
120
|
+
cipher: str = field(
|
121
|
+
default_factory=lambda: Env.get('APP_CIPHER', Cipher.AES_256_CBC),
|
122
|
+
metadata={
|
123
|
+
"description": "The cipher used for encryption. Defaults to 'AES_256_CBC'.",
|
124
|
+
"required": True,
|
125
|
+
"default": "Cipher.AES_256_CBC"
|
126
|
+
}
|
127
|
+
)
|
128
|
+
|
129
|
+
key: str = field(
|
130
|
+
default_factory=lambda: Env.get('APP_KEY'),
|
131
|
+
metadata={
|
132
|
+
"description": "The encryption key for the application. Defaults to None.",
|
133
|
+
"required": False,
|
134
|
+
"default": None
|
135
|
+
}
|
136
|
+
)
|
137
|
+
|
138
|
+
maintenance: str = field(
|
139
|
+
default_factory=lambda: Env.get('APP_MAINTENANCE', '/maintenance'),
|
140
|
+
metadata={
|
141
|
+
"description": "The maintenance configuration for the application. Defaults to '/maintenance'.",
|
142
|
+
"required": True,
|
143
|
+
"default": "/maintenance"
|
144
|
+
}
|
145
|
+
)
|
146
|
+
|
147
|
+
def __post_init__(self):
|
148
|
+
"""
|
149
|
+
Validates and normalizes the attributes after dataclass initialization.
|
150
|
+
|
151
|
+
Ensures that all fields have the correct types and values, raising TypeError
|
152
|
+
if any field is invalid. This helps catch configuration errors early.
|
153
|
+
"""
|
154
|
+
if not isinstance(self.name, str) or not self.name.strip():
|
155
|
+
raise OrionisIntegrityException("The 'name' attribute must be a non-empty string of type str.")
|
156
|
+
|
157
|
+
if not isinstance(self.env, Environments):
|
158
|
+
if isinstance(self.env, str):
|
159
|
+
value = str(self.env).strip().upper()
|
160
|
+
if value in Environments._member_names_:
|
161
|
+
self.env = getattr(Environments, value)
|
162
|
+
else:
|
163
|
+
raise OrionisIntegrityException(f"Invalid environment value: {self.env}. Must be one of {Environments._member_names_}.")
|
164
|
+
else:
|
165
|
+
raise OrionisIntegrityException("The 'env' attribute must be of type Environments.")
|
166
|
+
|
167
|
+
if not isinstance(self.debug, bool):
|
168
|
+
raise OrionisIntegrityException("The 'debug' attribute must be a boolean.")
|
169
|
+
|
170
|
+
if not isinstance(self.url, str) or not self.url.strip():
|
171
|
+
raise OrionisIntegrityException("The 'url' attribute must be a non-empty string.")
|
172
|
+
|
173
|
+
if not isinstance(self.port, int):
|
174
|
+
raise OrionisIntegrityException("The 'port' attribute must be an integer.")
|
175
|
+
|
176
|
+
if not isinstance(self.workers, int):
|
177
|
+
raise OrionisIntegrityException("The 'workers' attribute must be an integer.")
|
178
|
+
|
179
|
+
if not isinstance(self.reload, bool):
|
180
|
+
raise OrionisIntegrityException("The 'reload' attribute must be a boolean.")
|
181
|
+
|
182
|
+
if not isinstance(self.timezone, str) or not self.timezone.strip():
|
183
|
+
raise OrionisIntegrityException("The 'timezone' attribute must be a non-empty string.")
|
184
|
+
|
185
|
+
if not isinstance(self.locale, str) or not self.locale.strip():
|
186
|
+
raise OrionisIntegrityException("The 'locale' attribute must be a non-empty string.")
|
187
|
+
|
188
|
+
if not isinstance(self.fallback_locale, str) or not self.fallback_locale.strip():
|
189
|
+
raise OrionisIntegrityException("The 'fallback_locale' attribute must be a non-empty string.")
|
190
|
+
|
191
|
+
if not isinstance(self.cipher, Cipher):
|
192
|
+
if isinstance(self.cipher, str):
|
193
|
+
value = str(self.cipher).strip().upper()
|
194
|
+
if value in Cipher._member_names_:
|
195
|
+
self.cipher = getattr(Cipher, value)
|
196
|
+
else:
|
197
|
+
raise OrionisIntegrityException(f"Invalid cipher value: {self.cipher}. Must be one of {Cipher._member_names_}.")
|
198
|
+
else:
|
199
|
+
raise OrionisIntegrityException("The 'cipher' attribute must be of type Cipher.")
|
200
|
+
|
201
|
+
if self.key is not None and not isinstance(self.key, str):
|
202
|
+
raise OrionisIntegrityException("The 'key' attribute must be a string or None.")
|
203
|
+
|
204
|
+
if not isinstance(self.maintenance, str):
|
205
|
+
raise OrionisIntegrityException("The 'maintenance' attribute must be a string (A Route).")
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
|
3
|
+
class Cipher(Enum):
|
4
|
+
"""
|
5
|
+
Enumeration of supported AES cipher modes.
|
6
|
+
|
7
|
+
This enum defines various Advanced Encryption Standard (AES) cipher modes and key sizes
|
8
|
+
commonly used for encryption and decryption operations.
|
9
|
+
|
10
|
+
Members:
|
11
|
+
AES_128_CBC: AES with 128-bit key in Cipher Block Chaining (CBC) mode.
|
12
|
+
AES_192_CBC: AES with 192-bit key in CBC mode.
|
13
|
+
AES_256_CBC: AES with 256-bit key in CBC mode.
|
14
|
+
AES_128_GCM: AES with 128-bit key in Galois/Counter Mode (GCM).
|
15
|
+
AES_256_GCM: AES with 256-bit key in GCM.
|
16
|
+
AES_CTR: AES in Counter (CTR) mode.
|
17
|
+
AES_CFB: AES in Cipher Feedback (CFB) mode.
|
18
|
+
AES_CFB8: AES in CFB mode with 8-bit feedback.
|
19
|
+
AES_CFB128: AES in CFB mode with 128-bit feedback.
|
20
|
+
AES_OFB: AES in Output Feedback (OFB) mode.
|
21
|
+
AES_ECB: AES in Electronic Codebook (ECB) mode.
|
22
|
+
"""
|
23
|
+
|
24
|
+
AES_128_CBC = "AES-128-CBC"
|
25
|
+
AES_192_CBC = "AES-192-CBC"
|
26
|
+
AES_256_CBC = "AES-256-CBC"
|
27
|
+
AES_128_GCM = "AES-128-GCM"
|
28
|
+
AES_256_GCM = "AES-256-GCM"
|
29
|
+
AES_CTR = "AES-CTR"
|
30
|
+
AES_CFB = "AES-CFB"
|
31
|
+
AES_CFB8 = "AES-CFB8"
|
32
|
+
AES_CFB128 = "AES-CFB128"
|
33
|
+
AES_OFB = "AES-OFB"
|
34
|
+
AES_ECB = "AES-ECB"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
|
3
|
+
class Environments(Enum):
|
4
|
+
"""
|
5
|
+
Enumeration of possible application environments.
|
6
|
+
|
7
|
+
Attributes:
|
8
|
+
DEVELOPMENT: Represents the development environment.
|
9
|
+
TESTING: Represents the testing environment.
|
10
|
+
PRODUCTION: Represents the production environment.
|
11
|
+
"""
|
12
|
+
|
13
|
+
DEVELOPMENT = 'development'
|
14
|
+
TESTING = 'testing'
|
15
|
+
PRODUCTION = 'production'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
|
3
|
+
@dataclass(unsafe_hash=True, kw_only=True)
|
4
|
+
class Auth:
|
5
|
+
"""
|
6
|
+
Represents the authentication entity within the system.
|
7
|
+
|
8
|
+
This class serves as a placeholder for authentication-related attributes and methods.
|
9
|
+
Extend this class to implement authentication logic such as user credentials, token management, or session handling.
|
10
|
+
"""
|
11
|
+
pass
|
@@ -0,0 +1,58 @@
|
|
1
|
+
from dataclasses import dataclass, field
|
2
|
+
from orionis.luminate.config.cache.entities.file import File
|
3
|
+
from orionis.luminate.config.cache.entities.stores import Stores
|
4
|
+
from orionis.luminate.config.cache.enums.drivers import Drivers
|
5
|
+
from orionis.luminate.config.exceptions.integrity_exception import OrionisIntegrityException
|
6
|
+
from orionis.luminate.services.environment import Env
|
7
|
+
|
8
|
+
@dataclass
|
9
|
+
class Cache:
|
10
|
+
"""
|
11
|
+
Represents the cache configuration for the application.
|
12
|
+
Attributes:
|
13
|
+
default (Drivers | str): The default cache storage type. Can be a member of the Drivers enum or a string
|
14
|
+
(e.g., 'memory', 'file'). Defaults to the value of the 'CACHE_STORE' environment variable or Drivers.MEMORY.
|
15
|
+
stores (Stores): The configuration for available cache stores. Defaults to a Stores instance with a file store
|
16
|
+
at the path specified by the 'CACHE_PATH' environment variable or "storage/framework/cache/data".
|
17
|
+
Methods:
|
18
|
+
__post_init__():
|
19
|
+
- Validates that 'default' is either a Drivers enum member or a string.
|
20
|
+
- Converts 'default' from string to Drivers enum if necessary.
|
21
|
+
- Validates that 'stores' is an instance of Stores.
|
22
|
+
"""
|
23
|
+
|
24
|
+
default: Drivers | str = field(
|
25
|
+
default=Env.get("CACHE_STORE", Drivers.MEMORY),
|
26
|
+
metadata={
|
27
|
+
"description": "The default cache storage type (e.g., 'memory' or 'file').",
|
28
|
+
"type": Drivers,
|
29
|
+
},
|
30
|
+
)
|
31
|
+
|
32
|
+
stores: Stores = field(
|
33
|
+
default_factory=lambda: Stores(
|
34
|
+
file=File(
|
35
|
+
path=Env.get("CACHE_PATH", "storage/framework/cache/data")
|
36
|
+
)
|
37
|
+
)
|
38
|
+
)
|
39
|
+
|
40
|
+
def __post_init__(self):
|
41
|
+
"""
|
42
|
+
Post-initialization processing to ensure the cache configuration is set correctly.
|
43
|
+
"""
|
44
|
+
# Ensure the default cache store is valid
|
45
|
+
if not isinstance(self.default, (Drivers, str)):
|
46
|
+
raise OrionisIntegrityException("The default cache store must be an instance of Drivers or a string.")
|
47
|
+
|
48
|
+
# Convert string to Drivers enum if applicable
|
49
|
+
if isinstance(self.default, str):
|
50
|
+
value = self.default.upper().strip()
|
51
|
+
if value not in Drivers._member_names_:
|
52
|
+
raise OrionisIntegrityException(f"Invalid cache driver: {self.default}. Must be one of {Drivers._member_names_}.")
|
53
|
+
else:
|
54
|
+
self.default = getattr(Drivers, value)
|
55
|
+
|
56
|
+
# Ensure the stores attribute is an instance of Stores
|
57
|
+
if not isinstance(self.stores, Stores):
|
58
|
+
raise OrionisIntegrityException("The stores must be an instance of Stores.")
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from dataclasses import dataclass, field
|
2
|
+
from orionis.luminate.services.paths import Resolver
|
3
|
+
|
4
|
+
@dataclass
|
5
|
+
class File:
|
6
|
+
"""
|
7
|
+
Represents a file storage path.
|
8
|
+
|
9
|
+
Attributes
|
10
|
+
----------
|
11
|
+
path : str
|
12
|
+
The file path used for caching.
|
13
|
+
"""
|
14
|
+
path: str = field(
|
15
|
+
default_factory=lambda:Resolver().relativePath('storage/framework/cache/data').toString(),
|
16
|
+
metadata={
|
17
|
+
"description": "The file path used for caching.",
|
18
|
+
"type": str,
|
19
|
+
},
|
20
|
+
)
|
21
|
+
|
22
|
+
def __post_init__(self):
|
23
|
+
"""
|
24
|
+
Post-initialization processing to ensure the path is set correctly.
|
25
|
+
"""
|
26
|
+
if not self.path:
|
27
|
+
raise ValueError("The file path cannot be empty.")
|
28
|
+
if not isinstance(self.path, str):
|
29
|
+
raise TypeError("The file path must be a string.")
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from dataclasses import dataclass, field
|
2
|
+
from typing import Any
|
3
|
+
from orionis.luminate.config.cache.entities.file import File
|
4
|
+
from orionis.luminate.services.paths.resolver import Resolver
|
5
|
+
|
6
|
+
@dataclass
|
7
|
+
class Stores:
|
8
|
+
"""
|
9
|
+
Represents a collection of cache storage backends for the application.
|
10
|
+
Attributes:
|
11
|
+
file (File): An instance of `File` representing file-based cache storage.
|
12
|
+
The default path is set to 'storage/framework/cache/data', resolved
|
13
|
+
relative to the application's root directory.
|
14
|
+
Methods:
|
15
|
+
__post_init__():
|
16
|
+
Ensures that the 'file' attribute is properly initialized as an instance of `File`.
|
17
|
+
Raises a TypeError if the type check fails.
|
18
|
+
"""
|
19
|
+
|
20
|
+
file: File = field(
|
21
|
+
default_factory=lambda: File(
|
22
|
+
path=Resolver().relativePath('storage/framework/cache/data').toString()
|
23
|
+
),
|
24
|
+
metadata={
|
25
|
+
"description": "An instance of `File` representing file-based cache storage.",
|
26
|
+
"type": File,
|
27
|
+
},
|
28
|
+
)
|
29
|
+
|
30
|
+
def __post_init__(self):
|
31
|
+
"""
|
32
|
+
Post-initialization processing to ensure the stores are set correctly.
|
33
|
+
"""
|
34
|
+
if not isinstance(self.file, File):
|
35
|
+
raise TypeError("The file store must be an instance of File.")
|
@@ -1,7 +1,17 @@
|
|
1
|
-
from dataclasses import dataclass
|
2
|
-
from typing import List
|
1
|
+
from dataclasses import dataclass, field
|
2
|
+
from typing import Any, List
|
3
|
+
from orionis.luminate.config.exceptions.integrity_exception import OrionisIntegrityException
|
4
|
+
from orionis.luminate.services.workers.maximum_workers import MaximumWorkers
|
3
5
|
|
4
|
-
|
6
|
+
def defaultExecutionMode() -> Any:
|
7
|
+
"""
|
8
|
+
This function is a placeholder for the ExecutionMode enumeration.
|
9
|
+
In a real-world scenario, this would be replaced with the actual import statement.
|
10
|
+
"""
|
11
|
+
from orionis.luminate.test.enums.test_mode import ExecutionMode
|
12
|
+
return ExecutionMode.SEQUENTIAL
|
13
|
+
|
14
|
+
@dataclass(frozen=True, kw_only=True, slots=True)
|
5
15
|
class Testing:
|
6
16
|
"""
|
7
17
|
Testing is a dataclass that holds configuration options for running tests.
|
@@ -24,14 +34,182 @@ class Testing:
|
|
24
34
|
test_name_pattern (str | None): A pattern to match specific test names. Default is None.
|
25
35
|
tags (List[str] | None): A list of tags to filter tests. Default is None.
|
26
36
|
"""
|
27
|
-
verbosity: int =
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
verbosity: int = field(
|
38
|
+
default=2,
|
39
|
+
metadata={
|
40
|
+
"description": "The verbosity level of the test output. Default is 2.",
|
41
|
+
"required": True,
|
42
|
+
"default": 2
|
43
|
+
}
|
44
|
+
)
|
45
|
+
|
46
|
+
execution_mode : Any = field(
|
47
|
+
default_factory=lambda: defaultExecutionMode(),
|
48
|
+
metadata={
|
49
|
+
"description": "The mode of test execution. Default is ExecutionMode.SEQUENTIAL.",
|
50
|
+
"required": True,
|
51
|
+
"default": "ExecutionMode.SEQUENTIAL"
|
52
|
+
}
|
53
|
+
)
|
54
|
+
|
55
|
+
max_workers: int = field(
|
56
|
+
default_factory=lambda : MaximumWorkers().calculate(),
|
57
|
+
metadata={
|
58
|
+
"description": "The maximum number of worker threads/processes to use when running tests in parallel. Default is 4.",
|
59
|
+
"required": True,
|
60
|
+
"default": "MaximumWorkers.calculate()"
|
61
|
+
}
|
62
|
+
)
|
63
|
+
|
64
|
+
fail_fast: bool = field(
|
65
|
+
default=False,
|
66
|
+
metadata={
|
67
|
+
"description": "Whether to stop execution after the first test failure. Default is False.",
|
68
|
+
"required": True,
|
69
|
+
"default": False
|
70
|
+
}
|
71
|
+
)
|
72
|
+
|
73
|
+
print_result: bool = field(
|
74
|
+
default=True,
|
75
|
+
metadata={
|
76
|
+
"description": "Whether to print the test results to the console. Default is True.",
|
77
|
+
"required": True,
|
78
|
+
"default": True
|
79
|
+
}
|
80
|
+
)
|
81
|
+
|
82
|
+
throw_exception: bool = field(
|
83
|
+
default=False,
|
84
|
+
metadata={
|
85
|
+
"description": "Whether to throw an exception if a test fails. Default is False.",
|
86
|
+
"required": True,
|
87
|
+
"default": False
|
88
|
+
}
|
89
|
+
)
|
90
|
+
|
91
|
+
base_path: str = field(
|
92
|
+
default='tests',
|
93
|
+
metadata={
|
94
|
+
"description": "The base directory where tests are located. Default is 'tests'.",
|
95
|
+
"required": True,
|
96
|
+
"default": 'tests'
|
97
|
+
}
|
98
|
+
)
|
99
|
+
|
100
|
+
folder_path: str | list = field(
|
101
|
+
default='*',
|
102
|
+
metadata={
|
103
|
+
"description": "The folder path pattern to search for tests. Default is '*'.",
|
104
|
+
"required": True,
|
105
|
+
"default": '*'
|
106
|
+
}
|
107
|
+
)
|
108
|
+
|
109
|
+
pattern: str = field(
|
110
|
+
default='test_*.py',
|
111
|
+
metadata={
|
112
|
+
"description": "The filename pattern to identify test files. Default is 'test_*.py'.",
|
113
|
+
"required": True,
|
114
|
+
"default": 'test_*.py'
|
115
|
+
}
|
116
|
+
)
|
117
|
+
|
118
|
+
test_name_pattern: str | None = field(
|
119
|
+
default=None,
|
120
|
+
metadata={
|
121
|
+
"description": "A pattern to match specific test names. Default is None.",
|
122
|
+
"required": False,
|
123
|
+
"default": None
|
124
|
+
}
|
125
|
+
)
|
126
|
+
|
127
|
+
tags: List[str] | None = field(
|
128
|
+
default_factory=lambda:[],
|
129
|
+
metadata={
|
130
|
+
"description": "A list of tags to filter tests. Default is an empty list.",
|
131
|
+
"required": False,
|
132
|
+
"default": []
|
133
|
+
}
|
134
|
+
)
|
135
|
+
|
136
|
+
def __post_init__(self):
|
137
|
+
"""
|
138
|
+
Post-initialization validation for the testing configuration entity.
|
139
|
+
This method performs type and value checks on the instance attributes to ensure they meet the expected constraints:
|
140
|
+
- `verbosity` must be an integer between 0 and 2 (inclusive).
|
141
|
+
- `execution_mode` must not be None.
|
142
|
+
- `max_workers` must be a positive integer.
|
143
|
+
- `fail_fast`, `print_result`, and `throw_exception` must be booleans.
|
144
|
+
- `base_path`, `folder_path`, and `pattern` must be strings.
|
145
|
+
- `test_name_pattern` must be either a string or None.
|
146
|
+
- `tags` must be either None or a list of strings.
|
147
|
+
Raises:
|
148
|
+
OrionisIntegrityException: If any of the attributes do not meet the specified constraints.
|
149
|
+
"""
|
150
|
+
if not isinstance(self.verbosity, int) or self.verbosity < 0 or self.verbosity > 2:
|
151
|
+
raise OrionisIntegrityException(
|
152
|
+
f"Invalid value for 'verbosity': {self.verbosity}. It must be an integer between 0 (silent) and 2 (detailed output)."
|
153
|
+
)
|
154
|
+
|
155
|
+
if self.execution_mode is None:
|
156
|
+
raise OrionisIntegrityException(
|
157
|
+
"'execution_mode' cannot be None. Please provide a valid ExecutionMode value."
|
158
|
+
)
|
159
|
+
|
160
|
+
if not isinstance(self.max_workers, int) or self.max_workers < 1:
|
161
|
+
raise OrionisIntegrityException(
|
162
|
+
f"Invalid value for 'max_workers': {self.max_workers}. It must be a positive integer greater than 0."
|
163
|
+
)
|
164
|
+
|
165
|
+
if not isinstance(self.fail_fast, bool):
|
166
|
+
raise OrionisIntegrityException(
|
167
|
+
f"Invalid type for 'fail_fast': {type(self.fail_fast).__name__}. It must be a boolean (True or False)."
|
168
|
+
)
|
169
|
+
|
170
|
+
if not isinstance(self.print_result, bool):
|
171
|
+
raise OrionisIntegrityException(
|
172
|
+
f"Invalid type for 'print_result': {type(self.print_result).__name__}. It must be a boolean (True or False)."
|
173
|
+
)
|
174
|
+
|
175
|
+
if not isinstance(self.throw_exception, bool):
|
176
|
+
raise OrionisIntegrityException(
|
177
|
+
f"Invalid type for 'throw_exception': {type(self.throw_exception).__name__}. It must be a boolean (True or False)."
|
178
|
+
)
|
179
|
+
|
180
|
+
if not isinstance(self.base_path, str):
|
181
|
+
raise OrionisIntegrityException(
|
182
|
+
f"Invalid type for 'base_path': {type(self.base_path).__name__}. It must be a string representing the base directory for tests."
|
183
|
+
)
|
184
|
+
|
185
|
+
if not (isinstance(self.folder_path, str) or isinstance(self.folder_path, list)):
|
186
|
+
raise OrionisIntegrityException(
|
187
|
+
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."
|
188
|
+
)
|
189
|
+
if isinstance(self.folder_path, list):
|
190
|
+
for i, folder in enumerate(self.folder_path):
|
191
|
+
if not isinstance(folder, str):
|
192
|
+
raise OrionisIntegrityException(
|
193
|
+
f"Invalid type for folder at index {i} in 'folder_path': {type(folder).__name__}. Each folder path must be a string."
|
194
|
+
)
|
195
|
+
|
196
|
+
if not isinstance(self.pattern, str):
|
197
|
+
raise OrionisIntegrityException(
|
198
|
+
f"Invalid type for 'pattern': {type(self.pattern).__name__}. It must be a string representing the filename pattern for test files."
|
199
|
+
)
|
200
|
+
|
201
|
+
if self.test_name_pattern is not None and not isinstance(self.test_name_pattern, str):
|
202
|
+
raise OrionisIntegrityException(
|
203
|
+
f"Invalid type for 'test_name_pattern': {type(self.test_name_pattern).__name__}. It must be a string or None."
|
204
|
+
)
|
205
|
+
|
206
|
+
if self.tags is not None:
|
207
|
+
if not isinstance(self.tags, list):
|
208
|
+
raise OrionisIntegrityException(
|
209
|
+
f"Invalid type for 'tags': {type(self.tags).__name__}. It must be a list of strings or None."
|
210
|
+
)
|
211
|
+
for i, tag in enumerate(self.tags):
|
212
|
+
if not isinstance(tag, str):
|
213
|
+
raise OrionisIntegrityException(
|
214
|
+
f"Invalid type for tag at index {i} in 'tags': {type(tag).__name__}. Each tag must be a string."
|
215
|
+
)
|