]>
Commit | Line | Data |
---|---|---|
53e6db90 DC |
1 | <# |
2 | .Synopsis | |
3 | Activate a Python virtual environment for the current PowerShell session. | |
4 | ||
5 | .Description | |
6 | Pushes the python executable for a virtual environment to the front of the | |
7 | $Env:PATH environment variable and sets the prompt to signify that you are | |
8 | in a Python virtual environment. Makes use of the command line switches as | |
9 | well as the `pyvenv.cfg` file values present in the virtual environment. | |
10 | ||
11 | .Parameter VenvDir | |
12 | Path to the directory that contains the virtual environment to activate. The | |
13 | default value for this is the parent of the directory that the Activate.ps1 | |
14 | script is located within. | |
15 | ||
16 | .Parameter Prompt | |
17 | The prompt prefix to display when this virtual environment is activated. By | |
18 | default, this prompt is the name of the virtual environment folder (VenvDir) | |
19 | surrounded by parentheses and followed by a single space (ie. '(.venv) '). | |
20 | ||
21 | .Example | |
22 | Activate.ps1 | |
23 | Activates the Python virtual environment that contains the Activate.ps1 script. | |
24 | ||
25 | .Example | |
26 | Activate.ps1 -Verbose | |
27 | Activates the Python virtual environment that contains the Activate.ps1 script, | |
28 | and shows extra information about the activation as it executes. | |
29 | ||
30 | .Example | |
31 | Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv | |
32 | Activates the Python virtual environment located in the specified location. | |
33 | ||
34 | .Example | |
35 | Activate.ps1 -Prompt "MyPython" | |
36 | Activates the Python virtual environment that contains the Activate.ps1 script, | |
37 | and prefixes the current prompt with the specified string (surrounded in | |
38 | parentheses) while the virtual environment is active. | |
39 | ||
40 | .Notes | |
41 | On Windows, it may be required to enable this Activate.ps1 script by setting the | |
42 | execution policy for the user. You can do this by issuing the following PowerShell | |
43 | command: | |
44 | ||
45 | PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser | |
46 | ||
47 | For more information on Execution Policies: | |
48 | https://go.microsoft.com/fwlink/?LinkID=135170 | |
49 | ||
50 | #> | |
51 | Param( | |
52 | [Parameter(Mandatory = $false)] | |
53 | [String] | |
54 | $VenvDir, | |
55 | [Parameter(Mandatory = $false)] | |
56 | [String] | |
57 | $Prompt | |
58 | ) | |
59 | ||
60 | <# Function declarations --------------------------------------------------- #> | |
61 | ||
62 | <# | |
63 | .Synopsis | |
64 | Remove all shell session elements added by the Activate script, including the | |
65 | addition of the virtual environment's Python executable from the beginning of | |
66 | the PATH variable. | |
67 | ||
68 | .Parameter NonDestructive | |
69 | If present, do not remove this function from the global namespace for the | |
70 | session. | |
71 | ||
72 | #> | |
73 | function global:deactivate ([switch]$NonDestructive) { | |
74 | # Revert to original values | |
75 | ||
76 | # The prior prompt: | |
77 | if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { | |
78 | Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt | |
79 | Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT | |
80 | } | |
81 | ||
82 | # The prior PYTHONHOME: | |
83 | if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { | |
84 | Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME | |
85 | Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME | |
86 | } | |
87 | ||
88 | # The prior PATH: | |
89 | if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { | |
90 | Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH | |
91 | Remove-Item -Path Env:_OLD_VIRTUAL_PATH | |
92 | } | |
93 | ||
94 | # Just remove the VIRTUAL_ENV altogether: | |
95 | if (Test-Path -Path Env:VIRTUAL_ENV) { | |
96 | Remove-Item -Path env:VIRTUAL_ENV | |
97 | } | |
98 | ||
99 | # Just remove VIRTUAL_ENV_PROMPT altogether. | |
100 | if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { | |
101 | Remove-Item -Path env:VIRTUAL_ENV_PROMPT | |
102 | } | |
103 | ||
104 | # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: | |
105 | if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { | |
106 | Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force | |
107 | } | |
108 | ||
109 | # Leave deactivate function in the global namespace if requested: | |
110 | if (-not $NonDestructive) { | |
111 | Remove-Item -Path function:deactivate | |
112 | } | |
113 | } | |
114 | ||
115 | <# | |
116 | .Description | |
117 | Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the | |
118 | given folder, and returns them in a map. | |
119 | ||
120 | For each line in the pyvenv.cfg file, if that line can be parsed into exactly | |
121 | two strings separated by `=` (with any amount of whitespace surrounding the =) | |
122 | then it is considered a `key = value` line. The left hand string is the key, | |
123 | the right hand is the value. | |
124 | ||
125 | If the value starts with a `'` or a `"` then the first and last character is | |
126 | stripped from the value before being captured. | |
127 | ||
128 | .Parameter ConfigDir | |
129 | Path to the directory that contains the `pyvenv.cfg` file. | |
130 | #> | |
131 | function Get-PyVenvConfig( | |
132 | [String] | |
133 | $ConfigDir | |
134 | ) { | |
135 | Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" | |
136 | ||
137 | # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). | |
138 | $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue | |
139 | ||
140 | # An empty map will be returned if no config file is found. | |
141 | $pyvenvConfig = @{ } | |
142 | ||
143 | if ($pyvenvConfigPath) { | |
144 | ||
145 | Write-Verbose "File exists, parse `key = value` lines" | |
146 | $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath | |
147 | ||
148 | $pyvenvConfigContent | ForEach-Object { | |
149 | $keyval = $PSItem -split "\s*=\s*", 2 | |
150 | if ($keyval[0] -and $keyval[1]) { | |
151 | $val = $keyval[1] | |
152 | ||
153 | # Remove extraneous quotations around a string value. | |
154 | if ("'""".Contains($val.Substring(0, 1))) { | |
155 | $val = $val.Substring(1, $val.Length - 2) | |
156 | } | |
157 | ||
158 | $pyvenvConfig[$keyval[0]] = $val | |
159 | Write-Verbose "Adding Key: '$($keyval[0])'='$val'" | |
160 | } | |
161 | } | |
162 | } | |
163 | return $pyvenvConfig | |
164 | } | |
165 | ||
166 | ||
167 | <# Begin Activate script --------------------------------------------------- #> | |
168 | ||
169 | # Determine the containing directory of this script | |
170 | $VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition | |
171 | $VenvExecDir = Get-Item -Path $VenvExecPath | |
172 | ||
173 | Write-Verbose "Activation script is located in path: '$VenvExecPath'" | |
174 | Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" | |
175 | Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" | |
176 | ||
177 | # Set values required in priority: CmdLine, ConfigFile, Default | |
178 | # First, get the location of the virtual environment, it might not be | |
179 | # VenvExecDir if specified on the command line. | |
180 | if ($VenvDir) { | |
181 | Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" | |
182 | } | |
183 | else { | |
184 | Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." | |
185 | $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") | |
186 | Write-Verbose "VenvDir=$VenvDir" | |
187 | } | |
188 | ||
189 | # Next, read the `pyvenv.cfg` file to determine any required value such | |
190 | # as `prompt`. | |
191 | $pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir | |
192 | ||
193 | # Next, set the prompt from the command line, or the config file, or | |
194 | # just use the name of the virtual environment folder. | |
195 | if ($Prompt) { | |
196 | Write-Verbose "Prompt specified as argument, using '$Prompt'" | |
197 | } | |
198 | else { | |
199 | Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" | |
200 | if ($pyvenvCfg -and $pyvenvCfg['prompt']) { | |
201 | Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" | |
202 | $Prompt = $pyvenvCfg['prompt']; | |
203 | } | |
204 | else { | |
205 | Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" | |
206 | Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" | |
207 | $Prompt = Split-Path -Path $venvDir -Leaf | |
208 | } | |
209 | } | |
210 | ||
211 | Write-Verbose "Prompt = '$Prompt'" | |
212 | Write-Verbose "VenvDir='$VenvDir'" | |
213 | ||
214 | # Deactivate any currently active virtual environment, but leave the | |
215 | # deactivate function in place. | |
216 | deactivate -nondestructive | |
217 | ||
218 | # Now set the environment variable VIRTUAL_ENV, used by many tools to determine | |
219 | # that there is an activated venv. | |
220 | $env:VIRTUAL_ENV = $VenvDir | |
221 | ||
222 | if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { | |
223 | ||
224 | Write-Verbose "Setting prompt to '$Prompt'" | |
225 | ||
226 | # Set the prompt to include the env name | |
227 | # Make sure _OLD_VIRTUAL_PROMPT is global | |
228 | function global:_OLD_VIRTUAL_PROMPT { "" } | |
229 | Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT | |
230 | New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt | |
231 | ||
232 | function global:prompt { | |
233 | Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " | |
234 | _OLD_VIRTUAL_PROMPT | |
235 | } | |
236 | $env:VIRTUAL_ENV_PROMPT = $Prompt | |
237 | } | |
238 | ||
239 | # Clear PYTHONHOME | |
240 | if (Test-Path -Path Env:PYTHONHOME) { | |
241 | Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME | |
242 | Remove-Item -Path Env:PYTHONHOME | |
243 | } | |
244 | ||
245 | # Add the venv to the PATH | |
246 | Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH | |
247 | $Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" |