|
31 | 31 | from fastapi_fastkit.backend.main import ( |
32 | 32 | create_venv, |
33 | 33 | find_template_core_modules, |
| 34 | + inject_project_metadata, |
34 | 35 | install_dependencies, |
| 36 | + install_dependencies_with_manager, |
35 | 37 | ) |
36 | 38 | from fastapi_fastkit.backend.transducer import copy_and_convert_template |
37 | 39 | from fastapi_fastkit.core.settings import settings |
@@ -61,6 +63,10 @@ def __enter__(self) -> "TemplateInspector": |
61 | 63 | try: |
62 | 64 | os.makedirs(self.temp_dir, exist_ok=True) |
63 | 65 | copy_and_convert_template(str(self.template_path), self.temp_dir) |
| 66 | + |
| 67 | + # Inject dummy metadata for inspection |
| 68 | + self._inject_dummy_metadata() |
| 69 | + |
64 | 70 | self._cleanup_needed = True |
65 | 71 | self.template_config = self._load_template_config() |
66 | 72 | debug_log(f"Created temporary directory at {self.temp_dir}", "debug") |
@@ -112,6 +118,43 @@ def _load_template_config(self) -> Optional[Dict[str, Any]]: |
112 | 118 | debug_log(f"Failed to load template configuration: {e}", "warning") |
113 | 119 | return None |
114 | 120 |
|
| 121 | + def _inject_dummy_metadata(self) -> None: |
| 122 | + """Inject dummy metadata for template inspection.""" |
| 123 | + try: |
| 124 | + # Use dummy metadata for inspection |
| 125 | + dummy_metadata = { |
| 126 | + "project_name": "test-template", |
| 127 | + "author": "Template Inspector", |
| 128 | + "author_email": "[email protected]", |
| 129 | + "description": "Test project for template inspection", |
| 130 | + } |
| 131 | + |
| 132 | + inject_project_metadata( |
| 133 | + self.temp_dir, |
| 134 | + dummy_metadata["project_name"], |
| 135 | + dummy_metadata["author"], |
| 136 | + dummy_metadata["author_email"], |
| 137 | + dummy_metadata["description"], |
| 138 | + ) |
| 139 | + debug_log("Injected dummy metadata for template inspection", "info") |
| 140 | + |
| 141 | + except Exception as e: |
| 142 | + debug_log(f"Failed to inject dummy metadata: {e}", "warning") |
| 143 | + self.warnings.append(f"Failed to inject metadata: {str(e)}") |
| 144 | + |
| 145 | + def _detect_package_manager(self) -> str: |
| 146 | + """Detect the appropriate package manager for the template.""" |
| 147 | + # Check for pyproject.toml (modern Python packaging) |
| 148 | + if os.path.exists(os.path.join(self.temp_dir, "pyproject.toml")): |
| 149 | + return "uv" # Use UV for pyproject.toml based projects |
| 150 | + |
| 151 | + # Check for requirements.txt (traditional pip) |
| 152 | + if os.path.exists(os.path.join(self.temp_dir, "requirements.txt")): |
| 153 | + return "pip" |
| 154 | + |
| 155 | + # Default to pip if no dependency file found |
| 156 | + return "pip" |
| 157 | + |
115 | 158 | def _check_docker_available(self) -> bool: |
116 | 159 | """Check if Docker and Docker Compose are available.""" |
117 | 160 | try: |
@@ -393,7 +436,21 @@ def _test_with_standard_strategy(self) -> bool: |
393 | 436 | try: |
394 | 437 | # Create virtual environment for testing |
395 | 438 | venv_path = create_venv(self.temp_dir) |
396 | | - install_dependencies(self.temp_dir, venv_path) |
| 439 | + |
| 440 | + # Detect and use appropriate package manager |
| 441 | + package_manager = self._detect_package_manager() |
| 442 | + debug_log(f"Using package manager: {package_manager}", "info") |
| 443 | + |
| 444 | + try: |
| 445 | + install_dependencies_with_manager( |
| 446 | + self.temp_dir, venv_path, package_manager |
| 447 | + ) |
| 448 | + except Exception as dep_error: |
| 449 | + # Capture detailed dependency installation error |
| 450 | + error_msg = f"Failed to install dependencies: {str(dep_error)}" |
| 451 | + debug_log(f"Dependency installation failed: {dep_error}", "error") |
| 452 | + self.errors.append(error_msg) |
| 453 | + return False |
397 | 454 |
|
398 | 455 | # Check if scripts/test.sh exists |
399 | 456 | test_script_path = os.path.join(self.temp_dir, "scripts", "test.sh") |
@@ -557,7 +614,21 @@ def _test_with_fallback_strategy(self) -> bool: |
557 | 614 | try: |
558 | 615 | # Create virtual environment for testing |
559 | 616 | venv_path = create_venv(self.temp_dir) |
560 | | - install_dependencies(self.temp_dir, venv_path) |
| 617 | + |
| 618 | + # Detect and use appropriate package manager |
| 619 | + package_manager = self._detect_package_manager() |
| 620 | + debug_log(f"Using package manager: {package_manager}", "info") |
| 621 | + |
| 622 | + try: |
| 623 | + install_dependencies_with_manager( |
| 624 | + self.temp_dir, venv_path, package_manager |
| 625 | + ) |
| 626 | + except Exception as dep_error: |
| 627 | + # Capture detailed dependency installation error |
| 628 | + error_msg = f"Failed to install dependencies: {str(dep_error)}" |
| 629 | + debug_log(f"Dependency installation failed: {dep_error}", "error") |
| 630 | + self.errors.append(error_msg) |
| 631 | + return False |
561 | 632 |
|
562 | 633 | # Set up fallback environment (e.g., SQLite database) |
563 | 634 | fallback_config = self.template_config["fallback_testing"] |
@@ -683,6 +754,14 @@ def _wait_for_services_healthy(self, compose_file: str, timeout: int) -> None: |
683 | 754 | # Check if all services are running |
684 | 755 | all_running = True |
685 | 756 | for service in services: |
| 757 | + # Ensure service is a dictionary before calling .get() |
| 758 | + if not isinstance(service, dict): |
| 759 | + debug_log( |
| 760 | + f"Service info is not a dictionary: {service}", |
| 761 | + "warning", |
| 762 | + ) |
| 763 | + continue |
| 764 | + |
686 | 765 | if service.get("State") != "running": |
687 | 766 | all_running = False |
688 | 767 | debug_log( |
@@ -738,6 +817,11 @@ def _verify_services_running(self, compose_file: str) -> bool: |
738 | 817 | app_running = False |
739 | 818 |
|
740 | 819 | for service in services: |
| 820 | + # Ensure service is a dictionary before calling .get() |
| 821 | + if not isinstance(service, dict): |
| 822 | + debug_log(f"Service info is not a dictionary: {service}", "warning") |
| 823 | + continue |
| 824 | + |
741 | 825 | service_name = service.get("Name", "") |
742 | 826 | service_state = service.get("State", "") |
743 | 827 |
|
|
0 commit comments