Configuration Integration Design¶
This document specifies the integration between python-linter’s TOML-based configuration system and the emcd-appcore package’s configuration management infrastructure.
Design Overview¶
The configuration integration bridges python-linter’s project-specific TOML configuration requirements with emcd-appcore’s standardized configuration infrastructure, providing a unified configuration hierarchy while maintaining compatibility with both systems.
Integration Goals:
Preserve ADR-003 layered precedence model
Use simple functions for pyproject.toml discovery and loading
Leverage emcd-appcore’s standard preparation and configuration merging
Support Tyro dataclass-based CLI command integration
Enable command-line configuration overrides through dataclass attributes
Maintain zero-configuration operation with sensible defaults
Configuration Architecture¶
Configuration Sources Integration¶
The integration maintains ADR-003’s precedence hierarchy while adapting to emcd-appcore’s TomlAcquirer system:
┌─────────────────────┐
│ CLI Arguments │ ◄─── Highest precedence
│ (runtime overrides) │
└─────────────────────┘
│
┌─────────────────────┐
│ pyproject.toml │ ◄─── Project configuration
│ [tool.vibelinter] │
└─────────────────────┘
│
┌─────────────────────┐
│ emcd-appcore │ ◄─── Base application infrastructure
│ Built-in Defaults │
└─────────────────────┘
Configuration Flow:
Base Configuration: emcd-appcore provides application infrastructure configuration
Project Configuration: TomlAcquirer loads pyproject.toml [tool.vibelinter] sections
CLI Overrides: Command-line arguments override project configuration through configedits
Interface Specifications¶
Configuration Discovery and Loading¶
def discover_pyproject_toml(
start_path: __.Path,
max_depth: int = 5,
) -> __.Absential[ __.Path ]:
''' Discovers pyproject.toml by traversing directory hierarchy. '''
def acquire_configuration(
pyproject_path: __.Path,
) -> __.immut.Dictionary[ str, __.typx.Any ]:
''' Acquires [tool.vibelinter] section from pyproject.toml. '''
Configuration Merging Pattern:
def merge_configurations(
appcore: __.accret.Dictionary[ str, __.typx.Any ],
pyproject: __.cabc.Mapping[ str, __.typx.Any ],
) -> __.accret.Dictionary[ str, __.typx.Any ]:
''' Merges pyproject.toml configuration with appcore base configuration. '''
Configuration Schema Integration¶
ConfigurationSchema: __.typx.TypeAlias = __.typx.TypedDict(
'ConfigurationSchema', {
# Global settings
'render_as': str, # text, json, structured
'display_source': bool,
'exit_zero': bool,
# Rule configuration
'rules': __.cabc.Mapping[ str, __.cabc.Mapping[ str, __.typx.Any ] ],
# Severity overrides
'severity': __.cabc.Mapping[ str, str ],
}, total = False
)
Rule Configuration Structure:
RuleConfiguration: __.typx.TypeAlias = __.typx.TypedDict(
'RuleConfiguration', {
'enabled': bool,
'severity': str, # error, warning, info
'parameters': __.cabc.Mapping[ str, __.typx.Any ],
}, total = False
)
CLI Integration Pattern¶
async def prepare_configuration(
exits: __.ctxl.AsyncExitStack,
cli_command: CliCommand,
project_root: __.Absential[ __.Path ] = __.absent,
) -> __.appcore.state.Globals:
''' Prepares configuration with application-specific settings. '''
Configuration Access Patterns¶
Configuration Reader Interface¶
class ConfigurationReader( __.immut.DataclassObject ):
''' Provides typed access to configuration values. '''
configuration: __.accret.Dictionary[ str, __.typx.Any ]
def access_render_format( self ) -> str:
''' Accesses render format setting with default fallback. '''
def access_rule_configuration(
self,
rule_id: str,
) -> RuleConfiguration:
''' Accesses rule-specific configuration. '''
def access_rule_enablement(
self,
rule_id: str,
) -> bool:
''' Accesses rule enablement status. '''
def access_rule_severity(
self,
rule_id: str,
) -> str:
''' Accesses rule severity level. '''
def access_rule_parameters(
self,
rule_id: str,
) -> __.immut.Dictionary[ str, __.typx.Any ]:
''' Accesses rule-specific parameters. '''
Rule Registry Integration¶
class ConfigurationValidator( __.immut.DataclassObject ):
''' Validates configuration against rule registry. '''
registry: __.cabc.Mapping[ str, __.cabc.Mapping[ str, __.typx.Any ] ]
def validate_rule_references(
self,
configuration: __.cabc.Mapping[ str, __.typx.Any ],
) -> tuple[ str, ... ]:
''' Validates rule ID references against registry. '''
def validate_rule_parameters(
self,
rule_id: str,
parameters: __.cabc.Mapping[ str, __.typx.Any ],
) -> tuple[ str, ... ]:
''' Validates rule parameters against schema. '''
Configuration Examples¶
Basic pyproject.toml Integration¶
[tool.vibelinter]
render-as = "text"
display-source = true
exit-zero = false
[tool.vibelinter.rules]
VBL101 = true # blank-line-elimination
VBL102 = false # simple-naming-conventions
blank-line-elimination = true # alternative descriptive syntax
[tool.vibelinter.rules.VBL102] # rule-specific parameters
similarity-threshold = 0.85
allow-digits = true
[tool.vibelinter.severity]
VBL101 = "error"
VBL102 = "info"
CLI Override Examples¶
# Override render format (via dataclass attribute)
linter check --render-as=json src/
# Override rule enablement (via dataclass attribute)
linter check --disable-rule=VBL101 src/
# Override rule parameters (via dataclass attribute)
linter check --rule-config=VBL102.similarity_threshold=0.9 src/
Integration Workflow¶
Application Initialization¶
async def prepare_application(
exits: __.ctxl.AsyncExitStack,
cli_command: CliCommand,
) -> __.appcore.state.Globals:
''' Prepares application with integrated configuration. '''
# Use standard appcore preparation
auxdata = await __.appcore.preparation.prepare(
exits = exits,
environment = True,
)
# Discover pyproject.toml from project root
project_root = auxdata.distribution.provide_data_location( ).parent
pyproject_path = discover_pyproject_toml( project_root )
# Merge configurations if pyproject.toml exists
# Apply CLI overrides via configuration edits
# Return updated auxdata with final configuration
Configuration Access Pattern¶
async def execute_linting_workflow(
auxdata: __.appcore.state.Globals,
targets: __.cabc.Sequence[ __.Path ],
) -> None:
''' Executes linting with configuration-driven behavior. '''
# Access configuration through reader interface
config_reader = ConfigurationReader( auxdata.configuration )
# Configure rendering based on settings
render_format = config_reader.access_render_format( )
# Configure rules based on settings
enabled_rules = [
rule_id for rule_id in AVAILABLE_RULES
if config_reader.access_rule_enablement( rule_id )
]
Default Configuration Strategy¶
Built-in Defaults¶
DEFAULT_CONFIGURATION: __.immut.Dictionary[ str, __.typx.Any ] = __.immut.Dictionary(
render_as = 'text',
display_source = True,
exit_zero = False,
rules = __.immut.Dictionary(
# All rules enabled by default
VBL101 = True,
VBL102 = True,
VBL201 = True,
VBL301 = True,
),
severity = __.immut.Dictionary(
# Default severity levels
VBL101 = 'error',
VBL102 = 'error',
VBL201 = 'warning',
VBL301 = 'warning',
),
)
Configuration Discovery Fallback¶
def provide_fallback_configuration( ) -> __.immut.Dictionary[ str, __.typx.Any ]:
''' Provides fallback when no project configuration exists. '''
# Return copy of defaults for zero-configuration operation
return __.immut.Dictionary( DEFAULT_CONFIGURATION )
Error Handling Specifications¶
Configuration Exception Hierarchy¶
class ConfigurationOmnierror( __.Omnierror ):
''' Base for configuration-related errors. '''
class ConfigurationDiscoverFailure( ConfigurationOmnierror ):
''' Configuration file discovery failed. '''
class ConfigurationParseFailure( ConfigurationOmnierror ):
''' Configuration parsing failed. '''
class ConfigurationValidateFailure( ConfigurationOmnierror ):
''' Configuration validation failed. '''
class RuleReferenceInvalidity( ConfigurationOmnierror ):
''' Invalid rule reference in configuration. '''
Validation Error Handling¶
def validate_and_report_configuration(
configuration: __.cabc.Mapping[ str, __.typx.Any ],
) -> __.cabc.Sequence[ str ]:
''' Validates configuration and returns error messages. '''
Error Recovery Strategy:
Invalid rule references: Log warnings, continue with valid rules
Invalid parameters: Use parameter defaults, log warnings
Parse errors: Fall back to built-in defaults, report error
Discovery failures: Use built-in defaults, operate in zero-configuration mode
Integration Benefits¶
Architecture Benefits:
Consistency: Unified configuration infrastructure across application
Immutability: Leverages emcd-appcore’s immutable configuration model
Extensibility: Easy addition of new configuration sections and parameters
Type Safety: Strong typing through TypedDict schemas and validation
Error Handling: Comprehensive validation with graceful fallback
Development Benefits:
Zero Configuration: Works without any configuration files
Project Integration: Natural pyproject.toml integration for Python projects
CLI Flexibility: Runtime overrides for development and CI/CD workflows
Schema Evolution: Backward-compatible configuration updates
Operational Benefits:
Debugging: Clear configuration precedence and source tracking
Validation: Early detection of configuration errors with helpful messages
Performance: Cached configuration access with immutable structures
Testing: Easy configuration mocking and override for tests
Implementation Dependencies¶
External Dependencies:
emcd-appcore: Configuration infrastructure and application preparationaccretive: Immutable dictionary implementationabsence: Optional value handlingplatformdirs: Platform-specific directory management
Internal Dependencies:
Rule registry system for validation
Exception hierarchy for error handling
CLI argument processing for configuration edits
File discovery utilities for project configuration location
This design ensures seamless integration between python-linter’s domain-specific configuration requirements and emcd-appcore’s standardized application infrastructure, maintaining both systems’ architectural principles while providing a unified configuration experience.