Skip to content

Commit

Permalink
add custom kernel picker
Browse files Browse the repository at this point in the history
  • Loading branch information
brettfo committed Oct 27, 2022
1 parent 49a7ffe commit 4eebd8a
Show file tree
Hide file tree
Showing 161 changed files with 5,087 additions and 5,145 deletions.
279 changes: 279 additions & 0 deletions samples/stand-alone-kernels/perl/kernel.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
# Copyright (c) .NET Foundation and contributors. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.

# This is designed to be a stand-alone, out-of-process kernel, primarily used to ensure proper proxy
# handling. It requires a local `perl.exe` interpreter be available and can be used by executing
# the following in a notebook:
#
# #!connect stdio --kernel-name perl --command perl.exe kernel.pl

use JSON;
use Try::Tiny;

$|++; # autoflush

%suppressedValues = {};
foreach my $valueName ( keys %main:: ) {
if (!$suppressedValues{$valueName}) {
$suppressedValues{$valueName} = 1;
}
}

my $kernelUri = "kernel://perl-$$";

$kernelInfo = {
"localName" => "perl",
"languageName" => "perl",
"languageVersion" => "$^V",
"displayName" => "Perl $^V",
"uri" => $kernelUri,
"supportedKernelCommands" => [
{ "name" => "RequestKernelInfo" },
{ "name" => "RequestValue" },
{ "name" => "RequestValueInfos" },
{ "name" => "SendValue" },
{ "name" => "SubmitCode" }
],
"supportedDirectives" => []
};

# run with `perl.exe kernel.pl test` to ensure the value serialization works as expected
if (length(@ARGV) > 0 && $ARGV[0] eq "test") {
$scalar = 4;
@array = (1, 2, 3);
$arrayRef = [4, 5, 6];
%hash = ("theAnswer" => 42, "pi" => 3.14159);
$hashRef = {"theAnswer" => 42, "pi" => 3.14159};
##
@names = ("scalar", "array", "arrayRef", "hash", "hashRef");
@mimeTypes = ("text/plain", "application/json");
foreach my $mimeType (@mimeTypes) {
print "$mimeType:\n";
foreach my $name (@names) {
print " $name: " . getStringRepresentationOfValueName($name, $mimeType) . "\n";
}
}

exit(0);
}

# otherwise this is the kernel's entry point
publish({
"eventType" => "KernelReady",
"event" => {},
"command" => undef,
"routingSlip" => [
$kernelUri
]
});

publish({
"eventType" => "KernelInfoProduced",
"event" => {
"kernelInfo" => $kernelInfo,
},
"command" => undef,
"routingSlip" => [
$kernelUri
]
});

while (<STDIN>) {
chomp;
try {
$envelope = decode_json($_);
$commandType = $envelope->{'commandType'};
if ($commandType) {
$token = $envelope->{'token'};
$command = $envelope->{'command'};
$succeeded = false;
if ($commandType eq "RequestKernelInfo") {
#
# RequestKernelInfo
#
publish({
"eventType" => "KernelInfoProduced",
"event" => {
"kernelInfo" => $kernelInfo
},
"command" => $envelope,
"routingSlip" => [
$kernelUri
]
});
$succeeded = true;
} elsif ($commandType eq "RequestValue") {
#
# RequestValue
#
$valueName = $command->{'name'};
$mimeType = $command->{'mimeType'};
$formattedValue = "TODO";
$formattedValue = getStringRepresentationOfValueName($valueName, $mimeType);
publish({
"eventType" => "ValueProduced",
"event" => {
"name" => $valueName,
"formattedValue" => {
"mimeType" => $mimeType,
"value" => $formattedValue
}
},
"command" => $envelope,
"routingSlip" => [
$kernelUri
]
});
$succeeded = true;
} elsif ($commandType eq "RequestValueInfos") {
#
# RequestValueInfos
#
my @valueInfos = ();
foreach my $valueName ( keys %main:: ) {
if (!$suppressedValues{$valueName}) {
push(@valueInfos, { "name" => "$valueName" });
}
}
publish({
"eventType" => "ValueInfosProduced",
"event" => {
"valueInfos" => \@valueInfos
},
"command" => $envelope,
"routingSlip" => [
$kernelUri
]
});
$succeeded = true;
} elsif ($commandType eq "SendValue") {
#
# SendValue
#
$formattedValue = $command->{'formattedValue'};
if ($formattedValue->{'mimeType'} eq "application/json") {
$valueName = $command->{'name'};
$jsonValue = $formattedValue->{'value'};
$runtimeValue = decode_json($jsonValue);
$main::{$valueName} = $runtimeValue;
$succeeded = true;
}
} elsif ($commandType eq "SubmitCode") {
#
# SubmitCode
#
$code = $command->{'code'};
$result = eval $code;
publish({
"eventType" => "ReturnValueProduced",
"event" => {
"formattedValues" => [{
"mimeType" => "text/plain",
"value" => "$result"
}],
},
"command" => $envelope,
"routingSlip" => [
$kernelUri
]
});
$succeeded = true;
} else {
$succeeded = false;
}

if ($succeeded) {
publish({
"eventType" => "CommandSucceeded",
"event" => {},
"command" => $envelope,
"routingSlip" => [
$kernelUri
]
});
} else {
publish({
"eventType" => "CommandFailed",
"event" => {
"message" => "Unknown command type: $commandType"
},
"command" => $envelope,
"routingSlip" => [
$kernelUri
]
});
}
}
$eventType = $envelope->{'eventType'};
if ($eventType) {
# TODO
}
} catch {
print STDERR "error: $_\n";
}
}

sub publish {
print encode_json(\%{$_[0]}) . "\n";
}

sub getStringRepresentationOfValueName {
my $valueName = shift;
my $mimeType = shift;
my $rawValue = $main::{$valueName};
my $formattedValue;
if ($mimeType eq "application/json") {
my @asArray = @{getArray($rawValue)};
my %asHash = %{getHash($rawValue)};
if (@asArray) {
$rawValue = \@asArray;
}
elsif (%asHash) {
$rawValue = \%asHash;
}
else {
$rawValue = $$rawValue;
}
$formattedValue = encode_json($rawValue);
}
else {
# assume text/plain
my @asArray = @{getArray($rawValue)};
my %asHash = %{getHash($rawValue)};
if (@asArray) {
$formattedValue = "(" . join(", ", @asArray) . ")";
}
elsif (%asHash) {
$formattedValue = "(" . join(", ", map { "$_ => $asHash{$_}" } keys %asHash) . ")";
}
else {
$formattedValue = "$$rawValue";
}
}

return $formattedValue;
}

sub getArray {
my $rawValue = shift;
if (ref($$rawValue) eq "ARRAY") {
return \@$$rawValue;
}
elsif (@$rawValue) {
return \@$rawValue;
}

return undef;
}

