Environment Module

Core Feature

The Environment module is the heart of True Storage, providing powerful environment management with mode support, runtime configuration, and advanced stage management capabilities.

Overview

The Environment module offers a robust solution for managing configuration across different environments (development, testing, production) with features like:

  • Mode-Based Configuration: Switch between different environments seamlessly

  • Runtime Configuration: Change settings dynamically during execution

  • Stage Management: Define and manage custom stages beyond traditional environments

  • Decorator Support: Control function execution based on environment modes

  • State Management: Create and restore configuration snapshots

  • Type Safety: Validate configuration values with type checking

Key Components

Environment Class

class true_storage.env.Environment(env_data='.env', validator=None, parent=None, interpolate=True, mode=<MODES.DEV: dev>, *extenal_envs)[source]

Bases: object

Advanced environment configuration and management system.

This class provides a comprehensive environment variable management system with features like mode-specific variables, secure storage, and variable validation.

Variables:
  • _mode (MODES) – Current environment mode.

  • _instance (Environment) – Singleton instance of the environment.

  • _lock (threading.Lock) – Thread lock for singleton pattern.

  • _mode_vars (Dict[MODES, Set[str]]) – Mode-specific variable tracking.

  • _secure_mode_mappings (Dict[str, Set[MODES]]) – Secure storage of mode mappings.

Parameters:
  • env_data (EnvPath, optional) – Source of environment data. Defaults to “.env”.

  • validator (EnvValidatorProtocol, optional) – Validator for environment variables.

  • parent (Environment, optional) – Parent environment for inheritance.

  • interpolate (bool, optional) – Enable variable interpolation. Defaults to True.

static __new__(cls, *args, **kwargs)[source]

Implement thread-safe singleton pattern.

__init__(env_data='.env', validator=None, parent=None, interpolate=True, mode=<MODES.DEV: dev>, *extenal_envs)[source]
property envpath
property externalenvs
property mode_mappings: Dict[str, Set[MODES]]

Get a secure copy of the mode-to-variable mappings.

Returns:

A mapping of variable names to their allowed modes.

Return type:

Dict[str, Set[MODES]]

property variables: Dict[str, str]

Get all environment variables.

property secrets: Dict[str, str]

Get all secret environment variables.

property non_secrets: Dict[str, str]

Get all non-secret environment variables.

property mode: MODES

Get current environment mode.

property parent: Environment | None

Get parent environment.

property snapshots: List[EnvSnapshot]

Get list of environment snapshots.

property mode_variables: Dict[str, str]

Get all variables specific to the current mode.

Returns:

Dictionary of mode-specific variables.

Return type:

Dict[str, str]

_interpolate_value(value)[source]

Interpolate environment variables in value.

Return type:

str

load_env()[source]

Load environment variables with inheritance and interpolation.

Return type:

None

mark(mode)[source]

Decorator for mode-specific function execution.

Parameters:

mode (MODES) – Mode to execute the function in.

Returns:

Decorated function that executes in specified mode.

Return type:

Callable

Example

>>> env = Environment()
>>> @env.mark(MODES.TEST)
... def test_function():
...     return env.get('TEST_CONFIG')  # Only accessible in test mode
with_mode(mode)[source]

Context manager for temporary mode switching.

Parameters:

mode (MODES) – Mode to temporarily switch to.

Yields:

Environment – Self with temporarily changed mode.

Return type:

ModeContext

Example

>>> env = Environment()
>>> with env.with_mode(MODES.PROD):
...     secret = env.get('API_KEY')  # Access production-only variable
_is_mode_var(key, mode=None)[source]

Check if a variable belongs to a specific mode.

Return type:

bool

mark_as_mode_var(key, mode)[source]

Mark a variable as belonging to a specific mode.

Return type:

None

_get_mode_key(key, mode=None)[source]

Generate a mode-specific key for an environment variable.

Parameters:
  • key (str) – Base variable name.

  • mode (MODES, optional) – Mode to generate key for. Defaults to current mode.

Returns:

Mode-specific variable key.

Return type:

str

static _get_base_key(key)[source]

Extract the base key from a mode-specific key.

Parameters:

key (str) – Mode-specific variable key.

Returns:

Base variable name without mode prefix/suffix.

Return type:

str

is_allowed_in_mode(key, mode)[source]

Check if a variable is allowed in a specific mode.

Parameters:
  • key (str) – The variable name to check.

  • mode (MODES) – The mode to check against.

Returns:

True if the variable is accessible in the specified mode, False otherwise.

Return type:

bool

static create_snapshot()[source]

Create a snapshot of the current environment state.

Returns:

Snapshot containing current variable values.

Return type:

EnvSnapshot

Example

>>> env = Environment()
>>> snapshot = env.create_snapshot()
>>> env.set({'DEBUG': 'false'})
>>> env.rollback(snapshot)  # Restore previous state
static rollback(snapshot)[source]

Rollback environment to a previous snapshot.

Parameters:

snapshot (EnvSnapshot) – Snapshot to restore from.

Return type:

None

Example

>>> env = Environment()
>>> snapshot = env.create_snapshot()
>>> env.set({'DEBUG': 'false'})
>>> env.rollback(snapshot)  # Restore DEBUG to previous value
get(key, default=None, mode=None)[source]

Retrieve an environment variable with mode support.

Parameters:
  • key (str) – The variable name to retrieve.

  • mode (MODES) – To specify a mode or it will go for current mode.

  • default (Any, optional) – Default value if variable not found. Defaults to None.

Returns:

The value of the environment variable.

Return type:

str

Raises:

ModeError – If the variable is not accessible in the current mode.

set(items, system_env=False, modes=None)[source]

Set environment variables with mode-specific access control.

Return type:

None

_validate_and_set_value(key, value, system_env, modes)[source]

Validate and set a single environment variable.

Return type:

None

_validate_value(key, value)[source]

Validate the value if a validator is present.

Return type:

Any

_set_value_in_environments(key, value, system_env, modes)[source]

Set the value in appropriate environments based on modes.

Return type:

None

_track_mode_variables(key, modes)[source]

Track variables for each mode.

Return type:

None

delete(key, modes=None)[source]

Delete an environment variable from specified modes.

Parameters:
  • key (str) – The variable name to delete.

  • modes (List[MODES], optional) – List of modes to delete from. If None, deletes from all modes.

Return type:

None

Example

>>> env = Environment()
>>> env.delete('DEBUG', modes=[MODES.PROD])  # Remove from production only
>>> env.delete('API_KEY')  # Remove from all modes
static _normalize_modes(modes)[source]

Normalize the modes list to handle None case.

Parameters:

modes (List[MODES], optional) – List of modes to normalize.

Returns:

All available modes if input is None, otherwise the input list.

Return type:

List[MODES]

_delete_from_env(key, modes)[source]

Delete the variable from specified modes in the environment.

Parameters:
  • key (str) – The variable name to delete.

  • modes (List[MODES]) – List of modes to delete from.

Return type:

None

_delete_common_variable(key)[source]

Delete a common (non-mode-specific) variable.

Parameters:

key (str) – The variable name to delete.

Return type:

None

_delete_mode_specific_variable(key, mode)[source]

Delete a mode-specific variable.

Parameters:
  • key (str) – The variable name to delete.

  • mode (MODES) – The mode to delete from.

Return type:

None

_update_secure_mappings(key, modes)[source]

Update the secure mode mappings after variable deletion.

Parameters:
  • key (str) – The variable name that was deleted.

  • modes (List[MODES]) – The modes it was deleted from.

Return type:

None

__str__()[source]

Get string representation of environment state.

Return type:

str

__repr__()[source]

Get detailed string representation for debugging.

Return type:

str

format_debug(batch_size=10)[source]

Format environment data for debugging in batches.

Return type:

str

_format_basic_info()[source]

Format basic environment information.

Return type:

str

_format_variables_by_mode(batch_size)[source]

Format variables for each mode.

Return type:

str

_format_secrets(batch_size)[source]

Format secret variables.

Return type:

str

_format_mode_mappings()[source]

Format mode mappings.

Return type:

str

_format_snapshots()[source]

Format snapshots information.

Return type:

str

_format_batch(title, items, batch_size, start=0)[source]

Format a batch of items with a title.

Return type:

str

__getitem__(key)[source]

Get environment variable using dictionary-style access with mode support.

Return type:

str

__setitem__(key, value)[source]

Set environment variable using dictionary-style access with mode support.

Return type:

None

__delitem__(key)[source]

Delete environment variable using dictionary-style access with mode support.

Return type:

None

__contains__(key)[source]

Check if environment variable exists using ‘in’ operator with mode support.

Return type:

bool

__iter__()[source]

Iterate over environment variables.

__len__()[source]

Get number of unique base environment variables.

Return type:

int

