Pythonic task execution library for managing shell-oriented subprocesses and organizing executable Python code into CLI-invokable tasks
Overall
score
96%
Invoke provides a sophisticated multi-source configuration system that supports files, environment variables, command-line arguments, and Python dictionaries with hierarchical merging and attribute-style access.
Main configuration management system with multi-source loading and hierarchical merging.
class Config:
"""
Configuration management with multi-source loading and merging.
Supports loading from:
- Default values
- System configuration files
- User configuration files
- Project configuration files
- Environment variables
- Runtime overrides
- Collection-specific configuration
Attributes:
- _defaults (dict): Default configuration values
- _overrides (dict): Runtime override values
- _system (dict): System-level configuration
- _user (dict): User-level configuration
- _project (dict): Project-level configuration
- _runtime (dict): Runtime configuration
- _collection (dict): Collection-specific configuration
- _env (dict): Environment variable configuration
"""
def __init__(self, defaults=None, overrides=None, lazy=False, runtime_path=None, system_prefix=None, user_prefix=None, project_location=None, env_prefix=None, file_prefix=None):
"""
Initialize Config object.
Parameters:
- defaults (dict, optional): Default configuration values
- overrides (dict, optional): Runtime override values
- lazy (bool): Whether to defer configuration loading
- runtime_path (str, optional): Runtime configuration file path
- system_prefix (str, optional): System config file prefix
- user_prefix (str, optional): User config file prefix
- project_location (str, optional): Project root directory
- env_prefix (str, optional): Environment variable prefix
- file_prefix (str, optional): Configuration file prefix
"""
@classmethod
def global_defaults(cls):
"""
Get global default configuration values.
Returns:
dict: Global default configuration
"""
def load_defaults(self, merge=True):
"""
Load default configuration values.
Parameters:
- merge (bool): Whether to merge with existing configuration
Returns:
Config: Self for method chaining
"""
def load_overrides(self, merge=True):
"""
Load runtime override configuration.
Parameters:
- merge (bool): Whether to merge with existing configuration
Returns:
Config: Self for method chaining
"""
def load_system(self, merge=True):
"""
Load system-level configuration files.
Parameters:
- merge (bool): Whether to merge with existing configuration
Returns:
Config: Self for method chaining
"""
def load_user(self, merge=True):
"""
Load user-level configuration files.
Parameters:
- merge (bool): Whether to merge with existing configuration
Returns:
Config: Self for method chaining
"""
def load_project(self, merge=True):
"""
Load project-level configuration files.
Parameters:
- merge (bool): Whether to merge with existing configuration
Returns:
Config: Self for method chaining
"""
def load_runtime(self, merge=True):
"""
Load runtime configuration file.
Parameters:
- merge (bool): Whether to merge with existing configuration
Returns:
Config: Self for method chaining
"""
def load_shell_env(self, merge=True):
"""
Load configuration from environment variables.
Parameters:
- merge (bool): Whether to merge with existing configuration
Returns:
Config: Self for method chaining
"""
def load_collection(self, collection, merge=True):
"""
Load collection-specific configuration.
Parameters:
- collection (Collection): Task collection
- merge (bool): Whether to merge with existing configuration
Returns:
Config: Self for method chaining
"""
def set_project_location(self, path):
"""
Set project root directory for configuration files.
Parameters:
- path (str): Project root directory path
"""
def set_runtime_path(self, path):
"""
Set runtime configuration file path.
Parameters:
- path (str): Runtime configuration file path
"""
def merge(self, *dicts):
"""
Merge configuration dictionaries hierarchically.
Parameters:
- *dicts: Configuration dictionaries to merge
Returns:
Config: New merged configuration
"""
def clone(self, into=None):
"""
Create a copy of this configuration.
Parameters:
- into (type, optional): Class to clone into
Returns:
Config: Cloned configuration object
"""Base class providing nested dictionary access with attribute-style syntax.
class DataProxy:
"""
Nested dictionary with attribute-style access.
Provides both dict-style (obj['key']) and attribute-style (obj.key)
access to nested configuration data.
"""
@classmethod
def from_data(cls, data):
"""
Create DataProxy from dictionary data.
Parameters:
- data (dict): Dictionary data to wrap
Returns:
DataProxy: Proxy object for the data
"""
def __getitem__(self, key):
"""Get item using dict-style access."""
def __setitem__(self, key, value):
"""Set item using dict-style access."""
def __delitem__(self, key):
"""Delete item using dict-style access."""
def __contains__(self, key):
"""Test membership using 'in' operator."""
def __iter__(self):
"""Iterate over keys."""
def __len__(self):
"""Get number of top-level keys."""
def __getattr__(self, key):
"""Get item using attribute-style access."""
def __setattr__(self, key, value):
"""Set item using attribute-style access."""
def get(self, key, default=None):
"""Get item with default value."""
def pop(self, key, *args):
"""Remove and return item."""
def popitem(self):
"""Remove and return arbitrary item."""
def clear(self):
"""Remove all items."""
def update(self, other):
"""Update with items from another mapping."""
def keys(self):
"""Get view of keys."""
def values(self):
"""Get view of values."""
def items(self):
"""Get view of key-value pairs."""Helper functions for configuration manipulation.
def merge_dicts(base, updates):
"""
Recursively merge configuration dictionaries.
Parameters:
- base (dict): Base configuration dictionary
- updates (dict): Updates to apply
Returns:
dict: Merged configuration dictionary
"""
def copy_dict(source):
"""
Deep copy a configuration dictionary.
Parameters:
- source (dict): Dictionary to copy
Returns:
dict: Deep copy of source dictionary
"""
def excise(dict_, keypath):
"""
Remove nested key from dictionary.
Parameters:
- dict_ (dict): Dictionary to modify
- keypath (str): Dot-separated key path (e.g., 'section.subsection.key')
Returns:
any: Removed value
"""
def obliterate(base, deletions):
"""
Remove multiple nested keys from dictionary.
Parameters:
- base (dict): Dictionary to modify
- deletions (list): List of dot-separated key paths to remove
Returns:
dict: Modified dictionary
"""from invoke import Config
# Create configuration with defaults
config = Config({
'run': {
'echo': True,
'pty': False
},
'sudo': {
'password': None
}
})
# Access configuration values
print(config.run.echo) # True
print(config['run']['pty']) # False
# Modify configuration
config.run.timeout = 30
config['sudo']['password'] = 'secret'from invoke import Config
# Load from all default sources
config = Config()
config.load_defaults()
config.load_system() # /etc/invoke.yaml
config.load_user() # ~/.invoke.yaml
config.load_project() # ./invoke.yaml
config.load_shell_env() # Environment variables
# Check final configuration
print(f"Echo enabled: {config.run.echo}")Create configuration files in YAML or JSON format:
invoke.yaml:
run:
echo: true
pty: false
warn: false
sudo:
password: null
prompt_for_password: true
tasks:
auto_dash_names: true
collection_name: 'tasks'invoke.json:
{
"run": {
"echo": true,
"pty": false,
"shell": "/bin/bash"
},
"sudo": {
"password": null
}
}import os
from invoke import Config
# Set environment variables (prefix with INVOKE_)
os.environ['INVOKE_RUN_ECHO'] = 'false'
os.environ['INVOKE_RUN_PTY'] = 'true'
os.environ['INVOKE_SUDO_PASSWORD'] = 'mypassword'
# Load configuration including environment
config = Config()
config.load_defaults()
config.load_shell_env()
print(config.run.echo) # False (from env var)
print(config.run.pty) # True (from env var)from invoke import Config, merge_dicts
# Base configuration
base_config = Config({
'run': {'echo': True, 'pty': False},
'sudo': {'password': None}
})
# Override configuration
overrides = {
'run': {'pty': True, 'timeout': 30},
'new_section': {'enabled': True}
}
# Merge configurations
merged = base_config.merge(overrides)
print(merged.run.echo) # True (from base)
print(merged.run.pty) # True (from override)
print(merged.run.timeout) # 30 (from override)
# Clone configuration
cloned = base_config.clone()
cloned.run.echo = False
print(base_config.run.echo) # True (original unchanged)
print(cloned.run.echo) # False (clone modified)from invoke import Context, Config
# Create custom configuration
config = Config({
'run': {
'echo': True,
'pty': True,
'shell': '/bin/zsh'
}
})
# Use with context
ctx = Context(config=config)
result = ctx.run("echo 'Hello World'") # Uses custom configfrom invoke import task, Context
@task
def deploy(ctx, env='staging'):
"""Deploy with environment-specific configuration."""
# Access configuration for current environment
db_host = ctx.config.environments[env].database.host
api_key = ctx.config.environments[env].api_key
ctx.run(f"deploy.sh --host {db_host} --key {api_key}")
# Configuration file (invoke.yaml):
# environments:
# staging:
# database:
# host: staging-db.example.com
# api_key: staging-key
# production:
# database:
# host: prod-db.example.com
# api_key: prod-keyfrom invoke import Config
from invoke.exceptions import UncastableEnvVar, AmbiguousEnvVar
try:
config = Config()
config.load_shell_env()
except UncastableEnvVar as e:
print(f"Invalid environment variable: {e}")
except AmbiguousEnvVar as e:
print(f"Ambiguous environment variable: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-invokedocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10