-
Notifications
You must be signed in to change notification settings - Fork 0
/
PythonUtils.psm1
221 lines (203 loc) · 6.82 KB
/
PythonUtils.psm1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
<#
.SYNOPSIS
Module for working with multiple Python environments.
.DESCRIPTION
Module for working with multiple Python environments.
.EXAMPLE
PS C:\> <example usage>
Explanation of what the example does
.INPUTS
Inputs (if any)
.OUTPUTS
Output (if any)
.NOTES
General notes
#>
class PythonVersionInfo {
[version]$Version;
[int]$Bit;
[string]$VersionText;
PythonVersionInfo([string]$versionInfo) {
$this.VersionText = $versionInfo
[regex]$versionRe = [regex]::new("^(?<version>(\d+\.?)*).+?((?<bit>\d+) bit)", [System.Text.RegularExpressions.RegexOptions]::ExplicitCapture)
$match = $versionRe.Match($versionInfo)
if (-not $match) {
throw [System.FormatException]::new($versionInfo)
}
$this.Version = New-Object version $match.Groups["version"].Value
$this.Bit = [int]::Parse($match.Groups["bit"])
}
}
class PythonExeInfo {
[System.IO.FileInfo]$Path;
[version]$Version;
[int]$Bit;
PythonExeInfo($path, $version) {
$this.Path = $path
$versionInfo = New-Object PythonVersionInfo $version
$this.Version = $versionInfo.Version
$this.Bit = $versionInfo.Bit
}
}
<#
.SYNOPSIS
Lists the Python executables found on the system.
.DESCRIPTION
Lists the Python executables found on the system.
.EXAMPLE
PS C:\> Get-Pythons
Path Version Bit
---- ------- ---
C:\Python27\ArcGIS10.5\python.exe 2.7.13 32
C:\Python27\ArcGISx6410.5\python.exe 2.7.13 64
C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\python.exe 3.5.3 64
.OUTPUTS
List of objects with the following properties:
* Path - Path to Python executable
* Version - Python version number
* Bit - Integer: either 32 or 64.
.NOTES
General notes
#>
function Get-Pythons() {
Write-Host "Searching for Python environments..."
# The the paths to the python.exe files in expected ArcGIS software installation locations.
$pythons = (Get-ChildItem -Path "$env:HOMEDRIVE\\Python*\**\python.exe") + (Get-ChildItem -Path "$env:ProgramFiles\ArcGIS\Pro\bin\Python\envs\**\python.exe")
# Create temporary python code file.
$tempCommandFile = New-TemporaryFile
# Create the python command text string.
$verCommand = [string]::Join([System.Environment]::NewLine, $(
"from __future__ import print_function, unicode_literals",
"from sys import version, executable",
"print('`"%s`", `"%s`"' % (executable, version))"))
# Write the Python command to the temp script file.
Write-Output $verCommand | Out-File $tempCommandFile -Encoding utf8
# Add CSV header
[string]$versionInfo = "Path,Version"
# Initialize list of temp files containing version information.
$versionTempFiles = @()
$processes = @()
try {
foreach ($py in $pythons) {
# Create a temp. file to write output to and append to list of temp files.
$tempVersionFile = New-TemporaryFile
$versionTempFiles += $tempVersionFile
# Run python script to print version info, redirecting output to the temp file.
$processes += Start-Process $py $tempCommandFile.FullName -NoNewWindow -PassThru -RedirectStandardOutput $tempVersionFile
}
# Wait for all the Python processes to run before attempting to read from the temp files.
Wait-Process -InputObject $processes
# Combine the contents of the temp files to the versionInfo string.
# This string will contain a CSV table.
foreach ($tempFile in $versionTempFiles) {
$versionInfo += [System.Environment]::NewLine + (Get-Content -Path $tempFile)
}
}
finally {
Remove-Item $tempCommandFile
}
# Convert the version from CSV to objects, then from generic objects to PythonExeInfo objects.
return $versionInfo | ConvertFrom-Csv | ForEach-Object {
New-Object PythonExeInfo @($_.Path, $_.Version)
}
}
<#
.SYNOPSIS
Short description
.DESCRIPTION
Long description
.EXAMPLE
PS C:\> <example usage>
Explanation of what the example does
.INPUTS
Inputs (if any)
.OUTPUTS
Output (if any)
.NOTES
General notes
#>
function Get-PythonTool (
[Parameter(Mandatory, HelpMessage = "Enter tool name")]
[string]$toolName
) {
return (Get-ChildItem -Path "$env:HOMEDRIVE\\Python*\**\Scripts\$toolName") + (Get-ChildItem -Path "$env:ProgramFiles\ArcGIS\Pro\bin\Python\envs\*\Scripts\$toolName")
}
class PackageInfo {
[string]$Package
[string]$Version
[System.IO.FileInfo]$PipLocation
PackageInfo($package, $version, $pip) {
$this.Package = $package
$this.Version = $version
$this.PipLocation = $pip
}
}
function Get-PythonPackages {
$pips = Get-PythonTool "pip.exe"
$output = @()
$originalLocation = Get-Location
try {
foreach ($pip in $pips) {
Set-Location $pip.Directory
$moduleList = pip list | Select-String -Pattern "^-" -NotMatch | Convert-String -Example "xlwt 1.2.0 =xlwt,1.2.0" | ConvertFrom-Csv
foreach ($module in $moduleList) {
$pkInfo = New-Object PackageInfo @($module.Package, $module.Version, $pip)
$output += $($pkInfo)
}
}
}
finally {
Set-Location $originalLocation
}
return $output
}
function Install-PythonPackage (
[Parameter(Mandatory)]
[string]
$packageName,
[switch]
$User,
[switch]
$Editable
) {
$pips = Get-PythonTool "pip.exe"
if (-not $pips) {
Write-Error "Could not find any instances of pip.exe"
}
else {
# $procs = @()
$procParams = "install"
if ($Editable) {
$procParams += " -e"
}
$procParams += " $packageName"
if ($User) {
$procParams += " --user"
}
foreach ($pip in $pips) {
Write-Host "Installing to $pip..." -ForegroundColor Yellow
Start-Process $pip $procParams -NoNewWindow -Wait
# $procs += $p
}
# Wait-Process $procs
# return $procs | ForEach-Object { return $($_.Path, $_.ExitCode) }
}
}
function Uninstall-PythonPackage (
[Parameter(Mandatory)]
[string]
$packageName) {
$pips = Get-PythonTool "pip.exe"
if (-not $pips) {
Write-Error "Could not find any instances of pip.exe"
}
else {
# $procs = @()
foreach ($pip in $pips) {
Start-Process $pip "uninstall $packageName" -NoNewWindow -Wait
# $procs += $p
}
# Wait-Process $procs
# return $procs | ForEach-Object { return $($_.Path, $_.ExitCode) }
}
}