filter(search_value, search_in='key', exclude_secrets=True, mode_specific=True)[source]

Filter environment variables with mode and secret support.

Return type:

Dict[str, str]

filter_with_predicate(predicate, exclude_secrets=True, mode_specific=True)[source]

Filter environment variables with a predicate function.

Return type:

Dict[str, str]

classmethod from_json(json_path, **kwargs)[source]

Create an Environment instance from a JSON file.

Return type:

Environment

classmethod from_dict(env_dict, **kwargs)[source]

Create an Environment instance from a dictionary.

Return type:

Environment

classmethod from_config(config_path, **kwargs)[source]

Create an Environment instance from a configuration file.

Return type:

Environment

validate_external_envs(extenal_envs)[source]
write_env(env_path=None, flush=False)[source]

Write environment variables to a file, organized by mode.

This method writes the current environment variables to a file, organizing them by mode. It determines the output path, organizes the variables, formats them into sections, and then writes them to the specified file.

Notes

If env_path is None it will override the existing env file!

Parameters:
  • env_path (Optional[str]) – The path to write the environment file. If None, a default path will be used.

  • flush (bool) – If True, flush the file buffer immediately after writing.

Return type:

None

Returns:

None

Raises:
  • IOError – If there’s an error writing to the file.

  • OSError – if os’s (system) error

Modes

class true_storage.env.MODES(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: str, Enum

Environment modes for configuration management.

This enum defines different operational modes for environment variable management, each with specific behaviors and access patterns.

Variables:
  • ALL (str) – Special mode for variables accessible across all modes.

  • DEV (str) – Development mode for local development environment.

  • TEST (str) – Testing mode for test environment.

  • STAGE (str) – Staging mode for pre-production environment.

  • PROD (str) – Production mode for live environment.

ALL = 'all'
DEV = 'dev'
TEST = 'test'
STAGE = 'stage'
PROD = 'prod'
__init__(value)[source]
classmethod _generate_next_value_(name, start, count, last_values)[source]

Generate the next value for enum members.

property is_development: bool

Check if the current mode is a development mode.

property is_production: bool

Check if the current mode is production mode.

property is_all: bool

Check if the current mode is ALL mode.

property prefix: str

Get the prefix for environment variables in this mode.

property suffix: str

Get the suffix for environment variables in this mode.

classmethod with_stages(**new_stages)[source]

Create a new MODES enum with additional custom stages.

Parameters:

**new_stages (str) – Keyword arguments of new stage names and their values

Return type:

Type[Enum]

Returns:

A new MODES enum class with additional stages

Raises:

ValueError – If a stage name conflicts with existing stages

classmethod get_stage(name)[source]

Get a stage by name.

Parameters:

name (str) – Name of the stage to get

Return type:

MODES

Returns:

Either a MODES enum member or a CustomStage instance

Raises:

ValueError – If stage doesn’t exist

Usage Examples

Basic Usage

# Initialize environment with mode
env = Environment(mode=MODES.DEV)

# Set environment variables
env.set("DATABASE_URL", "postgresql://localhost:5432/db", modes=[MODES.DEV])
env.set("DATABASE_URL", "postgresql://prod:5432/db", modes=[MODES.PROD])

# Get current environment variable
db_url = env.get("DATABASE_URL")  # Returns dev URL in DEV mode

Mode Switching

# Using context manager
with env.with_mode(MODES.PROD):
    prod_url = env.get("DATABASE_URL")  # Gets production URL

# Using mode property
env.mode = MODES.TEST
test_config = env.get("TEST_CONFIG")

# Using decorators
@env.mark(MODES.PROD)
def production_task():
    # Only runs in production mode
    pass

Advanced Features

# Create configuration snapshot
snapshot = env.create_snapshot()

# Make temporary changes
env.set("TEMP_VAR", "temporary")

# Restore previous state
env.rollback(snapshot)

# Custom stages
env.with_stage(STAGING="staging", QA="qa")
@env.mark(MODES.STAGING)
def staging_task():
    pass

Best Practices

  1. Mode Management: - Always set a default mode during initialization - Use context managers for temporary mode switches - Avoid global mode changes in library code

  2. Variable Handling: - Use type hints for better validation - Set defaults for optional variables - Group related variables by mode

  3. State Management: - Create snapshots before major changes - Use rollback for testing and cleanup - Maintain separate configurations per mode

  4. Security: - Never store sensitive data in code - Use separate files for different environments - Implement proper access controls

See Also