### Install envresolve for Development Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/installation.md Sets up the envresolve project for development, including cloning the repository and installing development dependencies. It also includes commands to run tests and quality checks using nox. ```bash # Clone the repository git clone https://github.com/osoekawaitlab/envresolve.git cd envresolve # Install with development dependencies uv sync # Run tests nox -s tests # Run all quality checks nox -s check_all ``` -------------------------------- ### Install envresolve using pip Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/installation.md Installs the envresolve Python package from the Python Package Index (PyPI) using pip. This is the standard method for end-users. ```bash pip install envresolve ``` -------------------------------- ### Install envresolve using uv Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/installation.md Installs the envresolve Python package using the uv package installer. uv is known for its speed and efficiency in Python dependency management. ```bash uv pip install envresolve ``` -------------------------------- ### Install Dependencies with uv Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md Installs the project's dependencies using the uv package manager. This command should be run after cloning the repository and setting up the environment. ```bash uv sync ``` -------------------------------- ### Setup Live Azure Tests for envresolve Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md One-time setup steps for running live integration tests against Azure Key Vault. This involves configuring Terraform, applying resources, and sourcing a setup script to set environment variables. ```bash # 1. Configure terraform (requires Azure subscription and az login) cd infra/terraform cp terraform.tfvars.example terraform.tfvars # 2. Edit terraform.tfvars with your values: # - subscription_id, tenant_id, name_prefix # - test_principal_object_id (get your object ID: az ad signed-in-user show --query id -o tsv) # 3. Create resources terraform init terraform apply # 4. Return to project root and set environment variables (per shell session) cd ../.. source scripts/setup_live_tests.sh ``` -------------------------------- ### Clone and Setup envresolve Repository Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md Steps to clone the envresolve repository locally and set up the upstream remote for syncing with the main repository. This is a crucial first step for any contributor. ```bash git clone https://github.com/YOUR-USERNAME/envresolve.git cd envresolve git remote add upstream https://github.com/osoekawaitlab/envresolve.git ``` -------------------------------- ### Bash: Install envresolve with Azure Extra Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md This command installs the envresolve library with the necessary dependencies for Azure Key Vault integration. It's a one-time setup step required before using Azure-specific features like `register_azure_kv_provider`. Ensure you have pip installed. ```bash pip install envresolve[azure] ``` -------------------------------- ### Setup Development Environment with uv and nox Source: https://github.com/osoekawaitlab/envresolve/blob/main/README.md Sets up the development environment for the envresolve project. It involves installing `uv` for dependency management, cloning the repository, and installing project dependencies including development and Azure extras. ```bash # Install uv (if not already installed) pip install uv # Clone the repository git clone https://github.com/osoekawaitlab/envresolve.git cd envresolve # Install dependencies (including dev dependencies) uv pip install -e ".[azure]" --group=dev ``` -------------------------------- ### Install envresolve with Azure Key Vault Support Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/installation.md Installs the envresolve package with the 'azure' extra, enabling support for Azure Key Vault secrets. This requires installing additional dependencies: 'azure-identity' and 'azure-keyvault-secrets'. After installation, the Azure Key Vault provider must be registered. ```bash pip install envresolve[azure] ``` ```python import envresolve envresolve.register_azure_kv_provider() ``` -------------------------------- ### Bash Command to Copy Terraform Configuration Example Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/live-tests.md Copies an example Terraform variable file to a new file, which the user will then edit. This is a standard practice for configuring Terraform. ```bash cp terraform.tfvars.example terraform.tfvars ``` -------------------------------- ### Initialize and Apply Terraform Source: https://github.com/osoekawaitlab/envresolve/blob/main/infra/terraform/README.md Standard Terraform commands for initializing the project, planning the infrastructure changes, and applying them to create the Azure resources. Requires Terraform to be installed and Azure credentials to be configured. ```bash terraform init terraform plan terraform apply ``` -------------------------------- ### Bash Commands for Terraform Initialization and Application Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/live-tests.md Initializes the Terraform working directory and applies the configuration to provision Azure resources. Requires Terraform to be installed and configured. ```bash terraform init terraform apply ``` -------------------------------- ### Build and Serve Project Documentation with nox Source: https://github.com/osoekawaitlab/envresolve/blob/main/README.md Builds the project documentation using `nox` and optionally serves it locally for live preview. The `docs_build` command generates the documentation, while `docs_serve` builds and starts a local web server, typically at http://localhost:8000. ```bash # Build documentation nox -s docs_build # Serve documentation locally (with live reload) nox -s docs_serve # Open http://localhost:8000 ``` -------------------------------- ### Install envresolve Package Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/index.md Provides commands for installing the envresolve Python package. The basic installation includes only variable expansion, while the '[azure]' extra installs support for Azure Key Vault integration. ```bash # Basic installation (variable expansion only) pip install envresolve # With Azure Key Vault support pip install envresolve[azure] ``` -------------------------------- ### Install envresolve Package Source: https://github.com/osoekawaitlab/envresolve/blob/main/README.md Installs the envresolve Python package using pip. Supports basic installation for variable expansion only, or with optional Azure Key Vault support by including the `[azure]` extra. ```bash pip install envresolve pip install envresolve[azure] ``` -------------------------------- ### Run All envresolve Tests with Nox Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md Executes all tests for the envresolve project using the nox automation tool. This is a primary step to verify setup and ensure changes do not break existing functionality. ```bash nox -s tests ``` -------------------------------- ### Python: Loading and Exporting from .env File Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md This snippet demonstrates the initial setup for loading configuration from a `.env` file and potentially exporting variables. While the code itself is minimal, it implies that `envresolve` can process `.env` files to make their contents available for expansion and secret resolution, including plain values, variable references, and `akv://` URIs. ```python import os import envresolve envresolve.register_azure_kv_provider() # .env may contain plain values, variable references, and akv:// URIs ``` -------------------------------- ### Set up and Run Live Azure Tests Source: https://github.com/osoekawaitlab/envresolve/blob/main/README.md Configures and executes optional integration tests against a real Azure Key Vault. This involves Terraform setup for Azure resources, logging into Azure CLI, sourcing a setup script, and then running the live tests using `nox`. ```bash # One-time setup cd infra/terraform cp terraform.tfvars.example terraform.tfvars # Edit terraform.tfvars with your Azure credentials terraform init terraform apply # Before running tests az login source scripts/setup_live_tests.sh # Run live tests nox -s tests_live ``` -------------------------------- ### Setup Live Test Environment with Terraform Outputs Source: https://github.com/osoekawaitlab/envresolve/blob/main/infra/terraform/README.md Scripts to export Terraform output variables as environment variables, facilitating the setup of the live test environment. This allows test suites to access Key Vault details like name, secret name, value, and version. ```bash # Automated method (from project root) source scripts/setup_live_tests.sh # Manual method (from infra/terraform directory) export ENVRESOLVE_LIVE_KEY_VAULT_NAME=$(terraform output -raw key_vault_name) export ENVRESOLVE_LIVE_SECRET_NAME=$(terraform output -raw sample_secret_name) export ENVRESOLVE_LIVE_SECRET_VALUE=$(terraform output -raw sample_secret_value) export ENVRESOLVE_LIVE_SECRET_VERSION=$(terraform output -raw sample_secret_version) ``` -------------------------------- ### Provider Configuration API Example in Python Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0009-manual-provider-registration-pattern.md Illustrates a potential provider configuration API using a builder pattern. This approach is useful when providers require complex initialization parameters such as credentials, cache settings, or retry policies. ```python register_azure_kv_provider( credential=my_credential, cache_ttl=600, retry_policy=my_policy ) ``` -------------------------------- ### Register Azure Key Vault Provider in Python Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Shows how to register the Azure Key Vault provider for secret resolution using `envresolve`. Includes basic registration with default credentials, custom credentials using `ManagedIdentityCredential` or `ClientSecretCredential`, and mocking for testing. Requires `envresolve[azure]` and Azure authentication setup. ```python import envresolve # Basic registration with DefaultAzureCredential # Requires: pip install envresolve[azure] # Requires: Azure authentication (az login, managed identity, etc.) try: envresolve.register_azure_kv_provider() except envresolve.ProviderRegistrationError as e: print(f"Failed to register provider: {e}") print("Install Azure dependencies: pip install envresolve[azure]") # Custom provider with specific credentials from envresolve.providers.azure_kv import AzureKVProvider from azure.identity import ManagedIdentityCredential # Use managed identity with specific client ID custom_credential = ManagedIdentityCredential(client_id="your-client-id") custom_provider = AzureKVProvider(credential=custom_credential) envresolve.register_azure_kv_provider(provider=custom_provider) # Service principal authentication from azure.identity import ClientSecretCredential credential = ClientSecretCredential( tenant_id="tenant-id", client_id="client-id", client_secret="client-secret" ) provider = AzureKVProvider(credential=credential) envresolve.register_azure_kv_provider(provider=provider) # Mock provider for testing from unittest.mock import MagicMock mock_provider = MagicMock() mock_provider.resolve.return_value = "mocked-secret-value" envresolve.register_azure_kv_provider(provider=mock_provider) ``` -------------------------------- ### Handle Provider and Secret Resolution Errors in envresolve Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Provides a robust example for handling errors during provider registration and secret resolution in envresolve. It catches specific exceptions like ProviderRegistrationError and SecretResolutionError, allowing for graceful failure and informative logging. ```python import envresolve from envresolve.exceptions import ProviderRegistrationError, SecretResolutionError try: # This might fail if 'envresolve[azure]' is not installed envresolve.register_azure_kv_provider() # This might fail due to permissions, network issues, or if the secret doesn't exist secret_value = envresolve.resolve_secret("akv://corp-vault/db-password") print(secret_value) except ProviderRegistrationError as e: print(f"Provider setup failed: {e}") # Example: Provider setup failed: Azure Key Vault provider requires: azure-identity, azure-keyvault-secrets. Install with: pip install envresolve[azure] except SecretResolutionError as e: print(f"Failed to fetch secret: {e}") ``` -------------------------------- ### EnvResolver: Resolve os.environ with Granular Error Handling Source: https://context7.com/osoekawaitlab/envresolve/llms.txt This example illustrates using EnvResolver to process and resolve environment variables from `os.environ`. It highlights parameters for controlling overwriting, stopping on expansion errors, and stopping on resolution errors. ```python from envresolve.api import EnvResolver resolver = EnvResolver() resolved = resolver.resolve_os_environ( prefix="APP_", overwrite=True, stop_on_expansion_error=False, stop_on_resolution_error=True ) ``` -------------------------------- ### Default Value Behavior Change Example Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0017-load-env-dotenv-path-parameter.md This example shows the difference in behavior when calling `load_env()` without arguments before and after the signature update. ```python # Before: Explicit path, always loads `.env` in cwd # load_env() # Loads ./.env # After: None triggers search, finds .env from cwd # load_env() # Searches for .env starting from cwd, walks up if not found ``` -------------------------------- ### Handle Secret Resolution Errors (Python) Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Shows how to catch SecretResolutionError for Azure-specific failures during secret retrieval. The example demonstrates how to access the failing URI and the original underlying error from the exception object. ```python import envresolve from envresolve.exceptions import SecretResolutionError envresolve.register_azure_kv_provider() try: envresolve.resolve_secret("akv://missing-vault/api-key") except SecretResolutionError as exc: print(exc) # Human-readable message print(exc.uri) # akv://missing-vault/api-key print(exc.original_error) # Underlying Azure exception (if available) ``` -------------------------------- ### Python: Iterative Secret Resolution with Variable Expansion Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Illustrates `resolve_secret`'s ability to perform iterative resolution, allowing it to chain indirections and combine secret resolution with variable expansion. In this example, an `akv://` URI first resolves a reference which itself contains an environment variable, demonstrating dynamic configuration loading. ```python import os import envresolve envresolve.register_azure_kv_provider() os.environ["ENVIRONMENT"] = "prod" # akv://config/service → "akv://vault-${ENVIRONMENT}/service" secret = envresolve.resolve_secret("akv://config/service") print(secret) # Resolved value from akv://vault-prod/service ``` -------------------------------- ### Enhanced Error Message Example (Python) Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0006-nested-variable-expansion-implementation.md Illustrates an enhanced error message format for variable expansion failures. This format aims to provide more context by showing the partial expansion state leading up to the error, aiding in debugging. ```python VariableNotFoundError: MISSING During expansion of: "${DB_${ENV}}" → "${DB_prod}" → "${DB_prod_MISSING}" ``` -------------------------------- ### Filter Environment Variable Resolution by Prefix Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Resolves environment variables that start with a specified prefix and strips the prefix from the resolved keys. This is useful for managing configurations for different environments (e.g., DEV, PROD). The original prefixed keys are removed from `os.environ` after resolution. ```python import os import envresolve envresolve.register_azure_kv_provider() # Different environments using prefixes os.environ["DEV_API_KEY"] = "akv://dev-vault/api-key" os.environ["DEV_DB_URL"] = "akv://dev-vault/db-url" os.environ["PROD_API_KEY"] = "akv://prod-vault/api-key" os.environ["PROD_DB_URL"] = "akv://prod-vault/db-url" # Resolve only DEV_ variables and strip the prefix resolved = envresolve.resolve_os_environ(prefix="DEV_") # Results have prefix stripped print(resolved["API_KEY"]) print(resolved["DB_URL"]) # os.environ is updated with stripped keys print(os.environ["API_KEY"]) assert "DEV_API_KEY" not in os.environ ``` -------------------------------- ### Python AST-Based Variable Expansion Example Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0006-nested-variable-expansion-implementation.md Demonstrates the concept of an Abstract Syntax Tree (AST) based approach for variable expansion. It shows a hypothetical parsed structure for a nested variable like '${VAR_${NESTED}}', illustrating the potential for explicit structure and detailed error reporting, though it introduces significant complexity. ```python from dataclasses import dataclass from typing import List, Union @dataclass class Literal: value: str @dataclass class BraceExpansion: name: Union[str, List['Node']] Node = Union[Literal, BraceExpansion] def parse(expression: str) -> Node: # Placeholder for actual parsing logic # Example structure for "${VAR_${NESTED}}": return BraceExpansion(name=[ Literal("VAR_"), BraceExpansion(name="NESTED") ]) def evaluate(ast: Node, env: dict[str, str]) -> str: # Placeholder for actual evaluation logic pass # Example usage: # ast = parse("${VAR_${NESTED}}") # result = evaluate(ast, env) ``` -------------------------------- ### Model-Based API Example (Alternative) Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0005-string-based-api-with-idempotent-resolution.md This alternative approach demonstrates returning structured data models with metadata for resolved values. It includes the value, original source, and potentially other details like timestamp or cache status. However, it requires users to extract the actual string value, adding friction. ```python result = resolve("akv://vault/secret") # → ResolutionResult secret = result.value # → str source = result.source # → "akv://vault/secret" ``` -------------------------------- ### Build and Serve envresolve Documentation Locally Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md Commands to build the project's documentation using MkDocs and serve it locally for preview. This is useful for contributors who are updating or adding documentation. ```bash # Serve documentation locally mkdocs serve # Build documentation mkdocs build ``` -------------------------------- ### Text-based Cycle Length Limit Example Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0008-circular-reference-chain-tracking.md This example shows a text-based representation for truncating long cycles. It indicates the start and end of a cycle and notes its length when it exceeds a predefined limit, preventing excessively long error messages. ```text "Circular reference: A -> B -> ... -> Y -> Z -> A (50 variables in cycle)" ``` -------------------------------- ### Parameter Name Change Example Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0017-load-env-dotenv-path-parameter.md This example illustrates the change in parameter naming from `path` to `dotenv_path` when calling the `load_env()` function. ```python # Before # envresolve.load_env(path=".env") # After envresolve.load_env(dotenv_path=".env") ``` -------------------------------- ### Plugin System with Setuptools Entry Points in Python Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0009-manual-provider-registration-pattern.md Illustrates using setuptools entry points for automatic discovery of providers. This standard Python plugin pattern allows third-party packages to extend functionality without explicit imports, though it can be overkill for simple use cases. ```python # setup.py entry_points={ "envresolve.providers": [ "akv = envresolve.providers.azure_kv:AzureKVProvider" ] } ``` -------------------------------- ### EnvResolver: Basic Instance Creation and Provider Registration Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Demonstrates the fundamental usage of EnvResolver, including creating an isolated resolver instance and registering a custom Azure Key Vault provider with a specific credential. ```python from envresolve.api import EnvResolver from envresolve.providers.azure_kv import AzureKVProvider from azure.identity import ManagedIdentityCredential # Create isolated resolver instance resolver = EnvResolver() # Register provider custom_provider = AzureKVProvider( credential=ManagedIdentityCredential(client_id="client-id") ) resolver.register_azure_kv_provider(provider=custom_provider) # Resolve secrets secret = resolver.resolve_secret("akv://vault/secret") print(secret) ``` -------------------------------- ### Python: Simple Variable Expansion using ${VAR} syntax Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Demonstrates how to expand environment variables using the ${VAR} syntax with the `expand_variables` function. It takes a string containing the variable and a dictionary of environment variables as input, returning the expanded string. This is useful for dynamically setting configuration values. ```python from envresolve import expand_variables env = {"VAULT_NAME": "my-vault"} result = expand_variables("${VAULT_NAME}", env) print(result) # Output: my-vault ``` -------------------------------- ### Bash Script for Terraform Directory Navigation Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/live-tests.md Navigates the user into the Terraform directory for infrastructure management. This is a common step before executing Terraform commands. ```bash cd infra/terraform ``` -------------------------------- ### Python: Simple Variable Expansion using $VAR syntax Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Shows how to expand environment variables using the simpler $VAR syntax with the `expand_variables` function. Similar to ${VAR}, it substitutes variable placeholders in a string with their corresponding values from an environment dictionary. This provides a more concise way to reference variables. ```python from envresolve import expand_variables env = {"VAULT_NAME": "my-vault"} result = expand_variables("$VAULT_NAME", env) print(result) # Output: my-vault ``` -------------------------------- ### Run Live Azure Tests for envresolve Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md Executes the live integration tests against Azure Key Vault infrastructure using nox. These tests validate changes affecting Azure SDK integration or provider implementations. ```bash nox -s tests_live ``` -------------------------------- ### Bash Command for Azure CLI Authentication Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/live-tests.md Logs the user into their Azure account using the Azure CLI. This is a prerequisite for interacting with Azure services. ```bash az login ``` -------------------------------- ### Handle EnvironmentVariableResolutionError with Context Source: https://context7.com/osoekawaitlab/envresolve/llms.txt This example shows how to catch EnvironmentVariableResolutionError, which provides context about failed variable resolution. It prints the failed variable key and the underlying cause, including specific variable names if the error is a VariableNotFoundError. ```python try: envresolve.load_env(dotenv_path=".env") except EnvironmentVariableResolutionError as e: print(f"Failed variable: {e.context_key}") print(f"Cause: {e.original_error}") # Access the underlying exception if isinstance(e.original_error, VariableNotFoundError): print(f"Missing variable: {e.original_error.variable_name}") ``` -------------------------------- ### Python: Example of Message-Based Exception Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0003-structured-exception-design.md Demonstrates raising a Python exception with a formatted error message passed directly to the constructor. This approach is simpler but lacks structured error data for programmatic access or robust testing. ```python raise VariableNotFoundError(f"Variable not found: {var_name}") ``` -------------------------------- ### Configure Terraform Remote Backend Source: https://github.com/osoekawaitlab/envresolve/blob/main/infra/terraform/README.md Commands to copy and edit the Terraform backend configuration file for remote state storage. Essential for team collaboration and CI/CD pipelines, ensuring state is managed centrally rather than locally. ```bash cp backend.tf.example backend.tf # Edit backend.tf with your Azure Storage account details terraform init -migrate-state ``` -------------------------------- ### Execute envresolve Code Quality Checks with Nox Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md Runs various code quality checks for the envresolve project using nox. This includes type checking with mypy, linting with ruff, and code formatting. ```bash # Type checking Nox -s mypy # Linting Nox -s lint # Format code Nox -s format_code # All quality checks Nox -s quality # Everything (tests + quality) Nox -s check_all ``` -------------------------------- ### Directly Resolve Azure Key Vault Secrets in Python Source: https://github.com/osoekawaitlab/envresolve/blob/main/README.md Fetch individual secrets directly from Azure Key Vault using their URI. This requires the 'envresolve[azure]' installation and Azure authentication. The function handles potential provider registration and secret resolution errors. ```python import envresolve # Requires: pip install envresolve[azure] # Requires: Azure authentication (az login, Managed Identity, etc.) try: envresolve.register_azure_kv_provider() secret_value = envresolve.resolve_secret("akv://corp-vault/db-password") print(secret_value) except envresolve.ProviderRegistrationError as e: print(f"Azure SDK not available: {e}") except envresolve.SecretResolutionError as e: print(f"Failed to fetch secret: {e}") ``` -------------------------------- ### envresolve Exception Classes (Python) Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Illustrates the use of various custom exception classes provided by envresolve for detailed error handling during variable expansion, URI parsing, and secret resolution. ```python from envresolve import ( EnvResolveError, CircularReferenceError, VariableNotFoundError, URIParseError, SecretResolutionError, ProviderRegistrationError, MutuallyExclusiveArgumentsError, EnvironmentVariableResolutionError ) import envresolve # Base exception - catch all envresolve errors try: result = envresolve.resolve_secret("akv://${VAULT}/${SECRET}") except EnvResolveError as e: print(f"An envresolve error occurred: {e}") # CircularReferenceError - circular variable reference detected env = {"A": "${B}", "B": "${C}", "C": "${A}"} try: result = envresolve.expand_variables(env["A"], env) except CircularReferenceError as e: print(f"Variable: {e.variable_name}") print(f"Chain: {' -> '.join(e.chain)}") # VariableNotFoundError - referenced variable not in environment try: result = envresolve.expand_variables("${UNDEFINED}", {{}}) except VariableNotFoundError as e: print(f"Missing variable: {e.variable_name}") # URIParseError - invalid secret URI format try: result = envresolve.resolve_secret("akv://vault-without-secret/") except URIParseError as e: print(f"Invalid URI: {e.uri}") print(f"Error: {e}") # SecretResolutionError - failed to fetch secret from provider envresolve.register_azure_kv_provider() try: result = envresolve.resolve_secret("akv://vault/nonexistent") except SecretResolutionError as e: print(f"Failed URI: {e.uri}") print(f"Original error: {e.original_error}") ``` -------------------------------- ### Python Error Handling Callback Example Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0018-granular-error-handling.md Demonstrates an alternative error handling strategy using a callback function in Python. This approach allows for maximum flexibility by letting users define custom logic for suppressing each error, though it increases API complexity. ```python from typing import Callable def load_env(error_handler: Callable[[Exception, str], bool] = None): # ... function implementation ... pass ``` -------------------------------- ### Python: Expand Variables from os.environ using EnvExpander Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Explains how to use the `EnvExpander` class to expand variables directly from the system's environment variables (`os.environ`). The expander takes a snapshot of `os.environ` upon initialization. Changes to environment variables after initialization will not be reflected. This is useful for applications that rely heavily on system-level environment configuration. ```python import os from envresolve import EnvExpander # Set environment variable os.environ["VAULT_NAME"] = "production-vault" expander = EnvExpander() result = expander.expand("akv://${VAULT_NAME}/secret") print(result) # Output: akv://production-vault/secret ``` -------------------------------- ### Run Specific envresolve Tests with Nox Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md Provides commands to run specific sets of tests within the envresolve project using nox, including unit tests, end-to-end tests, and tests across all supported Python versions. ```bash # Unit tests only Nox -s tests_unit # E2E tests only Nox -s tests_e2e # All Python versions Nox -s tests_all_versions ``` -------------------------------- ### Python: Register Azure Key Vault Provider Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Registers the Azure Key Vault provider with envresolve, enabling the resolution of secrets stored in Azure Key Vault. The `register_azure_kv_provider()` function is idempotent, meaning it can be safely called multiple times, for example, during application startup. This step is crucial for `resolve_secret` to interact with Azure Key Vault. ```python import envresolve envresolve.register_azure_kv_provider() ``` -------------------------------- ### EnvExpander: Expand Variables using os.environ Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Demonstrates the use of EnvExpander to expand variables using the current process's environment variables (os.environ). It sets environment variables and then uses EnvExpander to substitute placeholders in a string. ```python from envresolve import EnvExpander import os os.environ["VAULT_NAME"] = "prod-vault" os.environ["SECRET_NAME"] = "db-password" expander = EnvExpander() result = expander.expand("akv://${VAULT_NAME}/${SECRET_NAME}") print(result) # akv://prod-vault/db-password ``` -------------------------------- ### Python: Manual Provider Registration and Global Registry Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0009-manual-provider-registration-pattern.md Demonstrates the implementation pattern for manual provider registration using a global dictionary in Python. This pattern involves defining a dictionary to store providers, a function to register a specific provider (e.g., Azure Key Vault), and a helper function to retrieve providers by scheme. ```python # api.py from typing import Dict # Assuming SecretProvider and SecretResolutionError are defined elsewhere class SecretProvider: pass class SecretResolutionError(Exception): pass _PROVIDERS: Dict[str, SecretProvider] = {} def register_azure_kv_provider() -> None: """Register Azure Key Vault provider for akv:// and kv:// schemes.""" # Assuming AzureKVProvider is defined elsewhere class AzureKVProvider(SecretProvider): pass provider = AzureKVProvider() _PROVIDERS["akv"] = provider _PROVIDERS["kv"] = provider # Alias def _get_provider(scheme: str) -> SecretProvider: """Get provider for scheme, raise if not registered.""" if scheme not in _PROVIDERS: raise SecretResolutionError(f"No provider registered for scheme '{scheme}'") return _PROVIDERS[scheme] ``` -------------------------------- ### Run envresolve Tests with nox Source: https://github.com/osoekawaitlab/envresolve/blob/main/README.md Executes various test suites for the envresolve project using `nox`. Options include unit tests, end-to-end tests, full test suites, cross-version testing, and tests excluding Azure SDK dependencies. ```bash # Quick test during development # Unit tests only (fast) nox -s tests_unit # E2E tests with mocked Azure SDK nox -s tests_e2e # Full test suite # All tests with coverage report (HTML in htmlcov/) nox -s tests # Test across Python versions # Test on Python 3.10-3.14 nox -s tests_all_versions # Test without Azure SDK # For environments without Azure dependencies nox -s tests_without_azure ``` -------------------------------- ### EnvResolver: Multiple Isolated Resolvers with Different Configurations Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Shows how to create and manage multiple, independent EnvResolver instances, each with its own provider configurations. This is useful for scenarios requiring distinct secret resolution settings for different environments or applications. ```python from envresolve.api import EnvResolver from envresolve.providers.azure_kv import AzureKVProvider from azure.identity import ManagedIdentityCredential # Multiple isolated resolvers with different configurations prod_resolver = EnvResolver() prod_resolver.register_azure_kv_provider( provider=AzureKVProvider( credential=ManagedIdentityCredential(client_id="prod-client-id") ) ) dev_resolver = EnvResolver() dev_resolver.register_azure_kv_provider( provider=AzureKVProvider( credential=ManagedIdentityCredential(client_id="dev-client-id") ) ) prod_secret = prod_resolver.resolve_secret("akv://prod-vault/secret") dev_secret = dev_resolver.resolve_secret("akv://dev-vault/secret") ``` -------------------------------- ### Lazy Azure KV Provider Registration with Rich Error Handling Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0014-importlib-lazy-import.md This Python code snippet demonstrates how to lazily import the Azure Key Vault provider module using `importlib.import_module`. It includes robust error handling to catch `ImportError` and provide specific guidance on missing dependencies (`azure-identity`, `azure-keyvault-secrets`), raising a custom `ProviderRegistrationError` with installation instructions. ```python import importlib def register_azure_kv_provider(self, **kwargs: Any) -> None: try: provider_module = importlib.import_module("envresolve.providers.azure_kv") provider_class = provider_module.AzureKVProvider except ImportError as exc: # Missing provider module or downstream deps missing: list[str] = [] try: importlib.util.find_spec("azure.identity") except (ImportError, ModuleNotFoundError): missing.append("azure-identity") try: importlib.util.find_spec("azure.keyvault.secrets") except (ImportError, ModuleNotFoundError): missing.append("azure-keyvault-secrets") if missing: hint = ", ".join(missing) raise ProviderRegistrationError( f"Azure Key Vault provider requires {hint}. " "Install with `pip install envresolve[azure]`.", original_error=exc ) from exc raise ProviderRegistrationError( "Failed to import Azure Key Vault provider; see chained exception for details.", original_error=exc ) from exc provider = provider_class(**kwargs) self._providers["akv"] = provider ``` -------------------------------- ### Conditionally Skip Azure Doctests with Pytest Fixture (Python) Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0011-conditional-doctest-skip.md This Python code snippet defines a pytest fixture to automatically skip doctests related to Azure Key Vault usage if the necessary Azure SDK packages ('azure-identity', 'azure-keyvault-secrets') are not installed. It checks for the availability of these modules and uses pytest.skip() to skip the relevant doctests, ensuring tests pass gracefully in environments without the optional dependencies. ```python import importlib.util import pytest def _azure_sdk_available() -> bool: try: return ( importlib.util.find_spec("azure.identity") is not None and importlib.util.find_spec("azure.keyvault.secrets") is not None ) except (ImportError, ModuleNotFoundError): return False @pytest.fixture(autouse=True) def _skip_azure_doctests(request: pytest.FixtureRequest) -> None: if not isinstance(request.node, pytest.DoctestItem): return if "api.py" in str(request.node.fspath): azure_tests = ["register_azure_kv_provider", "load_env"] is_azure = any(name in request.node.name for name in azure_tests) if is_azure and not _azure_sdk_available(): pytest.skip("Azure SDK not available") ``` -------------------------------- ### AzureKVProvider for Azure Key Vault Secrets (Python) Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Shows how to implement and use the AzureKVProvider for resolving secrets from Azure Key Vault. It covers credential configuration, client caching, and direct provider usage. ```python from envresolve.providers.azure_kv import AzureKVProvider from azure.identity import DefaultAzureCredential, ManagedIdentityCredential from envresolve.models import ParsedURI import envresolve # Create provider with default credential provider = AzureKVProvider() # Create provider with custom credential custom_credential = ManagedIdentityCredential(client_id="your-client-id") provider = AzureKVProvider(credential=custom_credential) # Register custom provider envresolve.register_azure_kv_provider(provider=provider) # Direct provider usage (advanced) parsed_uri = ParsedURI( scheme="akv", vault="my-vault", secret="db-password", version=None ) try: secret_value = provider.resolve(parsed_uri) print(f"Secret value: {secret_value}") except envresolve.SecretResolutionError as e: print(f"Resolution failed: {e}") # Resolve with specific version versioned_uri = ParsedURI( scheme="akv", vault="my-vault", secret="api-key", version="abc123def456" ) secret_value = provider.resolve(versioned_uri) # Multiple vaults with single provider (clients are cached) provider = AzureKVProvider() envresolve.register_azure_kv_provider(provider=provider) vault1_secret = envresolve.resolve_secret("akv://vault1/secret1") vault2_secret = envresolve.resolve_secret("akv://vault2/secret2") vault1_another = envresolve.resolve_secret("akv://vault1/secret3") # Provider maintains separate cached clients for vault1 and vault2 ``` -------------------------------- ### Resolve Environment Variables with envresolve (Python) Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Demonstrates how to use envresolve to resolve environment variables, with options to prevent overwriting existing variables, handle expansion errors gracefully, and ignore specific keys. ```python import os import envresolve # Resolve without overwriting os.environ os.environ["SECRET"] = "akv://vault/secret" resolved = envresolve.resolve_os_environ(overwrite=False) # resolved["SECRET"] contains actual secret value # os.environ["SECRET"] still contains "akv://vault/secret" # Granular error handling - skip expansion errors os.environ["OPTIONAL_VAR"] = "${MIGHT_NOT_EXIST}" os.environ["REQUIRED_SECRET"] = "akv://vault/required" resolved = envresolve.resolve_os_environ( stop_on_expansion_error=False, # Skip missing variables stop_on_resolution_error=True # Always catch secret failures ) # Skip specific variables (e.g., shell prompt with literal $ characters) os.environ["PS1"] = "${USER}@${HOST}$ " # Should not be expanded os.environ["API_KEY"] = "akv://vault/api-key" resolved = envresolve.resolve_os_environ(ignore_keys=["PS1", "PS2"]) # Error handling with context from envresolve import ( EnvironmentVariableResolutionError, MutuallyExclusiveArgumentsError ) try: # Cannot specify both keys and prefix resolved = envresolve.resolve_os_environ( keys=["SECRET"], prefix="DEV_" ) except MutuallyExclusiveArgumentsError as e: print(f"Arguments {e.arg1} and {e.arg2} are mutually exclusive") try: resolved = envresolve.resolve_os_environ() except EnvironmentVariableResolutionError as e: print(f"Failed variable: {e.context_key}") print(f"Underlying error: {e.original_error}") ``` -------------------------------- ### Factory Pattern for Provider Creation in Python Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0009-manual-provider-registration-pattern.md Shows the use of a factory pattern for creating providers, offering flexible configuration and avoiding global state. Users are responsible for managing the provider lifecycle, which can be verbose for simple scenarios. ```python provider = ProviderFactory.create("azure_kv", vault="my-vault") result = resolve_secret("akv://...", provider=provider) ``` -------------------------------- ### Python: Expand Variables from .env File using DotEnvExpander Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Shows how to use `DotEnvExpander` to load and expand variables defined in a `.env` file. The class reads variables from the specified file, allowing them to be used within the application. This facilitates managing configuration separately from code, especially in development environments. ```python from envresolve import DotEnvExpander # Contents of .env: # VAULT_NAME=my-company-vault # DB_PASSWORD=akv://${VAULT_NAME}/db-password # API_KEY=akv://${VAULT_NAME}/api-key expander = DotEnvExpander(".env") db_password_uri = expander.expand("${DB_PASSWORD}") api_key_uri = expander.expand("${API_KEY}") print(db_password_uri) # Output: akv://my-company-vault/db-password print(api_key_uri) # Output: akv://my-company-vault/api-key ``` -------------------------------- ### Destroy Live Azure Test Resources Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/contributing.md Command to destroy the Azure resources provisioned for live integration tests. This should be run when the resources are no longer needed to avoid ongoing costs. ```bash cd infra/terraform terraform destroy ``` -------------------------------- ### Perform Code Quality Checks with nox Source: https://github.com/osoekawaitlab/envresolve/blob/main/README.md Runs code quality checks for the envresolve project using `nox`. This includes type checking with `mypy`, linting with `ruff`, and code formatting. Individual checks can be run, or all checks combined. ```bash # Run all quality checks # Type checking (mypy) + linting (ruff) nox -s quality # Individual checks # Type checking only nox -s mypy # Linting only nox -s lint # Auto-format code nox -s format_code # Run everything # Tests + quality checks nox -s check_all ``` -------------------------------- ### CustomExpander: Create a Custom Variable Expansion Logic Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Shows how to create a custom expander class by inheriting from envresolve.application.expanders.Expander. This custom expander merges the current environment variables with a provided dictionary of custom variables for expansion. ```python from envresolve.application.expanders import Expander from envresolve.services.expansion import expand_variables import os class CustomExpander(Expander): def __init__(self, custom_vars: dict[str, str]): self.env = dict(os.environ) self.env.update(custom_vars) def expand(self, value: str) -> str: return expand_variables(value, self.env) expander = CustomExpander({"CUSTOM_VAR": "custom-value"}) result = expander.expand("Value: ${CUSTOM_VAR}") print(result) # Value: custom-value ``` -------------------------------- ### Bash Command to Set Live Test Environment Variables Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/developer-guide/live-tests.md Sources a shell script that exports necessary Azure Key Vault details as environment variables. These variables are used by the test runner. ```bash source scripts/setup_live_tests.sh ``` -------------------------------- ### Python: Auto-Registration via Import (Alternative) Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0009-manual-provider-registration-pattern.md Presents an alternative implementation pattern where providers are automatically registered upon module import. This approach is contrasted with manual registration, highlighting its pros and cons, particularly concerning side effects and initialization control. ```python # providers/azure_kv.py # Auto-registers on import from envresolve.api import _PROVIDERS # Assuming AzureKVProvider is defined and imported correctly class SecretProvider: pass class AzureKVProvider(SecretProvider): pass # This line causes the side effect on import _PROVIDERS["akv"] = AzureKVProvider() ``` -------------------------------- ### Alternative: Factory Functions for Variable Expansion (Python) Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/adr/0004-stateless-function-based-variable-expansion.md This alternative shows factory functions that create callable expanders. One factory creates an expander for a given environment dictionary, and another specifically for `os.environ`. This was considered less discoverable than a class-based approach. ```python from typing import Callable def create_expander(env: dict[str, str]) -> Callable[[str], str]: return lambda text: expand_variables(text, env) def create_env_expander() -> Callable[[str], str]: return lambda text: expand_variables(text, dict(os.environ)) ``` -------------------------------- ### Expand Variables with envresolve in Python Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Demonstrates how to use the `expand_variables` function to resolve environment variables within strings. Supports basic expansion, multiple variables, nested references, and error handling for missing variables and circular references. Requires the `envresolve` library. ```python from envresolve import expand_variables # Simple variable expansion env = {"VAULT": "corp-vault", "SECRET": "db-password"} result = expand_variables("akv://${VAULT}/${SECRET}", env) print(result) # akv://corp-vault/db-password # Multiple variables in one string env = { "VAULT_NAME": "my-vault", "SECRET_PATH": "db-password", "FULL_URI": "akv://${VAULT_NAME}/${SECRET_PATH}" } result = expand_variables(env["FULL_URI"], env) print(result) # akv://my-vault/db-password # Nested variable expansion env = { "ENV": "prod", "VAULT": "${ENV}-vault", "URI": "akv://${VAULT}/secret" } result = expand_variables(env["URI"], env) print(result) # akv://prod-vault/secret # Error handling for missing variables from envresolve import VariableNotFoundError try: result = expand_variables("${MISSING_VAR}", {"OTHER": "value"}) except VariableNotFoundError as e: print(f"Variable not found: {e.variable_name}") # Error handling for circular references from envresolve import CircularReferenceError env = {"A": "${B}", "B": "${A}"} try: result = expand_variables(env["A"], env) except CircularReferenceError as e: print(f"Circular reference: {' -> '.join(e.chain)}") ``` -------------------------------- ### DotEnvExpander: Load and Expand Variables from .env File Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Illustrates how to use DotEnvExpander to load environment variables from a specified .env file and then expand variables within strings using these loaded values. It also shows how to access the loaded environment variables directly. ```python from envresolve import DotEnvExpander from pathlib import Path # Example .env content: # ENVIRONMENT=staging # VAULT=${ENVIRONMENT}-vault # SECRET_URI=akv://${VAULT}/api-key env_file = Path("config/.env") expander = DotEnvExpander(env_file) result = expander.expand("${SECRET_URI}") print(result) # akv://staging-vault/api-key # Access loaded environment print(expander.env["VAULT"]) # staging-vault ``` -------------------------------- ### Resolve Plain Strings and Non-Secret URIs Source: https://context7.com/osoekawaitlab/envresolve/llms.txt Demonstrates how envresolve.resolve_secret() handles plain strings and non-secret URIs by passing them through unchanged. It also shows comprehensive error handling for various resolution failures. ```python import envresolve # Idempotent - plain strings pass through unchanged plain = envresolve.resolve_secret("just-a-string") assert plain == "just-a-string" # Non-secret URIs pass through unchanged postgres_uri = envresolve.resolve_secret("postgres://localhost:5432/mydb") assert postgres_uri == "postgres://localhost:5432/mydb" # Comprehensive error handling try: secret = envresolve.resolve_secret("akv://${VAULT}/${SECRET}") except envresolve.VariableNotFoundError as e: print(f"Missing environment variable: {e.variable_name}") except envresolve.URIParseError as e: print(f"Invalid URI format: {e.uri}") except envresolve.SecretResolutionError as e: print(f"Failed to fetch secret: {e.uri}") except envresolve.CircularReferenceError as e: print(f"Circular reference: {' -> '.join(e.chain)}") ``` -------------------------------- ### Load .env and Export to os.environ Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Loads environment variables from a .env file in the current directory and exports them to `os.environ`. By default, it overrides existing variables. The `export` parameter can be set to `False` to only return a dictionary, and `override` can be set to `True` to intentionally replace existing `os.environ` values. ```python import os import envresolve # By default, searches for .env in current directory and exports to os.environ resolved = envresolve.load_env() print(resolved["DB_PASSWORD"]) print(os.environ["DB_PASSWORD"]) # Exported unless override=False and already set # Use export=False when you only need the resolved dictionary, or set # override=True if you want to intentionally replace existing os.environ # values. ``` -------------------------------- ### Handle ProviderRegistrationError for Azure SDK Dependencies Source: https://context7.com/osoekawaitlab/envresolve/llms.txt This snippet demonstrates how to catch and handle a ProviderRegistrationError, which typically occurs when Azure SDK dependencies are missing. It prints a user-friendly message and the original error for debugging. ```python try: envresolve.register_azure_kv_provider() except ProviderRegistrationError as e: print(f"Registration failed: {e}") print(f"Original error: {e.original_error}") ``` -------------------------------- ### EnvResolver: Resolve Secrets with Custom Environment Source: https://context7.com/osoekawaitlab/envresolve/llms.txt This snippet shows how to use EnvResolver to resolve secrets using a custom environment dictionary, allowing for temporary or specific environment configurations during resolution. ```python from envresolve.api import EnvResolver resolver = EnvResolver() custom_env = { "VAULT": "custom-vault", "SECRET": "custom-secret" } result = resolver.resolve_with_env("akv://${VAULT}/${SECRET}", custom_env) print(result) ``` -------------------------------- ### Handle Mutually Exclusive Arguments in resolve_os_environ (Python) Source: https://github.com/osoekawaitlab/envresolve/blob/main/docs/user-guide/basic-usage.md Demonstrates how to handle the MutuallyExclusiveArgumentsError when calling resolve_os_environ with conflicting parameters like 'keys' and 'prefix'. It shows how to catch the specific error and access the names of the conflicting arguments. ```python import envresolve from envresolve.exceptions import MutuallyExclusiveArgumentsError envresolve.register_azure_kv_provider() try: # This will raise an error - cannot specify both envresolve.resolve_os_environ( keys=["API_KEY"], prefix="DEV_" ) except MutuallyExclusiveArgumentsError as e: print(f"Error: {e}") # Error: Arguments 'keys' and 'prefix' are mutually exclusive. # Specify either 'keys' or 'prefix', but not both. # Access argument names programmatically print(f"Conflicting arguments: {e.arg1} and {e.arg2}") # Conflicting arguments: keys and prefix ``` ```python try: envresolve.resolve_os_environ(keys=["API_KEY"], prefix="DEV_") except TypeError as e: print(f"Invalid argument combination: {e}") ```