sub getHash {
my $rawValue = shift;
if (ref($$rawValue) eq "HASH") {
return \%$$rawValue;
}
elsif (%$rawValue) {
return \%$rawValue;
}

return undef;
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ Microsoft.DotNet.Interactive.Documents
public System.Collections.Generic.List<InteractiveDocumentOutputElement> Outputs { get;}
public abstract class InteractiveDocumentOutputElement
public class KernelInfo
.ctor(System.String name, System.Collections.Generic.IReadOnlyCollection<System.String> aliases = null)
.ctor(System.String name, System.String languageName = null, System.Collections.Generic.IReadOnlyCollection<System.String> aliases = null)
public System.Collections.Generic.IReadOnlyCollection<System.String> Aliases { get;}
public System.String LanguageName { get;}
public System.String Name { get;}
public System.String ToString()
public class KernelInfoCollection, System.Collections.Generic.ICollection<KernelInfo>, System.Collections.Generic.IEnumerable<KernelInfo>, System.Collections.IEnumerable
Expand Down Expand Up @@ -77,7 +78,8 @@ Microsoft.DotNet.Interactive.Documents
public System.String Text { get;}
Microsoft.DotNet.Interactive.Documents.Jupyter
public class InputCellMetadata
.ctor(System.String language = null)
.ctor(System.String kernelName = null, System.String language = null)
public System.String KernelName { get;}
public System.String Language { get;}
public static class InteractiveDocumentExtensions
public static Microsoft.DotNet.Interactive.Documents.InteractiveDocument WithJupyterMetadata(System.String language = C#)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,9 @@ Microsoft.DotNet.Interactive
public System.Threading.Tasks.Task<Microsoft.DotNet.Interactive.Connection.ProxyKernel> ConnectProxyKernelOnDefaultConnectorAsync(System.String localName, System.Uri remoteKernelUri, System.String[] aliases = null)
public System.Void Dispose()
public class KernelInfo
.ctor(System.String localName, System.String languageName = null, System.String languageVersion = null, System.String[] aliases = null)
.ctor(System.String localName, System.String languageName = null, System.String languageVersion = null, System.String displayName = null, System.String[] aliases = null)
public System.String[] Aliases { get; set;}
public System.String DisplayName { get;}
public System.String LanguageName { get;}
public System.String LanguageVersion { get;}
public System.String LocalName { get;}
Expand Down Expand Up @@ -424,9 +425,9 @@ Microsoft.DotNet.Interactive.Commands
public class RequestValueInfos : KernelCommand
.ctor(System.String targetKernelName = null)
public class SendEditableCode : KernelCommand
.ctor(System.String language, System.String code, System.String targetKernelName = vscode)
.ctor(System.String kernelName, System.String code, System.String targetKernelName = vscode)
public System.String Code { get;}
public System.String Language { get;}
public System.String KernelName { get;}
public class SendValue : KernelCommand
.ctor(System.String name, System.Object value, Microsoft.DotNet.Interactive.FormattedValue formattedValue = null, System.String targetKernelName = null)
public Microsoft.DotNet.Interactive.FormattedValue FormattedValue { get;}
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public CSharpKernel() : this(DefaultKernelName)
{

}
public CSharpKernel(string name) : base(name, "C#", "10.0")
public CSharpKernel(string name) : base(name, languageName: "C#", languageVersion: "10.0", displayName: "C# Script")
{
_workspace = new InteractiveWorkspace();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Threading.Tasks;
using Assent;
using FluentAssertions;
using FluentAssertions.Execution;
using Microsoft.DotNet.Interactive.Tests.Utility;
using Xunit;

Expand Down Expand Up @@ -433,6 +434,44 @@ public void Kernel_languages_can_be_specified_in_metadata()
});
}

[Fact]
public void dib_file_with_only_metadata_section_can_be_loaded()
{
var content = @"#!meta
{""theAnswer"":42}";
var document = ParseDib(content);
document
.Metadata
.Should()
.ContainKey("theAnswer");
}

[Fact]
public void kernel_selector_can_immediately_follow_metadata_section()
{
var content = @"#!meta
{""theAnswer"":42}
#!csharp
var x = 1;";
var document = ParseDib(content);

using var _ = new AssertionScope();

// validate metadata
document
.Metadata
.Should()
.ContainKey("theAnswer");

// validate content
document
.Elements
.Single()
.Contents
.Should()
.Be("var x = 1;");
}

[Fact]
public void Metadata_section_is_not_added_as_a_document_element()
{
Expand Down Expand Up @@ -590,7 +629,7 @@ private async Task<string> RoundTripDib(string notebookFile)
var inputDoc = CodeSubmission.Parse(expectedContent);

var resultContent = inputDoc.ToCodeSubmissionContent();

return resultContent;
}

Expand Down
Loading

0 comments on commit 4eebd8a

Please sign in to comment.