From 180a350f6dc8d027aa1bcca105079bfa415224e7 Mon Sep 17 00:00:00 2001 From: OhMyApps <74984020+GiGiDKR@users.noreply.github.com> Date: Fri, 27 Jun 2025 23:58:13 +0200 Subject: [PATCH] fix: improve the Python path detection in mock tests and ensures logger initialization order is correct. Fix run-server.ps1 to handle PowerShell script creation correctly and ensure pip is installed in the uv environment. --- patch/patch_crossplatform.py | 171 +++++++++++++++++-------- patch/validation_crossplatform.py | 200 ++++++++++++++++++++++++++++-- run-server.ps1 | 23 +++- 3 files changed, 328 insertions(+), 66 deletions(-) diff --git a/patch/patch_crossplatform.py b/patch/patch_crossplatform.py index 06f4d8a..4a723e9 100644 --- a/patch/patch_crossplatform.py +++ b/patch/patch_crossplatform.py @@ -33,6 +33,14 @@ FIXED ISSUES: - Simulator couldn't find Windows Python executable - Solution: Added Windows-specific path detection +7. BASE TEST CLASSES LOGGER BUG: + - AttributeError: logger used before initialization in test classes + - Solution: Initialize logger before calling _get_python_path() in BaseSimulatorTest + +8. BASE TEST PYTHON PATH DETECTION ON WINDOWS: + - Test classes couldn't find Windows Python executable + - Solution: Added Windows-specific path detection to BaseSimulatorTest + MODIFIED FILES: - utils/file_utils.py : Home patterns + Unix path validation - tests/test_file_protection.py : Cross-platform assertions @@ -40,6 +48,7 @@ MODIFIED FILES: - run_integration_tests.sh : Windows venv detection - code_quality_checks.sh : Windows venv and tools detection - communication_simulator_test.py : Logger initialization order + Windows paths +- simulator_tests/base_test.py : Logger initialization order + Windows paths Usage: python patch_complet_crossplatform.py [--dry-run] [--backup] [--validate-only] @@ -73,6 +82,7 @@ class CrossPlatformPatcher: "run_integration_tests_sh": self.workspace_root / "run_integration_tests.sh", "code_quality_checks_sh": self.workspace_root / "code_quality_checks.sh", "communication_simulator": self.workspace_root / "communication_simulator_test.py", + "base_test": self.workspace_root / "simulator_tests" / "base_test.py", } for _, path in files.items(): @@ -509,7 +519,7 @@ fi""" # Fallback to system python if venv doesn't exist self.logger.warning("Virtual environment not found, using system python") - return "python\"""" + return "python""" new_python_path = """ def _get_python_path(self) -> str: \"\"\"Get the Python path for the virtual environment\"\"\" @@ -536,7 +546,89 @@ fi""" # Fallback to system python if venv doesn't exist self.logger.warning("Virtual environment not found, using system python") - return "python\"""" + return "python""" + + if old_python_path in content: + content = content.replace(old_python_path, new_python_path) + return content, True + + return content, False + + def patch_base_test_logger_init(self, content: str) -> tuple[str, bool]: + """Patch 11: Fix logger initialization order in BaseSimulatorTest.""" + # Check if already patched + if "# Configure logging first" in content and "# Now get python path" in content: + return content, False + + # Fix the initialization order in BaseSimulatorTest + old_init_order = """ def __init__(self, verbose: bool = False): + self.verbose = verbose + self.test_files = {} + self.test_dir = None + self.python_path = self._get_python_path() + + # Configure logging + log_level = logging.DEBUG if verbose else logging.INFO + logging.basicConfig(level=log_level, format="%(asctime)s - %(levelname)s - %(message)s") + self.logger = logging.getLogger(self.__class__.__name__)""" + + new_init_order = """ def __init__(self, verbose: bool = False): + self.verbose = verbose + self.test_files = {} + self.test_dir = None + + # Configure logging first + log_level = logging.DEBUG if verbose else logging.INFO + logging.basicConfig(level=log_level, format="%(asctime)s - %(levelname)s - %(message)s") + self.logger = logging.getLogger(self.__class__.__name__) + + # Now get python path (after logger is configured) + self.python_path = self._get_python_path()""" + + if old_init_order in content: + content = content.replace(old_init_order, new_init_order) + return content, True + + return content, False + + def patch_base_test_python_path(self, content: str) -> tuple[str, bool]: + """Patch 12: Add Windows Python path detection to BaseSimulatorTest.""" + # Check if already patched + if "import platform" in content and 'platform.system() == "Windows"' in content: + return content, False + + # Fix the _get_python_path method in BaseSimulatorTest + old_python_path = """ def _get_python_path(self) -> str: + \"\"\"Get the Python path for the virtual environment\"\"\" + current_dir = os.getcwd() + venv_python = os.path.join(current_dir, ".zen_venv", "bin", "python") + + if os.path.exists(venv_python): + return venv_python + + # Fallback to system python if venv doesn't exist + self.logger.warning("Virtual environment not found, using system python") + return "python""" + + new_python_path = """ def _get_python_path(self) -> str: + \"\"\"Get the Python path for the virtual environment\"\"\" + import platform + current_dir = os.getcwd() + + # Check for different venv structures + if platform.system() == "Windows": + # Windows paths + zen_venv_python = os.path.join(current_dir, ".zen_venv", "Scripts", "python.exe") + else: + # Unix/Linux/macOS paths + zen_venv_python = os.path.join(current_dir, ".zen_venv", "bin", "python") + + if os.path.exists(zen_venv_python): + return zen_venv_python + + # Fallback to system python if venv doesn't exist + self.logger.warning("Virtual environment not found, using system python") + return "python""" if old_python_path in content: content = content.replace(old_python_path, new_python_path) @@ -674,68 +766,28 @@ fi""" else: print(" โ„น๏ธ communication_simulator_test.py already patched") - # Patch 6: run_integration_tests.sh - print("\n๐Ÿ”ง Patching run_integration_tests.sh...") + # Patch 11 & 12: simulator_tests/base_test.py + print("\n๐Ÿ”ง Patching simulator_tests/base_test.py...") - run_integration_content = self.read_file(files["run_integration_tests_sh"]) - run_integration_content, modified6 = self.patch_shell_venv_detection(run_integration_content) + base_test_content = self.read_file(files["base_test"]) + base_test_content, modified11 = self.patch_base_test_logger_init(base_test_content) + base_test_content, modified12 = self.patch_base_test_python_path(base_test_content) - if modified6: + if modified11 or modified12: if create_backups: - backup = self.create_backup(files["run_integration_tests_sh"]) + backup = self.create_backup(files["base_test"]) print(f" โœ… Backup created: {backup}") - self.write_file(files["run_integration_tests_sh"], run_integration_content) - print(" โœ… Windows venv detection added") - self.patches_applied.append("Windows venv detection (run_integration_tests.sh)") - else: - print(" โ„น๏ธ run_integration_tests.sh already patched") + self.write_file(files["base_test"], base_test_content) - # Patch 7 & 8: code_quality_checks.sh - print("\n๐Ÿ”ง Patching code_quality_checks.sh...") - - code_quality_content = self.read_file(files["code_quality_checks_sh"]) - code_quality_content, modified7 = self.patch_shell_python_detection(code_quality_content) - code_quality_content, modified8 = self.patch_shell_tool_paths(code_quality_content) - - if modified7 or modified8: - if create_backups: - backup = self.create_backup(files["code_quality_checks_sh"]) - print(f" โœ… Backup created: {backup}") - - self.write_file(files["code_quality_checks_sh"], code_quality_content) - - if modified7: - print(" โœ… Windows Python detection added") - self.patches_applied.append("Windows Python detection (code_quality_checks.sh)") - if modified8: - print(" โœ… Windows tool paths added") - self.patches_applied.append("Windows tool paths (code_quality_checks.sh)") - else: - print(" โ„น๏ธ code_quality_checks.sh already patched") - - # Patch 9: communication_simulator_test.py - print("\n๐Ÿ”ง Patching communication_simulator_test.py...") - - simulator_content = self.read_file(files["communication_simulator"]) - simulator_content, modified9 = self.patch_simulator_logger_init(simulator_content) - simulator_content, modified10 = self.patch_simulator_python_path(simulator_content) - - if modified9 or modified10: - if create_backups: - backup = self.create_backup(files["communication_simulator"]) - print(f" โœ… Backup created: {backup}") - - self.write_file(files["communication_simulator"], simulator_content) - - if modified9: + if modified11: print(" โœ… Logger initialization order fixed") - self.patches_applied.append("Logger initialization order") - if modified10: + self.patches_applied.append("Logger initialization (base_test.py)") + if modified12: print(" โœ… Windows Python path detection added") - self.patches_applied.append("Windows Python path detection") + self.patches_applied.append("Windows Python paths (base_test.py)") else: - print(" โ„น๏ธ communication_simulator_test.py already patched") + print(" โ„น๏ธ simulator_tests/base_test.py already patched") return all_success @@ -791,6 +843,15 @@ fi""" if "import platform" not in simulator_content: errors.append("Windows Python path detection missing in communication_simulator_test.py") + # Validate simulator_tests/base_test.py + base_test_content = self.read_file(files["base_test"]) + + if "# Configure logging first" not in base_test_content or "# Now get python path" not in base_test_content: + errors.append("Logger initialization order missing in base_test.py") + + if "import platform" not in base_test_content or 'platform.system() == "Windows"' not in base_test_content: + errors.append("Windows Python path detection missing in base_test.py") + return errors def show_diff_summary(self, files: dict[str, Path]) -> None: diff --git a/patch/validation_crossplatform.py b/patch/validation_crossplatform.py index f74cd57..39cb1a8 100644 --- a/patch/validation_crossplatform.py +++ b/patch/validation_crossplatform.py @@ -2,8 +2,25 @@ """ Validation script for all cross-platform fixes. -This script runs a series of tests to validate that all applied fixes -work correctly on Windows. +This script runs a comprehensive series of tests to validate that all applied fixes +work correctly on Windows, including: + +1. Home directory pattern detection (Windows, macOS, Linux) +2. Unix path validation on Windows +3. Safe files functionality with temporary files +4. Cross-platform file discovery with Path.parts +5. Communication simulator logger and Python path fixes +6. BaseSimulatorTest logger and Python path fixes +7. Shell scripts Windows virtual environment support + +Tests cover all modified files: +- utils/file_utils.py +- tests/test_file_protection.py +- tests/test_utils.py +- communication_simulator_test.py +- simulator_tests/base_test.py +- run_integration_tests.sh +- code_quality_checks.sh """ import sys @@ -11,7 +28,7 @@ import tempfile from pathlib import Path from unittest.mock import patch -# Add parent directory to Python path to import from workspace root +# Add parent directory to path to import project modules sys.path.insert(0, str(Path(__file__).parent.parent)) # Import functions to test @@ -124,8 +141,7 @@ def test_safe_files_functionality(): success1 = all([has_begin, has_content, has_end, has_tokens]) - # Test nonexistent Unix path - # (should return FILE NOT FOUND, not path error) + # Test nonexistent Unix path (should return FILE NOT FOUND, not path error) content, tokens = read_file_content("/etc/nonexistent") not_found = "--- FILE NOT FOUND:" in content no_path_error = "Relative paths are not supported" not in content @@ -138,8 +154,7 @@ def test_safe_files_functionality(): success2 = all([not_found, no_path_error, has_tokens2]) success = success1 and success2 - status = "passed" if success else "failed" - print(f"\nResult: Safe files tests {status}") + print(f"\nResult: Safe files tests {'passed' if success else 'failed'}") finally: # Clean up @@ -195,6 +210,172 @@ def test_cross_platform_file_discovery(): return success +def test_communication_simulator_fixes(): + """Test 5: Communication simulator fixes""" + print("\n๐Ÿงช Test 5: Communication simulator fixes") + print("-" * 60) + + try: + # Import and test CommunicationSimulator + from communication_simulator_test import CommunicationSimulator + + # Test that we can create an instance without logger errors + simulator = CommunicationSimulator(verbose=False, keep_logs=True) + + # Check that logger is properly initialized + has_logger = hasattr(simulator, "logger") and simulator.logger is not None + print(f" โœ… Logger initialized: {has_logger}") + + # Check that python_path is set + has_python_path = hasattr(simulator, "python_path") and simulator.python_path is not None + print(f" โœ… Python path set: {has_python_path}") + + # Check that the path detection logic includes Windows + import os + import platform + + if platform.system() == "Windows": + # Test Windows path detection + current_dir = os.getcwd() + expected_paths = [ + os.path.join(current_dir, ".zen_venv", "Scripts", "python.exe"), + os.path.join(current_dir, "venv", "Scripts", "python.exe"), + ] + + # Check if the method would detect Windows paths + windows_detection = any("Scripts" in path for path in expected_paths) + print(f" โœ… Windows path detection: {windows_detection}") + else: + windows_detection = True # Pass on non-Windows systems + print(" โœ… Windows path detection: N/A (not Windows)") + + success = all([has_logger, has_python_path, windows_detection]) + print(f"\nResult: Communication simulator {'passed' if success else 'failed'}") + + return success + + except Exception as e: + print(f" โŒ Error testing CommunicationSimulator: {e}") + print("\nResult: Communication simulator failed") + return False + + +def test_base_simulator_test_fixes(): + """Test 6: BaseSimulatorTest fixes.""" + print("\n๐Ÿงช Test 6: BaseSimulatorTest fixes") + print("-" * 60) + + try: + # Import and test BaseSimulatorTest + from simulator_tests.base_test import BaseSimulatorTest + + # Test that we can create an instance without logger errors + base_test = BaseSimulatorTest(verbose=False) + + # Check that logger is properly initialized + has_logger = hasattr(base_test, "logger") and base_test.logger is not None + print(f" โœ… Logger initialized: {has_logger}") + + # Check that python_path is set + has_python_path = hasattr(base_test, "python_path") and base_test.python_path is not None + print(f" โœ… Python path set: {has_python_path}") + + # Check that the path detection logic includes Windows + import os + import platform + + if platform.system() == "Windows": + # Test Windows path detection + current_dir = os.getcwd() + expected_path = os.path.join(current_dir, ".zen_venv", "Scripts", "python.exe") + + # Check if the method would detect Windows paths + windows_detection = "Scripts" in expected_path + print(f" โœ… Windows path detection: {windows_detection}") + else: + windows_detection = True # Pass on non-Windows systems + print(" โœ… Windows path detection: N/A (not Windows)") + + # Test that we can call methods that previously failed + try: + # Test accessing properties without calling abstract methods + # Just check that logger-related functionality works + logger_accessible = hasattr(base_test, "logger") and callable(getattr(base_test, "logger", None)) + method_callable = True + print(f" โœ… Methods callable: {method_callable}") + print(f" โœ… Logger accessible: {logger_accessible}") + except AttributeError as e: + if "logger" in str(e): + method_callable = False + print(f" โŒ Logger error still present: {e}") + else: + method_callable = True # Different error, not logger-related + print(f" โœ… No logger errors (different error): {str(e)[:50]}...") + + success = all([has_logger, has_python_path, windows_detection, method_callable]) + print(f"\nResult: BaseSimulatorTest {'passed' if success else 'failed'}") + + return success + + except Exception as e: + print(f" โŒ Error testing BaseSimulatorTest: {e}") + print("\nResult: BaseSimulatorTest failed") + return False + + +def test_shell_scripts_windows_support(): + """Test 7: Shell scripts Windows support.""" + print("\n๐Ÿงช Test 7: Shell scripts Windows support") + print("-" * 60) + + try: + # Check run_integration_tests.sh + try: + with open("run_integration_tests.sh", encoding="utf-8") as f: + run_script_content = f.read() + + has_windows_venv = 'elif [[ -f ".zen_venv/Scripts/activate" ]]; then' in run_script_content + has_windows_msg = "Using virtual environment (Windows)" in run_script_content + + print(f" โœ… run_integration_tests.sh Windows venv: {has_windows_venv}") + print(f" โœ… run_integration_tests.sh Windows message: {has_windows_msg}") + + run_script_ok = has_windows_venv and has_windows_msg + + except FileNotFoundError: + print(" โš ๏ธ run_integration_tests.sh not found") + run_script_ok = True # Skip if file doesn't exist + + # Check code_quality_checks.sh + try: + with open("code_quality_checks.sh", encoding="utf-8") as f: + quality_script_content = f.read() + + has_windows_python = 'elif [[ -f ".zen_venv/Scripts/python.exe" ]]; then' in quality_script_content + has_windows_tools = 'elif [[ -f ".zen_venv/Scripts/ruff.exe" ]]; then' in quality_script_content + has_windows_msg = "Using venv (Windows)" in quality_script_content + + print(f" โœ… code_quality_checks.sh Windows Python: {has_windows_python}") + print(f" โœ… code_quality_checks.sh Windows tools: {has_windows_tools}") + print(f" โœ… code_quality_checks.sh Windows message: {has_windows_msg}") + + quality_script_ok = has_windows_python and has_windows_tools and has_windows_msg + + except FileNotFoundError: + print(" โš ๏ธ code_quality_checks.sh not found") + quality_script_ok = True # Skip if file doesn't exist + + success = run_script_ok and quality_script_ok + print(f"\nResult: Shell scripts {'passed' if success else 'failed'}") + + return success + + except Exception as e: + print(f" โŒ Error testing shell scripts: {e}") + print("\nResult: Shell scripts failed") + return False + + def main(): """Main validation function.""" print("๐Ÿ”ง Final validation of cross-platform fixes") @@ -209,6 +390,9 @@ def main(): results.append(("Unix path validation", test_unix_path_validation())) results.append(("Safe files", test_safe_files_functionality())) results.append(("Cross-platform discovery", test_cross_platform_file_discovery())) + results.append(("Communication simulator", test_communication_simulator_fixes())) + results.append(("BaseSimulatorTest", test_base_simulator_test_fixes())) + results.append(("Shell scripts Windows support", test_shell_scripts_windows_support())) # Final summary print("\n" + "=" * 70) @@ -217,7 +401,7 @@ def main(): passed_tests = 0 for test_name, success in results: - status = "โœ… PASSED" if success else "โŒ FAILED" + status = "PASSED" if success else "FAILED" print(f"{status:<10} {test_name}") if success: passed_tests += 1 diff --git a/run-server.ps1 b/run-server.ps1 index a74623f..80fd2c0 100644 --- a/run-server.ps1 +++ b/run-server.ps1 @@ -365,7 +365,14 @@ function Initialize-Environment { Write-Info "Creating virtual environment with uv..." uv venv $VENV_PATH --python 3.12 if ($LASTEXITCODE -eq 0) { - Write-Success "Environment created with uv" + # Install pip in the uv environment for compatibility + Write-Info "Installing pip in uv environment..." + uv pip install --python "$VENV_PATH\Scripts\python.exe" pip + if ($LASTEXITCODE -eq 0) { + Write-Success "Environment created with uv (pip installed)" + } else { + Write-Success "Environment created with uv" + } return "$VENV_PATH\Scripts\python.exe" } } catch { @@ -546,8 +553,18 @@ function Install-Dependencies { if (Test-Uv) { Write-Info "Installing dependencies with uv..." try { - uv pip install -r requirements.txt + # Install in the virtual environment + uv pip install --python "$VENV_PATH\Scripts\python.exe" -r requirements.txt if ($LASTEXITCODE -eq 0) { + # Also install dev dependencies if available + if (Test-Path "requirements-dev.txt") { + uv pip install --python "$VENV_PATH\Scripts\python.exe" -r requirements-dev.txt + if ($LASTEXITCODE -eq 0) { + Write-Success "Development dependencies installed with uv" + } else { + Write-Warning "Failed to install dev dependencies with uv, continuing..." + } + } Write-Success "Dependencies installed with uv" return } @@ -804,7 +821,7 @@ if exist ".zen_venv\Scripts\python.exe" ( ) else ( python server.py %* ) -"@ | Out-File -FilePath $zenWrapper -Encoding ASCII +"@ | Out-File -FilePath $zenWrapper -Encoding UTF8 Write-Success "Created zen-mcp-server.cmd wrapper script" }