Skip to main content

Enhanced environment variable management with multi-format support

Project description

envdot

Enhanced environment variable management for Python with multi-format support and automatic type detection.

Features

  • 🔧 Multiple Format Support: .env, .json, .yaml, .yml, and .ini files
  • 🎯 Automatic Type Detection: Automatically converts strings to bool, int, float, or keeps as string
  • 💾 Read and Write: Load from and save to configuration files
  • 🔄 Method Chaining: Fluent API for cleaner code
  • 🌍 OS Environment Integration: Seamlessly works with os.environ
  • 📦 Zero Dependencies: Core functionality works without external packages (YAML support requires PyYAML)

Installation

pip install envdot

# With YAML support
pip install envdot[yaml]

# With all extras
pip install envdot[all]

Quick Start

Basic Usage

$ cat .env
CELERY_BACKEND=redis://redis:6379/0
CELERY_BROKER=redis://redis:6379/0
DEBUG=true
DEBUGGER_SERVER=5.5
DEBUG_SERVER=false
DJANGO_ALLOWED_HOSTS="localhost 127.0.0.1 [::1] 192.168.100.2 192.168.100.2"
POSTGRES_DB=django_celery
POSTGRES_PASSWORD=password1234-8
POSTGRES_USER=celery_admin
PYTHONDONTWRITEBYTECODE=true
PYTHONUNBUFFERED=true
RABBITMQ_DEFAULT_PASS=hackmeplease
RABBITMQ_DEFAULT_USER=syslog
RABBITMQ_HOST_DJANGO=rabbitmq
RABBITMQ_MANAGEMENT=true
RABBITMQ_PASSWORD_DJANGO=123-8
RABBITMQ_USERNAME_DJANGO=syslog
SECRET_KEY=dbaa1_i7%*3r9-=z-+_mz4r-!qeed@(-a_r(g@k8jo8y3r27%m
In [1]: from envdot import load_env, show

In [2]: load_env()
Out[2]: DotEnv(filepath=.env, vars=18)

In [3]: show()
Out[3]:
{'CELERY_BACKEND': 'redis://redis:6379/0',
 'CELERY_BROKER': 'redis://redis:6379/0',
 'DEBUG': True,
 'DEBUGGER_SERVER': 5.5,
 'DEBUG_SERVER': False,
 'DJANGO_ALLOWED_HOSTS': 'localhost 127.0.0.1 [::1] 192.168.100.2 192.168.100.2',
 'POSTGRES_DB': 'django_celery',
 'POSTGRES_PASSWORD': 'password1234-8',
 'POSTGRES_USER': 'celery_admin',
 'PYTHONDONTWRITEBYTECODE': True,
 'PYTHONUNBUFFERED': True,
 'RABBITMQ_DEFAULT_PASS': 'hackmeplease',
 'RABBITMQ_DEFAULT_USER': 'syslog',
 'RABBITMQ_HOST_DJANGO': 'rabbitmq',
 'RABBITMQ_MANAGEMENT': True,
 'RABBITMQ_PASSWORD_DJANGO': '123-8',
 'RABBITMQ_USERNAME_DJANGO': 'syslog',
 'SECRET_KEY': 'dbaa1_i7%*3r9-=z-+_mz4r-!qeed@(-a_r(g@k8jo8y3r27%m'}

In [4]: config = load_env()

In [5]: config.show()
Out[5]:
{'CELERY_BACKEND': 'redis://redis:6379/0',
 'CELERY_BROKER': 'redis://redis:6379/0',
 'DEBUG': True,
 'DEBUGGER_SERVER': 5.5,
 'DEBUG_SERVER': False,
 'DJANGO_ALLOWED_HOSTS': 'localhost 127.0.0.1 [::1] 192.168.100.2 192.168.100.2',
 'POSTGRES_DB': 'django_celery',
 'POSTGRES_PASSWORD': 'password1234-8',
 'POSTGRES_USER': 'celery_admin',
 'PYTHONDONTWRITEBYTECODE': True,
 'PYTHONUNBUFFERED': True,
 'RABBITMQ_DEFAULT_PASS': 'hackmeplease',
 'RABBITMQ_DEFAULT_USER': 'syslog',
 'RABBITMQ_HOST_DJANGO': 'rabbitmq',
 'RABBITMQ_MANAGEMENT': True,
 'RABBITMQ_PASSWORD_DJANGO': '123-8',
 'RABBITMQ_USERNAME_DJANGO': 'syslog',
 'SECRET_KEY': 'dbaa1_i7%*3r9-=z-+_mz4r-!qeed@(-a_r(g@k8jo8y3r27%m'}

In [6]: config.DEBUG_SERVER
Out[6]: False

In [7]: config.DEBUG_SERVER = True

In [8]: show()
Out[8]:
{'CELERY_BACKEND': 'redis://redis:6379/0',
 'CELERY_BROKER': 'redis://redis:6379/0',
 'DEBUG': True,
 'DEBUGGER_SERVER': 5.5,
 'DEBUG_SERVER': True,
 'DJANGO_ALLOWED_HOSTS': 'localhost 127.0.0.1 [::1] 192.168.100.2 192.168.100.2',
 'POSTGRES_DB': 'django_celery',
 'POSTGRES_PASSWORD': 'password1234-8',
 'POSTGRES_USER': 'celery_admin',
 'PYTHONDONTWRITEBYTECODE': True,
 'PYTHONUNBUFFERED': True,
 'RABBITMQ_DEFAULT_PASS': 'hackmeplease',
 'RABBITMQ_DEFAULT_USER': 'syslog',
 'RABBITMQ_HOST_DJANGO': 'rabbitmq',
 'RABBITMQ_MANAGEMENT': True,
 'RABBITMQ_PASSWORD_DJANGO': '123-8',
 'RABBITMQ_USERNAME_DJANGO': 'syslog',
 'SECRET_KEY': 'dbaa1_i7%*3r9-=z-+_mz4r-!qeed@(-a_r(g@k8jo8y3r27%m'}

In [9]: config.show()
Out[9]:
{'CELERY_BACKEND': 'redis://redis:6379/0',
 'CELERY_BROKER': 'redis://redis:6379/0',
 'DEBUG': True,
 'DEBUGGER_SERVER': 5.5,
 'DEBUG_SERVER': True,
 'DJANGO_ALLOWED_HOSTS': 'localhost 127.0.0.1 [::1] 192.168.100.2 192.168.100.2',
 'POSTGRES_DB': 'django_celery',
 'POSTGRES_PASSWORD': 'password1234-8',
 'POSTGRES_USER': 'celery_admin',
 'PYTHONDONTWRITEBYTECODE': True,
 'PYTHONUNBUFFERED': True,
 'RABBITMQ_DEFAULT_PASS': 'hackmeplease',
 'RABBITMQ_DEFAULT_USER': 'syslog',
 'RABBITMQ_HOST_DJANGO': 'rabbitmq',
 'RABBITMQ_MANAGEMENT': True,
 'RABBITMQ_PASSWORD_DJANGO': '123-8',
 'RABBITMQ_USERNAME_DJANGO': 'syslog',
 'SECRET_KEY': 'dbaa1_i7%*3r9-=z-+_mz4r-!qeed@(-a_r(g@k8jo8y3r27%m'}

In [10]: os.getenv('DEBUG_SERVER')
Out[10]: True

In [11]: config.DEBUG_SERVER = False

In [12]: os.getenv('DEBUG_SERVER')
Out[12]: False
from envdot import DotEnv

# Auto-detect and load from common config files (.env, config.json, etc.)
env = DotEnv()

# Or specify a file
env = DotEnv('.env')

# Get values with automatic type detection
db_host = env.get('DB_HOST')            # Returns string
# or
db_host = os.getenv('DB_HOST')          # Returns string

db_port = env.get('DB_PORT')            # Returns int (auto-detected)
# or
db_port = os.getenv('DB_PORT')         # Returns int (auto-detected)

debug_mode = env.get('DEBUG')           # Returns bool (auto-detected)
# or
debug_mode = os.getenv('DEBUG')        # Returns bool (auto-detected)

api_timeout = env.get('API_TIMEOUT')    # Returns float (auto-detected)
# or
api_timeout = os.getenv('API_TIMEOUT') # Returns float (auto-detected)

# Set values
env.set('NEW_KEY', 'value')
# or
env.setenv('NEW_KEY', 'value')

env.set('FEATURE_ENABLED', True)
# or
env.setenv('FEATURE_ENABLED', True)

# Save to file
env.save('.env')
# or
env.save()
# or
os.save_env()

Convenience Functions

from envdot import load_env, get_env, set_env, save_env

# Load configuration
load_env('.env')

# or just
load_env()

# Get values
database_url = get_env('DATABASE_URL')
max_connections = get_env('MAX_CONNECTIONS', default=100)

# Set values
set_env('NEW_FEATURE', True)

# Save changes
save_env('.env') # or just save_env()

Working with Different File Formats

.env File

env = DotEnv('.env')
env.load()

JSON File

env = DotEnv('config.json')
env.load()

YAML File

env = DotEnv('config.yaml')
env.load()  # Requires PyYAML

INI File

env = DotEnv('config.ini')
env.load()

Type Detection Examples

The package automatically detects and converts types:

# Given this .env file:
# DEBUG=true
# PORT=8080
# TIMEOUT=30.5
# APP_NAME=MyApp
# EMPTY_VALUE=

env = DotEnv('.env') # or load_env() or load_env('.env')

env.get('DEBUG')      # Returns: True (bool)
env.get('PORT')       # Returns: 8080 (int)
env.get('TIMEOUT')    # Returns: 30.5 (float)
env.get('APP_NAME')   # Returns: 'MyApp' (str)
env.get('EMPTY_VALUE') # Returns: None

# env.get same as os.getenv

Explicit Type Casting

# Force a specific type
version = env.get('VERSION', cast_type=str)
port = env.get('PORT', cast_type=int)
enabled = env.get('ENABLED', cast_type=bool)

Method Chaining

env = DotEnv('.env') \
    .load() \
    .set('NEW_KEY', 'value') \
    .set('ANOTHER_KEY', 123) \
    .save()

Dictionary-Style Access

env = DotEnv('.env')

# Get values
value = env['KEY_NAME']

# Set values
env['NEW_KEY'] = 'new value'

# Check existence
if 'API_KEY' in env:
    print("API key is configured")

# Get all variables
all_vars = env.all()

Advanced Features

Load Without Overriding

env.load(override=False)  # Keep existing values

Load Without Applying to OS Environment

env.load(apply_to_os=False)  # Don't set in os.environ

Save to Different Format

env = DotEnv('.env')
env.load()
env.save('config.json')  # Convert .env to JSON

Clear Variables

env.clear()  # Clear internal storage only
env.clear(clear_os=True)  # Also clear from os.environ

Delete Specific Keys

env.delete('OLD_KEY')
env.delete('TEMP_KEY', remove_from_os=True)

Type Detection Rules

The package uses the following rules for automatic type detection:

  • Boolean: true, yes, on, 1True | false, no, off, 0False
  • None: none, null, empty string → None
  • Integer: Numbers without decimal point → int
  • Float: Numbers with decimal point → float
  • String: Everything else → str

File Format Examples

.env

DEBUG=true
PORT=8080
DATABASE_URL=postgresql://localhost/mydb

.json

{
  "DEBUG": true,
  "PORT": 8080,
  "DATABASE_URL": "postgresql://localhost/mydb"
}

.yaml

DEBUG: true
PORT: 8080
DATABASE_URL: postgresql://localhost/mydb

.ini

[DEFAULT]
DEBUG = true
PORT = 8080
DATABASE_URL = postgresql://localhost/mydb

API Reference

DotEnv Class

__init__(filepath=None, auto_load=True)

Initialize DotEnv instance.

load(filepath=None, override=True, apply_to_os=True)

Load environment variables from file.

get(key, default=None, cast_type=None)

Get environment variable with automatic type detection.

set(key, value, apply_to_os=True)

Set environment variable.

save(filepath=None, format=None)

Save environment variables to file.

delete(key, remove_from_os=True)

Delete environment variable.

all()

Get all environment variables as dictionary.

keys()

Get all variable names.

clear(clear_os=False)

Clear all stored variables.

Convenience Functions

  • load_env(filepath=None, **kwargs) - Load environment variables
  • get_env(key, default=None, cast_type=None) - Get environment variable
  • set_env(key, value, **kwargs) - Set environment variable
  • save_env(filepath=None, **kwargs) - Save environment variables

License

MIT License

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Author

Hadi Cahyadi

Buy Me a Coffee

Donate via Ko-fi

Support me on Patreon

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

envdot-1.0.10.tar.gz (17.9 kB view details)

Uploaded Source

Built Distribution

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

envdot-1.0.10-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

Details for the file envdot-1.0.10.tar.gz.

File metadata

  • Download URL: envdot-1.0.10.tar.gz
  • Upload date:
  • Size: 17.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.4

File hashes

Hashes for envdot-1.0.10.tar.gz
Algorithm Hash digest
SHA256 fda9bb9304375abfacc265353e3d4beb2373f45753deb50cf378ffdf83ca040f
MD5 eaab5c88a8e7e1b90842dc493bb686ff
BLAKE2b-256 f16b0a3f1e490ce6c2dd942ea676f0d00d315ab9a354dcf8d5032cabea03f2f7

See more details on using hashes here.

File details

Details for the file envdot-1.0.10-py3-none-any.whl.

File metadata

  • Download URL: envdot-1.0.10-py3-none-any.whl
  • Upload date:
  • Size: 13.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.4

File hashes

Hashes for envdot-1.0.10-py3-none-any.whl
Algorithm Hash digest
SHA256 4006303e80ae435162a45f3bb1de3d07170975da823f8071b72b238ba344fa3b
MD5 a4f36a9cb879a3aea1a5e9faa798b7d5
BLAKE2b-256 2fc96156cd43d072342b8b071dd9446621aee2831d833b3438b69bc6402db81c

See more details on using hashes here.

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