Skip to content

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

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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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