Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser server error handling improvements #3035

Merged
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -98,49 +98,3 @@ Microsoft.DotNet.Interactive.Documents.Jupyter
public static System.Void Write(Microsoft.DotNet.Interactive.Documents.InteractiveDocument document, System.IO.Stream stream, Microsoft.DotNet.Interactive.Documents.KernelInfoCollection kernelInfos)
public static System.Void Write(Microsoft.DotNet.Interactive.Documents.InteractiveDocument document, System.IO.TextWriter writer)
public static System.Void Write(Microsoft.DotNet.Interactive.Documents.InteractiveDocument document, System.IO.TextWriter writer, Microsoft.DotNet.Interactive.Documents.KernelInfoCollection kernelInfos)
Microsoft.DotNet.Interactive.Documents.ParserServer
public enum DocumentSerializationType : System.Enum, System.IComparable, System.IConvertible, System.IFormattable
Dib=0
Ipynb=1
public class NotebookErrorResponse : NotebookParserServerResponse
.ctor(System.String id, System.String errorMessage)
public System.String ErrorMessage { get;}
public abstract class NotebookParseOrSerializeRequest
public static NotebookParseOrSerializeRequest FromJson(System.String json)
public System.String DefaultLanguage { get;}
public System.String Id { get;}
public DocumentSerializationType SerializationType { get;}
public RequestType Type { get;}
public class NotebookParseRequest : NotebookParseOrSerializeRequest
.ctor(System.String id, DocumentSerializationType serializationType, System.String defaultLanguage, System.Byte[] rawData)
public System.Byte[] RawData { get;}
public RequestType Type { get;}
public class NotebookParseResponse : NotebookParserServerResponse
.ctor(System.String id, Microsoft.DotNet.Interactive.Documents.InteractiveDocument document)
public Microsoft.DotNet.Interactive.Documents.InteractiveDocument Document { get;}
public class NotebookParserServer, System.IDisposable
public static NotebookParserServerResponse HandleRequest(NotebookParseOrSerializeRequest request)
.ctor(System.IO.TextReader input, System.IO.TextWriter output)
public System.IO.TextReader Input { get;}
public System.IO.TextWriter Output { get;}
public System.Void Dispose()
public System.Threading.Tasks.Task RunAsync()
public static class NotebookParserServerExtensions
public static System.String ToJson()
public static System.String ToJson()
public abstract class NotebookParserServerResponse
public static NotebookParserServerResponse FromJson(System.String json)
public System.String Id { get;}
public class NotebookSerializeRequest : NotebookParseOrSerializeRequest
.ctor(System.String id, DocumentSerializationType serializationType, System.String defaultLanguage, System.String newLine, Microsoft.DotNet.Interactive.Documents.InteractiveDocument document)
public Microsoft.DotNet.Interactive.Documents.InteractiveDocument Document { get;}
public System.String NewLine { get;}
public RequestType Type { get;}
public class NotebookSerializeResponse : NotebookParserServerResponse
.ctor(System.String id, System.Byte[] rawData)
public System.Byte[] RawData { get;}
public static class ParserServerSerializer
public static System.Text.Json.JsonSerializerOptions JsonSerializerOptions { get;}
public enum RequestType : System.Enum, System.IComparable, System.IConvertible, System.IFormattable
Parse=0
Serialize=1
Original file line number Diff line number Diff line change
Expand Up @@ -536,12 +536,12 @@ public async Task dib_file_can_be_round_tripped_through_read_and_write_without_t

private static string GetDibContent(Dictionary<string, object> metadata)
{
if (metadata == null)
if (metadata is null)
{
throw new ArgumentNullException(nameof(metadata));
}

var serializedMetadata = JsonSerializer.Serialize(metadata, ParserServer.ParserServerSerializer.JsonSerializerOptions);
var serializedMetadata = JsonSerializer.Serialize(metadata, App.ParserServer.ParserServerSerializer.JsonSerializerOptions);

return $@"#!meta

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Linq;
using System.Text;
using FluentAssertions;
using Microsoft.DotNet.Interactive.Documents.ParserServer;
using Microsoft.DotNet.Interactive.App.ParserServer;
using Newtonsoft.Json;

using Xunit;
Expand Down Expand Up @@ -500,19 +500,20 @@ public void Notebook_parser_server_can_serialize_file_based_on_document_type(Doc
}

[Fact]
public void Notebook_parser_server_returns_an_error_on_unsupported_document_type()
public void Notebook_parser_server_throws_on_unsupported_document_type()
{
var request = new NotebookParseRequest(
"the-id",
serializationType: (DocumentSerializationType)42,
defaultLanguage: "csharp",
rawData: Array.Empty<byte>());
var response = NotebookParserServer.HandleRequest(request);
response
var handle = () => NotebookParserServer.HandleRequest(request);

handle.Invoking(h => h())
.Should()
.BeOfType<NotebookErrorResponse>()
.Throw<NotSupportedException>()
.Which
.ErrorMessage
.Message
.Should()
.Contain($"Unable to parse an interactive document with type '{(int)request.SerializationType}'");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is orthogonal - but should our exception messages be localized?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't typically localize exception messages.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My assumption was that exception messages should be localized if they can ever end up being displayed to the end user...

For C#, we would display localized messages for compilation errors etc., would we not? It seems strange that we would always display English messages for any errors that originate within .NET Interactive itself...

}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Assent;
using FluentAssertions;
using FluentAssertions.Execution;
using Microsoft.DotNet.Interactive.Documents.ParserServer;
using Microsoft.DotNet.Interactive.App.ParserServer;
using Xunit;

namespace Microsoft.DotNet.Interactive.Documents.Tests;
Expand Down Expand Up @@ -77,16 +77,6 @@ public void NotebookSerializeResponse_serialization_contract()
this.Assent(json, _configuration);
}

[Fact]
public void NotebookErrorResponse_serialization_contract()
{
var response = new NotebookErrorResponse("the-id", "some error message");

var json = response.ToJson();

this.Assent(json, _configuration);
}

private string GetTestFileContents(string extension = "json", [CallerFilePath] string thisFilePath = null, [CallerMemberName] string testName = null)
{
var fileName = $"{GetType().Name}.{testName}.approved.{extension}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.DotNet.Interactive.Documents.ParserServer;
using Microsoft.DotNet.Interactive.App.ParserServer;
using Nerdbank.Streams;
using Pocket;
using Xunit;
Expand Down
7 changes: 3 additions & 4 deletions src/Microsoft.DotNet.Interactive.Documents/CodeSubmission.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.DotNet.Interactive.Documents.ParserServer;
using Microsoft.DotNet.Interactive.Documents.Utility;
using Microsoft.DotNet.Interactive.Utility;

Expand Down Expand Up @@ -53,7 +52,7 @@ public static InteractiveDocument Parse(

var metadataString = sb.ToString();

metadata = JsonSerializer.Deserialize<Dictionary<string, object>>(metadataString, ParserServerSerializer.JsonSerializerOptions);
metadata = JsonSerializer.Deserialize<Dictionary<string, object>>(metadataString, InteractiveDocument.JsonSerializerOptions);

if (InteractiveDocument.TryGetKernelInfoFromMetadata(metadata, out var kernelInfoFromMetadata))
{
Expand Down Expand Up @@ -170,7 +169,7 @@ public static string ToCodeSubmissionContent(
{
lines.Add($"{MagicCommandPrefix}meta");
lines.Add("");
lines.Add(JsonSerializer.Serialize(document.Metadata, ParserServerSerializer.JsonSerializerOptions));
lines.Add(JsonSerializer.Serialize(document.Metadata, InteractiveDocument.JsonSerializerOptions));
lines.Add("");
}

Expand Down Expand Up @@ -226,4 +225,4 @@ public static void Write(InteractiveDocument document, TextWriter writer, Kernel
InteractiveDocument.MergeKernelInfos(document, kernelInfos);
Write(document, writer, newline);
}
}
}
31 changes: 26 additions & 5 deletions src/Microsoft.DotNet.Interactive.Documents/InteractiveDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,37 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.DotNet.Interactive.Documents.Json;
using Microsoft.DotNet.Interactive.Documents.Jupyter;
using Microsoft.DotNet.Interactive.Documents.ParserServer;
using Microsoft.DotNet.Interactive.Documents.Utility;
using Microsoft.DotNet.Interactive.Utility;

namespace Microsoft.DotNet.Interactive.Documents;

public class InteractiveDocument : IEnumerable
{
static InteractiveDocument()
{
JsonSerializerOptions = new JsonSerializerOptions
{
WriteIndented = false,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.AllowNamedFloatingPointLiterals,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
Converters =
{
new ByteArrayConverter(),
new DataDictionaryConverter(),
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase),
new InteractiveDocumentConverter(),
}
};
}

private static Parser? _importFieldsParser;
private static Argument<FileInfo>? _importedFileArgument;

Expand Down Expand Up @@ -254,15 +274,15 @@ internal static bool TryGetKernelInfoFromMetadata(
if (metadata.TryGetValue("kernelInfo", out var kernelInfoObj) )
{
if (kernelInfoObj is JsonElement kernelInfoJson &&
kernelInfoJson.Deserialize<KernelInfoCollection>(ParserServerSerializer.JsonSerializerOptions) is
JsonSerializer.Deserialize<KernelInfoCollection>(kernelInfoJson, JsonSerializerOptions) is
{ } kernelInfoDeserialized)
{
kernelInfo = kernelInfoDeserialized;
return true;
}

// todo: the kernelInfo should not deserialize as a dictionary
if (kernelInfoObj is Dictionary<string,object> kernelInfoAsDictionary)
if (kernelInfoObj is Dictionary<string, object> kernelInfoAsDictionary)
{
var deserializedKernelInfo = new KernelInfoCollection();
if (kernelInfoAsDictionary.TryGetValue("defaultKernelName", out var defaultKernelNameObj) &&
Expand All @@ -272,11 +292,11 @@ internal static bool TryGetKernelInfoFromMetadata(
}

if (kernelInfoAsDictionary.TryGetValue("items",
out var items))
out var items))
{
if (items is IEnumerable<object> itemList)
{
foreach (var item in itemList.Cast<IDictionary<string,object>>())
foreach (var item in itemList.Cast<IDictionary<string, object>>())
{
if (item.TryGetValue("name", out var nameObj) &&
nameObj is string name)
Expand Down Expand Up @@ -437,4 +457,5 @@ private static void EnsureInputFieldParserIsInitialized()
.Build();
}

internal static JsonSerializerOptions JsonSerializerOptions { get; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// 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.

#nullable enable
using System;
using System.Collections.Generic;
using System.Text.Json;

Expand Down Expand Up @@ -54,7 +56,8 @@ internal static class JsonReaderExtensions
{
case JsonTokenType.StartArray:
var lines = JsonSerializer.Deserialize<string[]>(ref reader);
return string.Join("", lines);

return string.Join("", lines ?? Array.Empty<string>());

case JsonTokenType.String:
return reader.GetString();
Expand Down
1 change: 0 additions & 1 deletion src/Microsoft.DotNet.Interactive.Documents/KernelInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Microsoft.DotNet.Interactive.Documents.ParserServer;

namespace Microsoft.DotNet.Interactive.Documents;

Expand Down
Loading