Skip to content

Commit

Permalink
add dotnet kernel for C# and F#
Browse files Browse the repository at this point in the history
  • Loading branch information
anpin committed Nov 23, 2024
1 parent 38ee7c1 commit 660d9c3
Show file tree
Hide file tree
Showing 11 changed files with 487 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<img src="modules/kernels/scala/logo-64x64.png" width="45" />
<img src="modules/kernels/typescript/logo-64x64.png" width="45" />
<img src="modules/kernels/zsh/logo-64x64.png" width="45" />
<img src="modules/kernels/dotnet/logo-64x64.png" width="45" />
</p>

This repository provides a Nix-based framework for the definition of
Expand Down
10 changes: 10 additions & 0 deletions examples/dotnet/csharp/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
self,
system,
pkgs,
...
}: {
kernel.dotnet.csharp-example = {
enable = true;
};
}
166 changes: 166 additions & 0 deletions examples/dotnet/csharp/test.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "d13cad64-62c0-4b87-b8ef-0242658baa0f",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"data": {
"text/html": [
"\r\n",
"<div>\r\n",
" <div id='dotnet-interactive-this-cell-1199835.Microsoft.DotNet.Interactive.Http.HttpPort' style='display: none'>\r\n",
" The below script needs to be able to find the current output cell; this is an easy method to get it.\r\n",
" </div>\r\n",
" <script type='text/javascript'>\r\n",
"async function probeAddresses(probingAddresses) {\r\n",
" function timeout(ms, promise) {\r\n",
" return new Promise(function (resolve, reject) {\r\n",
" setTimeout(function () {\r\n",
" reject(new Error('timeout'))\r\n",
" }, ms)\r\n",
" promise.then(resolve, reject)\r\n",
" })\r\n",
" }\r\n",
"\r\n",
" if (Array.isArray(probingAddresses)) {\r\n",
" for (let i = 0; i < probingAddresses.length; i++) {\r\n",
"\r\n",
" let rootUrl = probingAddresses[i];\r\n",
"\r\n",
" if (!rootUrl.endsWith('/')) {\r\n",
" rootUrl = `${rootUrl}/`;\r\n",
" }\r\n",
"\r\n",
" try {\r\n",
" let response = await timeout(1000, fetch(`${rootUrl}discovery`, {\r\n",
" method: 'POST',\r\n",
" cache: 'no-cache',\r\n",
" mode: 'cors',\r\n",
" timeout: 1000,\r\n",
" headers: {\r\n",
" 'Content-Type': 'text/plain'\r\n",
" },\r\n",
" body: probingAddresses[i]\r\n",
" }));\r\n",
"\r\n",
" if (response.status == 200) {\r\n",
" return rootUrl;\r\n",
" }\r\n",
" }\r\n",
" catch (e) { }\r\n",
" }\r\n",
" }\r\n",
"}\r\n",
"\r\n",
"function loadDotnetInteractiveApi() {\r\n",
" probeAddresses([\"http://192.168.0.106:2051/\", \"http://192.168.100.2:2051/\", \"http://172.16.10.2:2051/\", \"http://127.0.0.1:2051/\"])\r\n",
" .then((root) => {\r\n",
" // use probing to find host url and api resources\r\n",
" // load interactive helpers and language services\r\n",
" let dotnetInteractiveRequire = require.config({\r\n",
" context: '1199835.Microsoft.DotNet.Interactive.Http.HttpPort',\r\n",
" paths:\r\n",
" {\r\n",
" 'dotnet-interactive': `${root}resources`\r\n",
" }\r\n",
" }) || require;\r\n",
"\r\n",
" window.dotnetInteractiveRequire = dotnetInteractiveRequire;\r\n",
"\r\n",
" window.configureRequireFromExtension = function(extensionName, extensionCacheBuster) {\r\n",
" let paths = {};\r\n",
" paths[extensionName] = `${root}extensions/${extensionName}/resources/`;\r\n",
" \r\n",
" let internalRequire = require.config({\r\n",
" context: extensionCacheBuster,\r\n",
" paths: paths,\r\n",
" urlArgs: `cacheBuster=${extensionCacheBuster}`\r\n",
" }) || require;\r\n",
"\r\n",
" return internalRequire\r\n",
" };\r\n",
" \r\n",
" dotnetInteractiveRequire([\r\n",
" 'dotnet-interactive/dotnet-interactive'\r\n",
" ],\r\n",
" function (dotnet) {\r\n",
" dotnet.init(window);\r\n",
" },\r\n",
" function (error) {\r\n",
" console.log(error);\r\n",
" }\r\n",
" );\r\n",
" })\r\n",
" .catch(error => {console.log(error);});\r\n",
" }\r\n",
"\r\n",
"// ensure `require` is available globally\r\n",
"if ((typeof(require) !== typeof(Function)) || (typeof(require.config) !== typeof(Function))) {\r\n",
" let require_script = document.createElement('script');\r\n",
" require_script.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js');\r\n",
" require_script.setAttribute('type', 'text/javascript');\r\n",
" \r\n",
" \r\n",
" require_script.onload = function() {\r\n",
" loadDotnetInteractiveApi();\r\n",
" };\r\n",
"\r\n",
" document.getElementsByTagName('head')[0].appendChild(require_script);\r\n",
"}\r\n",
"else {\r\n",
" loadDotnetInteractiveApi();\r\n",
"}\r\n",
"\r\n",
" </script>\r\n",
"</div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello world\n"
]
}
],
"source": [
"var b = new[] { \"hello\", \"world\" }; \n",
"Console.WriteLine(string.Join(\" \", b));"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5082b04d-1edd-4a81-8462-fa571311cd33",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "dotnet-csharp-example kernel",
"language": "dotnet",
"name": "dotnet-csharp-example"
},
"language_info": {
"file_extension": ".cs",
"mimetype": "text/x-csharp",
"name": "C#",
"pygments_lexer": "csharp",
"version": "12.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
13 changes: 13 additions & 0 deletions examples/dotnet/csharp/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import os
from testbook import testbook

current_dir = os.path.dirname(os.path.abspath(__file__))

@testbook(f'{current_dir}/test.ipynb', execute=True, kernel_name="dotnet-csharp-example")
def test_nb(tb):
result = tb.cell_output_text(0)
assert result == 'hello world'

if __name__ == '__main__':
test_nb()

11 changes: 11 additions & 0 deletions examples/dotnet/fsharp/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
self,
system,
pkgs,
...
}: {
kernel.dotnet.fsharp-example = {
enable = true;
language = "fsharp";
};
}
158 changes: 158 additions & 0 deletions examples/dotnet/fsharp/test.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "d13cad64-62c0-4b87-b8ef-0242658baa0f",
"metadata": {
"vscode": {
"languageId": "rust"
}
},
"outputs": [
{
"data": {
"text/html": [
"\r\n",
"<div>\r\n",
" <div id='dotnet-interactive-this-cell-1181845.Microsoft.DotNet.Interactive.Http.HttpPort' style='display: none'>\r\n",
" The below script needs to be able to find the current output cell; this is an easy method to get it.\r\n",
" </div>\r\n",
" <script type='text/javascript'>\r\n",
"async function probeAddresses(probingAddresses) {\r\n",
" function timeout(ms, promise) {\r\n",
" return new Promise(function (resolve, reject) {\r\n",
" setTimeout(function () {\r\n",
" reject(new Error('timeout'))\r\n",
" }, ms)\r\n",
" promise.then(resolve, reject)\r\n",
" })\r\n",
" }\r\n",
"\r\n",
" if (Array.isArray(probingAddresses)) {\r\n",
" for (let i = 0; i < probingAddresses.length; i++) {\r\n",
"\r\n",
" let rootUrl = probingAddresses[i];\r\n",
"\r\n",
" if (!rootUrl.endsWith('/')) {\r\n",
" rootUrl = `${rootUrl}/`;\r\n",
" }\r\n",
"\r\n",
" try {\r\n",
" let response = await timeout(1000, fetch(`${rootUrl}discovery`, {\r\n",
" method: 'POST',\r\n",
" cache: 'no-cache',\r\n",
" mode: 'cors',\r\n",
" timeout: 1000,\r\n",
" headers: {\r\n",
" 'Content-Type': 'text/plain'\r\n",
" },\r\n",
" body: probingAddresses[i]\r\n",
" }));\r\n",
"\r\n",
" if (response.status == 200) {\r\n",
" return rootUrl;\r\n",
" }\r\n",
" }\r\n",
" catch (e) { }\r\n",
" }\r\n",
" }\r\n",
"}\r\n",
"\r\n",
"function loadDotnetInteractiveApi() {\r\n",
" probeAddresses([\"http://192.168.0.106:2051/\", \"http://192.168.100.2:2051/\", \"http://172.16.10.2:2051/\", \"http://127.0.0.1:2051/\"])\r\n",
" .then((root) => {\r\n",
" // use probing to find host url and api resources\r\n",
" // load interactive helpers and language services\r\n",
" let dotnetInteractiveRequire = require.config({\r\n",
" context: '1181845.Microsoft.DotNet.Interactive.Http.HttpPort',\r\n",
" paths:\r\n",
" {\r\n",
" 'dotnet-interactive': `${root}resources`\r\n",
" }\r\n",
" }) || require;\r\n",
"\r\n",
" window.dotnetInteractiveRequire = dotnetInteractiveRequire;\r\n",
"\r\n",
" window.configureRequireFromExtension = function(extensionName, extensionCacheBuster) {\r\n",
" let paths = {};\r\n",
" paths[extensionName] = `${root}extensions/${extensionName}/resources/`;\r\n",
" \r\n",
" let internalRequire = require.config({\r\n",
" context: extensionCacheBuster,\r\n",
" paths: paths,\r\n",
" urlArgs: `cacheBuster=${extensionCacheBuster}`\r\n",
" }) || require;\r\n",
"\r\n",
" return internalRequire\r\n",
" };\r\n",
" \r\n",
" dotnetInteractiveRequire([\r\n",
" 'dotnet-interactive/dotnet-interactive'\r\n",
" ],\r\n",
" function (dotnet) {\r\n",
" dotnet.init(window);\r\n",
" },\r\n",
" function (error) {\r\n",
" console.log(error);\r\n",
" }\r\n",
" );\r\n",
" })\r\n",
" .catch(error => {console.log(error);});\r\n",
" }\r\n",
"\r\n",
"// ensure `require` is available globally\r\n",
"if ((typeof(require) !== typeof(Function)) || (typeof(require.config) !== typeof(Function))) {\r\n",
" let require_script = document.createElement('script');\r\n",
" require_script.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js');\r\n",
" require_script.setAttribute('type', 'text/javascript');\r\n",
" \r\n",
" \r\n",
" require_script.onload = function() {\r\n",
" loadDotnetInteractiveApi();\r\n",
" };\r\n",
"\r\n",
" document.getElementsByTagName('head')[0].appendChild(require_script);\r\n",
"}\r\n",
"else {\r\n",
" loadDotnetInteractiveApi();\r\n",
"}\r\n",
"\r\n",
" </script>\r\n",
"</div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10]"
]
}
],
"source": [
"let m = [0 .. 10]\n",
"printf \"%A\" m"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "dotnet-fsharp-example kernel",
"language": "dotnet",
"name": "dotnet-fsharp-example"
},
"language_info": {
"file_extension": ".fs",
"mimetype": "text/x-fsharp",
"name": "F#",
"pygments_lexer": "fsharp",
"version": "8.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
13 changes: 13 additions & 0 deletions examples/dotnet/fsharp/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import os
from testbook import testbook

current_dir = os.path.dirname(os.path.abspath(__file__))

@testbook(f'{current_dir}/test.ipynb', execute=True, kernel_name="dotnet-fsharp-example")
def test_nb(tb):
result = tb.cell_output_text(0)
assert result == '[0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10]'

if __name__ == '__main__':
test_nb()

1 change: 1 addition & 0 deletions modules/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ in {
./../modules/kernels/scala
./../modules/kernels/typescript
./../modules/kernels/zsh
./../modules/kernels/dotnet
];
# TODO: add kernels
#++ map (name: ./. + "/../modules/kernels/${name}/module.nix") (builtins.attrNames (builtins.readDir ./../modules/kernels));
Expand Down
Loading

0 comments on commit 660d9c3

Please sign in to comment.