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

tracking std out prints #343

Merged
merged 11 commits into from
Jul 23, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Events;
using Microsoft.DotNet.Interactive.Jupyter.Protocol;
using WorkspaceServer.Kernel;

namespace Microsoft.DotNet.Interactive.Jupyter
{
Expand All @@ -31,7 +30,7 @@ public async Task Handle(JupyterRequestContext context)

var command = new RequestCompletion(completeRequest.Code, completeRequest.CursorPosition);

var openRequest = new InflightRequest(context, completeRequest, 0, null);
var openRequest = new InflightRequest(context, completeRequest, 0);

InFlightRequests[command] = openRequest;

Expand Down
29 changes: 20 additions & 9 deletions Microsoft.DotNet.Interactive.Jupyter/ExecuteRequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Events;
using Microsoft.DotNet.Interactive.Jupyter.Protocol;
using WorkspaceServer.Kernel;

namespace Microsoft.DotNet.Interactive.Jupyter
{
public class ExecuteRequestHandler : RequestHandlerBase<ExecuteRequest>
{
private int _executionCount;

public ExecuteRequestHandler(IKernel kernel) : base(kernel)
{
}
Expand All @@ -30,9 +29,8 @@ public async Task Handle(JupyterRequestContext context)
var executionCount = executeRequest.Silent ? _executionCount : Interlocked.Increment(ref _executionCount);

var command = new SubmitCode(executeRequest.Code, "csharp");
var id = Guid.NewGuid();
var transient = new Dictionary<string, object> { { "display_id", id.ToString() } };
var openRequest = new InflightRequest(context, executeRequest, executionCount, transient);

var openRequest = new InflightRequest(context, executeRequest, executionCount);

InFlightRequests[command] = openRequest;

Expand Down Expand Up @@ -79,6 +77,13 @@ public async Task Handle(JupyterRequestContext context)
}
}

private static Dictionary<string, object> CreateTransient()
{
var id = Guid.NewGuid();
var transient = new Dictionary<string, object> { { "display_id", id.ToString() } };
return transient;
}

void OnKernelResultEvent(IKernelEvent value)
{
switch (value)
Expand All @@ -96,7 +101,7 @@ void OnKernelResultEvent(IKernelEvent value)
case IncompleteCodeSubmissionReceived _:
case CompleteCodeSubmissionReceived _:
break;
default:
default:
throw new NotSupportedException();
}
}
Expand Down Expand Up @@ -152,12 +157,18 @@ private static void OnValueProduced(

try
{
var transient = CreateTransient();
// executeResult data
var executeResultData = new ExecuteResult(
var executeResultData = valueProduced.IsLastValue
? new ExecuteResult(
openRequest.ExecutionCount,
transient: openRequest.Transient,
transient: transient,
data: valueProduced?.FormattedValues
?.ToDictionary(k => k.MimeType, v => v.Value))
: new DisplayData(
transient: transient,
data: valueProduced?.FormattedValues
?.ToDictionary(k => k.MimeType ?? "text/plain", v => v.Value));
?.ToDictionary(k => k.MimeType, v => v.Value));

if (!openRequest.Request.Silent)
{
Expand Down
6 changes: 1 addition & 5 deletions Microsoft.DotNet.Interactive.Jupyter/RequestHandlerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Reactive.Disposables;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Jupyter.Protocol;
using WorkspaceServer.Kernel;

namespace Microsoft.DotNet.Interactive.Jupyter
{
Expand Down Expand Up @@ -41,18 +40,15 @@ public void Dispose()
protected class InflightRequest : IDisposable
{
private readonly CompositeDisposable _disposables = new CompositeDisposable();
public Dictionary<string, object> Transient { get; }
public JupyterRequestContext Context { get; }
public T Request { get; }
public int ExecutionCount { get; }

public InflightRequest(JupyterRequestContext context, T request, int executionCount,
Dictionary<string, object> transient)
public InflightRequest(JupyterRequestContext context, T request, int executionCount)
{
Context = context;
Request = request;
ExecutionCount = executionCount;
Transient = transient;
}

public void AddDisposable(IDisposable disposable)
Expand Down
4 changes: 2 additions & 2 deletions Microsoft.DotNet.Interactive.Rendering/Formatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace Microsoft.DotNet.Interactive.Rendering
/// </summary>
public static class Formatter
{
private const string DefaultMimeType = "text/plain";
private static Func<Type, bool> _autoGenerateForType = t => false;
private static int _defaultListExpansionLimit;
private static int _recursionLimit;
Expand Down Expand Up @@ -358,8 +359,7 @@ private static void TryRegisterDefault(string typeName, Action<object, TextWrite

public static string MimeTypeFor(Type type)
{
_mimeTypesByType.TryGetValue(type, out var mimeType);
return mimeType;
return _mimeTypesByType.TryGetValue(type, out var mimeType) ? mimeType : DefaultMimeType;
}

public static void SetMimeType(Type type, string mimeType)
Expand Down
3 changes: 2 additions & 1 deletion Microsoft.DotNet.Interactive.Rendering/PocketView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ private void SetContent(object[] args)
break;

default:
if (Formatter.MimeTypeFor(item.GetType()) != null)
var mimeType = Formatter.MimeTypeFor(item.GetType());
if (mimeType != null && mimeType != "text/plain")
{
item.FormatTo(writer);
}
Expand Down
6 changes: 4 additions & 2 deletions Microsoft.DotNet.Interactive/Events/ValueProduced.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ namespace Microsoft.DotNet.Interactive.Events
{
public class ValueProduced : KernelEventBase
{
public ValueProduced(
object value,
public ValueProduced(object value,
SubmitCode submitCode,
bool isLastValue = false,
colombod marked this conversation as resolved.
Show resolved Hide resolved
IReadOnlyCollection<FormattedValue> formattedValues = null) : base(submitCode)
{
Value = value;
IsLastValue = isLastValue;
FormattedValues = formattedValues;
}

public object Value { get; }
public bool IsLastValue { get; }

public IReadOnlyCollection<FormattedValue> FormattedValues { get; }
}
Expand Down
7 changes: 7 additions & 0 deletions Microsoft.DotNet.Interactive/FormattedValue.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
// 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
{
public class FormattedValue
{
public FormattedValue(string mimeType, object value)
{
if (string.IsNullOrWhiteSpace(mimeType))
{
throw new ArgumentException("Value cannot be null or whitespace.", nameof(mimeType));
}

MimeType = mimeType;
Value = value;
}
Expand Down
77 changes: 58 additions & 19 deletions WorkspaceServer.Tests/Kernel/CSharpKernelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public async Task it_returns_the_result_of_a_non_null_expression()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("123", "csharp"));
await kernel.SendAsync(new SubmitCode("123"));

KernelEvents.OfType<ValueProduced>()
.Last()
Expand All @@ -44,9 +44,9 @@ public async Task when_it_throws_exception_after_a_value_was_produced_then_only_
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("using System;", "csharp"));
await kernel.SendAsync(new SubmitCode("2 + 2", "csharp"));
await kernel.SendAsync(new SubmitCode("adddddddddd", "csharp"));
await kernel.SendAsync(new SubmitCode("using System;"));
await kernel.SendAsync(new SubmitCode("2 + 2"));
await kernel.SendAsync(new SubmitCode("adddddddddd"));

var (failure, lastCodeSubmissionEvaluationFailedPosition) = KernelEvents
.Select((error, pos) => (error, pos))
Expand Down Expand Up @@ -75,8 +75,8 @@ public async Task it_returns_exceptions_thrown_in_user_code()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("using System;", "csharp"));
await kernel.SendAsync(new SubmitCode("throw new NotImplementedException();", "csharp"));
await kernel.SendAsync(new SubmitCode("using System;"));
await kernel.SendAsync(new SubmitCode("throw new NotImplementedException();"));

KernelEvents.Last()
.Should()
Expand All @@ -92,8 +92,8 @@ public async Task it_returns_diagnostics()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("using System;", "csharp"));
await kernel.SendAsync(new SubmitCode("aaaadd", "csharp"));
await kernel.SendAsync(new SubmitCode("using System;"));
await kernel.SendAsync(new SubmitCode("aaaadd"));

KernelEvents.Last()
.Should()
Expand All @@ -109,9 +109,9 @@ public async Task it_notifies_when_submission_is_complete()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var a =", "csharp"));
await kernel.SendAsync(new SubmitCode("var a ="));

await kernel.SendAsync(new SubmitCode("12;", "csharp"));
await kernel.SendAsync(new SubmitCode("12;"));

KernelEvents.Should()
.NotContain(e => e is ValueProduced);
Expand All @@ -126,7 +126,7 @@ public async Task it_notifies_when_submission_is_incomplete()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var a =", "csharp"));
await kernel.SendAsync(new SubmitCode("var a ="));

KernelEvents.Should()
.NotContain(e => e is ValueProduced);
Expand All @@ -141,7 +141,7 @@ public async Task it_returns_the_result_of_a_null_expression()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("null", "csharp"));
await kernel.SendAsync(new SubmitCode("null"));

KernelEvents.OfType<ValueProduced>()
.Last()
Expand All @@ -155,7 +155,7 @@ public async Task it_does_not_return_a_result_for_a_statement()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var x = 1;", "csharp"));
await kernel.SendAsync(new SubmitCode("var x = 1;"));

KernelEvents
.Should()
Expand All @@ -167,9 +167,9 @@ public async Task it_aggregates_multiple_submissions()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var x = new List<int>{1,2};", "csharp"));
await kernel.SendAsync(new SubmitCode("x.Add(3);", "csharp"));
await kernel.SendAsync(new SubmitCode("x.Max()", "csharp"));
await kernel.SendAsync(new SubmitCode("var x = new List<int>{1,2};"));
await kernel.SendAsync(new SubmitCode("x.Add(3);"));
await kernel.SendAsync(new SubmitCode("x.Max()"));

KernelEvents.OfType<ValueProduced>()
.Last()
Expand All @@ -178,13 +178,52 @@ public async Task it_aggregates_multiple_submissions()
.Be(3);
}

[Fact]
public async Task it_produces_values_when_executing_Console_output()
{
var kernel = CreateKernel();

var kernelCommand = new SubmitCode(@"
Console.Write(""value one"");
Console.Write(""value two"");
Console.Write(""value three"");");
await kernel.SendAsync(kernelCommand);

KernelEvents.OfType<ValueProduced>()
.Should()
.BeEquivalentTo(
new ValueProduced("value one", kernelCommand, false, new[] { new FormattedValue("text/plain", "value one"), }),
new ValueProduced("value two", kernelCommand, false, new[] { new FormattedValue("text/plain", "value two"), }),
new ValueProduced("value three", kernelCommand, false, new[] { new FormattedValue("text/plain", "value three"), }));
}

[Fact]
public async Task it_produces_a_final_value_if_the_code_expression_evaluates()
{
var kernel = CreateKernel();

var kernelCommand = new SubmitCode(@"
Console.Write(""value one"");
Console.Write(""value two"");
Console.Write(""value three"");
5", "csharp");
colombod marked this conversation as resolved.
Show resolved Hide resolved
await kernel.SendAsync(kernelCommand);

KernelEvents.OfType<ValueProduced>()
.Should()
.HaveCount(4)
.And
.ContainSingle(e => e.IsLastValue);

}

[Fact(Skip = "requires support for cs8 in roslyn scripting")]
public async Task it_supports_csharp_8()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var text = \"meow? meow!\";", "csharp"));
await kernel.SendAsync(new SubmitCode("text[^5..^0]", "csharp"));
await kernel.SendAsync(new SubmitCode("var text = \"meow? meow!\";"));
await kernel.SendAsync(new SubmitCode("text[^5..^0]"));

KernelEvents.OfType<ValueProduced>()
.Last()
Expand Down Expand Up @@ -280,7 +319,7 @@ await kernel.SendAsync(
.Should()
.Contain(i => i.DisplayText == "SerializeObject");
}

[Fact]
public async Task The_extend_directive_can_be_used_to_load_a_kernel_extension()
{
Expand Down
Loading