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.baseENVO_EXTENDED_BY=.env.overrides - Auto-Coerced Types -
env.MY_VAL # 5 <int>automatically converts strings toint,float,bool,Path,dict,list, and more - Validation - using
@min/@max/@type/etcdeclarations insample.env - Self-Documenting - comments in the
sample.envget loaded into theEnvobject 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.txtwill use the firs path that exists - Multiple file formats — Load from
.env,.json,.yaml, and.tomlfiles - 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.envin your project root - let the user overwrite variables using
.envor by runningenvo config - load in parsed variables with
from envo import Envandenv = 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):
- Spec file defaults (
sample.env) - Extended files (
ENVO_EXTENDS) - Main
.envfile - Extending files (
ENVO_EXTENDED_BY) - 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 |
| Add | $A+$B |
Addition (numbers) or concatenation (strings) | number or string |
| Subtract | $A-$B |
Subtraction | number |
| Multiply | $A*$B |
Multiplication | number |
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file modularizer_envo-0.1.1.tar.gz.
File metadata
- Download URL: modularizer_envo-0.1.1.tar.gz
- Upload date:
- Size: 58.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce89d355e04e4d27b8fc85310c866ad34e08f1e28c0623cac277359120ef64e4
|
|
| MD5 |
05db4e2572e5e40d8904f2200f6a8b62
|
|
| BLAKE2b-256 |
b237a63fdea51d71520f85a5a99d6692c60b03e4603c9a6cc7b2ccff225d36e3
|
Provenance
The following attestation bundles were made for modularizer_envo-0.1.1.tar.gz:
Publisher:
publish.yml on modularizer/envo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
modularizer_envo-0.1.1.tar.gz -
Subject digest:
ce89d355e04e4d27b8fc85310c866ad34e08f1e28c0623cac277359120ef64e4 - Sigstore transparency entry: 844913931
- Sigstore integration time:
-
Permalink:
modularizer/envo@df3732c728ad50303eb5033433c25c649467236d -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/modularizer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@df3732c728ad50303eb5033433c25c649467236d -
Trigger Event:
release
-
Statement type:
File details
Details for the file modularizer_envo-0.1.1-py3-none-any.whl.
File metadata
- Download URL: modularizer_envo-0.1.1-py3-none-any.whl
- Upload date:
- Size: 59.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2c52813bbba1f03c8210d510fa8591af3c113ba7af7ecf604189e1ef75a75b88
|
|
| MD5 |
9d09a3b989c5b308ac3af571e142aa10
|
|
| BLAKE2b-256 |
5f4270a618e9cb2fd6fe23a70455fa2181b83869d99c642273496ab4e52cf1d7
|
Provenance
The following attestation bundles were made for modularizer_envo-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on modularizer/envo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
modularizer_envo-0.1.1-py3-none-any.whl -
Subject digest:
2c52813bbba1f03c8210d510fa8591af3c113ba7af7ecf604189e1ef75a75b88 - Sigstore transparency entry: 844913937
- Sigstore integration time:
-
Permalink:
modularizer/envo@df3732c728ad50303eb5033433c25c649467236d -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/modularizer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@df3732c728ad50303eb5033433c25c649467236d -
Trigger Event:
release
-
Statement type: