Overview
The configuration system is the core feature of pyrig that automatically generates and maintains your entire project structure. When you runpyrig mkroot or pyrig init, pyrig discovers all ConfigFile subclasses across your project and its dependencies, then creates or updates every configuration file your project needs.
The config system is declarative and idempotent - you define what configuration should exist, and pyrig ensures it does, preserving your customizations.
How It Works
ConfigFile Base Class
All configuration files are defined as Python classes inheriting fromConfigFile. Each subclass specifies:
- Where the file should be located (
parent_path()) - What content it should contain (
_configs()) - How to read and write it (
_load()and_dump())
Automatic Discovery
ConfigFile subclasses are automatically discovered across all packages in your dependency chain:Validation Process
When a ConfigFile is validated, it follows this workflow:Correctness Criteria
A config file is considered correct if:- Empty file - User opted out (file exists but has 0 bytes)
- Superset validation - Actual config contains all expected keys and values
Intelligent Merging
When configurations are missing or incorrect, pyrig merges them intelligently:Dictionary Merging Rules
Dictionary Merging Rules
- Missing keys are added with expected values
- Incorrect values are overwritten with expected values from
_configs() - Extra keys added by users are preserved
- Nested dicts are merged recursively
List Merging Rules
List Merging Rules
- Missing items are inserted at the correct index
- Extra items are preserved
- Order matters - lists are validated by index
Priority-Based Validation
Config files can specify validation priority to handle dependencies:| Priority | Value | Config Files | Reason |
|---|---|---|---|
| HIGH | 30 | LICENSE | Must exist before pyproject.toml |
| MEDIUM | 20 | pyproject.toml | Many configs read from this |
| LOW | 10 | init.py files | Create package structure first |
| DEFAULT | 0 | Most configs | No specific order required |
Files within the same priority group are validated in parallel using ThreadPoolExecutor for performance. Priority groups are processed sequentially.
Format-Specific Subclasses
Pyrig provides specialized base classes for common file formats:YamlConfigFile
config/my_config.yaml.
TomlConfigFile
my_config.toml with formatted output.
JsonConfigFile
config/my_config.json.
PythonConfigFile
myapp/src/my_config.py.
See all format-specific subclasses
See all format-specific subclasses
- DictConfigFile - Base for dict-based configs
- ListConfigFile - Base for list-based configs (e.g., .gitignore)
- StringConfigFile - Plain text files
- WorkflowConfigFile - GitHub Actions workflows
- MarkdownConfigFile - Markdown files
- InitConfigFile -
__init__.pyfiles with docstrings - CopyModuleConfigFile - Copy entire modules from dependencies
Caching System
Bothload() and configs() use @functools.cache for performance:
dump() is called.
Filename Derivation
Filenames are automatically derived from class names:| Class Name | Filename |
|---|---|
MyConfigFile | my_config |
PyprojectConfigFile | pyproject |
DotEnvConfigFile | dot_env |
GitignoreConfigFile | gitignore |
- Removes abstract parent class suffixes (
ConfigFile,YamlConfigFile, etc.) - Converts to snake_case
- Adds the file extension
filename() for custom names:
Opt-Out Mechanism
Users can opt out of any config file by emptying it:Deleting a file will cause it to be recreated. Emptying it is the only way to opt out.
Accessing Config Files with .I
Use the .I class property to access an instance of any ConfigFile:
.I pattern.
Best Practices
1. Inherit from format-specific classes
1. Inherit from format-specific classes
Use
YamlConfigFile, TomlConfigFile, etc. instead of implementing _load() and _dump() yourself.2. Keep configs minimal
2. Keep configs minimal
Only specify required values. The validation system checks for supersets, so users can add extra configuration.
3. Use priority for dependencies
3. Use priority for dependencies
If your config reads from another config file, use priority to ensure correct ordering.
4. Document expected structure
4. Document expected structure
Use docstrings and type hints to document your config structure.
5. Never mutate cached results
5. Never mutate cached results
Always create new structures instead of modifying results from
load() or configs().Related Concepts
CLI System
How pyrig discovers and registers CLI commands
Multi-Package Inheritance
The
.I and .L pattern for cross-package discoveryResources
Managing static files in your project
Config Architecture
Deep dive into the config system design