Skip to main content

Environment variable loading utility with project root detection

Project description

envo

Environment variable loading utility.

envo provides a powerful, type-safe way to manage environment variables in Python projects. It automatically discovers .env files, coerces values to appropriate types, validates against specifications, and offers both programmatic and CLI interfaces.

Features

  • Load From Many Sources - .env.sample + .env.base + .other.yaml + c.json + d.toml + .env + os.environ
  • Refs - ENV_VAR_B=$ENV_VAR_A
  • Math - ITEM_COUNT=($MODE=="prod")?5:10
  • Chaining - ENVO_EXTENDS=.env.base ENVO_EXTENDED_BY=.env.overrides
  • Auto-Coerced Types - env.MY_VAL # 5 <int> automatically converts strings to int, float, bool, Path, dict, list, and more
  • Validation - using @min/@max/@type/etc declarations in sample.env
  • Self-Documenting - comments in the sample.env get loaded into the Env object and used/shown in commandline tools
  • CLI Tools - for validating, configuring, etc.
  • Path Substitution - % references the project root, and can be used for filepath env variables
  • Path Fallbacks - /file-a.txt|/file-b.txt will use the firs path that exists
  • Multiple file formats — Load from .env, .json, .yaml, and .toml files
  • Variable grouping — Auto-detected from sample.env, helps with grabbing chunks of env variables
  • Customizable — Override behavior with ENVO_* environment variables
  • Supports .py env specs - Allow using .py files to specify default values

How to use?

Requirements

  • Python 3.10+

Install

pip install modularizer-envo

Your job is simple:

  • write a sample.env in your project root
  • let the user overwrite variables using .env or by running envo config
  • load in parsed variables with from envo import Env and env = Env()

Quick Start

Programmatic Usage

from envo import Env

# Auto-discover and load environment
env = Env()

# Access with automatic type coercion
debug = env.DEBUG          # bool
port = env.PORT            # int
db_url = env.DATABASE_URL  # str

# Or use the pre-built global instance
from envo import env
print(env.DEBUG)

Using a Spec File

Create a sample.env file to define your environment schema:

# sample.env - Environment Variable Specification

# =============================================================================
# database - Database Configuration
# =============================================================================
DB_HOST=localhost          # Database hostname @required
DB_PORT=5432               # Port number @type:int @range:1-65535
DB_NAME=myapp              # Database name

# =============================================================================
# server - Server Configuration  
# =============================================================================
DEBUG=false                # Enable debug mode @type:bool
PORT=8080                  # Server port @type:int
LOG_LEVEL=info             # Log level @choices:debug,info,warn,error

Then in your code:

from envo import Env

env = Env()  # Automatically uses sample.env as spec

# Values are validated and coerced according to spec
port = env.DB_PORT    # int: 5432
debug = env.DEBUG     # bool: False

CLI Commands

envo show - Display environment variables with colored output.

envo validate - Validate a .env file against a spec.

envo config - Interactive TUI for browsing and editing environment variables.

Spec File Format

Basic .env Spec

# =============================================================================
# group_name - Group Description
# =============================================================================

VARIABLE_NAME=default_value  # Documentation text @directive:value

# Supported directives:
#   @type:int|float|bool|str|path|json|list|glob
#   @min:N          - Minimum value
#   @max:N          - Maximum value
#   @range:N-M      - Range constraint
#   @choices:a,b,c  - Valid choices
#   @pattern:regex  - Regex pattern
#   @required       - Value must be non-empty

JSON/YAML Spec

# config.yaml
database:
  DB_HOST:
    default: localhost
    help: Database hostname
    required: true
  DB_PORT:
    default: 5432
    type: int
    min: 1
    max: 65535

server:
  DEBUG:
    default: false
    type: bool
  PORT:
    default: 8080
    type: int

Type Coercion

envo automatically coerces values based on content or explicit type hints:

Type Examples Notes
bool true, false, 1, 0, yes, no, on, off Case-insensitive
int 42, 1_000_000 Underscores allowed
float 3.14, 1_000.5 Underscores allowed
path /home/user, ~/data, %/config % = project root
dict/list {"key": "value"}, ["a", "b"] JSON format
null null, none Becomes Python None
# Explicit type override
env.get("PORT", type=int)
env.get("HOSTS", type=list)
env.get_as("CONFIG_PATH", Path)

File Chaining

Chain multiple configuration files with priority control:

# base.env - Load another file with LOWER priority (we override it)
ENVO_EXTENDS=defaults.env
DB_HOST=production-db

# .env - Load another file with HIGHER priority (it overrides us)
ENVO_EXTENDED_BY=.env.local

Priority order (lowest to highest):

  1. Spec file defaults (sample.env)
  2. Extended files (ENVO_EXTENDS)
  3. Main .env file
  4. Extending files (ENVO_EXTENDED_BY)
  5. System environment variables (os.environ)

Variable References

Reference other variables with $VAR_NAME:

BASE_DIR=/app
DATA_DIR=$BASE_DIR/data
LOG_DIR=$BASE_DIR/logs
FULL_URL=http://$HOST:$PORT/api

Use % to reference the project root:

CONFIG_PATH=%/config
DATA_PATH=%/data

Expression Operators

Envo supports logical and arithmetic expressions for dynamic configuration:

