Coverage for session_buddy / core / lifecycle / project_context.py: 27.66%

39 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-04 00:43 -0800

1"""Project context analysis for session management. 

2 

3This module provides utilities for analyzing project structure, detecting 

4frameworks, and gathering project health indicators. 

5""" 

6 

7from __future__ import annotations 

8 

9from contextlib import suppress 

10from typing import TYPE_CHECKING 

11 

12from session_buddy.utils.git_operations import is_git_repository 

13 

14if TYPE_CHECKING: 

15 from pathlib import Path 

16 

17 

18def check_readme_exists(project_dir: Path) -> bool: 

19 """Check if README file exists.""" 

20 return any( 

21 (project_dir / name).exists() 

22 for name in ("README.md", "README.rst", "README.txt", "readme.md") 

23 ) 

24 

25 

26def check_venv_exists(project_dir: Path) -> bool: 

27 """Check if virtual environment exists.""" 

28 return any( 

29 (project_dir / name).exists() for name in (".venv", "venv", ".env", "env") 

30 ) 

31 

32 

33def check_tests_exist(project_dir: Path) -> bool: 

34 """Check if test directories exist.""" 

35 return any((project_dir / name).exists() for name in ("tests", "test", "testing")) 

36 

37 

38def check_docs_exist(project_dir: Path) -> bool: 

39 """Check if documentation directories exist.""" 

40 return any((project_dir / name).exists() for name in ("docs", "documentation")) 

41 

42 

43def check_ci_cd_exists(project_dir: Path) -> bool: 

44 """Check if CI/CD configuration exists.""" 

45 return any( 

46 (project_dir / name).exists() 

47 for name in (".github", ".gitlab-ci.yml", ".travis.yml", "Jenkinsfile") 

48 ) 

49 

50 

51def get_basic_project_indicators(project_dir: Path) -> dict[str, bool]: 

52 """Get basic project structure indicators.""" 

53 return { 

54 "has_pyproject_toml": (project_dir / "pyproject.toml").exists(), 

55 "has_setup_py": (project_dir / "setup.py").exists(), 

56 "has_requirements_txt": (project_dir / "requirements.txt").exists(), 

57 "has_readme": check_readme_exists(project_dir), 

58 "has_git_repo": is_git_repository(project_dir), 

59 "has_venv": check_venv_exists(project_dir), 

60 "has_tests": check_tests_exist(project_dir), 

61 "has_src_structure": (project_dir / "src").exists(), 

62 "has_docs": check_docs_exist(project_dir), 

63 "has_ci_cd": check_ci_cd_exists(project_dir), 

64 } 

65 

66 

67def check_framework_imports(content: str, indicators: dict[str, bool]) -> None: 

68 """Check for framework imports in file content.""" 

69 if "import fastapi" in content or "from fastapi" in content: 

70 indicators["uses_fastapi"] = True 

71 if "import django" in content or "from django" in content: 

72 indicators["uses_django"] = True 

73 if "import flask" in content or "from flask" in content: 

74 indicators["uses_flask"] = True 

75 

76 

77def detect_python_frameworks( 

78 python_files: list[Path], indicators: dict[str, bool] 

79) -> None: 

80 """Detect Python frameworks from file content.""" 

81 for py_file in python_files[:10]: # Sample first 10 files 

82 try: 

83 with py_file.open("r", encoding="utf-8") as f: 

84 content = f.read(1000) # Read first 1000 chars 

85 check_framework_imports(content, indicators) 

86 except (UnicodeDecodeError, PermissionError): 

87 continue 

88 

89 

90def add_python_context_indicators( 

91 project_dir: Path, indicators: dict[str, bool] 

92) -> None: 

93 """Add Python-specific context indicators.""" 

94 with suppress(Exception): 

95 python_files = list(project_dir.glob("**/*.py")) 

96 indicators["has_python_files"] = len(python_files) > 0 

97 detect_python_frameworks(python_files, indicators) 

98 

99 

100async def analyze_project_context(project_dir: Path) -> dict[str, bool]: 

101 """Analyze project directory for common indicators and patterns.""" 

102 indicators = get_basic_project_indicators(project_dir) 

103 add_python_context_indicators(project_dir, indicators) 

104 return indicators