1"""Project context analysis for session management.

2

3 This module provides utilities for analyzing project structure, detecting

4 frameworks, and gathering project health indicators.

5"""

6

7 from __future__ import annotations

8

9 from contextlib import suppress

10 from typing import TYPE_CHECKING

11

12 from session_buddy.utils.git_operations import is_git_repository

13

14 if TYPE_CHECKING:

15 from pathlib import Path

16

17

18 def 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

26 def 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

33 def 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

38 def 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

43 def 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

51 def 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

67 def 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

77 def 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

90 def 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

100 async 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