Environment Variables
Orionis provides a comprehensive environment variable management system that goes far beyond simple string reading. While most frameworks are limited to reading .env values as raw strings, Orionis incorporates type hints, dynamic casting, bidirectional serialization, and strict key validation, turning environment variables into first-class citizens of the Python type system.
Module Architecture
Section titled “Module Architecture”The environment module is composed of several collaborating layers:
| Component | Responsibility |
|---|---|
Env | High-level static facade — main entry point |
DotEnv | Singleton engine that reads, writes, and manages the .env file |
EnvironmentCaster | Dynamic casting engine with 10 supported types |
ValidateKeyName | Key name validator (^[A-Z][A-Z0-9_]*$) |
ValidateTypes | Type hint validator and inferrer |
EnvironmentValueType | Enum with the 10 supported types |
SecureKeyGenerator | Cryptographic key generator compatible with APP_KEY |
env() | Global helper function for quick access |
The Env Facade
Section titled “The Env Facade”The Env class is the main entry point for interacting with environment variables. All its methods are @classmethod, so no instantiation is required.
from orionis.services.environment.env import EnvInternally, Env delegates all operations to a singleton instance of DotEnv, created automatically on the first call.
Contract
Section titled “Contract”Env implements the abstract contract IEnv, which defines the public interface:
from orionis.services.environment.contracts.env import IEnv| Method | Signature | Return |
|---|---|---|
get | (key, default=None) | object |
set | (key, value, type_hint=None, *, only_os=False) | bool |
unset | (key, *, only_os=False) | bool |
all | () | dict[str, Any] |
reload | () | bool |
Reading Variables
Section titled “Reading Variables”The get Method
Section titled “The get Method”Retrieves the value of an environment variable. If the key exists, the value is automatically parsed to the corresponding Python type. If not, it returns the default value.
# simple readdb_host = Env.get("DB_HOST")
# with default valuedb_port = Env.get("DB_PORT", 5432)Automatic Value Parsing
Section titled “Automatic Value Parsing”Unlike other frameworks where get() always returns a str, Orionis detects and converts stored values automatically:
Value in .env | Python Type Returned |
|---|---|
true / false | bool |
null, none, nan, nil | None |
42 | int |
3.14 | float |
[1, 2, 3] | list |
{'key': 'val'} | dict |
(1, 2) | tuple |
{1, 2, 3} | set |
int:42 | int (via type hint) |
base64:SGVsbG8= | str (decoded) |
path:/usr/local | str (POSIX path) |
Hello World | str |
The parsing engine follows this resolution sequence:
- If the value is
None, returnsNone - If it is already a basic Python type (
bool,int,float, etc.), returns it directly - If it is an empty string or matches
null,none,nan, ornil, returnsNone - If it is
trueorfalse(case-insensitive), returnsbool - If it starts with a supported type prefix (e.g.,
int:,list:), delegates toEnvironmentCaster - Attempts evaluation with
ast.literal_evalfor Python literals - If all else fails, returns the original string
Writing Variables
Section titled “Writing Variables”The set Method
Section titled “The set Method”Sets or updates an environment variable. By default, it writes to both the .env file and os.environ.
# simple writeEnv.set("APP_NAME", "Orionis")
# with explicit type hintEnv.set("APP_PORT", "8000", type_hint="int")
# process memory only (not persisted to .env)Env.set("TEMP_TOKEN", "abc123", only_os=True)Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
key | str | Variable name (must match ^[A-Z][A-Z0-9_]*$) |
value | str | float | bool | list | dict | tuple | set | Value to assign |
type_hint | str | EnvironmentValueType | None | Explicit type for serialization |
only_os | bool | If True, only sets in os.environ |
Value Serialization
Section titled “Value Serialization”When writing a value, the engine serializes it automatically:
| Python Type | Representation in .env |
|---|---|
None | null |
bool | true / false |
int / float | String representation ("42", "3.14") |
list / dict / tuple / set | repr() representation |
str | Text with whitespace trimmed |
When a type_hint is provided, the value is stored with a type prefix:
Env.set("PORT", 8080, type_hint="int")# In .env: PORT="int:8080"
Env.set("HOSTS", ["a", "b"], type_hint="list")# In .env: HOSTS="list:['a', 'b']"Removing Variables
Section titled “Removing Variables”The unset Method
Section titled “The unset Method”Removes an environment variable from the .env file and from os.environ.
# complete removalEnv.unset("OLD_KEY")
# only remove from os.environ (keep in .env)Env.unset("CACHED_KEY", only_os=True)The operation always returns True, even if the key did not exist.
Querying and Reloading
Section titled “Querying and Reloading”The all Method
Section titled “The all Method”Returns all variables from the .env file as a dictionary with parsed values:
config = Env.all()# {'DB_HOST': 'localhost', 'DB_PORT': 5432, 'DEBUG': True}The reload Method
Section titled “The reload Method”Reloads variables from the .env file. Useful when the file has been modified externally:
Env.reload()Internally, it destroys the DotEnv singleton instance and creates a new one, ensuring a completely clean state.
Type Hints — The Type System
Section titled “Type Hints — The Type System”One of the most distinctive features of Orionis is the type hints system for environment variables. It allows storing and retrieving values with explicit types using the type:value format directly in the .env file.
Supported Types
Section titled “Supported Types”The EnvironmentValueType enum defines the 10 available types:
from orionis.services.environment.enums.value_type import EnvironmentValueType| Member | Value | Example in .env | Python Type |
|---|---|---|---|
STR | str | str:hello | str |
INT | int | int:42 | int |
FLOAT | float | float:3.14 | float |
BOOL | bool | bool:true | bool |
LIST | list | list:[1, 2, 3] | list |
DICT | dict | dict:{'a': 1} | dict |
TUPLE | tuple | tuple:(1, 2) | tuple |
SET | set | set:{1, 2, 3} | set |
BASE64 | base64 | base64:SGVsbG8= | str |
PATH | path | path:/usr/local/bin | str |
Writing with Type Hints
Section titled “Writing with Type Hints”from orionis.services.environment.enums.value_type import EnvironmentValueType
# using stringEnv.set("API_PORT", 3000, type_hint="int")
# using enumEnv.set("API_PORT", 3000, type_hint=EnvironmentValueType.INT)Reading with Type Hints
Section titled “Reading with Type Hints”When reading a variable that has a type prefix, the EnvironmentCaster converts it automatically:
# If in .env: API_PORT="int:3000"port = Env.get("API_PORT")print(type(port)) # <class 'int'>print(port) # 3000Bool Type Special Behavior
Section titled “Bool Type Special Behavior”The boolean caster recognizes multiple representations:
| Truthy | Falsy |
|---|---|
true | false |
1 | 0 |
yes | no |
on | off |
enabled | disabled |
Path Type Special Behavior
Section titled “Path Type Special Behavior”Paths are normalized to POSIX format and resolved as absolute:
Env.set("UPLOAD_DIR", "./uploads", type_hint="path")# Stores: path:/absolute/path/to/uploadsBase64 Type Special Behavior
Section titled “Base64 Type Special Behavior”If the value is already valid Base64, it is preserved. Otherwise, it is encoded automatically:
Env.set("SECRET", "my-secret", type_hint="base64")# Stores: base64:bXktc2VjcmV0Key Validation
Section titled “Key Validation”All environment variable keys are validated against the strict pattern ^[A-Z][A-Z0-9_]*$:
| Key | Valid | Reason |
|---|---|---|
DB_HOST | ✅ | Uppercase, underscores, correct |
VAR123 | ✅ | Digits after first letter |
A__B | ✅ | Multiple underscores allowed |
myVar | ❌ | Contains lowercase |
1VAR | ❌ | Starts with digit |
_VAR | ❌ | Starts with underscore |
MY-VAR | ❌ | Contains hyphen |
# TypeError if not a stringEnv.set(123, "value") # raises TypeError
# ValueError if pattern not matchedEnv.set("my_var", "value") # raises ValueErrorThe DotEnv Engine
Section titled “The DotEnv Engine”DotEnv is the internal layer that directly manages the .env file. It implements the Singleton pattern and is thread-safe via threading.RLock.
from orionis.services.environment.core.dot_env import DotEnvFeatures
Section titled “Features”- Singleton: A single shared instance across the entire application
- Thread-safe: All operations use
threading.RLock - Auto-creation: If the
.envfile does not exist, it is created automatically - Configurable path: Accepts a custom path in the constructor
- Dual persistence: Writes to both the
.envfile andos.environsimultaneously
Initialization
Section titled “Initialization”# uses .env in the current directory (default behavior)dotenv = DotEnv()
# custom pathdotenv = DotEnv(path="/config/.env.production")Secure Key Generator
Section titled “Secure Key Generator”The module includes SecureKeyGenerator for generating cryptographic keys compatible with the APP_KEY format (base64:<payload>):
from orionis.services.environment.key.key_generator import SecureKeyGeneratorSupported Ciphers
Section titled “Supported Ciphers”| Cipher | Key Size |
|---|---|
AES-128-CBC | 16 bytes |
AES-256-CBC | 32 bytes |
AES-128-GCM | 16 bytes |
AES-256-GCM | 32 bytes |
# default cipher: AES-256-CBCkey = SecureKeyGenerator.generate()# "base64:xK9m2..."
# specific cipher with stringkey = SecureKeyGenerator.generate("AES-128-GCM")
# specific cipher with enumfrom orionis.foundation.config.app.enums.ciphers import Cipherkey = SecureKeyGenerator.generate(Cipher.AES_256_GCM)Each call produces a cryptographically unique key generated with os.urandom().
The env() Helper Function
Section titled “The env() Helper Function”For quick access from anywhere in the application, Orionis provides the global env() function:
from orionis.services.environment.helpers.functions import env
# equivalent to Env.get("DB_HOST")host = env("DB_HOST")
# with default valueport = env("DB_PORT", 3306)The function simply delegates to Env.get(), accepting the same key and default parameters.
Integrated Example
Section titled “Integrated Example”from orionis.services.environment.env import Envfrom orionis.services.environment.helpers.functions import envfrom orionis.services.environment.key.key_generator import SecureKeyGenerator
# Generate and set an application keyapp_key = SecureKeyGenerator.generate()Env.set("APP_KEY", app_key, type_hint="base64")
# Configure variables with explicit typesEnv.set("APP_DEBUG", True, type_hint="bool")Env.set("APP_PORT", 8080, type_hint="int")Env.set("ALLOWED_HOSTS", ["localhost", "127.0.0.1"], type_hint="list")Env.set("DB_CONFIG", {"host": "localhost", "port": 5432}, type_hint="dict")
# Reads with automatic castingdebug = Env.get("APP_DEBUG") # bool: Trueport = Env.get("APP_PORT") # int: 8080hosts = env("ALLOWED_HOSTS") # list: ['localhost', '127.0.0.1']db = env("DB_CONFIG") # dict: {'host': 'localhost', 'port': 5432}
# Query all configurationall_vars = Env.all()
# Temporary variable in memory onlyEnv.set("REQUEST_ID", "abc-123", only_os=True)
# Reload after external changeEnv.reload()