VENV (defaulting)
VS Code Python Virtual Environment Activation Workarounds
Problem Summary
Issue: VS Code Python extension (version 1.102.0) fails to automatically activate virtual environments in both terminal and application execution contexts, despite correct configuration settings.
Impact: - New users cannot run generated projects without manual venv activation - Breaks the "computed default virtual environments" feature that solves the "default venv for new users" problem - Affects both terminal activation and Python application execution - Represents a critical regression in VS Code Python extension functionality
Root Cause
The VS Code Python extension has a regression where standard settings like python.defaultInterpreterPath
and python.terminal.activateEnvironment
are not reliably working. This is documented in GitHub issue #22879.
VS Code Background
How VS Code Handles Virtual Environments
Project Opening:
- VS Code reads .vscode/settings.json
and applies workspace settings
- Python extension detects interpreter path and configures IntelliSense
- .env
file is loaded for environment variables
- Terminal profiles are configured but not executed
- No scripts run automatically - the project is ready but no terminal activation occurs
Terminal Creation:
- When you open a new terminal (Terminal → New Terminal), VS Code uses the default terminal profile
- Our custom "venv" profile executes: source .vscode/venv_init.sh && exec zsh --no-rcs
- The venv_init.sh
script runs, activates the virtual environment, and sets the prompt
- A new shell starts with the virtual environment already activated
Key Point: Virtual environment activation is "lazy loaded" - it only happens when you actually create a terminal, not when the project opens.
Comprehensive Solution
1. Enhanced VS Code Settings Template
File: api_logic_server_cli/prototypes/base/.vscode/settings.json
Key Changes:
{
"python.defaultInterpreterPath": "ApiLogicServerPython",
"python.terminal.activateEnvironment": true,
"python.terminal.activateEnvInCurrentTerminal": true,
"python.envFile": "${workspaceFolder}/.env",
"python.analysis.autoImportCompletions": true,
"python.analysis.extraPaths": ["ApiLogicServerVenvSitePackages"],
// Custom terminal profiles for reliable venv activation
"terminal.integrated.profiles.osx": {
"venv": {
"path": "/bin/zsh",
"args": ["-c", "source ${workspaceFolder}/.vscode/venv_init.sh && exec zsh --no-rcs"]
}
},
"terminal.integrated.profiles.linux": {
"venv": {
"path": "/bin/bash",
"args": ["-c", "source ${workspaceFolder}/.vscode/venv_init.sh && exec bash --noprofile --norc"]
}
},
"terminal.integrated.defaultProfile.osx": "venv",
"terminal.integrated.defaultProfile.linux": "venv"
}
2. Generated Project Files
The project generator now creates additional files to ensure reliable virtual environment activation:
.env
File
Purpose: Explicit Python path configuration for VS Code Python extension Content:
.vscode/venv_init.sh
Script
Purpose: Reliable terminal virtual environment activation with optional debugging Content:
#!/bin/bash
# Virtual Environment Initialization Script
# This script activates the virtual environment for terminal use
# Set DEBUG_VENV_INIT=1 to enable debug output
DEBUG_VENV_INIT=0
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "=== VENV INIT DEBUG ==="
echo "Shell: $0"
echo "ZSH_VERSION: $ZSH_VERSION"
echo "BASH_VERSION: $BASH_VERSION"
echo "Current PS1: $PS1"
echo "VIRTUAL_ENV before: $VIRTUAL_ENV"
fi
# Source the virtual environment activation script
if [ -f "<venv_path>/bin/activate" ]; then
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "Found activation script: <venv_path>/bin/activate"
fi
source <venv_path>/bin/activate
echo "Virtual environment activated: <venv_name>"
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "VIRTUAL_ENV after activation: $VIRTUAL_ENV"
fi
# Don't let virtualenv override the prompt
export VIRTUAL_ENV_DISABLE_PROMPT=1
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "Set VIRTUAL_ENV_DISABLE_PROMPT=1"
fi
# Override the prompt to ensure (venv) shows
if [ -n "${ZSH_VERSION}" ]; then
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "Setting zsh prompt"
fi
export PS1="(venv) %n@%m %1~ %# "
elif [ -n "${BASH_VERSION}" ]; then
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "Setting bash prompt"
fi
export PS1="(venv) \\u@\\h \\W \\$ "
else
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "Unknown shell - trying generic prompt"
fi
export PS1="(venv) $ "
fi
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "Final PS1: $PS1"
echo "Final VIRTUAL_ENV: $VIRTUAL_ENV"
fi
else
echo "Warning: Virtual environment activation script not found at <venv_path>/bin/activate"
fi
if [ "$DEBUG_VENV_INIT" = "1" ]; then
echo "=== END DEBUG ==="
fi
3. Template Placeholder System
Placeholders in settings.json:
- ApiLogicServerPython
→ Replaced with actual Python interpreter path
- ApiLogicServerVenvSitePackages
→ Replaced with venv site-packages path
Generation Code Integration:
- Enhanced api_logic_server.py
to create .env
files
- Added logic to generate venv_init.sh
scripts
- Implemented robust path computation and replacement
Technical Implementation Details
Path Computation Logic
# Compute virtual environment paths
venv_python_path = os.path.join(venv_directory, 'bin', 'python')
venv_site_packages = os.path.join(venv_directory, 'lib', f'python{python_version}', 'site-packages')
# Generate .env file
env_content = f"PYTHONPATH={venv_site_packages}\n"
with open(os.path.join(project_directory, '.env'), 'w') as f:
f.write(env_content)
# Generate venv_init.sh
init_script = f"""#!/bin/bash
if [ -f "{venv_python_path}" ]; then
source {os.path.join(venv_directory, 'bin', 'activate')}
export PYTHONPATH="{venv_site_packages}"
echo "Virtual environment activated"
else
echo "Warning: Virtual environment not found"
fi
"""
with open(os.path.join(project_directory, '.vscode', 'venv_init.sh'), 'w') as f:
f.write(init_script)
Cross-Platform Compatibility
- macOS: Uses
zsh
with custom terminal profile - Linux: Uses
bash
with custom terminal profile - Windows: Inherits default behavior (not affected by the regression)
Testing and Validation
Validation Steps
- Terminal Activation: Open new terminal → Should show
(venv)
prefix - Python Execution: Run Python files → Should use venv interpreter
- Package Access: Import project packages → Should work without PYTHONPATH issues
- Debug Configuration: VS Code debugging → Should use correct interpreter
Known Limitations
- Requires VS Code restart after project generation for full effect
- Custom terminal profiles may need user acknowledgment on first use
- Some VS Code Python extension features may still be unreliable
- Terminal starts without loading user's shell configuration files (zsh/bash rc files)
Troubleshooting
If virtual environment activation is not working:
- Enable Debug Mode: Edit
.vscode/venv_init.sh
and changeDEBUG_VENV_INIT=0
toDEBUG_VENV_INIT=1
- Open New Terminal: The debug output will show exactly what's happening
- Check Debug Output: Look for: - Whether the activation script is found - Which shell is being detected - Whether the virtual environment variables are set correctly - Whether the prompt is being set properly
Common issues and solutions:
- Script not found: Check that the virtual environment path is correct
- Wrong shell detected: The script should detect zsh on macOS
- Prompt not showing: Ensure --no-rcs
is working and not loading conflicting configurations
Future Considerations
Issue Tracking
- Reported to Microsoft: vscode-python #22879
- Monitoring for official fix from VS Code Python extension team
- Workarounds can be removed once regression is resolved
Maintenance Strategy
- Short-term: Maintain comprehensive workarounds
- Medium-term: Monitor VS Code Python extension updates
- Long-term: Simplify back to standard settings when regression is fixed
User Experience Impact
Before Workarounds
- Users had to manually activate virtual environments
- Python execution used system interpreter
- Import errors and dependency issues
- Poor new user experience
After Workarounds
- Automatic virtual environment activation
- Correct Python interpreter usage
- Seamless package imports
- Improved new user onboarding
Documentation Updates
README Updates
Add section explaining: - Virtual environment is automatically configured - No manual activation required - Troubleshooting steps if issues occur
Developer Documentation
- Document the template system enhancements
- Explain placeholder replacement mechanism
- Provide debugging guide for environment issues
Conclusion
These workarounds provide a robust solution to the VS Code Python extension regression while maintaining the goal of "computed default virtual environments for new users." The implementation is comprehensive enough to handle the current issues while being designed for easy removal once the upstream regression is resolved.
The solution ensures that generated projects work out-of-the-box for new users, which is critical for the ApiLogicServer user experience and adoption.