Skip to content

Commit 97f1f3a

Browse files
committed
Learning to write an extension
1 parent 4e81b25 commit 97f1f3a

File tree

4 files changed

+242
-0
lines changed

4 files changed

+242
-0
lines changed

src/NotebookUnit/NotebookUnit.csproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="microsoft.dotnet.interactive" Version="1.0.0-beta.20418.1" />
9+
<PackageReference Include="microsoft.dotnet.interactive.csharp" Version="1.0.0-beta.20418.1" />
10+
</ItemGroup>
11+
12+
</Project>

src/NotebookUnit/NuGet.config

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<solution>
4+
<add key="disableSourceControlIntegration" value="true" />
5+
</solution>
6+
<packageSources>
7+
<clear />
8+
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
9+
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
10+
<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
11+
<add key="dotnet3-dev" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json" />
12+
<add key="dotnet5" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json" />
13+
<add key="dotnet-try" value="https://dotnet.myget.org/F/dotnet-try/api/v3/index.json" />
14+
<add key="roslyn" value="https://dotnet.myget.org/F/roslyn/api/v3/index.json" />
15+
<add key="dotnet-corefxlab" value="https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json" />
16+
<add key="MachineLearning" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/MachineLearning/nuget/v3/index.json" />
17+
<add key="PSGallery" value="https://www.powershellgallery.com/api/v2/" />
18+
</packageSources>
19+
</configuration>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.CommandLine;
3+
using System.CommandLine.Invocation;
4+
using System.Threading.Tasks;
5+
using Microsoft.DotNet.Interactive;
6+
7+
namespace NotebookUnit
8+
{
9+
public class TestKernelExtension : IKernelExtension
10+
{
11+
public async Task OnLoadAsync(Kernel kernel)
12+
{
13+
14+
var testCommand = new Command("#!test", "Run the tests in this notebook");
15+
16+
testCommand.Handler = CommandHandler.Create(async (KernelInvocationContext context) =>
17+
{
18+
await context.DisplayAsync("This is a test", "text/plain");
19+
});
20+
21+
kernel.AddDirective(testCommand);
22+
23+
if (KernelInvocationContext.Current is { } context)
24+
{
25+
await context.DisplayAsync($"`{nameof(TestKernelExtension)}` is loaded. It adds unit test capabilities");
26+
}
27+
28+
}
29+
}
30+
}

