#!/usr/bin/env python3 """ Virtual Environment Setup Script for MIDI Arpeggiator This script creates and configures a virtual environment for the project. """ import subprocess import sys import os import platform import shutil def run_command(cmd, cwd=None, check=True): """Run a command and return the result""" try: print(f"Running: {' '.join(cmd)}") result = subprocess.run(cmd, cwd=cwd, check=check, capture_output=True, text=True) if result.stdout: print(result.stdout) return result except subprocess.CalledProcessError as e: print(f"Error running command: {e}") if e.stderr: print(f"Error output: {e.stderr}") if check: raise return e def check_python_version(): """Check if Python version is compatible""" version = sys.version_info if version.major < 3 or (version.major == 3 and version.minor < 8): print(f"ERROR: Python {version.major}.{version.minor} is not supported") print("Please use Python 3.8 or newer") return False print(f"OK: Python {version.major}.{version.minor}.{version.micro} is compatible") return True def create_virtual_environment(): """Create a virtual environment""" project_dir = os.path.dirname(os.path.abspath(__file__)) venv_dir = os.path.join(project_dir, "venv") if os.path.exists(venv_dir): print(f"Virtual environment already exists at {venv_dir}") response = input("Do you want to recreate it? (y/N): ") if response.lower().startswith('y'): print("Removing existing virtual environment...") shutil.rmtree(venv_dir) else: print("Using existing virtual environment") return venv_dir print("Creating virtual environment...") run_command([sys.executable, "-m", "venv", "venv"], cwd=project_dir) print(f"OK: Virtual environment created at {venv_dir}") return venv_dir def get_venv_python(venv_dir): """Get the path to the Python executable in the virtual environment""" if platform.system() == "Windows": return os.path.join(venv_dir, "Scripts", "python.exe") else: return os.path.join(venv_dir, "bin", "python") def get_venv_pip(venv_dir): """Get the path to pip in the virtual environment""" if platform.system() == "Windows": return os.path.join(venv_dir, "Scripts", "pip.exe") else: return os.path.join(venv_dir, "bin", "pip") def install_dependencies(venv_dir): """Install dependencies in the virtual environment""" project_dir = os.path.dirname(os.path.abspath(__file__)) pip_exe = get_venv_pip(venv_dir) python_exe = get_venv_python(venv_dir) # Upgrade pip first print("Upgrading pip...") run_command([python_exe, "-m", "pip", "install", "--upgrade", "pip"]) # Choose requirements file based on platform if platform.system() == "Windows": requirements_file = "requirements-windows.txt" print("Using Windows-specific requirements...") else: requirements_file = "requirements.txt" print("Using standard requirements...") requirements_path = os.path.join(project_dir, requirements_file) if not os.path.exists(requirements_path): print(f"ERROR: Requirements file not found: {requirements_path}") return False # Install core packages first core_packages = [ "PyQt5>=5.15.0", "numpy>=1.21.0", "pygame>=2.1.0", "mido>=1.2.10" ] print("Installing core packages...") for package in core_packages: try: run_command([pip_exe, "install", package]) print(f"OK: Installed {package}") except subprocess.CalledProcessError as e: print(f"ERROR: Failed to install {package}") return False # Try to install RTMIDI (may fail on some systems) rtmidi_packages = [ "python-rtmidi>=1.5.0", "python-rtmidi", "rtmidi-python>=1.1.0" ] rtmidi_installed = False for package in rtmidi_packages: try: print(f"Trying to install {package}...") run_command([pip_exe, "install", package]) rtmidi_installed = True print(f"OK: Successfully installed {package}") break except subprocess.CalledProcessError: print(f"WARNING: Failed to install {package}, trying next option...") if not rtmidi_installed: print("\nWARNING: Could not install any RTMIDI package.") print("The application will still work in simulator mode.") print("OK: Dependencies installation completed!") return True def create_activation_scripts(): """Create convenient activation scripts""" project_dir = os.path.dirname(os.path.abspath(__file__)) venv_dir = os.path.join(project_dir, "venv") if platform.system() == "Windows": # Windows batch file activate_script = os.path.join(project_dir, "activate.bat") with open(activate_script, 'w') as f: f.write(f'@echo off\n') f.write(f'call "{venv_dir}\\Scripts\\activate.bat"\n') f.write(f'echo Virtual environment activated!\n') f.write(f'echo Run "python run.py" to start the arpeggiator\n') # PowerShell script activate_ps_script = os.path.join(project_dir, "activate.ps1") with open(activate_ps_script, 'w') as f: f.write(f'& "{venv_dir}\\Scripts\\Activate.ps1"\n') f.write(f'Write-Host "Virtual environment activated!" -ForegroundColor Green\n') f.write(f'Write-Host "Run \'python run.py\' to start the arpeggiator" -ForegroundColor Cyan\n') run_script = os.path.join(project_dir, "run_in_venv.bat") with open(run_script, 'w') as f: f.write(f'@echo off\n') f.write(f'call "{venv_dir}\\Scripts\\activate.bat"\n') f.write(f'python run.py\n') print("OK: Created Windows activation scripts:") print(f" - {activate_script}") print(f" - {activate_ps_script}") print(f" - {run_script}") else: # Unix shell script activate_script = os.path.join(project_dir, "activate.sh") with open(activate_script, 'w') as f: f.write('#!/bin/bash\n') f.write(f'source "{venv_dir}/bin/activate"\n') f.write('echo "Virtual environment activated!"\n') f.write('echo "Run \'python run.py\' to start the arpeggiator"\n') os.chmod(activate_script, 0o755) run_script = os.path.join(project_dir, "run_in_venv.sh") with open(run_script, 'w') as f: f.write('#!/bin/bash\n') f.write(f'source "{venv_dir}/bin/activate"\n') f.write('python run.py\n') os.chmod(run_script, 0o755) print("OK: Created Unix activation scripts:") print(f" - {activate_script}") print(f" - {run_script}") def create_dev_requirements(): """Create development requirements file""" project_dir = os.path.dirname(os.path.abspath(__file__)) dev_requirements_path = os.path.join(project_dir, "requirements-dev.txt") dev_packages = [ "# Development dependencies", "pytest>=7.0.0", "pytest-qt>=4.0.0", "black>=22.0.0", "flake8>=4.0.0", "mypy>=0.950", "coverage>=6.0.0" ] with open(dev_requirements_path, 'w') as f: f.write('\n'.join(dev_packages)) print(f"OK: Created development requirements: {dev_requirements_path}") def verify_installation(venv_dir): """Verify that the installation works""" python_exe = get_venv_python(venv_dir) print("\nVerifying installation...") test_imports = [ ("PyQt5", "PyQt5"), ("numpy", "NumPy"), ("pygame", "Pygame"), ("mido", "Mido") ] all_good = True for module, display_name in test_imports: try: result = run_command([python_exe, "-c", f"import {module}; print('OK')"], check=False) if result.returncode == 0: print(f"OK: {display_name}") else: print(f"ERROR: {display_name}") all_good = False except: print(f"ERROR: {display_name}") all_good = False # Test RTMIDI (optional) try: result = run_command([python_exe, "-c", "import rtmidi; print('OK')"], check=False) if result.returncode == 0: print("OK: RTMIDI") else: print("WARNING: RTMIDI (will use simulator mode)") except: print("WARNING: RTMIDI (will use simulator mode)") return all_good def main(): """Main setup function""" # Handle Unicode issues on Windows console try: print("šŸŽ¹ MIDI Arpeggiator - Virtual Environment Setup") except UnicodeEncodeError: print("MIDI Arpeggiator - Virtual Environment Setup") print("=" * 50) # Check Python version if not check_python_version(): return 1 # Create virtual environment try: venv_dir = create_virtual_environment() except Exception as e: print(f"ERROR: Failed to create virtual environment: {e}") return 1 # Install dependencies try: if not install_dependencies(venv_dir): print("ERROR: Failed to install some dependencies") return 1 except Exception as e: print(f"ERROR: Failed to install dependencies: {e}") return 1 # Create activation scripts try: create_activation_scripts() create_dev_requirements() except Exception as e: print(f"ERROR: Failed to create scripts: {e}") return 1 # Verify installation if not verify_installation(venv_dir): print("WARNING: Some packages failed to install properly") print("The application may still work in simulator mode") try: print("\nšŸŽ‰ Virtual environment setup completed successfully!") except UnicodeEncodeError: print("\nVirtual environment setup completed successfully!") try: print("\nšŸ“‹ Next steps:") except UnicodeEncodeError: print("\nNext steps:") if platform.system() == "Windows": print(" 1. Activate the environment:") print(" • Command Prompt: activate.bat") print(" • PowerShell: .\\activate.ps1") print(" 2. Run the application:") print(" • In activated environment: python run.py") print(" • Direct run: run_in_venv.bat") else: print(" 1. Activate the environment: source activate.sh") print(" 2. Run the application: python run.py") print(" Or directly: ./run_in_venv.sh") try: print("\nšŸ’” Tips:") except UnicodeEncodeError: print("\nTips:") print(" • The virtual environment is in the 'venv' folder") print(" • Use 'deactivate' to exit the virtual environment") print(" • Delete 'venv' folder to completely remove the environment") return 0 if __name__ == "__main__": exit(main())