| <# |
| .Synopsis |
| Activate a Python virtual environment for the current PowerShell session. |
| |
| .Description |
| Pushes the python executable for a virtual environment to the front of the |
| $Env:PATH environment variable and sets the prompt to signify that you are |
| in a Python virtual environment. Makes use of the command line switches as |
| well as the `pyvenv.cfg` file values present in the virtual environment. |
| |
| .Parameter VenvDir |
| Path to the directory that contains the virtual environment to activate. The |
| default value for this is the parent of the directory that the Activate.ps1 |
| script is located within. |
| |
| .Parameter Prompt |
| The prompt prefix to display when this virtual environment is activated. By |
| default, this prompt is the name of the virtual environment folder (VenvDir) |
| surrounded by parentheses and followed by a single space (ie. '(.venv) '). |
| |
| .Example |
| Activate.ps1 |
| Activates the Python virtual environment that contains the Activate.ps1 script. |
| |
| .Example |
| Activate.ps1 -Verbose |
| Activates the Python virtual environment that contains the Activate.ps1 script, |
| and shows extra information about the activation as it executes. |
| |
| .Example |
| Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv |
| Activates the Python virtual environment located in the specified location. |
| |
| .Example |
| Activate.ps1 -Prompt "MyPython" |
| Activates the Python virtual environment that contains the Activate.ps1 script, |
| and prefixes the current prompt with the specified string (surrounded in |
| parentheses) while the virtual environment is active. |
| |
| .Notes |
| On Windows, it may be required to enable this Activate.ps1 script by setting the |
| execution policy for the user. You can do this by issuing the following PowerShell |
| command: |
| |
| PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser |
| |
| For more information on Execution Policies: |
| https://go.microsoft.com/fwlink/?LinkID=135170 |
| |
| #> |
| Param( |
| [Parameter(Mandatory = $false)] |
| [String] |
| $VenvDir, |
| [Parameter(Mandatory = $false)] |
| [String] |
| $Prompt |
| ) |
| |
| <# Function declarations --------------------------------------------------- #> |
| |
| <# |
| .Synopsis |
| Remove all shell session elements added by the Activate script, including the |
| addition of the virtual environment's Python executable from the beginning of |
| the PATH variable. |
| |
| .Parameter NonDestructive |
| If present, do not remove this function from the global namespace for the |
| session. |
| |
| #> |
| function global:deactivate ([switch]$NonDestructive) { |
| # Revert to original values |
| |
| # The prior prompt: |
| if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { |
| Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt |
| Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT |
| } |
| |
| # The prior PYTHONHOME: |
| if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { |
| Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME |
| Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME |
| } |
| |
| # The prior PATH: |
| if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { |
| Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH |
| Remove-Item -Path Env:_OLD_VIRTUAL_PATH |
| } |
| |
| # Just remove the VIRTUAL_ENV altogether: |
| if (Test-Path -Path Env:VIRTUAL_ENV) { |
| Remove-Item -Path env:VIRTUAL_ENV |
| } |
| |
| # Just remove VIRTUAL_ENV_PROMPT altogether. |
| if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { |
| Remove-Item -Path env:VIRTUAL_ENV_PROMPT |
| } |
| |
| # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: |
| if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { |
| Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force |
| } |
| |
| # Leave deactivate function in the global namespace if requested: |
| if (-not $NonDestructive) { |
| Remove-Item -Path function:deactivate |
| } |
| } |
| |
| <# |
| .Description |
| Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the |
| given folder, and returns them in a map. |
| |
| For each line in the pyvenv.cfg file, if that line can be parsed into exactly |
| two strings separated by `=` (with any amount of whitespace surrounding the =) |
| then it is considered a `key = value` line. The left hand string is the key, |
| the right hand is the value. |
| |
| If the value starts with a `'` or a `"` then the first and last character is |
| stripped from the value before being captured. |
| |
| .Parameter ConfigDir |
| Path to the directory that contains the `pyvenv.cfg` file. |
| #> |
| function Get-PyVenvConfig( |
| [String] |
| $ConfigDir |
| ) { |
| Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" |
| |
| # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). |
| $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue |
| |
| # An empty map will be returned if no config file is found. |
| $pyvenvConfig = @{ } |
| |
| if ($pyvenvConfigPath) { |
| |
| Write-Verbose "File exists, parse `key = value` lines" |
| $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath |
| |
| $pyvenvConfigContent | ForEach-Object { |
| $keyval = $PSItem -split "\s*=\s*", 2 |
| if ($keyval[0] -and $keyval[1]) { |
| $val = $keyval[1] |
| |
| # Remove extraneous quotations around a string value. |
| if ("'""".Contains($val.Substring(0, 1))) { |
| $val = $val.Substring(1, $val.Length - 2) |
| } |
| |
| $pyvenvConfig[$keyval[0]] = $val |
| Write-Verbose "Adding Key: '$($keyval[0])'='$val'" |
| } |
| } |
| } |
| return $pyvenvConfig |
| } |
| |
| |
| <# Begin Activate script --------------------------------------------------- #> |
| |
| # Determine the containing directory of this script |
| $VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition |
| $VenvExecDir = Get-Item -Path $VenvExecPath |
| |
| Write-Verbose "Activation script is located in path: '$VenvExecPath'" |
| Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" |
| Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" |
| |
| # Set values required in priority: CmdLine, ConfigFile, Default |
| # First, get the location of the virtual environment, it might not be |
| # VenvExecDir if specified on the command line. |
| if ($VenvDir) { |
| Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" |
| } |
| else { |
| Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." |
| $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") |
| Write-Verbose "VenvDir=$VenvDir" |
| } |
| |
| # Next, read the `pyvenv.cfg` file to determine any required value such |
| # as `prompt`. |
| $pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir |
| |
| # Next, set the prompt from the command line, or the config file, or |
| # just use the name of the virtual environment folder. |
| if ($Prompt) { |
| Write-Verbose "Prompt specified as argument, using '$Prompt'" |
| } |
| else { |
| Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" |
| if ($pyvenvCfg -and $pyvenvCfg['prompt']) { |
| Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" |
| $Prompt = $pyvenvCfg['prompt']; |
| } |
| else { |
| Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" |
| Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" |
| $Prompt = Split-Path -Path $venvDir -Leaf |
| } |
| } |
| |
| Write-Verbose "Prompt = '$Prompt'" |
| Write-Verbose "VenvDir='$VenvDir'" |
| |
| # Deactivate any currently active virtual environment, but leave the |
| # deactivate function in place. |
| deactivate -nondestructive |
| |
| # Now set the environment variable VIRTUAL_ENV, used by many tools to determine |
| # that there is an activated venv. |
| $env:VIRTUAL_ENV = $VenvDir |
| |
| if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { |
| |
| Write-Verbose "Setting prompt to '$Prompt'" |
| |
| # Set the prompt to include the env name |
| # Make sure _OLD_VIRTUAL_PROMPT is global |
| function global:_OLD_VIRTUAL_PROMPT { "" } |
| Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT |
| New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt |
| |
| function global:prompt { |
| Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " |
| _OLD_VIRTUAL_PROMPT |
| } |
| $env:VIRTUAL_ENV_PROMPT = $Prompt |
| } |
| |
| # Clear PYTHONHOME |
| if (Test-Path -Path Env:PYTHONHOME) { |
| Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME |
| Remove-Item -Path Env:PYTHONHOME |
| } |
| |
| # Add the venv to the PATH |
| Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH |
| $Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" |