Modern, extensible Python project management tool with comprehensive environment and build system support
—
Hierarchical configuration system with lazy loading, environment variable support, and file-based persistence. Manages application settings, project configuration, and plugin configuration.
File-based configuration management with support for reading, writing, validation, and default configuration restoration.
class ConfigFile:
"""
Configuration file manager for hatch settings.
Handles reading, writing, and managing the hatch configuration file
with support for default configuration restoration and validation.
"""
def __init__(self, path: Path | None = None):
"""
Initialize configuration file manager.
Args:
path (Path, optional): Path to configuration file.
If None, uses default location.
"""
@property
def path(self) -> Path:
"""
Path to the configuration file.
Returns:
Path object pointing to configuration file
"""
def save(self, content: str | None = None) -> None:
"""
Save configuration content to file.
Args:
content (str, optional): Configuration content to save.
If None, saves current configuration.
"""
def load(self) -> dict:
"""
Load configuration from file.
Returns:
Dict containing configuration data
Raises:
OSError: If file cannot be read
"""
def read(self) -> str:
"""
Read raw configuration file content.
Returns:
Raw configuration file content as string
"""
def read_scrubbed(self) -> str:
"""
Read configuration content with sensitive data removed.
Removes passwords, tokens, and other sensitive information
for safe display or logging.
Returns:
Scrubbed configuration content
"""
def restore(self) -> None:
"""
Restore default configuration.
Creates a new configuration file with default settings,
overwriting any existing configuration.
"""
@classmethod
def get_default_location(cls) -> Path:
"""
Get default configuration file location.
Returns:
Path to default configuration file location
"""Main configuration object providing access to all hatch settings with lazy loading and validation.
class RootConfig:
"""
Root configuration object with lazy field parsing.
Provides access to all hatch configuration sections including
directories, projects, publishing, templates, and terminal settings.
"""
@property
def mode(self) -> str:
"""
Configuration mode determining project resolution behavior.
Values:
- 'aware': Use configured project if no local project found
- 'local': Always use current directory
- 'project': Always use configured project
Returns:
Configuration mode string
"""
@property
def project(self) -> str | None:
"""
Default project name for project and aware modes.
Returns:
Project name or None if not configured
"""
@property
def shell(self) -> str:
"""
Default shell for environment activation and commands.
Returns:
Shell name or path
"""
@property
def dirs(self):
"""
Directory configuration for data and cache locations.
Returns:
DirectoryConfig object with data and cache directory paths
"""
@property
def projects(self) -> dict[str, str]:
"""
Configured projects mapping names to paths.
Returns:
Dict mapping project names to directory paths
"""
@property
def publish(self):
"""
Publishing configuration for package indices and authentication.
Returns:
PublishConfig object with index and authentication settings
"""
@property
def template(self):
"""
Template configuration for project initialization.
Returns:
TemplateConfig object with template settings and defaults
"""
@property
def terminal(self):
"""
Terminal configuration for output formatting and styles.
Returns:
TerminalConfig object with styling and display settings
"""Configuration for data storage, cache, and temporary file locations with platform-appropriate defaults.
class DirectoryConfig:
"""Configuration for hatch directories."""
@property
def data(self) -> str:
"""
Data directory for persistent hatch data.
Returns:
Path to data directory
"""
@property
def cache(self) -> str:
"""
Cache directory for temporary and cached data.
Returns:
Path to cache directory
"""
def expand_path(self, path: str) -> Path:
"""
Expand path with environment variables and user home.
Args:
path (str): Path to expand
Returns:
Expanded Path object
"""Configuration for package publishing including index URLs, authentication, and publishing options.
class PublishConfig:
"""Configuration for package publishing."""
@property
def index(self) -> str:
"""
Default package index URL.
Returns:
Package index URL (defaults to PyPI)
"""
@property
def username(self) -> str | None:
"""
Default username for package index authentication.
Returns:
Username or None if not configured
"""
@property
def repositories(self) -> dict[str, dict]:
"""
Configured package repositories.
Returns:
Dict mapping repository names to configuration dicts
"""
def get_repository_config(self, name: str) -> dict:
"""
Get configuration for named repository.
Args:
name (str): Repository name
Returns:
Repository configuration dict
"""Configuration for project templates including default values and template-specific settings.
class TemplateConfig:
"""Configuration for project templates."""
@property
def name(self) -> str:
"""
Default template name for project creation.
Returns:
Template name
"""
@property
def author(self) -> str | None:
"""
Default author name for new projects.
Returns:
Author name or None if not configured
"""
@property
def email(self) -> str | None:
"""
Default author email for new projects.
Returns:
Author email or None if not configured
"""
@property
def license(self) -> str:
"""
Default license for new projects.
Returns:
License identifier (defaults to 'MIT')
"""
@property
def plugins(self) -> dict[str, dict]:
"""
Template plugin configurations.
Returns:
Dict mapping template plugin names to configurations
"""Configuration for terminal output including colors, styles, and formatting options.
class TerminalConfig:
"""Configuration for terminal output."""
@property
def styles(self):
"""
Terminal styling configuration.
Returns:
StyleConfig object with color and formatting settings
"""
@property
def shell(self) -> str:
"""
Preferred shell for terminal operations.
Returns:
Shell name or path
"""Configuration system integration with environment variables for overriding settings and providing defaults.
class AppEnvVars:
"""Application environment variable names."""
ENV: str = 'HATCH_ENV' # Default environment name
ENV_ACTIVE: str = 'HATCH_ENV_ACTIVE' # Currently active environment
QUIET: str = 'HATCH_QUIET' # Quiet mode setting
VERBOSE: str = 'HATCH_VERBOSE' # Verbose mode setting
INTERACTIVE: str = 'HATCH_INTERACTIVE' # Interactive mode setting
PYTHON: str = 'HATCH_PYTHON' # Python executable path
NO_COLOR: str = 'NO_COLOR' # Disable colored output
FORCE_COLOR: str = 'FORCE_COLOR' # Force colored output
class ConfigEnvVars:
"""Configuration environment variable names."""
PROJECT: str = 'HATCH_PROJECT' # Project name override
DATA: str = 'HATCH_DATA_DIR' # Data directory path
CACHE: str = 'HATCH_CACHE_DIR' # Cache directory path
CONFIG: str = 'HATCH_CONFIG' # Configuration file path
class PublishEnvVars:
"""Publishing environment variable names."""
USER: str = 'HATCH_INDEX_USER' # Package index username
AUTH: str = 'HATCH_INDEX_AUTH' # Package index authentication
REPO: str = 'HATCH_INDEX_REPO' # Package index repository URL
CA_CERT: str = 'HATCH_INDEX_CA_CERT' # CA certificate path
CLIENT_CERT: str = 'HATCH_INDEX_CLIENT_CERT' # Client certificate path
CLIENT_KEY: str = 'HATCH_INDEX_CLIENT_KEY' # Client key pathUtilities for validating configuration structure, values, and consistency across different configuration sections.
def validate_config(config: dict) -> list[str]:
"""
Validate configuration structure and values.
Args:
config (dict): Configuration to validate
Returns:
List of validation errors (empty if valid)
"""
def validate_directory_config(dirs: dict) -> list[str]:
"""
Validate directory configuration.
Args:
dirs (dict): Directory configuration section
Returns:
List of validation errors
"""
def validate_publish_config(publish: dict) -> list[str]:
"""
Validate publishing configuration.
Args:
publish (dict): Publishing configuration section
Returns:
List of validation errors
"""
def validate_project_references(config: dict) -> list[str]:
"""
Validate project references in configuration.
Args:
config (dict): Full configuration
Returns:
List of validation errors for project references
"""Helper functions for configuration management including merging, path resolution, and default value handling.
def merge_configs(base: dict, override: dict) -> dict:
"""
Merge configuration dictionaries with override precedence.
Args:
base (dict): Base configuration
override (dict): Override configuration
Returns:
Merged configuration dict
"""
def resolve_config_path(path: str, config_dir: Path) -> Path:
"""
Resolve configuration path relative to config directory.
Args:
path (str): Path to resolve (may be relative or absolute)
config_dir (Path): Configuration directory for relative paths
Returns:
Resolved absolute Path
"""
def get_default_config() -> dict:
"""
Get default configuration structure.
Returns:
Dict with default configuration values
"""
def expand_env_vars(config: dict) -> dict:
"""
Expand environment variables in configuration values.
Args:
config (dict): Configuration with potential env var references
Returns:
Configuration with expanded environment variables
"""from hatch.config.user import ConfigFile
from hatch.config.model import RootConfig
# Load configuration
config_file = ConfigFile()
config_data = config_file.load()
config = RootConfig(config_data)
# Access configuration values
print(f"Mode: {config.mode}")
print(f"Data directory: {config.dirs.data}")
print(f"Cache directory: {config.dirs.cache}")
# Access project configuration
if config.project:
print(f"Default project: {config.project}")
# Access publishing configuration
print(f"Default index: {config.publish.index}")
repositories = config.publish.repositories
for name, repo_config in repositories.items():
print(f"Repository {name}: {repo_config.get('url')}")from hatch.config.user import ConfigFile
from pathlib import Path
# Create config file manager
config_file = ConfigFile()
# Check if config exists
if not config_file.path.exists():
print("Creating default configuration...")
config_file.restore()
# Read configuration
config_data = config_file.load()
print(f"Loaded config from: {config_file.path}")
# Read scrubbed version (safe for logging)
scrubbed_content = config_file.read_scrubbed()
print("Scrubbed configuration:")
print(scrubbed_content)
# Custom config file location
custom_config = ConfigFile(Path("./custom-config.toml"))
if custom_config.path.exists():
custom_data = custom_config.load()from hatch.config.constants import AppEnvVars, ConfigEnvVars
import os
# Set environment variables
os.environ[AppEnvVars.VERBOSE] = '2'
os.environ[AppEnvVars.ENV] = 'test'
os.environ[ConfigEnvVars.DATA] = '/custom/data/path'
# Configuration will automatically use these values
config_file = ConfigFile()
config_data = config_file.load()
config = RootConfig(config_data)
# Environment variables override configuration file values
print(f"Data directory: {config.dirs.data}") # Uses env var valuefrom hatch.config import validate_config, validate_publish_config
# Validate full configuration
config_data = config_file.load()
errors = validate_config(config_data)
if errors:
print("Configuration errors:")
for error in errors:
print(f" - {error}")
# Validate specific sections
publish_config = config_data.get('publish', {})
publish_errors = validate_publish_config(publish_config)
if publish_errors:
print("Publishing configuration errors:")
for error in publish_errors:
print(f" - {error}")from hatch.config.user import ConfigFile
from hatch.config import get_default_config, merge_configs
# Start with default configuration
config_data = get_default_config()
# Add custom settings
custom_settings = {
'mode': 'project',
'project': 'my-main-project',
'dirs': {
'data': '~/.local/share/hatch',
'cache': '~/.cache/hatch'
},
'publish': {
'index': 'https://my-private-index.com/simple/',
'username': 'myuser'
},
'template': {
'author': 'My Name',
'email': 'my@email.com',
'license': 'Apache-2.0'
}
}
# Merge configurations
final_config = merge_configs(config_data, custom_settings)
# Save configuration
config_file = ConfigFile()
import toml
config_file.save(toml.dumps(final_config))from hatch.config.model import RootConfig
# Configuration with project-specific settings
config_data = {
'mode': 'aware',
'projects': {
'web-app': '/path/to/web-app',
'api-service': '/path/to/api-service',
'shared-lib': '/path/to/shared-lib'
},
'project': 'web-app' # Default project
}
config = RootConfig(config_data)
# Access project paths
projects = config.projects
for name, path in projects.items():
print(f"Project {name}: {path}")
# Get default project
default_project = config.project
print(f"Default project: {default_project}")Install with Tessl CLI
npx tessl i tessl/pypi-hatch