diff --git a/cli/commands/issues.py b/cli/commands/issues.py index 4f2a4b11..60ca6020 100644 --- a/cli/commands/issues.py +++ b/cli/commands/issues.py @@ -2,7 +2,7 @@ Issue CLI commands. """ -from typing import List +from typing import List, Optional, Any from tddai import TddaiError from services import IssueService @@ -12,7 +12,7 @@ from cli.presenters import OutputFormatter, IssueView class IssueCommands: """Commands for issue operations.""" - def __init__(self): + def __init__(self) -> None: self.service = IssueService() def list_issues(self) -> None: @@ -53,8 +53,8 @@ class IssueCommands: def create_enhancement_issue(self, title: str, use_case: str, technical_requirements: str = "", - acceptance_criteria: List[str] = None, - dependencies: List[str] = None, + acceptance_criteria: Optional[List[str]] = None, + dependencies: Optional[List[str]] = None, priority: str = "Medium") -> None: """Create a structured enhancement issue.""" try: @@ -82,7 +82,7 @@ class IssueCommands: except TddaiError as e: OutputFormatter.exit_with_error(f"Error creating enhancement issue: {e}") - def create_from_template(self, template_file: str, **kwargs) -> None: + def create_from_template(self, template_file: str, **kwargs: Any) -> None: """Create issue from template file.""" try: OutputFormatter.info(f"Creating issue from template: {template_file}") diff --git a/cli/commands/workspace.py b/cli/commands/workspace.py index c455a861..00cb9e79 100644 --- a/cli/commands/workspace.py +++ b/cli/commands/workspace.py @@ -47,6 +47,7 @@ class WorkspaceCommands: OutputFormatter.error("No active issue workspace") print(" Nothing to finish") OutputFormatter.exit_with_error("", 1) + return # Explicit return for type checker # Get test count before finishing summary = self.service.get_workspace_summary() diff --git a/cli/core.py b/cli/core.py index 0e9474bb..ed1afb06 100644 --- a/cli/core.py +++ b/cli/core.py @@ -4,75 +4,76 @@ CLI framework core. Provides the main CLI framework and command delegation. """ +from typing import Any from .commands import WorkspaceCommands, IssueCommands, ProjectCommands, ExportCommands class CLIFramework: """Main CLI framework that delegates to command classes.""" - def __init__(self): + def __init__(self) -> None: self.workspace = WorkspaceCommands() self.issues = IssueCommands() self.project = ProjectCommands() self.export = ExportCommands() # Workspace operations - def workspace_status(self): + def workspace_status(self) -> None: return self.workspace.status() - def start_issue(self, issue_number: int): + def start_issue(self, issue_number: int) -> None: return self.workspace.start_issue(issue_number) - def finish_issue(self): + def finish_issue(self) -> None: return self.workspace.finish_issue() - def add_test_guidance(self): + def add_test_guidance(self) -> None: return self.workspace.add_test_guidance() # Issue operations - def list_issues(self): + def list_issues(self) -> None: return self.issues.list_issues() - def list_open_issues(self): + def list_open_issues(self) -> None: return self.issues.list_open_issues() - def show_issue(self, issue_number: int): + def show_issue(self, issue_number: int) -> None: return self.issues.show_issue(issue_number) - def create_issue(self, title: str, body: str, issue_type: str = "enhancement"): + def create_issue(self, title: str, body: str, issue_type: str = "enhancement") -> None: return self.issues.create_issue(title, body, issue_type) - def create_enhancement_issue(self, title: str, use_case: str, **kwargs): + def create_enhancement_issue(self, title: str, use_case: str, **kwargs: Any) -> None: return self.issues.create_enhancement_issue(title, use_case, **kwargs) - def create_from_template(self, template_file: str, **kwargs): + def create_from_template(self, template_file: str, **kwargs: Any) -> None: return self.issues.create_from_template(template_file, **kwargs) - def analyze_coverage(self, issue_number: int): + def analyze_coverage(self, issue_number: int) -> None: return self.issues.analyze_coverage(issue_number) # Project management operations - def setup_project_management(self): + def setup_project_management(self) -> None: return self.project.setup_project_management() - def move_issue_to_state(self, issue_number: int, state: str): + def move_issue_to_state(self, issue_number: int, state: str) -> None: return self.project.move_issue_to_state(issue_number, state) - def set_issue_priority(self, issue_number: int, priority: str): + def set_issue_priority(self, issue_number: int, priority: str) -> None: return self.project.set_issue_priority(issue_number, priority) - def create_milestone(self, title: str, description: str = ""): + def create_milestone(self, title: str, description: str = "") -> None: return self.project.create_milestone(title, description) - def list_milestones(self): + def list_milestones(self) -> None: return self.project.list_milestones() - def assign_issue_to_milestone(self, issue_number: int, milestone_id: int): + def assign_issue_to_milestone(self, issue_number: int, milestone_id: int) -> None: return self.project.assign_issue_to_milestone(issue_number, milestone_id) - def project_overview(self): + def project_overview(self) -> None: return self.project.project_overview() # Export operations - def issue_index(self, **kwargs): + def issue_index(self, **kwargs: Any) -> None: return self.export.issue_index(**kwargs) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 2379b3c1..981a669a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,3 +16,77 @@ markitect = "markitect.cli:main" [tool.setuptools.packages.find] include = ["markitect*"] exclude = ["tests*", "wiki*", "tddai*"] + +[tool.mypy] +# Basic mypy configuration for MarkiTect project +python_version = "3.12" +warn_return_any = true +warn_unused_configs = true +warn_redundant_casts = true +warn_unused_ignores = true +warn_no_return = true +warn_unreachable = true +strict_optional = true +disallow_untyped_calls = false # Gradual adoption +disallow_untyped_defs = false # Gradual adoption +disallow_incomplete_defs = false # Gradual adoption +check_untyped_defs = true +disallow_untyped_decorators = false # Gradual adoption +no_implicit_optional = true +show_error_codes = true +show_column_numbers = true +pretty = true + +# File patterns to exclude from type checking +exclude = [ + "^build/.*", + "^dist/.*", + "^\\.venv/.*", + "^\\.markitect_workspace/.*", + "^tests/.*", # Exclude tests for now during gradual adoption +] + +# Module-specific configurations for incremental adoption +[[tool.mypy.overrides]] +module = [ + "infrastructure.logging.*", + "infrastructure.repositories.*", + "infrastructure.exceptions", + "infrastructure.config", + "domain.*" +] +# Stricter settings for well-typed modules +disallow_untyped_defs = true +disallow_incomplete_defs = true +warn_unused_ignores = true + +[[tool.mypy.overrides]] +module = [ + "tddai_cli", + "markitect.cli", + "cli.*" +] +# Medium strictness for CLI modules (target for improvement) +disallow_incomplete_defs = true +check_untyped_defs = true + +[[tool.mypy.overrides]] +module = [ + "markitect.*", + "services.*", + "gitea.*" +] +# Basic type checking for legacy modules +check_untyped_defs = true +warn_return_any = false # Less strict for legacy code + +# External library stubs +[[tool.mypy.overrides]] +module = [ + "markdown_it.*", + "jsonpath_ng.*", + "click.*", + "tabulate.*", + "yaml.*" +] +ignore_missing_imports = true diff --git a/services/issue_service.py b/services/issue_service.py index 4f525e01..1dad97f1 100644 --- a/services/issue_service.py +++ b/services/issue_service.py @@ -35,8 +35,8 @@ class IssueService: def create_enhancement_issue(self, title: str, use_case: str, technical_requirements: str = "", - acceptance_criteria: List[str] = None, - dependencies: List[str] = None, + acceptance_criteria: Optional[List[str]] = None, + dependencies: Optional[List[str]] = None, priority: str = "Medium") -> Dict[str, Any]: """Create a structured enhancement issue.""" return self.issue_creator.create_enhancement_issue( diff --git a/services/project_service.py b/services/project_service.py index ad8ee49b..6cc9f9a8 100644 --- a/services/project_service.py +++ b/services/project_service.py @@ -2,7 +2,7 @@ Project service - business logic for project management operations. """ -from typing import List, Dict, Any +from typing import List, Dict, Any, Optional from tddai.project_manager import ProjectManager, ProjectState, Priority, Milestone, Label from tddai import TddaiError @@ -18,7 +18,7 @@ class ProjectService: """Setup project management labels and structure.""" self.project_manager.ensure_project_labels() - def create_milestone(self, title: str, description: str = "", due_date: str = None) -> Milestone: + def create_milestone(self, title: str, description: str = "", due_date: Optional[str] = None) -> Milestone: """Create a new milestone (project).""" return self.project_manager.create_milestone(title, description, due_date) diff --git a/tddai/issue_creator.py b/tddai/issue_creator.py index 1ad6725d..b9837c50 100644 --- a/tddai/issue_creator.py +++ b/tddai/issue_creator.py @@ -71,8 +71,8 @@ class IssueCreator: def create_enhancement_issue(self, title: str, use_case: str, technical_requirements: str = "", - acceptance_criteria: List[str] = None, - dependencies: List[str] = None, + acceptance_criteria: Optional[List[str]] = None, + dependencies: Optional[List[str]] = None, priority: str = "Medium") -> Dict[str, Any]: """Create an enhancement issue with structured format. @@ -123,7 +123,7 @@ class IssueCreator: ) def create_bug_issue(self, title: str, description: str, - steps_to_reproduce: List[str] = None, + steps_to_reproduce: Optional[List[str]] = None, expected_behavior: str = "", actual_behavior: str = "", environment: str = "") -> Dict[str, Any]: diff --git a/tddai/project_manager.py b/tddai/project_manager.py index 580b9ed8..9049df90 100644 --- a/tddai/project_manager.py +++ b/tddai/project_manager.py @@ -82,7 +82,7 @@ class ProjectManager: # Milestone Management (Projects) - def create_milestone(self, title: str, description: str = "", due_date: str = None) -> Milestone: + def create_milestone(self, title: str, description: str = "", due_date: Optional[str] = None) -> Milestone: """Create a new milestone (project).""" try: return self.gitea_client.milestones.create(title, description, due_date) diff --git a/tddai_cli.py b/tddai_cli.py index 2ff607e7..e1abefcc 100644 --- a/tddai_cli.py +++ b/tddai_cli.py @@ -9,6 +9,7 @@ Business logic is handled by services, presentation by CLI framework. import sys import argparse from pathlib import Path +from typing import Optional, Any # Add current directory to path so we can import modules sys.path.insert(0, str(Path(__file__).parent)) @@ -16,9 +17,9 @@ sys.path.insert(0, str(Path(__file__).parent)) from cli import CLIFramework # Lazy initialization of CLI framework -_cli_framework = None +_cli_framework: Optional[CLIFramework] = None -def _get_cli(): +def _get_cli() -> CLIFramework: """Get CLI framework instance (lazy initialization).""" global _cli_framework if _cli_framework is None: @@ -26,49 +27,49 @@ def _get_cli(): return _cli_framework -def workspace_status(): +def workspace_status() -> None: """Show current workspace status.""" _get_cli().workspace_status() -def start_issue(issue_number: int): +def start_issue(issue_number: int) -> None: """Start working on an issue.""" _get_cli().start_issue(issue_number) -def finish_issue(): +def finish_issue() -> None: """Finish current issue workspace.""" _get_cli().finish_issue() -def add_test_guidance(): +def add_test_guidance() -> None: """Show guidance for adding tests.""" _get_cli().add_test_guidance() -def list_issues(): +def list_issues() -> None: """List all issues.""" _get_cli().list_issues() -def list_open_issues(): +def list_open_issues() -> None: """List only open issues.""" _get_cli().list_open_issues() -def show_issue(issue_number: int): +def show_issue(issue_number: int) -> None: """Show detailed issue information.""" _get_cli().show_issue(issue_number) -def create_issue(title: str, body: str, issue_type: str = "enhancement"): +def create_issue(title: str, body: str, issue_type: str = "enhancement") -> None: """Create a new issue.""" _get_cli().create_issue(title, body, issue_type) def create_enhancement_issue(title: str, use_case: str, technical_requirements: str = "", acceptance_criteria: str = "", dependencies: str = "", - priority: str = "Medium"): + priority: str = "Medium") -> None: """Create a structured enhancement issue.""" # Parse acceptance criteria if provided criteria_list = [] @@ -90,52 +91,52 @@ def create_enhancement_issue(title: str, use_case: str, technical_requirements: ) -def create_from_template(template_file: str, **kwargs): +def create_from_template(template_file: str, **kwargs: Any) -> None: """Create issue from template file.""" _get_cli().create_from_template(template_file, **kwargs) -def analyze_coverage(issue_number: int): +def analyze_coverage(issue_number: int) -> None: """Analyze test coverage for a specific issue.""" _get_cli().analyze_coverage(issue_number) -def setup_project_management(): +def setup_project_management() -> None: """Setup project management labels and milestones.""" _get_cli().setup_project_management() -def move_issue_to_state(issue_number: int, state: str): +def move_issue_to_state(issue_number: int, state: str) -> None: """Move issue to a specific project state.""" _get_cli().move_issue_to_state(issue_number, state) -def set_issue_priority(issue_number: int, priority: str): +def set_issue_priority(issue_number: int, priority: str) -> None: """Set issue priority.""" _get_cli().set_issue_priority(issue_number, priority) -def create_milestone(title: str, description: str = ""): +def create_milestone(title: str, description: str = "") -> None: """Create a new milestone (project).""" _get_cli().create_milestone(title, description) -def list_milestones(): +def list_milestones() -> None: """List all milestones.""" _get_cli().list_milestones() -def assign_issue_to_milestone(issue_number: int, milestone_id: int): +def assign_issue_to_milestone(issue_number: int, milestone_id: int) -> None: """Assign issue to a milestone.""" _get_cli().assign_issue_to_milestone(issue_number, milestone_id) -def project_overview(): +def project_overview() -> None: """Show project management overview.""" _get_cli().project_overview() -def issue_index(format_type="tsv", sort_by="number", filter_state=None, filter_priority=None, include_state=False): +def issue_index(format_type: str = "tsv", sort_by: str = "number", filter_state: Optional[str] = None, filter_priority: Optional[str] = None, include_state: bool = False) -> None: """Output compact index of all issues for Unix processing.""" _get_cli().issue_index( format_type=format_type, @@ -146,7 +147,7 @@ def issue_index(format_type="tsv", sort_by="number", filter_state=None, filter_p ) -def main(): +def main() -> None: """Main CLI entry point.""" parser = argparse.ArgumentParser(description="tddai CLI tool") subparsers = parser.add_subparsers(dest='command', help='Available commands')