Skip to main content

Peaceful, type-safe Python configuration with strict separation from code

Project description

๐Ÿง˜ DotZen

Peaceful, type-safe Python configuration that just works.

PyPI version Python Support License: MIT

codecov Documentation Status

Package Downloads

Code style: black

Documentation | PyPI Package | GitHub | Changelog


๐ŸŒŸ Overview

DotZen brings zen to Python configuration management. Load settings from environment variables, .env files, JSON, YAML, or cloud secret managers with automatic type casting, validation, and a beautiful fluent API.

No more config chaos. Just pure zen. ๐Ÿง˜โ€โ™‚๏ธโœจ

โœจ Key Highlights

from dotzen import config

# Simple, elegant, type-safe
DEBUG = config('DEBUG', cast=bool, default=False)
PORT = config('PORT', cast=int, default=8000)
DATABASE_URL = config('DATABASE_URL')
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=list)

Why Choose DotZen?

Traditional Config ๐Ÿ˜ซ DotZen โœจ
Scattered sources Multiple libraries needed Unified API One interface for all sources
String soup Manual type conversion everywhere Type Safety Automatic casting & validation
Runtime failures Errors only in production Early Validation Catch issues at startup
Copy-paste code Boilerplate in every project Design Patterns Elegant, reusable architecture
Hardcoded secrets Security nightmares Cloud-Native First-class secrets support

๐Ÿš€ Quick Start

Installation

# Core library (zero dependencies)
pip install dotzen

# With cloud provider support
pip install dotzen[aws]        # AWS Secrets Manager
pip install dotzen[gcp]        # Google Cloud Secret Manager
pip install dotzen[azure]      # Azure Key Vault
pip install dotzen[cloud]      # All cloud providers

# Everything included
pip install dotzen[all]

Basic Usage

from dotzen import config

# Get configuration values with automatic type casting
API_KEY = config('API_KEY')
DEBUG = config('DEBUG', cast=bool, default=False)
MAX_CONNECTIONS = config('MAX_CONNECTIONS', cast=int, default=100)
ALLOWED_ORIGINS = config('ALLOWED_ORIGINS', cast=list)

Advanced Usage with Builder Pattern

from dotzen import ConfigBuilder

# Build a configuration with multiple sources
config = (ConfigBuilder()
    .add_environment('APP_')        # Env vars with prefix
    .add_dotenv('.env')             # .env file
    .add_json('config.json')        # JSON config
    .add_secrets('/run/secrets')    # Docker secrets
    .build())

# Type-safe access with convenience methods
debug = config.get_bool('DEBUG', default=False)
port = config.get_int('PORT', default=8000)
timeout = config.get_float('TIMEOUT', default=30.0)
hosts = config.get_list('ALLOWED_HOSTS')

๐ŸŽฏ Features

๐Ÿ”„ Multi-Source Configuration

DotZen implements a Chain of Responsibility pattern, checking sources in priority order:

config = (ConfigBuilder()
    .add_environment()           # 1๏ธโƒฃ Highest priority
    .add_dotenv('.env')          # 2๏ธโƒฃ
    .add_json('config.json')     # 3๏ธโƒฃ
    .add_aws_secrets('prod')     # 4๏ธโƒฃ
    .build())                    # 5๏ธโƒฃ Default values (lowest priority)

๐Ÿ›ก๏ธ Type Safety & Automatic Casting

# Automatic type conversion with validation
DEBUG = config.get_bool('DEBUG')           # str โ†’ bool
PORT = config.get_int('PORT')              # str โ†’ int
RATE_LIMIT = config.get_float('RATE')     # str โ†’ float
SERVERS = config.get_list('SERVERS')       # str โ†’ list

# Boolean casting supports multiple formats
# True:  "true", "yes", "1", "on", "t", "y"
# False: "false", "no", "0", "off", "f", "n"

โœ… Built-in Validation

from dotzen import ConfigBuilder
from dotzen.validators import URLValidator, RangeValidator, RegexValidator

config = (ConfigBuilder()
    .add_environment()
    .with_validator(URLValidator('DATABASE_URL'))
    .with_validator(RangeValidator('PORT', 1024, 65535))
    .with_validator(RegexValidator('API_KEY', r'^[A-Za-z0-9]{32}$'))
    .build())

# Configuration is validated at build time
# Errors are caught before your app starts! ๐ŸŽ‰

๐ŸŒ Cloud Secrets Support

# AWS Secrets Manager
config = (ConfigBuilder()
    .add_environment()
    .add_aws_secrets('prod/myapp', region='us-east-1')
    .build())

# Google Cloud Secret Manager
config = (ConfigBuilder()
    .add_environment()
    .add_gcp_secrets('projects/my-project/secrets')
    .build())

# Azure Key Vault
config = (ConfigBuilder()
    .add_environment()
    .add_azure_keyvault('https://myvault.vault.azure.net')
    .build())

# HashiCorp Vault
config = (ConfigBuilder()
    .add_environment()
    .add_vault_secrets('secret/myapp', url='https://vault.example.com')
    .build())

๐ŸŽจ Fluent API Design

DotZen uses the Builder Pattern for an intuitive, chainable API:

config = (ConfigBuilder()
    .add_environment('MYAPP_')
    .add_dotenv('.env')
    .add_dotenv('.env.local', override=True)
    .add_json('config.json')
    .add_yaml('settings.yaml')
    .with_validator(URLValidator('DATABASE_URL'))
    .with_type('MAX_WORKERS', int)
    .build())

๐Ÿญ Auto-Detection Factory

Let DotZen automatically detect your configuration files:

from dotzen import ConfigFactory

# Automatically finds and loads:
# - .env
# - config.json
# - settings.json
config = ConfigFactory.auto_config()

๐Ÿ“š Real-World Examples

Django Settings

# settings.py
from dotzen import config

# Core settings
DEBUG = config('DEBUG', cast=bool, default=False)
SECRET_KEY = config('SECRET_KEY')
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=list, default=[])

# Database configuration
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': config('DB_NAME'),
        'USER': config('DB_USER'),
        'PASSWORD': config('DB_PASSWORD'),
        'HOST': config('DB_HOST', default='localhost'),
        'PORT': config('DB_PORT', cast=int, default=5432),
    }
}

# Email configuration
EMAIL_HOST = config('EMAIL_HOST', default='smtp.gmail.com')
EMAIL_PORT = config('EMAIL_PORT', cast=int, default=587)
EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool, default=True)
EMAIL_HOST_USER = config('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')

# Redis cache
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': config('REDIS_URL', default='redis://127.0.0.1:6379/1'),
    }
}

FastAPI Application

from fastapi import FastAPI, Depends
from dotzen import ConfigBuilder

# Build configuration at startup
config = (ConfigBuilder()
    .add_environment()
    .add_dotenv()
    .add_json('config.json')
    .build())

app = FastAPI(
    title=config('APP_NAME', default='My API'),
    debug=config.get_bool('DEBUG', default=False),
    version=config('VERSION', default='1.1.0'),
)

# Dependency injection
def get_database_url():
    return config('DATABASE_URL')

@app.get("/health")
async def health_check():
    return {
        "status": "healthy",
        "environment": config('ENVIRONMENT', default='development'),
        "version": config('VERSION', default='1.1.0'),
    }

@app.get("/config")
async def get_config_info():
    return {
        "debug_mode": config.get_bool('DEBUG', False),
        "max_connections": config.get_int('MAX_CONNECTIONS', 100),
        "timeout": config.get_float('TIMEOUT', 30.0),
    }

Flask Application

from flask import Flask
from dotzen import config

app = Flask(__name__)

