Skip to content

Feature Request: Refactor Configuration Architecture for Better CLI/Library Separation #12

@rahlk

Description

@rahlk

Summary

Refactor the current parameter-passing approach to use a layered configuration pattern that cleanly separates CLI concerns from core analysis configuration, improving both library usability and maintainability.

Current State

The Codeanalyzer class currently accepts individual parameters in its constructor:

with Codeanalyzer(
    input, analysis_level, using_codeql, rebuild_analysis, cache_dir, clear_cache
) as analyzer:

This approach has several limitations:

  • Library users must pass CLI-specific parameters (like clear_cache)
  • Parameter explosion as new options are added
  • Tight coupling between CLI and core analysis logic
  • Hard to test - requires mocking many individual parameters
  • No validation of parameter combinations
  • No config file support - difficult to extend

Proposed Solution

1. Core Configuration Object

Create an AnalysisOptions class that contains only analysis-relevant settings:

@dataclass
class AnalysisOptions:
    input_path: Path
    analysis_level: int = 1
    using_codeql: bool = False
    rebuild_analysis: bool = False
    cache_dir: Optional[Path] = None
    
    def validate(self):
        # Centralized validation logic
        pass
    
    @classmethod
    def from_dict(cls, config: dict):
        # Support for config files
        pass

2. CLI Configuration Layer

Create a CLIOptions class for CLI-specific concerns:

@dataclass
class CLIOptions:
    output_dir: Optional[Path] = None
    output_format: OutputFormat = OutputFormat.JSON
    verbosity: int = 0
    clear_cache: bool = True
    
    def setup_logging(self):
        # Handle CLI-specific setup
        pass

3. Updated Core Interface

Modify Codeanalyzer to accept the configuration object:

class Codeanalyzer:
    def __init__(self, options: AnalysisOptions):
        self.options = options
        # Clean, single source of configuration

Benefits

For Library Users

  • Clean API: Single configuration object instead of many parameters
  • Type Safety: Better IDE support and validation
  • Extensibility: Easy to add new options without breaking existing code
  • Testability: Simple to create test configurations
# Clean library usage
options = AnalysisOptions(
    input_path=Path("my_project"),
    analysis_level=2,
    using_codeql=True
)
with Codeanalyzer(options) as analyzer:
    results = analyzer.analyze()

For CLI Users

  • No breaking changes: CLI interface remains the same
  • Better error messages: Centralized validation
  • Future extensibility: Config file support, presets, etc.

For Maintainers

  • Separation of concerns: CLI logic separate from analysis logic
  • Easier testing: Mock configuration objects instead of individual parameters
  • Better validation: Centralized parameter validation and type checking
  • Extensibility: Easy to add features like config files, environment variables

Backward Compatibility

  • CLI interface remains unchanged
  • Library interface change is breaking, but provides clear migration path
  • Consider deprecation warnings for old constructor signature

Testing Strategy

  • Unit tests for configuration validation
  • Integration tests for CLI/library interfaces
  • Test configuration serialization/deserialization
  • Test error handling and validation

Success Metrics

  • Reduced coupling between CLI and core analysis
  • Improved library API usability
  • Foundation for future configuration enhancements
  • Better test coverage of configuration logic

References

Similar patterns used successfully in:

  • MyPy (mypy.options.Options)
  • Black (black.FileMode)
  • Pylint (pylint.config.Configuration)
  • WALA (AnalysisOptions)

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions