Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,21 @@ Microsoft.DotNet.Interactive.Documents
public System.String ErrorName { get;}
public System.String ErrorValue { get;}
public System.String[] StackTrace { get;}
public class InputField
.ctor(System.String prompt, System.String typeHint = text)
public System.String Prompt { get; set;}
public System.String TypeHint { get; set;}
protected System.Boolean Equals(InputField other)
public System.Boolean Equals(System.Object obj)
public System.Int32 GetHashCode()
public class InteractiveDocument, System.Collections.IEnumerable
.ctor(System.Collections.Generic.IList<InteractiveDocumentElement> elements = null)
public System.Collections.Generic.IList<InteractiveDocumentElement> Elements { get; set;}
public System.Collections.Generic.IList<InteractiveDocumentElement> Elements { get;}
public System.Collections.Generic.IDictionary<System.String,System.Object> Metadata { get;}
public System.Void Add(InteractiveDocumentElement element)
public System.String GetDefaultKernelName()
public System.Collections.IEnumerator GetEnumerator()
public System.Collections.Generic.IReadOnlyCollection<InputField> GetInputFields()
public class InteractiveDocumentElement
.ctor()
.ctor(System.String contents = null, System.String kernelName = null, System.Collections.Generic.IEnumerable<InteractiveDocumentOutputElement> outputs = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ Microsoft.DotNet.Interactive
public class KeyValueStoreKernel : Kernel, IKernelCommandHandler<Microsoft.DotNet.Interactive.Commands.RequestKernelInfo>, IKernelCommandHandler<Microsoft.DotNet.Interactive.Commands.RequestValue>, IKernelCommandHandler<Microsoft.DotNet.Interactive.Commands.RequestValueInfos>, IKernelCommandHandler<Microsoft.DotNet.Interactive.Commands.SubmitCode>, Microsoft.DotNet.Interactive.ValueSharing.ISupportSetClrValue, System.IDisposable
.ctor(System.String name = value)
public ChooseKernelDirective ChooseKernelDirective { get;}
public System.Collections.Generic.IReadOnlyDictionary<System.String,System.Object> Values { get;}
public System.Threading.Tasks.Task HandleAsync(Microsoft.DotNet.Interactive.Commands.RequestValueInfos command, KernelInvocationContext context)
public System.Threading.Tasks.Task HandleAsync(Microsoft.DotNet.Interactive.Commands.RequestValue command, KernelInvocationContext context)
public System.Threading.Tasks.Task HandleAsync(Microsoft.DotNet.Interactive.Commands.SubmitCode command, KernelInvocationContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,55 @@ private static string GetDibContent(Dictionary<string, object> metadata)
";
}

[Fact]
public void Input_tokens_are_parsed_from_dib_files()
{
var dib = "#!value --from-file @input:filename --name myfile";

var document = CodeSubmission.Parse(dib);

document.GetInputFields()
.Should()
.ContainSingle()
.Which
.Prompt
.Should()
.Be("filename");
}

[Fact]
public void Password_tokens_are_parsed_from_dib_files()
{
var dib = "#!do-stuff --password @password:TOPSECRET";

var document = CodeSubmission.Parse(dib);

document.GetInputFields()
.Should()
.ContainSingle()
.Which
.Should()
.BeEquivalentTo(new InputField("TOPSECRET", "password"));
}

[Fact]
public void When_an_input_field_name_is_repeated_then_only_one_is_created_in_the_document()
{
var dib = @"
#!do-stuff @password:the-password
#!do-more-stuff @password:the-password
";

var document = CodeSubmission.Parse(dib);

document.GetInputFields()
.Should()
.ContainSingle()
.Which
.Should()
.BeEquivalentTo(new InputField("the-password", "password"));
}

private async Task<string> RoundTripDib(string notebookFile)
{
var expectedContent = await File.ReadAllTextAsync(notebookFile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,25 @@ public async Task ipynb_from_VSCode_can_be_round_tripped_through_read_and_write_
this.Assent(await RoundTripIpynb(path), _assentConfiguration);
}

[Fact]
public void Input_tokens_are_parsed_from_ipynb_files()
{
var ipynbJson = new InteractiveDocument
{
new("#!value --from-file @input:filename --name myfile")
}.SerializeToJupyter();

var document = Notebook.Parse(ipynbJson);

document.GetInputFields()
.Should()
.ContainSingle()
.Which
.Prompt
.Should()
.Be("filename");
}

private async Task<string> RoundTripIpynb(string notebookFile)
{
var expectedContent = await File.ReadAllTextAsync(notebookFile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
using FluentAssertions;
using Microsoft.DotNet.Interactive.Documents.ParserServer;
using Nerdbank.Streams;
using Pocket;
using Xunit;

namespace Microsoft.DotNet.Interactive.Documents.Tests
{
public class NotebookParserServerTests_TextInterface
public class NotebookParserServerTests_TextInterface : IDisposable
{
private readonly CompositeDisposable _disposables = new();

[Theory]
[InlineData("\n")]
[InlineData("\r\n")]
Expand Down Expand Up @@ -119,14 +122,13 @@ public async Task Notebook_parser_server_does_nothing_with_garbage_input_and_ski
.Be("the-id");
}

private static async IAsyncEnumerable<NotebookParserServerResponse> GetResponseObjectsEnumerable(string inputText)
private async IAsyncEnumerable<NotebookParserServerResponse> GetResponseObjectsEnumerable(string inputText)
{
using var input = new StringReader(inputText);
var stream = new SimplexStream();
var output = new StreamWriter(stream);
var server = new NotebookParserServer(input, output);

// FIX: (GetResponseObjectsEnumerable) clean up properly
_disposables.Add(server);

var _ = Task.Run(() => server.RunAsync()); // start server listener in the background

Expand All @@ -140,8 +142,17 @@ private static async IAsyncEnumerable<NotebookParserServerResponse> GetResponseO
var responseObject = NotebookParserServerResponse.FromJson(responseText);
yield return responseObject;
}
else
{
break;
}
}
}

public void Dispose()
{
_disposables.Dispose();
}
}

internal static class IAsyncEnumeratorExtensions
Expand Down
22 changes: 12 additions & 10 deletions src/Microsoft.DotNet.Interactive.Documents/CodeSubmission.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Microsoft.DotNet.Interactive.Documents
{
public static class CodeSubmission
{
private const string InteractiveNotebookCellSpecifier = "#!";
internal const string MagicCommandPrefix = "#!";

public static Encoding Encoding => new UTF8Encoding(false);

Expand Down Expand Up @@ -65,9 +65,9 @@ public static InteractiveDocument Parse(
}
}

if (line.StartsWith(InteractiveNotebookCellSpecifier))
if (line.StartsWith(MagicCommandPrefix))
{
var cellLanguage = line.Substring(InteractiveNotebookCellSpecifier.Length);
var cellLanguage = line.Substring(MagicCommandPrefix.Length);

if (kernelInfo.TryGetByAlias(cellLanguage, out var name))
{
Expand All @@ -82,6 +82,8 @@ public static InteractiveDocument Parse(
{
// unrecognized language, probably a magic command
currentElementLines.Add(line);

document.AddMagicCommandLine(line);
}
}
else
Expand All @@ -99,11 +101,6 @@ public static InteractiveDocument Parse(
document.Elements.Add(CreateElement(currentLanguage, Array.Empty<string>()));
}

InteractiveDocumentElement CreateElement(string elementLanguage, IEnumerable<string> elementLines)
{
return new(string.Join("\n", elementLines), elementLanguage);
}

if (metadata is not null)
{
document.Metadata.MergeWith(metadata);
Expand All @@ -130,6 +127,11 @@ void AddElement()
document.Elements.Add(CreateElement(currentLanguage, currentElementLines));
}
}

InteractiveDocumentElement CreateElement(string elementLanguage, IEnumerable<string> elementLines)
{
return new(string.Join("\n", elementLines), elementLanguage);
}
}

public static InteractiveDocument Read(
Expand Down Expand Up @@ -158,7 +160,7 @@ public static string ToCodeSubmissionContent(

if (document.Metadata.Count > 0)
{
lines.Add($"{InteractiveNotebookCellSpecifier}meta");
lines.Add($"{MagicCommandPrefix}meta");
lines.Add("");
lines.Add(JsonSerializer.Serialize(document.Metadata, ParserServerSerializer.JsonSerializerOptions));
lines.Add("");
Expand All @@ -176,7 +178,7 @@ public static string ToCodeSubmissionContent(
{
if (element.KernelName is not null)
{
lines.Add($"{InteractiveNotebookCellSpecifier}{element.KernelName}");
lines.Add($"{MagicCommandPrefix}{element.KernelName}");
lines.Add("");
}

Expand Down
49 changes: 49 additions & 0 deletions src/Microsoft.DotNet.Interactive.Documents/InputField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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.

using System;

namespace Microsoft.DotNet.Interactive.Documents;

public class InputField
{
public InputField(string prompt, string typeHint = "text")
{
Prompt = prompt;
TypeHint = typeHint;
}

public string Prompt { get; set; }

public string TypeHint { get; set; }

protected bool Equals(InputField other)
{
return Prompt == other.Prompt && TypeHint == other.TypeHint;
}

public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}

if (ReferenceEquals(this, obj))
{
return true;
}

if (obj.GetType() != this.GetType())
{
return false;
}

return Equals((InputField)obj);
}

public override int GetHashCode()
{
return HashCode.Combine(Prompt, TypeHint);
}
}
Loading