Browse Source
Add comprehensive virtual environment support
Add comprehensive virtual environment support
Features: - Automated virtual environment setup with setup_venv.py - Cross-platform activation scripts (Windows batch/PowerShell, Unix shell) - Direct run scripts for easy execution without manual activation - Development requirements with testing and linting tools - Comprehensive documentation in README_VENV.md - Proper .gitignore for Python projects Setup Process: - One-command setup: python setup_venv.py - Handles dependency installation with fallbacks for MIDI libraries - Creates platform-specific activation scripts automatically - Verifies installation and provides troubleshooting guidance - Updated main README with virtual environment instructions Benefits: - Dependency isolation from other Python projects - Reproducible installations across different machines - Easy cleanup and environment management - Development tool integration for testing and code quality - Graceful handling of problematic MIDI library installations Usage: Windows: run_in_venv.bat or activate.bat && python run.py Linux/Mac: ./run_in_venv.sh or source activate.sh && python run.py 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>master
8 changed files with 679 additions and 2 deletions
-
91.gitignore
-
57README.md
-
187README_VENV.md
-
4activate.bat
-
3activate.ps1
-
7requirements-dev.txt
-
3run_in_venv.bat
-
329setup_venv.py
@ -0,0 +1,91 @@ |
|||
# Virtual Environment |
|||
venv/ |
|||
env/ |
|||
.env |
|||
|
|||
# Python |
|||
__pycache__/ |
|||
*.py[cod] |
|||
*$py.class |
|||
*.so |
|||
.Python |
|||
build/ |
|||
develop-eggs/ |
|||
dist/ |
|||
downloads/ |
|||
eggs/ |
|||
.eggs/ |
|||
lib/ |
|||
lib64/ |
|||
parts/ |
|||
sdist/ |
|||
var/ |
|||
wheels/ |
|||
pip-wheel-metadata/ |
|||
share/python-wheels/ |
|||
*.egg-info/ |
|||
.installed.cfg |
|||
*.egg |
|||
MANIFEST |
|||
|
|||
# PyQt5 |
|||
*.ui~ |
|||
|
|||
# IDE |
|||
.vscode/ |
|||
.idea/ |
|||
*.swp |
|||
*.swo |
|||
*~ |
|||
|
|||
# OS |
|||
.DS_Store |
|||
Thumbs.db |
|||
|
|||
# Logs |
|||
*.log |
|||
|
|||
# Configuration backups |
|||
config.json.bak |
|||
config.json.old |
|||
|
|||
# Temporary files |
|||
*.tmp |
|||
*.temp |
|||
|
|||
# Coverage reports |
|||
htmlcov/ |
|||
.tox/ |
|||
.coverage |
|||
.coverage.* |
|||
.cache |
|||
nosetests.xml |
|||
coverage.xml |
|||
*.cover |
|||
*.py,cover |
|||
.hypothesis/ |
|||
.pytest_cache/ |
|||
|
|||
# Environments |
|||
.env |
|||
.venv |
|||
env/ |
|||
venv/ |
|||
ENV/ |
|||
env.bak/ |
|||
venv.bak/ |
|||
|
|||
# mypy |
|||
.mypy_cache/ |
|||
.dmypy.json |
|||
dmypy.json |
|||
|
|||
# Black |
|||
.black |
|||
|
|||
# Generated activation scripts (optional - user can choose to track these) |
|||
# activate.bat |
|||
# activate.ps1 |
|||
# activate.sh |
|||
# run_in_venv.bat |
|||
# run_in_venv.sh |
|||
@ -0,0 +1,187 @@ |
|||
# Virtual Environment Setup |
|||
|
|||
This project now supports virtual environment setup for better dependency management and isolation. |
|||
|
|||
## Quick Setup |
|||
|
|||
### Windows |
|||
```bash |
|||
# Run the setup script |
|||
python setup_venv.py |
|||
|
|||
# Activate the virtual environment (choose one) |
|||
activate.bat # Command Prompt |
|||
.\activate.ps1 # PowerShell |
|||
|
|||
# Run the application |
|||
python run.py |
|||
|
|||
# Or run directly without manual activation |
|||
run_in_venv.bat |
|||
``` |
|||
|
|||
### Linux/Mac |
|||
```bash |
|||
# Run the setup script |
|||
python3 setup_venv.py |
|||
|
|||
# Activate the virtual environment |
|||
source activate.sh |
|||
|
|||
# Run the application |
|||
python run.py |
|||
|
|||
# Or run directly without manual activation |
|||
./run_in_venv.sh |
|||
``` |
|||
|
|||
## What the Setup Script Does |
|||
|
|||
1. **Creates a virtual environment** in the `venv` folder |
|||
2. **Installs all dependencies** from requirements files |
|||
3. **Creates activation scripts** for easy environment management |
|||
4. **Verifies installation** to ensure everything works |
|||
5. **Handles MIDI library issues** gracefully (falls back to simulator mode) |
|||
|
|||
## File Structure After Setup |
|||
|
|||
``` |
|||
arppegiator/ |
|||
├── venv/ # Virtual environment (created) |
|||
├── activate.bat # Windows activation (created) |
|||
├── activate.ps1 # PowerShell activation (created) |
|||
├── activate.sh # Unix activation (created) |
|||
├── run_in_venv.bat # Windows direct run (created) |
|||
├── run_in_venv.sh # Unix direct run (created) |
|||
├── setup_venv.py # Setup script (created) |
|||
├── requirements-dev.txt # Development dependencies (created) |
|||
├── requirements.txt # Main dependencies |
|||
├── requirements-windows.txt # Windows-specific dependencies |
|||
└── ... (rest of project files) |
|||
``` |
|||
|
|||
## Manual Virtual Environment Setup |
|||
|
|||
If the setup script doesn't work, you can set up manually: |
|||
|
|||
```bash |
|||
# Create virtual environment |
|||
python -m venv venv |
|||
|
|||
# Activate it |
|||
# Windows: |
|||
venv\Scripts\activate.bat |
|||
# Linux/Mac: |
|||
source venv/bin/activate |
|||
|
|||
# Install dependencies |
|||
pip install -r requirements.txt |
|||
|
|||
# Run the application |
|||
python run.py |
|||
``` |
|||
|
|||
## Development Setup |
|||
|
|||
For development with additional tools: |
|||
|
|||
```bash |
|||
# After setting up the main environment, install dev dependencies |
|||
pip install -r requirements-dev.txt |
|||
``` |
|||
|
|||
This includes: |
|||
- `pytest` - Testing framework |
|||
- `pytest-qt` - Qt application testing |
|||
- `black` - Code formatting |
|||
- `flake8` - Code linting |
|||
- `mypy` - Type checking |
|||
- `coverage` - Code coverage analysis |
|||
|
|||
## Troubleshooting |
|||
|
|||
### Common Issues |
|||
|
|||
**1. Python version too old** |
|||
- Requires Python 3.8 or newer |
|||
- Check with: `python --version` |
|||
|
|||
**2. Virtual environment creation fails** |
|||
- Make sure `venv` module is available: `python -m venv --help` |
|||
- On Ubuntu/Debian: `sudo apt install python3-venv` |
|||
|
|||
**3. Permission errors on Windows** |
|||
- Run Command Prompt/PowerShell as Administrator |
|||
- Or use: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` |
|||
|
|||
**4. MIDI libraries fail to install** |
|||
- This is normal on some systems |
|||
- The application will work in simulator mode |
|||
- For hardware MIDI, you may need Visual Studio Build Tools |
|||
|
|||
**5. PyQt5 installation fails** |
|||
- Try: `pip install --only-binary=PyQt5 PyQt5` |
|||
- Or install from conda: `conda install pyqt` |
|||
|
|||
### Verifying Installation |
|||
|
|||
Test that everything is working: |
|||
|
|||
```bash |
|||
# With environment activated |
|||
python -c " |
|||
import PyQt5; print('✅ PyQt5 OK') |
|||
import numpy; print('✅ NumPy OK') |
|||
import pygame; print('✅ Pygame OK') |
|||
import mido; print('✅ Mido OK') |
|||
try: |
|||
import rtmidi; print('✅ RTMIDI OK - Hardware MIDI available') |
|||
except: print('⚠️ RTMIDI not available - Simulator mode only') |
|||
print('🎹 Ready to run!') |
|||
" |
|||
``` |
|||
|
|||
### Removing the Virtual Environment |
|||
|
|||
To completely remove the virtual environment: |
|||
|
|||
```bash |
|||
# Make sure you're not in the environment |
|||
deactivate |
|||
|
|||
# Delete the environment folder |
|||
# Windows: |
|||
rmdir /s venv |
|||
# Linux/Mac: |
|||
rm -rf venv |
|||
|
|||
# Also remove the activation scripts if desired |
|||
# Windows: |
|||
del activate.bat activate.ps1 run_in_venv.bat |
|||
# Linux/Mac: |
|||
rm activate.sh run_in_venv.sh |
|||
``` |
|||
|
|||
## Benefits of Virtual Environment |
|||
|
|||
✅ **Isolation**: Dependencies don't conflict with other Python projects |
|||
✅ **Reproducibility**: Exact same versions across different machines |
|||
✅ **Cleanliness**: Easy to remove everything without affecting system Python |
|||
✅ **Testing**: Test with different dependency versions safely |
|||
✅ **Distribution**: Share exact environment with others |
|||
|
|||
## IDE Integration |
|||
|
|||
### VS Code |
|||
1. Open the project folder |
|||
2. VS Code should auto-detect the virtual environment in `venv/` |
|||
3. Select the Python interpreter: `Ctrl+Shift+P` → "Python: Select Interpreter" |
|||
4. Choose the one in `venv/Scripts/python.exe` (Windows) or `venv/bin/python` (Unix) |
|||
|
|||
### PyCharm |
|||
1. File → Settings → Project → Python Interpreter |
|||
2. Add → Existing Environment |
|||
3. Choose `venv/Scripts/python.exe` (Windows) or `venv/bin/python` (Unix) |
|||
|
|||
### Other IDEs |
|||
Point your IDE's Python interpreter to the one inside the `venv` folder. |
|||
@ -0,0 +1,4 @@ |
|||
@echo off |
|||
call "C:\git\arppegiator\venv\Scripts\activate.bat" |
|||
echo Virtual environment activated! |
|||
echo Run "python run.py" to start the arpeggiator |
|||
@ -0,0 +1,3 @@ |
|||
& "C:\git\arppegiator\venv\Scripts\Activate.ps1" |
|||
Write-Host "Virtual environment activated!" -ForegroundColor Green |
|||
Write-Host "Run 'python run.py' to start the arpeggiator" -ForegroundColor Cyan |
|||
@ -0,0 +1,7 @@ |
|||
# 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 |
|||
@ -0,0 +1,3 @@ |
|||
@echo off |
|||
call "C:\git\arppegiator\venv\Scripts\activate.bat" |
|||
python run.py |
|||
@ -0,0 +1,329 @@ |
|||
#!/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()) |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue