-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathInvokeExecuteNotebook.ps1
150 lines (122 loc) · 5.37 KB
/
InvokeExecuteNotebook.ps1
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
function Invoke-ExecuteNotebook {
<#
.Synopsis
Adds a new cell tagged with injected-parameters with input parameters in order to overwrite the values in parameters.
If no cell is tagged with parameters the injected cell will be inserted at the top of the notebook.
.Description
This opens up new opportunities for how notebooks can be used. For example:
Perhaps you have a financial report that you wish to run with different values on the first or last day of a month or at the beginning or end of the year, using parameters makes this task easier.
Do you want to run a notebook and depending on its results, choose a particular notebook to run next? You can now programmatically execute a workflow without having to copy and paste from notebook to notebook manually.
.Example
Invoke-ExecuteNotebook -InputNotebook .\basic.ipynb -Parameters @{arr = 1, 2, 3}
#>
param(
$InputNotebook,
$OutputNotebook,
[hashtable]$Parameters,
# When cells are run, it returns objects not strings
[Switch]$ReturnAsObjects,
[Switch]$Force,
[Switch]$DoNotLaunchBrowser,
[Switch]$DotNetInteractive
)
if (!$InputNotebook) { return }
if ([System.Uri]::IsWellFormedUriString($InputNotebook, [System.UriKind]::Absolute)) {
try {
$data = Invoke-RestMethod $InputNotebook
}
catch {
throw "$($InputNotebook) is not a valid Jupyter Notebook"
}
}
else {
$json = Get-Content $InputNotebook
$data = $json | ConvertFrom-Json
}
[System.Collections.ArrayList]$cells = $data.cells
$PSNotebookRunspace = New-PSNotebookRunspace -ReturnAsObjects:$ReturnAsObjects
if ($Parameters) {
$cvt = "@'`r`n" + ($Parameters | ConvertTo-Json) + "`r`n'@"
$source = @'
# injected parameters
$payload = {0} | ConvertFrom-Json
$names = $payload.psobject.Properties.name
$names | foreach-object {{ Set-Variable -Name $_ -Value $payload.$_ }}
Remove-Variable payload -ErrorAction SilentlyContinue
Remove-Variable names -ErrorAction SilentlyContinue
'@ -f $cvt
$newParams = New-CodeCell $source -DotNetInteractive:$DotNetInteractive | ConvertFrom-Json -Depth 3
$index = Get-ParameterInsertionIndex -InputNotebook $InputNotebook
$cells.Insert($index, $newParams)
}
$startedExecution = Get-Date
$totalCells = $cells.count
for ($idx = 0; $idx -lt $totalCells; $idx++) {
$pct = 100 * ($idx / $totalCells)
Write-Progress -Activity "[$($startedExecution)] Executing Notebook $($InputNotebook)" -Status "Running cell $($idx+1) of $($totalCells)" -PercentComplete $pct
$cell = $cells[$idx]
if ($cell.cell_type -ne 'code') { continue }
# Clear Errors
$PSNotebookRunspace.PowerShell.Streams.Error.Clear()
# Clear Commands
$PSNotebookRunspace.PowerShell.Commands.Clear()
$result = $PSNotebookRunspace.Invoke($cell.source)
if ($PSNotebookRunspace.PowerShell.Streams.Error.Count -gt 0) {
$text = $PSNotebookRunspace.PowerShell.Streams.Error | Out-String
}
else {
$text = $result
}
$cell.outputs = @()
if ($text) {
$cell.outputs += [ordered]@{
name = "stdout"
text = $text
output_type = "stream"
}
}
}
$data.cells = $cells
if ($OutputNotebook) {
$isUri = Test-Uri $OutputNotebook
if ($isUri) {
if ($OutputNotebook.startswith("gist://")) {
$OutFile = $OutputNotebook.replace("gist://", "")
$targetFileName = Split-Path $OutFile -Leaf
Write-Progress -Activity "Creating Gist" -Status $targetFileName
$contents = $data | ConvertTo-Json -Depth 5
$Show = !$DoNotLaunchBrowser
$result = New-GistNotebook -contents $contents -fileName $targetFileName -Show:$Show
}
elseif ($OutputNotebook.startswith("abs://")) {
if (Test-AzureBlobStorageUrl $outputNotebook) {
$fullName = [System.IO.Path]::GetRandomFileName()
ConvertTo-Json -InputObject $data -Depth 5 | Set-Content $fullName -Encoding utf8
try {
$headers = @{'x-ms-blob-type' = 'BlockBlob' }
Invoke-RestMethod -Uri ($OutputNotebook.Replace('abs', 'https')) -Method Put -Headers $headers -InFile $fullName
}
catch {
throw $_.Exception.Message
}
finally {
Remove-Item $fullName -ErrorAction SilentlyContinue
}
}
}
else {
throw "Invalid OutputNotebook url '{0}'" -f $OutputNotebook
}
}
else {
if ((Test-Path $OutputNotebook) -and !$Force) {
throw "$OutputNotebook already exists"
}
ConvertTo-Json -InputObject $data -Depth 5 |
Set-Content $OutputNotebook -Encoding utf8
}
}
else {
$data.cells.outputs.text
}
}