Operator Syntax Description Result
Ternary $VAR?yes:no If VAR is truthy, use "yes", else "no" yes or no
NOT !$VAR Logical negation true or false
AND $A&&$B Logical AND true or false
OR $A||$B Logical OR true or false
Equals $A==$B Equality check true or false
Not Equals $A!=$B Inequality check true or false

Note: Single | and / are NOT operators to avoid conflicts with path separators.

# Ternary - conditional values
DEBUG_MSG=$DEBUG?Debugging enabled:Production mode
DB_HOST=$USE_DOCKER?db:localhost

# Logical operators (use && and ||)
IS_READY=$DB_CONFIGURED&&$CACHE_CONFIGURED
USE_FALLBACK=$PRIMARY_DOWN||$FORCE_FALLBACK
FEATURE_OFF=!$FEATURE_ENABLED

# Comparisons
IS_PROD=$ENV==production
NOT_LOCAL=$ENV!=local

# Arithmetic
TOTAL_WORKERS=$CPU_COUNT*2
ADJUSTED_PORT=$BASE_PORT+$INSTANCE_ID

# String concatenation (when values aren't both numeric)
GREETING=$HELLO+$WORLD

# Combine with parentheses
SHOW_DEBUG=($DEBUG&&$VERBOSE)||$FORCE_DEBUG
COMPLEX_CALC=($A+$B)*$C

Truthiness: Values are truthy unless they are empty, false, 0, no, off, null, or none.

Variable Groups

Filter variables by group for organized access:

# Get all database variables
db_env = env.get_group("database")
print(db_env.DB_HOST)

# List all available groups
print(env.list_groups())

# Access all groups as a dict
for name, group_env in env.groups.items():
    print(f"{name}: {list(group_env.keys())}")

Configuration

Customize envo behavior with environment variables:

Variable Default Description
ENVO_DEFAULT_ENV_FILE .env Default env file name
ENVO_DEFAULT_SPEC_FILES sample.env,.env.sample Spec file search order
ENVO_DEFAULT_GROUP unknown Default group for ungrouped vars
ENVO_USE_SPEC_DEFAULT <default> Special value to use spec default
ENVO_BOOL_TRUE_VALUES true,1,yes,on,y,enable,enabled Values coerced to True
ENVO_BOOL_FALSE_VALUES false,0,no,off,n,disable,disabled Values coerced to False
ENVO_PROJECT_ROOT_CHAR % Character for project root substitution
ENVO_REF_CHAR $ Character for variable references

See sample.env in the repository for the complete list of configuration options, including color scheme customization.

Advanced Usage

Custom Spec

from envo import Env

env = Env(
    ".env",
    spec={
        "PORT": int,
        "DEBUG": bool,
        "HOSTS": list,
        "DB_*": {"groups": ("database",), "type": str},
        "API_*": {"groups": ("api",), "required": True},
    }
)

Multiple Files with Priority

# Load with explicit priority order
env = Env(
    "defaults.env",      # Lowest priority
    ".env",              # Medium priority
    ".env.local",        # Highest priority
)

# Control system environment handling
env = Env(
    ".env",
    existing_env_priority="lowest",  # or "highest" (default), "none"
)

Validation Pipeline

from envo import Env
from envo.spec_type import VariableSpec

env = Env(
    spec={
        "PORT": VariableSpec(
            type=int,
            default=8080,
            validator=lambda x: x if 1 <= x <= 65535 else ValueError("Invalid port"),
        ),
        "EMAIL": VariableSpec(
            type=str,
            pattern=r"^[^@]+@[^@]+\.[^@]+$",
            required=True,
        ),
    }
)

Access Raw Values

# Get the raw string value before coercion
raw_port = env.raw["PORT"]  # "8080" (string)

# Get the parsed/coerced value
port = env.PORT  # 8080 (int)

License

Unlicense — Public Domain

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

modularizer_envo-0.2.0.tar.gz (57.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

modularizer_envo-0.2.0-py3-none-any.whl (59.2 kB view details)

Uploaded Python 3

File details

Details for the file modularizer_envo-0.2.0.tar.gz.

File metadata

  • Download URL: modularizer_envo-0.2.0.tar.gz
  • Upload date:
  • Size: 57.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for modularizer_envo-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9b5492e96bb789688bbb945cbf1524804c4b142283d8f22868dce2d2f5e7bcef
MD5 9f442e6ad316e5cea43dd7c0f17d728b
BLAKE2b-256 7a0b6f729ca8f2a21dedbd912cda5aa4788c71dc69987f97264608f5e08b9333

See more details on using hashes here.

Provenance

The following attestation bundles were made for modularizer_envo-0.2.0.tar.gz:

Publisher: publish.yml on modularizer/envo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file modularizer_envo-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for modularizer_envo-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 369fe12cc23434d15d459d2ef0d8ec7db4a03253f7cd1235585abea09bf05af9
MD5 aefcaf1c15919f1712b83ce17f5a4790
BLAKE2b-256 68eb90e579a30bc58c8c9689c3d9c0db1f56f19d149a2009663856d8e3237ce5

See more details on using hashes here.

Provenance

The following attestation bundles were made for modularizer_envo-0.2.0-py3-none-any.whl:

Publisher: publish.yml on modularizer/envo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page