22# Python virtual env manager inspired by VirtualEnvWrapper
33#
44# Copyright (c) 2017 Regis FLORET
5- #
5+ #
66# Permission is hereby granted, free of charge, to any person obtaining a copy
77# of this software and associated documentation files (the "Software"), to deal
88# in the Software without restriction, including without limitation the rights
99# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1010# copies of the Software, and to permit persons to whom the Software is
1111# furnished to do so, subject to the following conditions:
12- #
12+ #
1313# The above copyright notice and this permission notice shall be included in all
1414# copies or substantial portions of the Software.
15- #
15+ #
1616# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1717# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1818# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -43,29 +43,29 @@ function Get-FullPyEnvPath($pypath) {
4343 return (" {0}\{1}" -f $WORKON_HOME , $pypath )
4444}
4545
46- #
46+ #
4747# Display a formated error message
4848#
4949function Write-FormatedError ($err ) {
50- Write-Host
50+ Write-Host
5151 Write-Host " ERROR: $err " - ForegroundColor Red
52- Write-Host
52+ Write-Host
5353}
5454
5555#
5656# Display a formated success messge
5757#
5858function Write-FormatedSuccess ($err ) {
59- Write-Host
59+ Write-Host
6060 Write-Host " SUCCESS: $err " - ForegroundColor Green
61- Write-Host
61+ Write-Host
6262}
6363
6464#
65- # Retrieve the python version with the path the python exe regarding the version.
65+ # Retrieve the python version with the path the python exe regarding the version.
6666# Python < 3.3 is for this function a Python 2 because the module venv comes with python 3.3
6767#
68- # Return the major version of python
68+ # Return the major version of python
6969#
7070function Get-PythonVersion ($Python ) {
7171 if (! (Test-Path $Python )) {
@@ -76,30 +76,30 @@ function Get-PythonVersion($Python) {
7676 $python_version = Invoke-Expression " & '$Python ' --version 2>&1"
7777 if (! $Python -and ! $python_version ) {
7878 Write-Host " I don't find any Python version into your path" - ForegroundColor Red
79- return
79+ return
8080 }
8181
8282 $is_version_2 = ($python_version -match " ^Python\s2" ) -or ($python_version -match " ^Python\s3.3" )
8383 $is_version_3 = $python_version -match " ^Python\s3" -and ! $is_version_2
84-
84+
8585 if (! $is_version_2 -and ! $is_version_3 ) {
8686 Write-FormatedError " Unknown Python Version expected Python 2 or Python 3 got $python_version "
87- return
87+ return
8888 }
8989
9090 return $ (if ($is_version_2 ) {" 2" } else {" 3" })
9191}
9292
9393#
94- # Common command to create the Python Virtual Environement.
94+ # Common command to create the Python Virtual Environement.
9595# $Command contains either the Py2 or Py3 command
9696#
9797function Invoke-CreatePyEnv ($Command , $Name ) {
9898 $NewEnv = Join-Path $WORKON_HOME $Name
9999 Write-Host " Creating virtual env... "
100-
100+
101101 Invoke-Expression " $Command '$NewEnv '"
102-
102+
103103 $VEnvScritpsPath = Join-Path $NewEnv " Scripts"
104104 $ActivatepPath = Join-Path $VEnvScritpsPath " activate.ps1"
105105 . $ActivatepPath
@@ -112,17 +112,18 @@ function Invoke-CreatePyEnv($Command, $Name) {
112112#
113113function New-Python2Env ($Python , $Name ) {
114114 $Command = (Join-Path (Join-Path (Split-Path $Python - Parent) " Scripts" ) " virtualenv.exe" )
115+
115116 if ((Test-Path $Command ) -eq $false ) {
116117 Write-FormatedError " You must install virtualenv program to create the Python virtual environment '$Name '"
117- return
118+ return
118119 }
119120
120121 Invoke-CreatePyEnv $Command $Name
121122}
122-
123- #
123+
124+ #
124125# Create Python Environment using the venv module
125- #
126+ #
126127function New-Python3Env ($Python , $Name ) {
127128 if (! $Python ) {
128129 $PythonExe = Find-Python
@@ -142,7 +143,7 @@ function Find-Python ($Python) {
142143 # The path contains the python executable
143144 if ($Python.EndsWith (' python.exe' ))
144145 {
145- if (! (Test-Path $Python ))
146+ if (! (Test-Path $Python ))
146147 {
147148 return $false
148149 }
@@ -159,7 +160,7 @@ function Find-Python ($Python) {
159160 if (! (Test-Path $Python )) {
160161 return $false
161162 }
162-
163+
163164 # The pas is a directory path not a executable path
164165 $PythonExe = Join-Path $Python " python.exe"
165166 if (! (Test-Path $PythonExe )) {
@@ -174,21 +175,21 @@ function Find-Python ($Python) {
174175#
175176function New-PythonEnv ($Python , $Name , $Packages , $Append ) {
176177 $version = Get-PythonVersion $Python
177-
178+
178179 BackupPath
179180 if ($Append ) {
180181 $Env: PYTHONPATH = " $Append ;$ ( $Env: PYTHONPATH ) "
181182 }
182183
183184 if ($Version -eq " 2" ) {
184- New-Python2Env - Python $Python - Name $Name
185+ New-Python2Env - Python $Python - Name $Name
185186 } elseif ($Version -eq " 3" ) {
186- New-Python3Env - Python $Python - Name $Name
187+ New-Python3Env - Python $Python - Name $Name
187188 } else {
188189 Write-FormatedError " This is the debug voice. I expected a Python version, got $Version "
189190 RestorePath
190-
191- }
191+
192+ }
192193}
193194
194195function BackupPath {
@@ -200,7 +201,7 @@ function RestorePath {
200201 $Env: Path = $Env: OLD_SYSTEM_PATH
201202}
202203
203- #
204+ #
204205# Test if there's currently a python virtual env
205206#
206207function Get-IsInPythonVenv ($Name ) {
@@ -245,17 +246,18 @@ function Workon {
245246 Write-FormatedError " Enable to find the activation script. You Python environment $Name seems compromized"
246247 return
247248 }
248-
249- . $activate_path
249+
250+ Load - Module $activate_path
250251
251252 $Env: OLD_PYTHON_PATH = $Env: PYTHON_PATH
252253 $Env: VIRTUAL_ENV = " $new_pyenv "
253254}
254255
255- #
256- # Create a new virtual environment.
257256#
258- function New-VirtualEnv {
257+ # Create a new virtual environment.
258+ #
259+ function New-VirtualEnv ()
260+ {
259261 Param (
260262 [Parameter (HelpMessage = " The virtual env name" )]
261263 [string ]$Name ,
@@ -302,10 +304,10 @@ function New-VirtualEnv {
302304 return
303305 }
304306
305- New-PythonEnv - Python $PythonRealPath - Name $Name
306-
307+ New-PythonEnv - Python $PythonRealPath - Name $Name
308+
307309 foreach ($Package in $Packages ) {
308- Invoke-Expression " $WORKON_HOME \$Name \Scripts\pip.exe install $Package "
310+ Invoke-Expression " $WORKON_HOME \$Name \Scripts\pip.exe install $Package "
309311 }
310312
311313
@@ -317,7 +319,6 @@ function New-VirtualEnv {
317319
318320 Invoke-Expression " $WORKON_HOME \$Name \Scripts\pip.exe install -r $Requirement "
319321 }
320-
321322}
322323
323324
@@ -348,14 +349,31 @@ function Get-VirtualEnvs {
348349 Write-Host
349350
350351 if ($children.Length ) {
352+ $failed = [System.Collections.ArrayList ]@ ()
353+
351354 for ($i = 0 ; $i -lt $children.Length ; $i ++ ) {
352355 $child = $children [$i ]
353- $PythonVersion = (((Invoke-Expression (" $WORKON_HOME \{0}\Scripts\Python.exe --version 2>&1" -f $child )) -replace " `r |`n " , " " ) -Split " " )[1 ]
354- Write-host (" `t {0,-30}{1,-15}" -f $child , $PythonVersion )
356+ try {
357+ $PythonVersion = (((Invoke-Expression (" $WORKON_HOME \{0}\Scripts\Python.exe --version 2>&1" -f " $child " )) -replace " `r |`n " , " " ) -Split " " )[1 ]
358+ Write-host (" `t {0,-30}{1,-15}" -f $child , $PythonVersion )
359+ } catch {
360+ $failed += $child
361+ }
355362 }
356363 } else {
357364 Write-Host " `t No Python Environments"
358365 }
366+ if ($failed.Length -gt 0 ) {
367+ Write-Host
368+ Write-Host " `t Additionnaly, one or more environments failed to be listed"
369+ Write-Host " `t =========================================================="
370+ Write-Host
371+ foreach ($item in $failed ) {
372+ Write-Host " `t $item "
373+ }
374+ }
375+
376+
359377 Write-Host
360378}
361379
@@ -366,7 +384,7 @@ function Remove-VirtualEnv {
366384 Param (
367385 [string ]$Name
368386 )
369-
387+
370388 if ((Get-IsInPythonVenv $Name ) -eq $true ) {
371389 Write-FormatedError " You want to destroy the Virtual Env you are in. Please type 'deactivate' before to dispose the environment before"
372390 return
@@ -379,26 +397,101 @@ function Remove-VirtualEnv {
379397
380398 $full_path = Get-FullPyEnvPath $Name
381399 if ((Test-Path $full_path ) -eq $true ) {
382- Remove-Item - Path $full_path - Recurse
400+ Remove-Item - Path $full_path - Recurse
383401 Write-FormatedSuccess " $Name was deleted permanently"
384402 } else {
385403 Write-FormatedError " $Name not found"
386404 }
387405}
388406
389- #
390- # Get the current version of VirtualEnvWrapper
391- #
407+ <#
408+ . Synopsis
409+ Get the current version of VirtualEnvWrapper
410+ #>
392411function Get-VirtualEnvVersion () {
393412 Write-Host " Version $Version "
394413}
395414
415+ <#
416+ . Synopsis
417+ Create a temporary environment.
418+ #>
419+ function New-TemporaryVirtualEnv () {
420+ Param (
421+ [Parameter (HelpMessage = " Change directory into the newly created virtual environment" )]
422+ [alias (" c" )]
423+ [switch ]
424+ $Cd = $False ,
425+
426+ [Parameter (HelpMessage = " Don't change directory" )]
427+ [alias (" n" )]
428+ [switch ]$NoCd = $false ,
429+
430+ # Reimplement New-VirtualEnv parameters
431+ [Parameter (HelpMessage = " The requirements file" )]
432+ [alias (" r" )]
433+ [string ]$Requirement ,
434+
435+ [Parameter (HelpMessage = " The Python directory where the python.exe lives" )]
436+ [string ]$Python ,
437+
438+ [Parameter (HelpMessage = " The package to install. Repeat the parameter for more than one" )]
439+ [alias (" i" )]
440+ [string []]$Packages ,
441+
442+ [Parameter (HelpMessage = " Associate an existing project directory to the new environment" )]
443+ [alias (" a" )]
444+ [string ]$Associate
445+ )
446+
447+ Begin
448+ {
449+ if ($NoCd -eq $true ) {
450+ $Cd = $false ;
451+ }
452+ }
453+
454+ Process
455+ {
456+ $uuid = (Invoke-Expression " python -c 'import uuid; print(str(uuid.uuid4()))'" )
457+ $dest_dir = " $WORKON_HOME /$uuid "
458+
459+ # Recompose command line
460+ $args = " "
461+ foreach ($param in $PSBoundParameters.GetEnumerator ())
462+ {
463+ $args += (" -{0} {1}" -f $param.Key , $param.Value )
464+ }
465+
466+ Invoke-Expression " New-VirtualEnv $uuid $args "
467+
468+ $message = " This is a temporary environment. It will be deleted when you run 'deactivate'."
469+ Write-Host $message
470+ $message | Out-File - FilePath " $dest_dir /README.tmpenv"
471+
472+ # Write deactivation file. See Workon rewriting deactivate feature
473+ $post_deactivate_file_content = @"
474+ if ((est-Path -Path `" $dest_dir /README.tmpenv`" ) {
475+ Write-Host `" Removing temporary environment $uuid `"
476+ # Change the location else MS Windows will refuse to remove the directory
477+ Set-Location `" $WORKON_HOME `"
478+ Remove-VirtualEnv $uuid
479+ }
480+ "@
481+ $post_deactivate_file_content | Out-File - FilePath " $WORKON_HOME /$uuid /postdeactivate.ps1"
482+
483+ if ($Cd -Eq $true ) {
484+ Set-Location - Path " $WORKON_HOME /$uuid "
485+ }
486+ }
487+ }
488+
396489#
397490# Powershell alias for naming convention
398491#
399- Set-Alias lsvirtualenv Get-VirtualEnvs
400- Set-Alias rmvirtualenv Remove-VirtualEnv
492+ Set-Alias lsvirtualenv Get-VirtualEnvs
493+ Set-Alias rmvirtualenv Remove-VirtualEnv
401494Set-Alias mkvirtualenv New-VirtualEnv
402-
495+ Set-Alias mktmpenv New-TemporaryVirtualEnv
403496
404497Write-Host " Virtual Env Wrapper for Powershell activated"
0 commit comments