# Configure Flask from DotZen
app.config['DEBUG'] = config('DEBUG', cast=bool, default=False)
app.config['SECRET_KEY'] = config('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = config('DATABASE_URL')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Custom settings
app.config['MAX_CONTENT_LENGTH'] = config('MAX_UPLOAD_SIZE', cast=int, default=16 * 1024 * 1024)
app.config['UPLOAD_FOLDER'] = config('UPLOAD_FOLDER', default='uploads')

@app.route('/config')
def show_config():
    return {
        'debug': app.config['DEBUG'],
        'environment': config('ENVIRONMENT', default='development'),
    }

Microservices with Docker Secrets

# docker-compose.yml provides secrets in /run/secrets/
from dotzen import ConfigBuilder

config = (ConfigBuilder()
    .add_environment()
    .add_secrets('/run/secrets')  # Docker secrets
    .add_dotenv('.env')
    .build())

# Access secrets seamlessly
DB_PASSWORD = config('db_password')
API_KEY = config('api_key')
JWT_SECRET = config('jwt_secret')

# Regular config
SERVICE_NAME = config('SERVICE_NAME', default='my-service')
PORT = config.get_int('PORT', default=8000)

Multi-Environment Configuration

import os
from dotzen import ConfigBuilder

# Determine environment
ENVIRONMENT = os.getenv('ENVIRONMENT', 'development')

# Load environment-specific configuration
config = (ConfigBuilder()
    .add_environment()
    .add_dotenv(f'.env.{ENVIRONMENT}')      # .env.development, .env.production
    .add_json(f'config.{ENVIRONMENT}.json')
    .add_dotenv('.env.local', override=True)  # Local overrides
    .build())

# Configuration adapts to environment automatically
DEBUG = config.get_bool('DEBUG')
DATABASE_URL = config('DATABASE_URL')
LOG_LEVEL = config('LOG_LEVEL', default='INFO')

Pydantic Integration

from pydantic import BaseModel, Field
from dotzen importfig

class DatabaseSettings(BaseModel):
    host: str = Field(default_factory=lambda: config('DB_HOST', default='localhost'))
    port: int = Field(default_factory=lambda: config('DB_PORT', cast=int, default=5432))
    user: str = Field(default_factory=lambda: config('DB_USER'))
    password: str = Field(default_factory=lambda: config('DB_PASSWORD'))
    database: str = Field(default_factory=lambda: config('DB_NAME'))

class AppSettings(BaseModel):
    debug: bool = Field(default_factory=lambda: config('DEBUG', cast=bool, default=False))
    secret_key: str = Field(default_factory=lambda: config('SECRET_KEY'))
    database: DatabaseSettings = Field(default_factory=DatabaseSettings)
    allowed_hosts: list = Field(default_factory=lambda: config('ALLOWED_HOSTS', cast=list, default=[]))

# Create settings instance
settings = AppSettings()

๐Ÿ—๏ธ Architecture & Design Patterns

DotZen is built on proven Gang of Four design patterns:

Design Patterns Used

Pattern Purpose Implementation
Strategy Pluggable config sources ConfigSource abstract base class
Chain of Responsibility Priority-based resolution ConfigChain tries sources in order
Builder Fluent construction ConfigBuilder for chainable API
Factory Auto-detection ConfigFactory.auto_config()
Singleton Global instance ConfigSingleton for app-wide access
Facade Simple interface Config class hides complexity
Null Object Graceful defaults NullSource for missing configs
Sentinel Undefined values UNDEFINED marker object

Architecture Diagram

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   ConfigBuilder                      โ”‚
โ”‚              (Builder Pattern)                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    โ”‚ builds
                    โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     Config                           โ”‚
โ”‚                (Facade Pattern)                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    โ”‚ uses
                    โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  ConfigChain                         โ”‚
โ”‚        (Chain of Responsibility Pattern)             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    โ”‚ coordinates
                    โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              ConfigSource (Strategy)                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ EnvironmentSource โ”‚ DotEnvSource โ”‚ JsonSourceโ”‚  โ”‚
โ”‚  โ”‚ YamlSource โ”‚ SecretSource โ”‚ AwsSecretsSource โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ†š Comparison with Alternatives

Feature Comparison Matrix

Feature DotZen python-decouple pydantic-settings dynaconf python-dotenv
Type Safety โœ… Full โš ๏ธ Basic โœ… Full โœ… Full โŒ None
Cloud Secrets โœ… Native โŒ No โš ๏ธ Limited โœ… Yes โŒ No
Fluent API โœ… Yes โŒ No โŒ No โš ๏ธ Limited โŒ No
Validation โœ… Built-in โš ๏ธ Basic โœ… Pydantic โœ… Yes โŒ No
Multi-Source โœ… Yes โš ๏ธ Limited โš ๏ธ Limited โœ… Yes โŒ Env only
Zero Core Deps โœ… Yes โœ… Yes โŒ No โŒ No โœ… Yes
Design Patterns โœ… 8 patterns โŒ None โš ๏ธ Some โš ๏ธ Some โŒ None
Docker Secrets โœ… Native โŒ No โŒ No โŒ No โŒ No
Auto-Detection โœ… Yes โŒ No โš ๏ธ Limited โœ… Yes โŒ No
Custom Sources โœ… Easy โŒ No โš ๏ธ Complex โš ๏ธ Complex โŒ No

When to Use DotZen

Perfect for:

  • ๐Ÿš€ Modern cloud-native applications
  • ๐Ÿข Microservices architectures
  • ๐Ÿ“ฆ 12-factor app compliance
  • ๐Ÿ” Applications requiring cloud secrets
  • ๐Ÿ‘ฅ Teams valuing clean, maintainable code
  • ๐ŸŽฏ Projects needing validated configuration

Consider alternatives if:

  • You only need basic .env file parsing โ†’ python-dotenv
  • You're heavily invested in Pydantic โ†’ pydantic-settings
  • You need legacy Python 2.7 support โ†’ python-decouple

๐Ÿ“– Documentation

Core Concepts

Configuration Sources

from dotzen import ConfigBuilder

# Available sources
builder = ConfigBuilder()
builder.add_environment()              # Environment variables
builder.add_environment('APP_')        # With prefix
builder.add_dotenv('.env')             # .env file
builder.add_json('config.json')        # JSON file
builder.add_yaml('config.yaml')        # YAML file (requires dotzen[yaml])
builder.add_toml('config.toml')        # TOML file (requires dotzen[toml])
builder.add_secrets('/run/secrets')    # Docker secrets
builder.add_aws_secrets('prod/myapp')  # AWS Secrets Manager
builder.add_gcp_secrets('projects/x')  # GCP Secret Manager
builder.add_azure_keyvault('url')      # Azure Key Vault
builder.add_vault_secrets('path')      # HashiCorp Vault

Type Casting

# Automatic casting
value = config.get('KEY', cast=int)
value = config.get('KEY', cast=bool)
value = config.get('KEY', cast=float)
value = config.get('KEY', cast=list)

# Convenience methods
value = config.get_int('KEY', default=0)
value = config.get_bool('KEY', default=False)
value = config.get_float('KEY', default=0.0)
value = config.get_list('KEY', default=[])

# Custom casting
def parse_json(value):
    import json
    return json.loads(value)

value = config.get('JSON_DATA', cast=parse_json)

Error Handling

from dotzen import UndefinedValueError, ValidationError, ConfigError

try:
    api_key = config('API_KEY')
except UndefinedValueError:
    print("API_KEY not found in configuration")

try:
    port = config.get_int('PORT')
except ValidationError as e:
    print(f"Invalid PORT value: {e}")

# Or use defaults
api_key = config('API_KEY', default='dev-key')
port = config.get_int('PORT', default=8000)

Advanced Usage

Custom Configuration Sources

from dotzen import ConfigSource

class RedisSource(ConfigSource):
    """Load configuration from Redis"""
    
    def __init__(self, redis_client, prefix='config:'):
        self.redis = redis_client
        self.prefix = prefix
    
    def load(self) -> Dict[str, str]:
        keys = self.redis.keys(f'{self.prefix}*')
        data = {}
        for key in keys:
            clean_key = key.decode().replace(self.prefix, '')
            data[clean_key] = self.redis.get(key).decode()
        return data
    
    def exists(self) -> bool:
        return self.redis.ping()

# Use custom source
import redis
redis_client = redis.Redis(host='localhost', port=6379)

config = (ConfigBuilder()
    .add_custom_source(RedisSource(redis_client))
    .build())

Custom Validators

from dotzen import ConfigBuilder, ValidationError

def email_validator(key: str, value: str):
    """Validate email format"""
    if '@' not in value:
        raise ValidationError(f"{key} must be a valid email")

def port_validator(key: str, value: int):
    """Validate port number"""
    if not (1024 <= value <= 65535):
        raise ValidationError(f"{key} must be between 1024 and 65535")

config = (ConfigBuilder()
    .add_environment()
    .with_validator(email_validator)
    .with_type('PORT', int)
    .with_validator(port_validator)
    .build())

Testing Configuration

import pytest
from dotzen import ConfigBuilder, ConfigSingleton

def test_config():
    """Test configuration loading"""
    # Reset singleton for testing
    ConfigSingleton.reset()
    
    # Create test config
    config = (ConfigBuilder()
        .add_environment()
        .build())
    
    # Test values
    assert config.get_bool('DEBUG', False) == False
    assert config.get_int('PORT', 8000) == 8000

@pytest.fixture
def test_config():
    """Fixture providing test configuration"""
    ConfigSingleton.reset()
    return (ConfigBuilder()
        .add_dotenv('.env.test')
        .build())

๐Ÿ”ง Installation Extras

Available Extras

# Cloud providers
pip install dotzen[aws]        # AWS Secrets Manager (boto3)
pip install dotzen[gcp]        # Google Cloud Secret Manager
pip install dotzen[azure]      # Azure Key Vault
pip install dotzen[vault]      # HashiCorp Vault
pip install dotzen[cloud]      # All cloud providers

# File formats
pip install dotzen[yaml]       # YAML support (PyYAML)
pip install dotzen[toml]       # TOML support
pip install dotzen[json5]      # JSON5 support
pip install dotzen[formats]    # All formats

# Development
pip install dotzen[dev]        # Testing and dev tools
pip install dotzen[docs]       # Documentation building
pip install dotzen[test]       # Testing with cloud mocks

# Everything
pip install dotzen[all]        # All features

๐Ÿค Contributing

We welcome contributions! Here's how to get started:

Development Setup

# Clone the repository
git clone https://github.com/carrington-dev/dotzen.git
cd dotzen

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install development dependencies
pip install -e ".[dev,test,all]"

# Install pre-commit hooks
pre-commit install

# Run tests
pytest

# Run type checking
mypy dotzen

# Format code
black dotzen tests
ruff check dotzen tests

Running Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=dotzen --cov-report=html

# Run specific test file
pytest tests/test_dotzen.py

# Run with verbose output
pytest -v

# Run only fast tests (skip cloud integration)
pytest -m "not integration"

Pull Request Process

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Format code (black . and ruff check --fix .)
  7. Commit your changes (git commit -m 'Add amazing feature')
  8. Push to the branch (git push origin feature/amazing-feature)
  9. Open a Pull Request

Please use our PR templates for:


๐Ÿ“ License

DotZen is released under the MIT License. See LICENSE for details.

MIT License

Copyright (c) 2025 Carrington Muleya

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

๐Ÿ™ Acknowledgments


๐Ÿ“Š Project Stats

GitHub stars GitHub forks GitHub watchers GitHub contributors GitHub last commit GitHub issues GitHub pull requests


๐Ÿ”— Links & Resources


๐Ÿ’ฌ Community & Support


Made with ๐Ÿง˜ and โค๏ธ by Carrington Muleya

Find your configuration zen. Try DotZen today!

โฌ† Back to Top

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

dotzen-1.1.0.tar.gz (39.2 kB view details)

Uploaded Source

Built Distribution

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

dotzen-1.1.0-py3-none-any.whl (18.4 kB view details)

Uploaded Python 3

File details

Details for the file dotzen-1.1.0.tar.gz.

File metadata

  • Download URL: dotzen-1.1.0.tar.gz
  • Upload date:
  • Size: 39.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.19

File hashes

Hashes for dotzen-1.1.0.tar.gz
Algorithm Hash digest
SHA256 ff49dfb969c9ff91231982feb6117e859cd17187e2d5f6a50960d69bce030c0d
MD5 4b99419ba89c62214957ef1e53fb7094
BLAKE2b-256 9018ecc3e188a23480ec48241023cc4d0037de3ae56bebaa9ddf2cdba81f9457

See more details on using hashes here.

File details

Details for the file dotzen-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: dotzen-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.19

File hashes

Hashes for dotzen-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5c0d175c810eaa6c4e45930b4e6e9b2cab83e1d8b0ba7852b025fcf37bcf3bad
MD5 6b7675d41e7b7f5d08cc490a9511a0ad
BLAKE2b-256 486325b65e2db1e1783c17ea53548171789b8d9637677331735ba8e4a4a0c4e2

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