orionis 0.420.0__py3-none-any.whl → 0.422.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orionis/__init__.py +0 -11
- orionis/foundation/config/app/entities/app.py +15 -14
- orionis/foundation/config/cache/entities/cache.py +2 -1
- orionis/foundation/config/cache/entities/file.py +1 -0
- orionis/foundation/config/cache/entities/stores.py +1 -0
- orionis/foundation/config/cors/entities/cors.py +1 -0
- orionis/foundation/config/database/entities/connections.py +5 -4
- orionis/foundation/config/database/entities/database.py +3 -2
- orionis/foundation/config/database/entities/mysql.py +7 -6
- orionis/foundation/config/database/entities/oracle.py +11 -10
- orionis/foundation/config/database/entities/pgsql.py +7 -6
- orionis/foundation/config/database/entities/sqlite.py +8 -7
- orionis/foundation/config/filesystems/entitites/aws.py +1 -0
- orionis/foundation/config/filesystems/entitites/disks.py +4 -3
- orionis/foundation/config/filesystems/entitites/filesystems.py +2 -1
- orionis/foundation/config/filesystems/entitites/local.py +1 -0
- orionis/foundation/config/filesystems/entitites/public.py +1 -0
- orionis/foundation/config/logging/entities/channels.py +7 -6
- orionis/foundation/config/logging/entities/chunked.py +1 -0
- orionis/foundation/config/logging/entities/daily.py +3 -2
- orionis/foundation/config/logging/entities/hourly.py +1 -0
- orionis/foundation/config/logging/entities/logging.py +2 -1
- orionis/foundation/config/logging/entities/monthly.py +1 -0
- orionis/foundation/config/logging/entities/stack.py +1 -0
- orionis/foundation/config/logging/entities/weekly.py +1 -0
- orionis/foundation/config/mail/entities/mail.py +1 -1
- orionis/foundation/config/mail/entities/mailers.py +2 -2
- orionis/foundation/config/queue/entities/brokers.py +2 -1
- orionis/foundation/config/queue/entities/database.py +1 -0
- orionis/foundation/config/queue/entities/queue.py +2 -1
- orionis/foundation/config/roots/paths.py +63 -62
- orionis/foundation/config/session/entities/session.py +9 -8
- orionis/foundation/config/startup.py +13 -12
- orionis/foundation/config/testing/entities/testing.py +2 -1
- orionis/metadata/framework.py +1 -1
- orionis/services/environment/contracts/{types.py → caster.py} +1 -29
- orionis/services/environment/core/dot_env.py +230 -142
- orionis/services/environment/dynamic/caster.py +902 -0
- orionis/services/environment/enums/{cast_type.py → value_type.py} +11 -10
- orionis/services/environment/key/key_generator.py +7 -15
- orionis/services/environment/validators/types.py +10 -10
- orionis/support/entities/base.py +25 -0
- {orionis-0.420.0.dist-info → orionis-0.422.0.dist-info}/METADATA +1 -1
- {orionis-0.420.0.dist-info → orionis-0.422.0.dist-info}/RECORD +49 -51
- tests/foundation/config/root/test_foundation_config_root_paths.py +4 -1
- orionis/services/environment/dynamic/types.py +0 -577
- orionis/services/environment/serializer/__init__.py +0 -0
- orionis/services/environment/serializer/values.py +0 -21
- {orionis-0.420.0.dist-info → orionis-0.422.0.dist-info}/WHEEL +0 -0
- {orionis-0.420.0.dist-info → orionis-0.422.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.420.0.dist-info → orionis-0.422.0.dist-info}/top_level.txt +0 -0
- {orionis-0.420.0.dist-info → orionis-0.422.0.dist-info}/zip-safe +0 -0
|
@@ -66,7 +66,7 @@ class Testing(BaseEntity):
|
|
|
66
66
|
default_factory = lambda : Workers().calculate(),
|
|
67
67
|
metadata = {
|
|
68
68
|
"description": "The maximum number of worker threads/processes to use when running tests in parallel.",
|
|
69
|
-
"default": Workers().calculate()
|
|
69
|
+
"default": lambda : Workers().calculate()
|
|
70
70
|
}
|
|
71
71
|
)
|
|
72
72
|
|
|
@@ -159,6 +159,7 @@ class Testing(BaseEntity):
|
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
def __post_init__(self):
|
|
162
|
+
super().__post_init__()
|
|
162
163
|
"""
|
|
163
164
|
Validate and normalize configuration options after initialization.
|
|
164
165
|
|
orionis/metadata/framework.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
|
|
3
|
-
class
|
|
3
|
+
class IEnvironmentCaster(ABC):
|
|
4
4
|
|
|
5
5
|
@abstractmethod
|
|
6
6
|
def to(self, type_hint: str):
|
|
@@ -19,34 +19,6 @@ class IEnvTypes(ABC):
|
|
|
19
19
|
"""
|
|
20
20
|
pass
|
|
21
21
|
|
|
22
|
-
@abstractmethod
|
|
23
|
-
def hasValidTypeHint(self) -> bool:
|
|
24
|
-
"""
|
|
25
|
-
Check if the type hint is valid.
|
|
26
|
-
|
|
27
|
-
Returns
|
|
28
|
-
-------
|
|
29
|
-
bool
|
|
30
|
-
True if the type hint is valid (exists in the OPTIONS set), False otherwise.
|
|
31
|
-
"""
|
|
32
|
-
pass
|
|
33
|
-
|
|
34
|
-
@abstractmethod
|
|
35
|
-
def explode(self) -> tuple:
|
|
36
|
-
"""
|
|
37
|
-
Returns a tuple containing the type hint and value string.
|
|
38
|
-
|
|
39
|
-
Returns
|
|
40
|
-
-------
|
|
41
|
-
tuple
|
|
42
|
-
A tuple (type_hint, value_str) where:
|
|
43
|
-
type_hint : str or None
|
|
44
|
-
The extracted type hint in lowercase, or None if not provided.
|
|
45
|
-
value_str : str or None
|
|
46
|
-
The extracted value string, or None if not provided.
|
|
47
|
-
"""
|
|
48
|
-
pass
|
|
49
|
-
|
|
50
22
|
@abstractmethod
|
|
51
23
|
def get(self):
|
|
52
24
|
"""
|
|
@@ -1,33 +1,35 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import ast
|
|
3
|
-
import re
|
|
4
3
|
import threading
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
from typing import Any, Optional, Union
|
|
7
6
|
from dotenv import dotenv_values, load_dotenv, set_key, unset_key
|
|
8
|
-
from orionis.services.environment.enums.
|
|
7
|
+
from orionis.services.environment.enums.value_type import EnvironmentValueType
|
|
9
8
|
from orionis.services.environment.validators.key_name import ValidateKeyName
|
|
10
9
|
from orionis.services.environment.validators.types import ValidateTypes
|
|
11
10
|
from orionis.support.patterns.singleton import Singleton
|
|
12
|
-
from orionis.services.environment.
|
|
13
|
-
from orionis.services.environment.dynamic.types import EnvTypes
|
|
11
|
+
from orionis.services.environment.dynamic.caster import EnvironmentCaster
|
|
14
12
|
|
|
15
13
|
class DotEnv(metaclass=Singleton):
|
|
16
14
|
|
|
17
15
|
# Thread-safe singleton instance lock
|
|
18
16
|
_lock = threading.RLock()
|
|
19
17
|
|
|
20
|
-
def __init__(
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
path: str = None
|
|
21
|
+
) -> None:
|
|
21
22
|
"""
|
|
22
|
-
Initialize the DotEnv service
|
|
23
|
+
Initialize the DotEnv service and prepare the `.env` file for environment variable management.
|
|
23
24
|
|
|
24
|
-
This
|
|
25
|
-
and loads
|
|
25
|
+
This constructor determines the location of the `.env` file, ensures its existence,
|
|
26
|
+
and loads its contents into the current process environment. If a custom path is provided,
|
|
27
|
+
it is resolved and used; otherwise, a `.env` file in the current working directory is used.
|
|
26
28
|
|
|
27
29
|
Parameters
|
|
28
30
|
----------
|
|
29
31
|
path : str, optional
|
|
30
|
-
The path to the `.env` file. If not
|
|
32
|
+
The path to the `.env` file. If not specified, defaults to a `.env` file
|
|
31
33
|
in the current working directory.
|
|
32
34
|
|
|
33
35
|
Returns
|
|
@@ -42,19 +44,19 @@ class DotEnv(metaclass=Singleton):
|
|
|
42
44
|
|
|
43
45
|
Notes
|
|
44
46
|
-----
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
+
- Ensures thread safety during initialization.
|
|
48
|
+
- If the specified `.env` file does not exist, it is created automatically.
|
|
49
|
+
- Loads environment variables from the `.env` file into the process environment.
|
|
47
50
|
"""
|
|
48
|
-
|
|
49
51
|
try:
|
|
50
52
|
|
|
51
|
-
#
|
|
53
|
+
# Ensure thread-safe initialization
|
|
52
54
|
with self._lock:
|
|
53
55
|
|
|
54
|
-
#
|
|
56
|
+
# Set default .env file path to current working directory
|
|
55
57
|
self.__resolved_path = Path(os.getcwd()) / ".env"
|
|
56
58
|
|
|
57
|
-
# If a path is provided, resolve it
|
|
59
|
+
# If a custom path is provided, resolve and use it
|
|
58
60
|
if path:
|
|
59
61
|
self.__resolved_path = Path(path).expanduser().resolve()
|
|
60
62
|
|
|
@@ -70,105 +72,67 @@ class DotEnv(metaclass=Singleton):
|
|
|
70
72
|
# Raise an error if the .env file cannot be created or accessed
|
|
71
73
|
raise OSError(f"Failed to create or access the .env file at {self.__resolved_path}: {e}")
|
|
72
74
|
|
|
73
|
-
def
|
|
75
|
+
def set(
|
|
76
|
+
self,
|
|
77
|
+
key: str,
|
|
78
|
+
value: Union[str, int, float, bool, list, dict, tuple, set],
|
|
79
|
+
type_hint: str | EnvironmentValueType = None
|
|
80
|
+
) -> bool:
|
|
74
81
|
"""
|
|
75
|
-
|
|
82
|
+
Set an environment variable in both the `.env` file and the current process environment.
|
|
83
|
+
|
|
84
|
+
This method serializes the provided value (optionally using a type hint), validates the key,
|
|
85
|
+
and updates the corresponding entry in the `.env` file as well as the process's environment
|
|
86
|
+
variables. Thread safety is ensured during the operation.
|
|
76
87
|
|
|
77
88
|
Parameters
|
|
78
89
|
----------
|
|
79
|
-
|
|
80
|
-
The
|
|
90
|
+
key : str
|
|
91
|
+
The name of the environment variable to set. Must be a valid environment variable name.
|
|
92
|
+
value : Union[str, int, float, bool, list, dict, tuple, set]
|
|
93
|
+
The value to assign to the environment variable. Supported types include string, integer,
|
|
94
|
+
float, boolean, list, dictionary, tuple, and set.
|
|
95
|
+
type_hint : str or EnvironmentValueType, optional
|
|
96
|
+
An explicit type hint to guide serialization. If provided, the value is serialized
|
|
97
|
+
according to the specified type.
|
|
81
98
|
|
|
82
99
|
Returns
|
|
83
100
|
-------
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
- Returns a boolean for 'true'/'false' strings (case-insensitive) or 1/0.
|
|
88
|
-
- Returns an int if the string represents an integer.
|
|
89
|
-
- Returns a float if the string represents a float.
|
|
90
|
-
- Attempts to evaluate the string as a Python literal (e.g., list, dict, tuple).
|
|
91
|
-
- Handles type hints via 'type:' prefix (e.g., 'int:42', 'bool:true').
|
|
92
|
-
- Returns the original string if no conversion is possible.
|
|
101
|
+
bool
|
|
102
|
+
Returns True if the environment variable was successfully set in both the `.env` file
|
|
103
|
+
and the current process environment.
|
|
93
104
|
|
|
94
105
|
Raises
|
|
95
106
|
------
|
|
96
|
-
|
|
97
|
-
If
|
|
98
|
-
"""
|
|
99
|
-
# Early return for None
|
|
100
|
-
if value is None:
|
|
101
|
-
return None
|
|
102
|
-
|
|
103
|
-
# Return immediately if already a basic type
|
|
104
|
-
if isinstance(value, (bool, int, float, dict, list, tuple, set)):
|
|
105
|
-
return value
|
|
106
|
-
|
|
107
|
-
# Convert to string and clean
|
|
108
|
-
value_str = str(value).strip()
|
|
109
|
-
|
|
110
|
-
# Handle empty strings and common null representations
|
|
111
|
-
# This includes 'none', 'null', 'nan', 'nil' (case-insensitive)
|
|
112
|
-
if not value_str or value_str.lower() in {'none', 'null', 'nan', 'nil'}:
|
|
113
|
-
return None
|
|
114
|
-
|
|
115
|
-
# Boolean detection (without type hint)
|
|
116
|
-
lower_val = value_str.lower()
|
|
117
|
-
if lower_val in ('true', 'false', 'yes', 'no', 'on', 'off', '1', '0'):
|
|
118
|
-
return lower_val in ('true', 'yes', 'on', '1')
|
|
119
|
-
|
|
120
|
-
# Handle type hints using the Type class
|
|
121
|
-
hints = EnvTypes(value_str)
|
|
122
|
-
if hints.hasValidTypeHint():
|
|
123
|
-
return hints.get()
|
|
124
|
-
|
|
125
|
-
# Try parseing to literal types, if failed, return the original value
|
|
126
|
-
try:
|
|
127
|
-
return ast.literal_eval(value_str)
|
|
128
|
-
except (ValueError, SyntaxError):
|
|
129
|
-
return value_str
|
|
130
|
-
|
|
131
|
-
def __serializeValue(self, value: Any, type_hint: str = None) -> str:
|
|
132
|
-
"""
|
|
133
|
-
Parameters
|
|
134
|
-
----------
|
|
135
|
-
value : Any
|
|
136
|
-
The value to serialize.
|
|
137
|
-
type_hint : str, optional
|
|
138
|
-
An optional type hint to guide serialization.
|
|
139
|
-
Returns
|
|
140
|
-
-------
|
|
141
|
-
str
|
|
142
|
-
The serialized string representation of the value.
|
|
143
|
-
Notes
|
|
144
|
-
-----
|
|
145
|
-
- If `value` is None, returns "null".
|
|
146
|
-
- If `type_hint` is provided, uses `EnvTypes` to serialize.
|
|
147
|
-
- Uses `repr()` for lists, dicts, tuples, and sets.
|
|
148
|
-
- Falls back to `str()` for other types.
|
|
107
|
+
OrionisEnvironmentValueError
|
|
108
|
+
If the provided key is not a valid environment variable name.
|
|
149
109
|
"""
|
|
110
|
+
with self._lock:
|
|
111
|
+
# Validate the environment variable key name.
|
|
112
|
+
__key = ValidateKeyName(key)
|
|
150
113
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return value.strip()
|
|
159
|
-
|
|
160
|
-
if isinstance(value, bool):
|
|
161
|
-
return str(value).lower()
|
|
114
|
+
# If a type hint is provided, validate and serialize the value accordingly.
|
|
115
|
+
if type_hint is not None:
|
|
116
|
+
__type = ValidateTypes(value, type_hint)
|
|
117
|
+
__value = self.__serializeValue(value, __type)
|
|
118
|
+
else:
|
|
119
|
+
# Serialize the value without a type hint.
|
|
120
|
+
__value = self.__serializeValue(value)
|
|
162
121
|
|
|
163
|
-
|
|
164
|
-
|
|
122
|
+
# Set the environment variable in the .env file.
|
|
123
|
+
set_key(self.__resolved_path, __key, __value)
|
|
165
124
|
|
|
166
|
-
|
|
167
|
-
|
|
125
|
+
# Update the environment variable in the current process environment.
|
|
126
|
+
os.environ[__key] = __value
|
|
168
127
|
|
|
169
|
-
|
|
128
|
+
# Indicate successful operation.
|
|
129
|
+
return True
|
|
170
130
|
|
|
171
|
-
def get(
|
|
131
|
+
def get(
|
|
132
|
+
self,
|
|
133
|
+
key: str,
|
|
134
|
+
default: Optional[Any] = None
|
|
135
|
+
) -> Any:
|
|
172
136
|
"""
|
|
173
137
|
Get the value of an environment variable.
|
|
174
138
|
|
|
@@ -192,89 +156,213 @@ class DotEnv(metaclass=Singleton):
|
|
|
192
156
|
with self._lock:
|
|
193
157
|
|
|
194
158
|
# Ensure the key is a string.
|
|
195
|
-
|
|
196
|
-
raise OrionisEnvironmentValueError(
|
|
197
|
-
f"Key must be a string, got {type(key).__name__}."
|
|
198
|
-
)
|
|
159
|
+
__key = ValidateKeyName(key)
|
|
199
160
|
|
|
200
161
|
# Get the value from the .env file or the current environment.
|
|
201
|
-
value = dotenv_values(self.__resolved_path).get(
|
|
162
|
+
value = dotenv_values(self.__resolved_path).get(__key)
|
|
202
163
|
|
|
203
164
|
# If the value is not found in the .env file, check the current environment variables.
|
|
204
165
|
if value is None:
|
|
205
|
-
value = os.getenv(
|
|
166
|
+
value = os.getenv(__key)
|
|
206
167
|
|
|
207
168
|
# Parse the value using the internal __parseValue method and return it
|
|
208
169
|
return self.__parseValue(value) if value is not None else default
|
|
209
170
|
|
|
210
|
-
def
|
|
171
|
+
def unset(self, key: str) -> bool:
|
|
211
172
|
"""
|
|
212
|
-
|
|
173
|
+
Remove an environment variable from both the `.env` file and the current process environment.
|
|
213
174
|
|
|
214
|
-
|
|
175
|
+
This method deletes the specified environment variable from the resolved `.env` file
|
|
176
|
+
and removes it from the current process's environment variables. The operation is
|
|
177
|
+
performed in a thread-safe manner. The key is validated before removal.
|
|
215
178
|
|
|
216
179
|
Parameters
|
|
217
180
|
----------
|
|
218
181
|
key : str
|
|
219
|
-
The name of the environment variable to
|
|
220
|
-
value : Union[str, int, float, bool, list, dict]
|
|
221
|
-
The value to assign to the environment variable. Supported types include string, integer, float, boolean, list, and dictionary.
|
|
222
|
-
type_hint : str, optional
|
|
223
|
-
The type of the value being set. If provided, it can be (path, str, int, float, bool, list, dict, tuple, set).
|
|
182
|
+
The name of the environment variable to remove. Must be a valid environment variable name.
|
|
224
183
|
|
|
225
184
|
Returns
|
|
226
185
|
-------
|
|
227
186
|
bool
|
|
228
|
-
True if the environment variable was successfully
|
|
187
|
+
Returns True if the environment variable was successfully removed from both the `.env` file
|
|
188
|
+
and the process environment. Returns True even if the variable does not exist.
|
|
189
|
+
|
|
190
|
+
Raises
|
|
191
|
+
------
|
|
192
|
+
OrionisEnvironmentValueError
|
|
193
|
+
If the provided key is not a valid environment variable name.
|
|
194
|
+
|
|
195
|
+
Notes
|
|
196
|
+
-----
|
|
197
|
+
- The method is thread-safe.
|
|
198
|
+
- If the environment variable does not exist, the method has no effect and returns True.
|
|
229
199
|
"""
|
|
230
200
|
with self._lock:
|
|
231
201
|
|
|
232
|
-
#
|
|
233
|
-
|
|
234
|
-
type = ValidateTypes(value, type_hint)
|
|
202
|
+
# Validate the environment variable key name.
|
|
203
|
+
validated_key = ValidateKeyName(key)
|
|
235
204
|
|
|
205
|
+
# Remove the key from the .env file.
|
|
206
|
+
unset_key(self.__resolved_path, validated_key)
|
|
236
207
|
|
|
208
|
+
# Remove the key from the current process environment, if present.
|
|
209
|
+
os.environ.pop(validated_key, None)
|
|
237
210
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
serialized_value = self.__serializeValue(value, type_hint)
|
|
211
|
+
# Indicate successful operation.
|
|
212
|
+
return True
|
|
241
213
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
214
|
+
def all(self) -> dict:
|
|
215
|
+
"""
|
|
216
|
+
Retrieve all environment variables from the resolved `.env` file as a dictionary.
|
|
245
217
|
|
|
246
|
-
|
|
247
|
-
|
|
218
|
+
This method reads all key-value pairs from the currently resolved `.env` file and
|
|
219
|
+
parses each value into its appropriate Python type using the internal `__parseValue`
|
|
220
|
+
method. The returned dictionary contains environment variable names as keys and their
|
|
221
|
+
parsed values as values.
|
|
248
222
|
|
|
249
|
-
|
|
223
|
+
Returns
|
|
224
|
+
-------
|
|
225
|
+
dict
|
|
226
|
+
A dictionary where each key is an environment variable name (str) and each value
|
|
227
|
+
is the parsed Python representation of the variable as determined by `__parseValue`.
|
|
228
|
+
If the `.env` file is empty, an empty dictionary is returned.
|
|
229
|
+
|
|
230
|
+
Notes
|
|
231
|
+
-----
|
|
232
|
+
- Thread safety is ensured during the read operation.
|
|
233
|
+
- Only variables present in the `.env` file are returned; variables set only in the
|
|
234
|
+
process environment are not included.
|
|
235
|
+
"""
|
|
236
|
+
with self._lock:
|
|
237
|
+
|
|
238
|
+
# Read all raw key-value pairs from the .env file
|
|
239
|
+
raw_values = dotenv_values(self.__resolved_path)
|
|
240
|
+
|
|
241
|
+
# Parse each value and return as a dictionary
|
|
242
|
+
return {k: self.__parseValue(v) for k, v in raw_values.items()}
|
|
243
|
+
|
|
244
|
+
def __serializeValue(
|
|
245
|
+
self,
|
|
246
|
+
value: Any,
|
|
247
|
+
type_hint: str | EnvironmentValueType = None
|
|
248
|
+
) -> str:
|
|
250
249
|
"""
|
|
251
|
-
|
|
250
|
+
Serialize a Python value into a string suitable for storage in a .env file.
|
|
251
|
+
|
|
252
|
+
This method converts the provided value into a string representation that can be
|
|
253
|
+
safely written to a .env file. If a type hint is provided, the value is serialized
|
|
254
|
+
according to the specified type using the EnvTypes utility. Otherwise, the method
|
|
255
|
+
infers the serialization strategy based on the value's type.
|
|
252
256
|
|
|
253
257
|
Parameters
|
|
254
258
|
----------
|
|
255
|
-
|
|
256
|
-
The
|
|
259
|
+
value : Any
|
|
260
|
+
The value to serialize. Supported types include None, str, int, float, bool,
|
|
261
|
+
list, dict, tuple, and set.
|
|
262
|
+
type_hint : str or EnvironmentValueType, optional
|
|
263
|
+
An explicit type hint to guide serialization. If provided, the value is
|
|
264
|
+
serialized using EnvTypes.
|
|
257
265
|
|
|
258
266
|
Returns
|
|
259
267
|
-------
|
|
260
|
-
|
|
261
|
-
|
|
268
|
+
str
|
|
269
|
+
The serialized string representation of the input value, suitable for storage
|
|
270
|
+
in a .env file. Returns "null" for None values.
|
|
262
271
|
"""
|
|
263
|
-
with self._lock:
|
|
264
|
-
unset_key(str(self.__resolved_path), key)
|
|
265
|
-
os.environ.pop(key, None)
|
|
266
|
-
return True
|
|
267
272
|
|
|
268
|
-
|
|
273
|
+
# Handle None values explicitly
|
|
274
|
+
if value is None:
|
|
275
|
+
return "null"
|
|
276
|
+
|
|
277
|
+
# If a type hint is provided, use EnvTypes for serialization
|
|
278
|
+
if type_hint:
|
|
279
|
+
|
|
280
|
+
# Use EnvironmentCaster to handle type hints
|
|
281
|
+
return EnvironmentCaster(value).to(type_hint)
|
|
282
|
+
|
|
283
|
+
else:
|
|
284
|
+
|
|
285
|
+
# Serialize strings by stripping whitespace
|
|
286
|
+
if isinstance(value, str):
|
|
287
|
+
return value.strip()
|
|
288
|
+
|
|
289
|
+
# Serialize booleans as lowercase strings ("true" or "false")
|
|
290
|
+
if isinstance(value, bool):
|
|
291
|
+
return str(value).lower()
|
|
292
|
+
|
|
293
|
+
# Serialize integers and floats as strings
|
|
294
|
+
if isinstance(value, (int, float)):
|
|
295
|
+
return str(value)
|
|
296
|
+
|
|
297
|
+
# Serialize collections (list, dict, tuple, set) using repr
|
|
298
|
+
if isinstance(value, (list, dict, tuple, set)):
|
|
299
|
+
return repr(value)
|
|
300
|
+
|
|
301
|
+
# Fallback: convert any other type to string
|
|
302
|
+
return str(value)
|
|
303
|
+
|
|
304
|
+
def __parseValue(
|
|
305
|
+
self,
|
|
306
|
+
value: Any
|
|
307
|
+
) -> Any:
|
|
269
308
|
"""
|
|
270
|
-
|
|
309
|
+
Parse a string or raw value from the .env file into its appropriate Python type.
|
|
310
|
+
|
|
311
|
+
This method attempts to convert the input value, which may be a string or already a Python object,
|
|
312
|
+
into its most suitable Python type. It handles common representations of null, booleans, and
|
|
313
|
+
attempts to parse collections and literals. If parsing fails, the original string is returned.
|
|
314
|
+
|
|
315
|
+
Parameters
|
|
316
|
+
----------
|
|
317
|
+
value : Any
|
|
318
|
+
The value to parse, typically a string read from the .env file, but may also be a Python object.
|
|
271
319
|
|
|
272
320
|
Returns
|
|
273
321
|
-------
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
322
|
+
Any
|
|
323
|
+
The parsed Python value. Returns `None` for recognized null representations, a boolean for
|
|
324
|
+
"true"/"false" strings, a Python literal (list, dict, int, etc.) if possible, or the original
|
|
325
|
+
string if no conversion is possible.
|
|
326
|
+
|
|
327
|
+
Notes
|
|
328
|
+
-----
|
|
329
|
+
- Recognizes 'none', 'null', 'nan', 'nil' (case-insensitive) as null values.
|
|
330
|
+
- Attempts to use `EnvironmentCaster` for advanced type parsing.
|
|
331
|
+
- Falls back to `ast.literal_eval` for literal evaluation.
|
|
332
|
+
- Returns the original string if all parsing attempts fail.
|
|
277
333
|
"""
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
334
|
+
|
|
335
|
+
# Early return for None values
|
|
336
|
+
if value is None:
|
|
337
|
+
return None
|
|
338
|
+
|
|
339
|
+
# Return immediately if already a basic Python type
|
|
340
|
+
if isinstance(value, (bool, int, float, dict, list, tuple, set)):
|
|
341
|
+
return value
|
|
342
|
+
|
|
343
|
+
# Convert the value to string for further processing
|
|
344
|
+
value_str = str(value)
|
|
345
|
+
|
|
346
|
+
# Handle empty strings and common null representations
|
|
347
|
+
# This includes 'none', 'null', 'nan', 'nil' (case-insensitive)
|
|
348
|
+
if not value_str or value_str.lower().strip() in {'none', 'null', 'nan', 'nil'}:
|
|
349
|
+
return None
|
|
350
|
+
|
|
351
|
+
# Boolean detection for string values (case-insensitive)
|
|
352
|
+
lower_val = value_str.lower().strip()
|
|
353
|
+
if lower_val in ('true', 'false'):
|
|
354
|
+
return lower_val == 'true'
|
|
355
|
+
|
|
356
|
+
# Attempt to parse using EnvironmentCaster for advanced types
|
|
357
|
+
# Try to detect if the value string starts with a known EnvironmentValueType prefix
|
|
358
|
+
env_type_prefixes = {str(e.value) for e in EnvironmentValueType}
|
|
359
|
+
if any(value_str.startswith(prefix) for prefix in env_type_prefixes):
|
|
360
|
+
return EnvironmentCaster(value_str).get()
|
|
361
|
+
|
|
362
|
+
# Attempt to parse using ast.literal_eval for Python literals
|
|
363
|
+
try:
|
|
364
|
+
return ast.literal_eval(value_str)
|
|
365
|
+
|
|
366
|
+
# Return the original string if parsing fails
|
|
367
|
+
except (ValueError, SyntaxError):
|
|
368
|
+
return value_str
|