src/TestnotebookUnit.ipynb

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {},
7+
"outputs": [
8+
{
9+
"data": {
10+
"text/html": [
11+
"\r\n",
12+
"<div>\r\n",
13+
" <div id='dotnet-interactive-this-cell-28751.6c5bc3419e7d4f0fba9610b517a8d24c' style='display: none'>\r\n",
14+
" The below script needs to be able to find the current output cell; this is an easy method to get it.\r\n",
15+
" </div>\r\n",
16+
" <script type='text/javascript'>\r\n",
17+
"// ensure `require` is available globally\r\n",
18+
"if (typeof require !== typeof Function || typeof require.config !== typeof Function) {\r\n",
19+
" let require_script = document.createElement('script');\r\n",
20+
" require_script.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js');\r\n",
21+
" require_script.setAttribute('type', 'text/javascript');\r\n",
22+
" require_script.onload = function () {\r\n",
23+
" loadDotnetInteractiveApi();\r\n",
24+
" };\r\n",
25+
"\r\n",
26+
" document.getElementsByTagName('head')[0].appendChild(require_script);\r\n",
27+
"}\r\n",
28+
"else {\r\n",
29+
" loadDotnetInteractiveApi();\r\n",
30+
"}\r\n",
31+
"\r\n",
32+
"async function probeAddresses(probingAddresses) {\r\n",
33+
" function timeout(ms, promise) {\r\n",
34+
" return new Promise(function (resolve, reject) {\r\n",
35+
" setTimeout(function () {\r\n",
36+
" reject(new Error('timeout'))\r\n",
37+
" }, ms)\r\n",
38+
" promise.then(resolve, reject)\r\n",
39+
" })\r\n",
40+
" }\r\n",
41+
"\r\n",
42+
" if (Array.isArray(probingAddresses)) {\r\n",
43+
" for (let i = 0; i < probingAddresses.length; i++) {\r\n",
44+
"\r\n",
45+
" let rootUrl = probingAddresses[i];\r\n",
46+
"\r\n",
47+
" if (!rootUrl.endsWith('/')) {\r\n",
48+
" rootUrl = `${rootUrl}/`;\r\n",
49+
" }\r\n",
50+
"\r\n",
51+
" try {\r\n",
52+
" let response = await timeout(1000, fetch(`${rootUrl}discovery`, {\r\n",
53+
" method: 'POST',\r\n",
54+
" cache: 'no-cache',\r\n",
55+
" mode: 'cors',\r\n",
56+
" timeout: 1000,\r\n",
57+
" headers: {\r\n",
58+
" 'Content-Type': 'text/plain'\r\n",
59+
" },\r\n",
60+
" body: probingAddresses[i]\r\n",
61+
" }));\r\n",
62+
"\r\n",
63+
" if (response.status == 200) {\r\n",
64+
" return rootUrl;\r\n",
65+
" }\r\n",
66+
" }\r\n",
67+
" catch (e) { }\r\n",
68+
" }\r\n",
69+
" }\r\n",
70+
"}\r\n",
71+
"\r\n",
72+
"function loadDotnetInteractiveApi() {\r\n",
73+
" probeAddresses([\"http://192.168.1.151:1025/\", \"http://127.0.0.1:1025/\"])\r\n",
74+
" .then((root) => {\r\n",
75+
" // use probing to find host url and api resources\r\n",
76+
" // load interactive helpers and language services\r\n",
77+
" let dotnetInteractiveRequire = require.config({\r\n",
78+
" context: '28751.6c5bc3419e7d4f0fba9610b517a8d24c',\r\n",
79+
" paths: {\r\n",
80+
" 'dotnet-interactive': `${root}resources`\r\n",
81+
" }\r\n",
82+
" }) || require;\r\n",
83+
"\r\n",
84+
" let dotnetInteractiveExtensionsRequire = require.config({\r\n",
85+
" context: '28751.6c5bc3419e7d4f0fba9610b517a8d24c',\r\n",
86+
" paths: {\r\n",
87+
" 'dotnet-interactive-extensions': `${root}extensions`\r\n",
88+
" }\r\n",
89+
" }) || require;\r\n",
90+
" if (!window.dotnetInteractiveRequire) {\r\n",
91+
" window.dotnetInteractiveRequire = dotnetInteractiveRequire;\r\n",
92+
" }\r\n",
93+
"\r\n",
94+
" if (!window.dotnetInteractiveExtensionsRequire) {\r\n",
95+
" window.dotnetInteractiveExtensionsRequire = dotnetInteractiveExtensionsRequire;\r\n",
96+
" }\r\n",
97+
"\r\n",
98+
" window.getExtensionRequire = function(extensionName, extensionCacheBuster) {\r\n",
99+
" let paths = {};\r\n",
100+
" paths[extensionName] = `${root}extensions/${extensionName}/resources/`;\r\n",
101+
" \r\n",
102+
" let internalRequire = require.config({\r\n",
103+
" context: extensionCacheBuster,\r\n",
104+
" paths: paths,\r\n",
105+
" urlArgs: `cacheBuster=${extensionCacheBuster}`\r\n",
106+
" }) || require;\r\n",
107+
"\r\n",
108+
" return internalRequire\r\n",
109+
" };\r\n",
110+
" \r\n",
111+
" dotnetInteractiveRequire([\r\n",
112+
" 'dotnet-interactive/dotnet-interactive'\r\n",
113+
" ],\r\n",
114+
" function (dotnet) {\r\n",
115+
" dotnet.init(window);\r\n",
116+
" },\r\n",
117+
" function (error) {\r\n",
118+
" console.log(error);\r\n",
119+
" }\r\n",
120+
" );\r\n",
121+
" })\r\n",
122+
" .catch(error => {console.log(error);});\r\n",
123+
" }\r\n",
124+
" </script>\r\n",
125+
"</div>"
126+
]
127+
},
128+
"metadata": {},
129+
"output_type": "display_data"
130+
},
131+
{
132+
"data": {
133+
"text/html": [
134+
"<div><strong>Restore sources</strong><ul><li><span>/home/csharpfritz/dev/csharp_with_csharpfritz/src/NotebookUnit/bin/Debug</span></li></ul></div>"
135+
]
136+
},
137+
"metadata": {},
138+
"output_type": "display_data"
139+
},
140+
{
141+
"data": {
142+
"text/plain": [
143+
"Installed package NotebookUnit version 0.1.0"
144+
]
145+
},
146+
"metadata": {},
147+
"output_type": "display_data"
148+
}
149+
],
150+
"source": [
151+
"#i nuget:/home/csharpfritz/dev/csharp_with_csharpfritz/src/NotebookUnit/bin/Debug\n",
152+
"#r nuget:NotebookUnit,0.1.0 "
153+
]
154+
},
155+
{
156+
"cell_type": "code",
157+
"execution_count": 2,
158+
"metadata": {},
159+
"outputs": [],
160+
"source": [
161+
"#!test -h"
162+
]
163+
}
164+
],
165+
"metadata": {
166+
"kernelspec": {
167+
"display_name": ".NET (C#)",
168+
"language": "C#",
169+
"name": ".net-csharp"
170+
},
171+
"language_info": {
172+
"file_extension": ".cs",
173+
"mimetype": "text/x-csharp",
174+
"name": "C#",
175+
"pygments_lexer": "csharp",
176+
"version": "8.0"
177+
}
178+
},
179+
"nbformat": 4,
180+
"nbformat_minor": 4
181+
}

0 commit comments

Comments
 (0)