17db96d56Sopenharmony_ci<#
27db96d56Sopenharmony_ci.Synopsis
37db96d56Sopenharmony_ciActivate a Python virtual environment for the current PowerShell session.
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci.Description
67db96d56Sopenharmony_ciPushes the python executable for a virtual environment to the front of the
77db96d56Sopenharmony_ci$Env:PATH environment variable and sets the prompt to signify that you are
87db96d56Sopenharmony_ciin a Python virtual environment. Makes use of the command line switches as
97db96d56Sopenharmony_ciwell as the `pyvenv.cfg` file values present in the virtual environment.
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ci.Parameter VenvDir
127db96d56Sopenharmony_ciPath to the directory that contains the virtual environment to activate. The
137db96d56Sopenharmony_cidefault value for this is the parent of the directory that the Activate.ps1
147db96d56Sopenharmony_ciscript is located within.
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci.Parameter Prompt
177db96d56Sopenharmony_ciThe prompt prefix to display when this virtual environment is activated. By
187db96d56Sopenharmony_cidefault, this prompt is the name of the virtual environment folder (VenvDir)
197db96d56Sopenharmony_cisurrounded by parentheses and followed by a single space (ie. '(.venv) ').
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci.Example
227db96d56Sopenharmony_ciActivate.ps1
237db96d56Sopenharmony_ciActivates the Python virtual environment that contains the Activate.ps1 script.
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ci.Example
267db96d56Sopenharmony_ciActivate.ps1 -Verbose
277db96d56Sopenharmony_ciActivates the Python virtual environment that contains the Activate.ps1 script,
287db96d56Sopenharmony_ciand shows extra information about the activation as it executes.
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci.Example
317db96d56Sopenharmony_ciActivate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
327db96d56Sopenharmony_ciActivates the Python virtual environment located in the specified location.
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ci.Example
357db96d56Sopenharmony_ciActivate.ps1 -Prompt "MyPython"
367db96d56Sopenharmony_ciActivates the Python virtual environment that contains the Activate.ps1 script,
377db96d56Sopenharmony_ciand prefixes the current prompt with the specified string (surrounded in
387db96d56Sopenharmony_ciparentheses) while the virtual environment is active.
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ci.Notes
417db96d56Sopenharmony_ciOn Windows, it may be required to enable this Activate.ps1 script by setting the
427db96d56Sopenharmony_ciexecution policy for the user. You can do this by issuing the following PowerShell
437db96d56Sopenharmony_cicommand:
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_ciPS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ciFor more information on Execution Policies: 
487db96d56Sopenharmony_cihttps://go.microsoft.com/fwlink/?LinkID=135170
497db96d56Sopenharmony_ci
507db96d56Sopenharmony_ci#>
517db96d56Sopenharmony_ciParam(
527db96d56Sopenharmony_ci    [Parameter(Mandatory = $false)]
537db96d56Sopenharmony_ci    [String]
547db96d56Sopenharmony_ci    $VenvDir,
557db96d56Sopenharmony_ci    [Parameter(Mandatory = $false)]
567db96d56Sopenharmony_ci    [String]
577db96d56Sopenharmony_ci    $Prompt
587db96d56Sopenharmony_ci)
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci<# Function declarations --------------------------------------------------- #>
617db96d56Sopenharmony_ci
627db96d56Sopenharmony_ci<#
637db96d56Sopenharmony_ci.Synopsis
647db96d56Sopenharmony_ciRemove all shell session elements added by the Activate script, including the
657db96d56Sopenharmony_ciaddition of the virtual environment's Python executable from the beginning of
667db96d56Sopenharmony_cithe PATH variable.
677db96d56Sopenharmony_ci
687db96d56Sopenharmony_ci.Parameter NonDestructive
697db96d56Sopenharmony_ciIf present, do not remove this function from the global namespace for the
707db96d56Sopenharmony_cisession.
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci#>
737db96d56Sopenharmony_cifunction global:deactivate ([switch]$NonDestructive) {
747db96d56Sopenharmony_ci    # Revert to original values
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ci    # The prior prompt:
777db96d56Sopenharmony_ci    if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
787db96d56Sopenharmony_ci        Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
797db96d56Sopenharmony_ci        Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
807db96d56Sopenharmony_ci    }
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci    # The prior PYTHONHOME:
837db96d56Sopenharmony_ci    if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
847db96d56Sopenharmony_ci        Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
857db96d56Sopenharmony_ci        Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
867db96d56Sopenharmony_ci    }
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_ci    # The prior PATH:
897db96d56Sopenharmony_ci    if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
907db96d56Sopenharmony_ci        Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
917db96d56Sopenharmony_ci        Remove-Item -Path Env:_OLD_VIRTUAL_PATH
927db96d56Sopenharmony_ci    }
937db96d56Sopenharmony_ci
947db96d56Sopenharmony_ci    # Just remove the VIRTUAL_ENV altogether:
957db96d56Sopenharmony_ci    if (Test-Path -Path Env:VIRTUAL_ENV) {
967db96d56Sopenharmony_ci        Remove-Item -Path env:VIRTUAL_ENV
977db96d56Sopenharmony_ci    }
987db96d56Sopenharmony_ci
997db96d56Sopenharmony_ci    # Just remove VIRTUAL_ENV_PROMPT altogether.
1007db96d56Sopenharmony_ci    if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
1017db96d56Sopenharmony_ci        Remove-Item -Path env:VIRTUAL_ENV_PROMPT
1027db96d56Sopenharmony_ci    }
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_ci    # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
1057db96d56Sopenharmony_ci    if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
1067db96d56Sopenharmony_ci        Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
1077db96d56Sopenharmony_ci    }
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci    # Leave deactivate function in the global namespace if requested:
1107db96d56Sopenharmony_ci    if (-not $NonDestructive) {
1117db96d56Sopenharmony_ci        Remove-Item -Path function:deactivate
1127db96d56Sopenharmony_ci    }
1137db96d56Sopenharmony_ci}
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci<#
1167db96d56Sopenharmony_ci.Description
1177db96d56Sopenharmony_ciGet-PyVenvConfig parses the values from the pyvenv.cfg file located in the
1187db96d56Sopenharmony_cigiven folder, and returns them in a map.
1197db96d56Sopenharmony_ci
1207db96d56Sopenharmony_ciFor each line in the pyvenv.cfg file, if that line can be parsed into exactly
1217db96d56Sopenharmony_citwo strings separated by `=` (with any amount of whitespace surrounding the =)
1227db96d56Sopenharmony_cithen it is considered a `key = value` line. The left hand string is the key,
1237db96d56Sopenharmony_cithe right hand is the value.
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ciIf the value starts with a `'` or a `"` then the first and last character is
1267db96d56Sopenharmony_cistripped from the value before being captured.
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci.Parameter ConfigDir
1297db96d56Sopenharmony_ciPath to the directory that contains the `pyvenv.cfg` file.
1307db96d56Sopenharmony_ci#>
1317db96d56Sopenharmony_cifunction Get-PyVenvConfig(
1327db96d56Sopenharmony_ci    [String]
1337db96d56Sopenharmony_ci    $ConfigDir
1347db96d56Sopenharmony_ci) {
1357db96d56Sopenharmony_ci    Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci    # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
1387db96d56Sopenharmony_ci    $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci    # An empty map will be returned if no config file is found.
1417db96d56Sopenharmony_ci    $pyvenvConfig = @{ }
1427db96d56Sopenharmony_ci
1437db96d56Sopenharmony_ci    if ($pyvenvConfigPath) {
1447db96d56Sopenharmony_ci
1457db96d56Sopenharmony_ci        Write-Verbose "File exists, parse `key = value` lines"
1467db96d56Sopenharmony_ci        $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
1477db96d56Sopenharmony_ci
1487db96d56Sopenharmony_ci        $pyvenvConfigContent | ForEach-Object {
1497db96d56Sopenharmony_ci            $keyval = $PSItem -split "\s*=\s*", 2
1507db96d56Sopenharmony_ci            if ($keyval[0] -and $keyval[1]) {
1517db96d56Sopenharmony_ci                $val = $keyval[1]
1527db96d56Sopenharmony_ci
1537db96d56Sopenharmony_ci                # Remove extraneous quotations around a string value.
1547db96d56Sopenharmony_ci                if ("'""".Contains($val.Substring(0, 1))) {
1557db96d56Sopenharmony_ci                    $val = $val.Substring(1, $val.Length - 2)
1567db96d56Sopenharmony_ci                }
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ci                $pyvenvConfig[$keyval[0]] = $val
1597db96d56Sopenharmony_ci                Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
1607db96d56Sopenharmony_ci            }
1617db96d56Sopenharmony_ci        }
1627db96d56Sopenharmony_ci    }
1637db96d56Sopenharmony_ci    return $pyvenvConfig
1647db96d56Sopenharmony_ci}
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci
1677db96d56Sopenharmony_ci<# Begin Activate script --------------------------------------------------- #>
1687db96d56Sopenharmony_ci
1697db96d56Sopenharmony_ci# Determine the containing directory of this script
1707db96d56Sopenharmony_ci$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
1717db96d56Sopenharmony_ci$VenvExecDir = Get-Item -Path $VenvExecPath
1727db96d56Sopenharmony_ci
1737db96d56Sopenharmony_ciWrite-Verbose "Activation script is located in path: '$VenvExecPath'"
1747db96d56Sopenharmony_ciWrite-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
1757db96d56Sopenharmony_ciWrite-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ci# Set values required in priority: CmdLine, ConfigFile, Default
1787db96d56Sopenharmony_ci# First, get the location of the virtual environment, it might not be
1797db96d56Sopenharmony_ci# VenvExecDir if specified on the command line.
1807db96d56Sopenharmony_ciif ($VenvDir) {
1817db96d56Sopenharmony_ci    Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
1827db96d56Sopenharmony_ci}
1837db96d56Sopenharmony_cielse {
1847db96d56Sopenharmony_ci    Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
1857db96d56Sopenharmony_ci    $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
1867db96d56Sopenharmony_ci    Write-Verbose "VenvDir=$VenvDir"
1877db96d56Sopenharmony_ci}
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_ci# Next, read the `pyvenv.cfg` file to determine any required value such
1907db96d56Sopenharmony_ci# as `prompt`.
1917db96d56Sopenharmony_ci$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
1927db96d56Sopenharmony_ci
1937db96d56Sopenharmony_ci# Next, set the prompt from the command line, or the config file, or
1947db96d56Sopenharmony_ci# just use the name of the virtual environment folder.
1957db96d56Sopenharmony_ciif ($Prompt) {
1967db96d56Sopenharmony_ci    Write-Verbose "Prompt specified as argument, using '$Prompt'"
1977db96d56Sopenharmony_ci}
1987db96d56Sopenharmony_cielse {
1997db96d56Sopenharmony_ci    Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
2007db96d56Sopenharmony_ci    if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
2017db96d56Sopenharmony_ci        Write-Verbose "  Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
2027db96d56Sopenharmony_ci        $Prompt = $pyvenvCfg['prompt'];
2037db96d56Sopenharmony_ci    }
2047db96d56Sopenharmony_ci    else {
2057db96d56Sopenharmony_ci        Write-Verbose "  Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
2067db96d56Sopenharmony_ci        Write-Verbose "  Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
2077db96d56Sopenharmony_ci        $Prompt = Split-Path -Path $venvDir -Leaf
2087db96d56Sopenharmony_ci    }
2097db96d56Sopenharmony_ci}
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ciWrite-Verbose "Prompt = '$Prompt'"
2127db96d56Sopenharmony_ciWrite-Verbose "VenvDir='$VenvDir'"
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_ci# Deactivate any currently active virtual environment, but leave the
2157db96d56Sopenharmony_ci# deactivate function in place.
2167db96d56Sopenharmony_cideactivate -nondestructive
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
2197db96d56Sopenharmony_ci# that there is an activated venv.
2207db96d56Sopenharmony_ci$env:VIRTUAL_ENV = $VenvDir
2217db96d56Sopenharmony_ci
2227db96d56Sopenharmony_ciif (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
2237db96d56Sopenharmony_ci
2247db96d56Sopenharmony_ci    Write-Verbose "Setting prompt to '$Prompt'"
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci    # Set the prompt to include the env name
2277db96d56Sopenharmony_ci    # Make sure _OLD_VIRTUAL_PROMPT is global
2287db96d56Sopenharmony_ci    function global:_OLD_VIRTUAL_PROMPT { "" }
2297db96d56Sopenharmony_ci    Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
2307db96d56Sopenharmony_ci    New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
2317db96d56Sopenharmony_ci
2327db96d56Sopenharmony_ci    function global:prompt {
2337db96d56Sopenharmony_ci        Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
2347db96d56Sopenharmony_ci        _OLD_VIRTUAL_PROMPT
2357db96d56Sopenharmony_ci    }
2367db96d56Sopenharmony_ci    $env:VIRTUAL_ENV_PROMPT = $Prompt
2377db96d56Sopenharmony_ci}
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ci# Clear PYTHONHOME
2407db96d56Sopenharmony_ciif (Test-Path -Path Env:PYTHONHOME) {
2417db96d56Sopenharmony_ci    Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
2427db96d56Sopenharmony_ci    Remove-Item -Path Env:PYTHONHOME
2437db96d56Sopenharmony_ci}
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci# Add the venv to the PATH
2467db96d56Sopenharmony_ciCopy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
2477db96d56Sopenharmony_ci$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
248