From 25b89c8592ad521240c7f089581c7a15475342a8 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Mon, 13 Apr 2020 17:17:54 -0700 Subject: [PATCH 1/7] R: reorganize a few tests, rename RegisterNugetResolvedPackageReferences -> RegisterResolvedPackageReferences --- .../CSharpKernelTests.cs | 42 ++++ .../SubmissionParsingTests.cs | 1 - .../CSharpKernel.cs | 4 +- .../FSharpKernel.fs | 2 +- ...DotNet.Interactive.PowerShell.Tests.csproj | 1 + .../PowerShellKernelTests.cs | 10 +- .../LanguageKernelTests.cs | 186 +----------------- Microsoft.DotNet.Interactive/ISupportNuget.cs | 6 +- .../KernelSupportsNugetExtensions.cs | 2 +- 9 files changed, 59 insertions(+), 195 deletions(-) create mode 100644 Microsoft.DotNet.Interactive.CSharp.Tests/CSharpKernelTests.cs diff --git a/Microsoft.DotNet.Interactive.CSharp.Tests/CSharpKernelTests.cs b/Microsoft.DotNet.Interactive.CSharp.Tests/CSharpKernelTests.cs new file mode 100644 index 0000000000..543b861d4f --- /dev/null +++ b/Microsoft.DotNet.Interactive.CSharp.Tests/CSharpKernelTests.cs @@ -0,0 +1,42 @@ +// 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.Threading.Tasks; +using FluentAssertions; +using Microsoft.DotNet.Interactive.Commands; +using Microsoft.DotNet.Interactive.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.Interactive.CSharp.Tests +{ + public class CSharpKernelTests : LanguageKernelTests + { + public CSharpKernelTests(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public async Task Script_state_is_available_within_middleware_pipeline() + { + var variableCountBeforeEvaluation = 0; + var variableCountAfterEvaluation = 0; + + using var kernel = new CSharpKernel(); + + kernel.AddMiddleware(async (command, context, next) => + { + var k = context.HandlingKernel as CSharpKernel; + + await next(command, context); + + variableCountAfterEvaluation = k.ScriptState.Variables.Length; + }); + + await kernel.SendAsync(new SubmitCode("var x = 1;")); + + variableCountBeforeEvaluation.Should().Be(0); + variableCountAfterEvaluation.Should().Be(1); + } + } +} \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive.CSharp.Tests/SubmissionParsingTests.cs b/Microsoft.DotNet.Interactive.CSharp.Tests/SubmissionParsingTests.cs index d3337f5cc4..bbef507340 100644 --- a/Microsoft.DotNet.Interactive.CSharp.Tests/SubmissionParsingTests.cs +++ b/Microsoft.DotNet.Interactive.CSharp.Tests/SubmissionParsingTests.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.DotNet.Interactive.Commands; -using Microsoft.DotNet.Interactive.Tests; using Microsoft.DotNet.Interactive.Tests.Utility; using Xunit; diff --git a/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs b/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs index a7caa114c8..2b4f0a4289 100644 --- a/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs +++ b/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net; using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -25,7 +24,6 @@ using Newtonsoft.Json.Linq; using XPlot.Plotly; using Task = System.Threading.Tasks.Task; -using System.ComponentModel; namespace Microsoft.DotNet.Interactive.CSharp { @@ -343,7 +341,7 @@ void ISupportNuget.Initialize(AssemblyResolutionProbe assemblyProbingPaths, Nati _nativeProbingRoots = nativeProbingRoots; } - void ISupportNuget.RegisterNugetResolvedPackageReferences(IReadOnlyList resolvedReferences) + void ISupportNuget.RegisterResolvedPackageReferences(IReadOnlyList resolvedReferences) { var references = resolvedReferences .SelectMany(r => r.AssemblyPaths) diff --git a/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs b/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs index 18104d037c..f5584f15b1 100644 --- a/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs +++ b/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs @@ -199,7 +199,7 @@ type FSharpKernel() as this = _assemblyProbingPaths <- assemblyProbingPaths _nativeProbingRoots <- nativeProbingRoots - member this.RegisterNugetResolvedPackageReferences (packageReferences: IReadOnlyList) = + member this.RegisterResolvedPackageReferences (packageReferences: IReadOnlyList) = // Generate #r and #I from packageReferences let sb = StringBuilder() let hashset = HashSet() diff --git a/Microsoft.DotNet.Interactive.PowerShell.Tests/Microsoft.DotNet.Interactive.PowerShell.Tests.csproj b/Microsoft.DotNet.Interactive.PowerShell.Tests/Microsoft.DotNet.Interactive.PowerShell.Tests.csproj index 1664055ffb..296c675796 100644 --- a/Microsoft.DotNet.Interactive.PowerShell.Tests/Microsoft.DotNet.Interactive.PowerShell.Tests.csproj +++ b/Microsoft.DotNet.Interactive.PowerShell.Tests/Microsoft.DotNet.Interactive.PowerShell.Tests.csproj @@ -15,6 +15,7 @@ + diff --git a/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs b/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs index e4b1931be7..e79d34c4e6 100644 --- a/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs +++ b/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs @@ -6,11 +6,19 @@ using System.Management.Automation; using System.Threading.Tasks; using FluentAssertions; +using System.Linq; +using System.Management.Automation; +using System.Threading.Tasks; +using Microsoft.DotNet.Interactive.Commands; +using Microsoft.DotNet.Interactive.Events; +using Microsoft.DotNet.Interactive.Tests; +using XPlot.Plotly; using Xunit; +using Xunit.Abstractions; namespace Microsoft.DotNet.Interactive.PowerShell.Tests { - public class PowerShellKernelTests + public class PowerShellKernelTests : LanguageKernelTests { private readonly string _allUsersCurrentHostProfilePath = Path.Combine(Path.GetDirectoryName(typeof(PSObject).Assembly.Location), "Microsoft.dotnet-interactive_profile.ps1"); diff --git a/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs b/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs index a187231f2b..d67848b30b 100644 --- a/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs +++ b/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs @@ -761,30 +761,7 @@ public async Task it_returns_completion_list_for_previously_declared_items(Langu .Contain(i => i.DisplayText == "alpha"); } - [Fact(Timeout = 45000)] - public async Task Script_state_is_available_within_middleware_pipeline() - { - var variableCountBeforeEvaluation = 0; - var variableCountAfterEvaluation = 0; - - using var kernel = new CSharpKernel(); - - kernel.AddMiddleware(async (command, context, next) => - { - var k = context.HandlingKernel as CSharpKernel; - - await next(command, context); - - variableCountAfterEvaluation = k.ScriptState.Variables.Length; - }); - - await kernel.SendAsync(new SubmitCode("var x = 1;")); - - variableCountBeforeEvaluation.Should().Be(0); - variableCountAfterEvaluation.Should().Be(1); - } - - [Fact(Timeout = 45000)] + [Fact] public async Task When_submission_is_split_then_CommandHandled_is_published_only_for_the_root_command() { var kernel = CreateKernel(Language.CSharp); @@ -801,166 +778,5 @@ public async Task When_submission_is_split_then_CommandHandled_is_published_only .Should() .Be(command); } - - [Fact()] - public async Task PowerShell_streams_handled_in_correct_order() - { - var kernel = CreateKernel(Language.PowerShell); - - const string yellow_foreground = "\u001b[93m"; - const string red_foreground = "\u001b[91m"; - const string reset = "\u001b[0m"; - - const string warningMessage = "I am a warning message"; - const string verboseMessage = "I am a verbose message"; - const string outputMessage = "I am output"; - const string debugMessage = "I am a debug message"; - const string hostMessage = "I am a message written to host"; - const string errorMessage = "I am a non-terminating error"; - - var command = new SubmitCode($@" -Write-Warning '{warningMessage}' -Write-Verbose '{verboseMessage}' -Verbose -'{outputMessage}' -Write-Debug '{debugMessage}' -Debug -Write-Host '{hostMessage}' -NoNewline -Write-Error '{errorMessage}' -"); - - await kernel.SendAsync(command); - - Assert.Collection(KernelEvents, - e => e.Should().BeOfType(), - e => e.Should().BeOfType(), - e => e.Should().BeOfType().Which - .Value.ToString().Should().Contain($"{yellow_foreground}WARNING: {warningMessage}{reset}"), - e => e.Should().BeOfType().Which - .Value.ToString().Should().Contain($"{yellow_foreground}VERBOSE: {verboseMessage}{reset}"), - e => e.Should().BeOfType().Which - .Value.ToString().Should().Be(outputMessage + Environment.NewLine), - e => e.Should().BeOfType().Which - .Value.ToString().Should().Contain($"{yellow_foreground}DEBUG: {debugMessage}{reset}"), - e => e.Should().BeOfType().Which - .Value.ToString().Should().Be(hostMessage), - e => e.Should().BeOfType().Which - .Value.ToString().Should().Contain($"{red_foreground}Write-Error: {red_foreground}{errorMessage}{reset}"), - e => e.Should().BeOfType()); - } - - [Fact()] - public async Task PowerShell_progress_sends_updated_display_values() - { - var kernel = CreateKernel(Language.PowerShell); - var command = new SubmitCode(@" -for ($j = 0; $j -le 4; $j += 4 ) { - $p = $j * 25 - Write-Progress -Id 1 -Activity 'Search in Progress' -Status ""$p% Complete"" -PercentComplete $p - Start-Sleep -Milliseconds 300 -} -"); - await kernel.SendAsync(command); - - Assert.Collection(KernelEvents, - e => e.Should().BeOfType(), - e => e.Should().BeOfType(), - e => e.Should().BeOfType().Which - .Value.Should().BeOfType().Which - .Should().Match("* Search in Progress* 0% Complete* [ * ] *"), - e => e.Should().BeOfType().Which - .Value.Should().BeOfType().Which - .Should().Match("* Search in Progress* 100% Complete* [ooo*ooo] *"), - e => e.Should().BeOfType().Which - .Value.Should().BeOfType().Which - .Should().Be(string.Empty), - e => e.Should().BeOfType()); - } - - [Fact()] - public void PowerShell_type_accelerators_present() - { - var kernel = CreateKernel(Language.PowerShell); - - var accelerator = typeof(PSObject).Assembly.GetType("System.Management.Automation.TypeAccelerators"); - dynamic typeAccelerators = accelerator.GetProperty("Get").GetValue(null); - Assert.Equal(typeAccelerators["Graph.Scatter"].FullName, $"{typeof(Graph).FullName}+Scatter"); - Assert.Equal(typeAccelerators["Layout"].FullName, $"{typeof(Layout).FullName}+Layout"); - Assert.Equal(typeAccelerators["Chart"].FullName, typeof(Chart).FullName); - } - - [Fact()] - public async Task PowerShell_token_variables_work() - { - var kernel = CreateKernel(Language.PowerShell); - - await kernel.SendAsync(new SubmitCode("echo /this/is/a/path")); - await kernel.SendAsync(new SubmitCode("$$; $^")); - - Assert.Collection(KernelEvents, - e => e.Should() - .BeOfType() - .Which.Code - .Should().Be("echo /this/is/a/path"), - e => e.Should() - .BeOfType() - .Which.Code - .Should().Be("echo /this/is/a/path"), - e => e.Should() - .BeOfType() - .Which.Value.ToString() - .Should().Be("/this/is/a/path" + Environment.NewLine), - e => e.Should().BeOfType(), - e => e.Should() - .BeOfType() - .Which.Code - .Should().Be("$$; $^"), - e => e.Should() - .BeOfType() - .Which.Code - .Should().Be("$$; $^"), - e => e.Should() - .BeOfType() - .Which.Value.ToString() - .Should().Be("/this/is/a/path" + Environment.NewLine), - e => e.Should() - .BeOfType() - .Which.Value.ToString() - .Should().Be("echo" + Environment.NewLine), - e => e.Should().BeOfType()); - } - - [Fact()] - public async Task PowerShell_get_history_should_work() - { - var kernel = CreateKernel(Language.PowerShell); - - await kernel.SendAsync(new SubmitCode("Get-Verb > $null")); - await kernel.SendAsync(new SubmitCode("echo bar > $null")); - await kernel.SendAsync(new SubmitCode("Get-History | % CommandLine")); - - var outputs = KernelEvents.OfType(); - outputs.Should().HaveCount(2); - Assert.Collection(outputs, - e => e.Value.As().Should().Be("Get-Verb > $null" + Environment.NewLine), - e => e.Value.As().Should().Be("echo bar > $null" + Environment.NewLine)); - } - - [Fact()] - public async Task PowerShell_native_executable_output_is_collected() - { - var kernel = CreateKernel(Language.PowerShell); - - var command = Platform.IsWindows - ? new SubmitCode("ping.exe -n 1 localhost") - : new SubmitCode("ping -c 1 localhost"); - - await kernel.SendAsync(command); - - var outputs = KernelEvents.OfType(); - outputs.Should().HaveCountGreaterThan(1); - outputs.Select(e => e.Value.ToString()) - .First(s => s.Trim().Length > 0) - .ToLowerInvariant() - .Should().Match("*ping*data*"); - } } } diff --git a/Microsoft.DotNet.Interactive/ISupportNuget.cs b/Microsoft.DotNet.Interactive/ISupportNuget.cs index 8f07e04b0f..dce0d596a8 100644 --- a/Microsoft.DotNet.Interactive/ISupportNuget.cs +++ b/Microsoft.DotNet.Interactive/ISupportNuget.cs @@ -12,12 +12,12 @@ public interface ISupportNuget // Set assemblyProbingPaths, nativeProbingRoots for Kernel. // These values are functions that return the list of discovered assemblies, and package roots // They are used by the dependecymanager for Assembly and Native dll resolving - public abstract void Initialize(AssemblyResolutionProbe assemblyProbingPaths, NativeResolutionProbe nativeProbingRoots); + public void Initialize(AssemblyResolutionProbe assemblyProbingPaths, NativeResolutionProbe nativeProbingRoots); - public abstract void RegisterNugetResolvedPackageReferences(IReadOnlyList packageReferences); + public void RegisterResolvedPackageReferences(IReadOnlyList packageReferences); // Summary: // Resolve reference for a list of package manager lines - public abstract IResolveDependenciesResult Resolve(IEnumerable packageManagerTextLines, string executionTfm, ResolvingErrorReport reportError); + public IResolveDependenciesResult Resolve(IEnumerable packageManagerTextLines, string executionTfm, ResolvingErrorReport reportError); } } \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive/KernelSupportsNugetExtensions.cs b/Microsoft.DotNet.Interactive/KernelSupportsNugetExtensions.cs index 232be7857e..a1d4f3d24c 100644 --- a/Microsoft.DotNet.Interactive/KernelSupportsNugetExtensions.cs +++ b/Microsoft.DotNet.Interactive/KernelSupportsNugetExtensions.cs @@ -212,7 +212,7 @@ internal static KernelCommandInvocation DoNugetRestore( if (result.Succeeded) { - (kernel as ISupportNuget)?.RegisterNugetResolvedPackageReferences(result.ResolvedReferences); + (kernel as ISupportNuget)?.RegisterResolvedPackageReferences(result.ResolvedReferences); foreach (var resolvedReference in result.ResolvedReferences) { From f3fa4189bbe9dcabc6dc569ef9e34ade86eaeb78 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Mon, 13 Apr 2020 17:18:30 -0700 Subject: [PATCH 2/7] GetKernel method, variable sharing test --- ...DotNet.Interactive.PowerShell.Tests.csproj | 1 + .../VariableSharingTests.cs | 53 +++++++++++++++++++ Microsoft.DotNet.Interactive/Kernel.cs | 31 +++++++++++ .../Utility/EnumerableExtensions.cs | 15 +++++- 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs diff --git a/Microsoft.DotNet.Interactive.PowerShell.Tests/Microsoft.DotNet.Interactive.PowerShell.Tests.csproj b/Microsoft.DotNet.Interactive.PowerShell.Tests/Microsoft.DotNet.Interactive.PowerShell.Tests.csproj index 296c675796..e2cf03eeeb 100644 --- a/Microsoft.DotNet.Interactive.PowerShell.Tests/Microsoft.DotNet.Interactive.PowerShell.Tests.csproj +++ b/Microsoft.DotNet.Interactive.PowerShell.Tests/Microsoft.DotNet.Interactive.PowerShell.Tests.csproj @@ -3,6 +3,7 @@ netcoreapp3.1 latest + $(NoWarn);8002;CS8002 false diff --git a/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs b/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs new file mode 100644 index 0000000000..3c566dc0e1 --- /dev/null +++ b/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs @@ -0,0 +1,53 @@ +// 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; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.DotNet.Interactive.CSharp; +using Microsoft.DotNet.Interactive.Events; +using Microsoft.DotNet.Interactive.FSharp; +using Microsoft.DotNet.Interactive.PowerShell; +using Microsoft.DotNet.Interactive.Tests.Utility; +using Xunit; + +namespace Microsoft.DotNet.Interactive.Tests +{ + public class VariableSharingTests + { + [Theory] + [InlineData( + "fsharp", + "let x = 123", + "csharp", + "GetKernel(\"fsharp\").TryGetVariable(\"x\", out var x);\nx")] + public async Task Variables_can_be_read_from_other_kernels( + string fromLanguage, + string codeToWrite, + string toLanguage, + string codeToRead) + { + using var kernel = new CompositeKernel + { + new CSharpKernel() + .UseKernelHelpers(), + new FSharpKernel() + .UseKernelHelpers(), + new PowerShellKernel() + }; + + using var events = kernel.KernelEvents.ToSubscribedList(); + + await kernel.SubmitCodeAsync($"#!{fromLanguage}\n{codeToWrite}"); + + await kernel.SubmitCodeAsync($"#!{toLanguage}\n{codeToRead}"); + + events.Should() + .ContainSingle() + .Which + .Value + .Should() + .Be(123); + } + } +} \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive/Kernel.cs b/Microsoft.DotNet.Interactive/Kernel.cs index 51bdabf9f6..af52a8be09 100644 --- a/Microsoft.DotNet.Interactive/Kernel.cs +++ b/Microsoft.DotNet.Interactive/Kernel.cs @@ -2,11 +2,14 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Html; using Microsoft.DotNet.Interactive.Commands; using Microsoft.DotNet.Interactive.Events; using Microsoft.DotNet.Interactive.Formatting; +using Microsoft.DotNet.Interactive.Utility; using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags; namespace Microsoft.DotNet.Interactive @@ -42,5 +45,33 @@ public static void Javascript( kernel.SendAsync(new DisplayValue(value, formatted))) .Wait(); } + + public static KernelBase GetKernel(string name) + { + var kernel = KernelInvocationContext.Current.HandlingKernel; + + KernelBase foundKernel = null; + + if (kernel is KernelBase kernelBase) + { + var root = kernelBase.RecurseWhileNotNull(k => k.ParentKernel).Last(); + + foundKernel = root switch + { + CompositeKernel c => c.ChildKernels + .OfType() + .FlattenBreadthFirst( + b => b switch + { + CompositeKernel composite => composite.ChildKernels.OfType(), + _ => Array.Empty() + }) + .SingleOrDefault(k => k.Name == name), + _ => null + }; + } + + return foundKernel ?? throw new KeyNotFoundException($"Kernel \"{name}\" was not found."); + } } } \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive/Utility/EnumerableExtensions.cs b/Microsoft.DotNet.Interactive/Utility/EnumerableExtensions.cs index 3e0fd7f79c..628b087f6e 100644 --- a/Microsoft.DotNet.Interactive/Utility/EnumerableExtensions.cs +++ b/Microsoft.DotNet.Interactive/Utility/EnumerableExtensions.cs @@ -31,7 +31,7 @@ internal static IEnumerable FlattenBreadthFirst( yield return current; } } - + internal static IEnumerable FlattenDepthFirst( this IEnumerable source, Func> children) @@ -55,5 +55,18 @@ internal static IEnumerable FlattenDepthFirst( yield return current; } } + + internal static IEnumerable RecurseWhileNotNull( + this T source, + Func next) + where T : class + { + yield return source; + + while ((source = next(source)) != null) + { + yield return source; + } + } } } \ No newline at end of file From ae5216883073ec82950b5717967e2fd138505079 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Tue, 21 Apr 2020 15:55:30 -0700 Subject: [PATCH 3/7] wip --- .../CSharpKernelTests.cs | 2 +- .../CSharpCodeGeneration.cs | 40 ++ .../CSharpKernel.cs | 113 +++-- .../FSharpKernel.fs | 22 +- .../DefaultPlainTextFormatterSet.cs | 25 +- ...osoft.DotNet.Interactive.Formatting.csproj | 4 + .../TypeExtensions.cs | 3 +- .../PowerShellKernelTests.cs | 4 +- ...osoft.DotNet.Interactive.PowerShell.csproj | 36 +- .../PowerShellKernel.cs | 17 +- .../LanguageKernelTestBase.cs | 2 +- .../LanguageKernelTests.cs | 97 +++- .../Utility/FakeKernel.cs | 6 - .../VariableSharingTests.cs | 25 +- .../CompositeKernel.cs | 56 ++- Microsoft.DotNet.Interactive/HtmlKernel.cs | 6 - .../JavaScriptKernel.cs | 7 - Microsoft.DotNet.Interactive/Kernel.cs | 11 +- Microsoft.DotNet.Interactive/KernelBase.cs | 2 - .../LanguageKernel.cs | 18 + .../TypeExtensions.cs | 2 +- NotebookExamples/Extensions.ipynb | 458 +++++++++++++++++- .../MagicCommandTests.about.cs | 5 +- .../HttpRouting/VariableRouter.cs | 26 +- dotnet-interactive/KernelExtensions.cs | 1 - 25 files changed, 780 insertions(+), 208 deletions(-) create mode 100644 Microsoft.DotNet.Interactive.CSharp/CSharpCodeGeneration.cs create mode 100644 Microsoft.DotNet.Interactive/LanguageKernel.cs diff --git a/Microsoft.DotNet.Interactive.CSharp.Tests/CSharpKernelTests.cs b/Microsoft.DotNet.Interactive.CSharp.Tests/CSharpKernelTests.cs index 543b861d4f..d5f18ecc74 100644 --- a/Microsoft.DotNet.Interactive.CSharp.Tests/CSharpKernelTests.cs +++ b/Microsoft.DotNet.Interactive.CSharp.Tests/CSharpKernelTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.DotNet.Interactive.CSharp.Tests { - public class CSharpKernelTests : LanguageKernelTests + public class CSharpKernelTests : LanguageKernelTestBase { public CSharpKernelTests(ITestOutputHelper output) : base(output) { diff --git a/Microsoft.DotNet.Interactive.CSharp/CSharpCodeGeneration.cs b/Microsoft.DotNet.Interactive.CSharp/CSharpCodeGeneration.cs new file mode 100644 index 0000000000..ee05be9121 --- /dev/null +++ b/Microsoft.DotNet.Interactive.CSharp/CSharpCodeGeneration.cs @@ -0,0 +1,40 @@ +// 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; +using System.IO; + +namespace Microsoft.DotNet.Interactive.CSharp +{ + internal static partial class TypeExtensions + { + public static void WriteCSharpDeclarationTo( + this Type type, + TextWriter writer) + { + var typeName = type.FullName ?? type.Name; + + if (typeName.Contains("`")) + { + writer.Write(typeName.Remove(typeName.IndexOf('`'))); + writer.Write("<"); + var genericArguments = type.GetGenericArguments(); + + for (var i = 0; i < genericArguments.Length; i++) + { + genericArguments[i].WriteCSharpDeclarationTo(writer); + if (i < genericArguments.Length - 1) + { + writer.Write(","); + } + } + + writer.Write(">"); + } + else + { + writer.Write(typeName); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs b/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs index 2b4f0a4289..c31a905ad1 100644 --- a/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs +++ b/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Reflection; using System.Text; +using System.Threading; using System.Threading.Tasks; using Microsoft.Interactive.DependencyManager; using Microsoft.CodeAnalysis; @@ -28,7 +29,7 @@ namespace Microsoft.DotNet.Interactive.CSharp { public class CSharpKernel : - KernelBase, + LanguageKernel, IExtensibleKernel, ISupportNuget { @@ -41,9 +42,9 @@ public class CSharpKernel : new CSharpParseOptions(LanguageVersion.Default, kind: SourceCodeKind.Script); private WorkspaceFixture _fixture; - private AssemblyResolutionProbe _assemblyProbingPaths; private NativeResolutionProbe _nativeProbingRoots; + private readonly Lazy _dependencies; internal ScriptOptions ScriptOptions = ScriptOptions.Default @@ -72,7 +73,6 @@ public CSharpKernel() : base(DefaultKernelName) RegisterForDisposal(() => { ScriptState = null; - (_dependencies as IDisposable)?.Dispose(); }); } @@ -84,14 +84,14 @@ public Task IsCompleteSubmissionAsync(string code) return Task.FromResult(SyntaxFactory.IsCompleteSubmission(syntaxTree)); } - public override bool TryGetVariable( + public override bool TryGetVariable( string name, - out object value) + out T value) { if (ScriptState?.Variables .LastOrDefault(v => v.Name == name) is { } variable) { - value = variable.Value; + value = (T) variable.Value; return true; } @@ -99,6 +99,19 @@ public override bool TryGetVariable( return false; } + public override async Task SetVariableAsync(string name, T value) + { + var csharpTypeDeclaration = new StringWriter(); + + value.GetType().WriteCSharpDeclarationTo(csharpTypeDeclaration); + + await RunAsync($"{csharpTypeDeclaration} {name} = default;"); + + var scriptVariable = ScriptState.GetVariable(name); + + scriptVariable.Value = value; + } + public override Task LspMethod(string methodName, JObject request) { LspResponse result; @@ -119,13 +132,13 @@ public override Task LspMethod(string methodName, JObject request) public TextDocumentHoverResponse TextDocumentHover(HoverParams hoverParams) { - return new TextDocumentHoverResponse() + return new TextDocumentHoverResponse { - Contents = new MarkupContent() + Contents = new MarkupContent { Kind = MarkupKind.Markdown, Value = $"textDocument/hover at position ({hoverParams.Position.Line}, {hoverParams.Position.Character}) with `markdown`", - }, + } }; } @@ -158,33 +171,16 @@ protected override async Task HandleSubmitCode( if (!context.CancellationToken.IsCancellationRequested) { - ScriptOptions = ScriptOptions.WithMetadataResolver( - ScriptMetadataResolver.Default.WithBaseDirectory( - Directory.GetCurrentDirectory())); - try { - if (ScriptState == null) - { - ScriptState = await CSharpScript.RunAsync( - code, - ScriptOptions, - cancellationToken: context.CancellationToken) - .UntilCancelled(context.CancellationToken); - } - else - { - ScriptState = await ScriptState.ContinueWithAsync( - code, - ScriptOptions, - catchException: e => - { - exception = e; - return true; - }, - cancellationToken: context.CancellationToken) - .UntilCancelled(context.CancellationToken); - } + await RunAsync( + code, + context.CancellationToken, + e => + { + exception = e; + return true; + }); } catch (CompilationErrorException cpe) { @@ -230,6 +226,34 @@ protected override async Task HandleSubmitCode( } } + private async Task RunAsync( + string code, + CancellationToken cancellationToken = default, + Func catchException = default) + { + ScriptOptions = ScriptOptions.WithMetadataResolver( + ScriptMetadataResolver.Default.WithBaseDirectory( + Directory.GetCurrentDirectory())); + + if (ScriptState == null) + { + ScriptState = await CSharpScript.RunAsync( + code, + ScriptOptions, + cancellationToken: cancellationToken) + .UntilCancelled(cancellationToken); + } + else + { + ScriptState = await ScriptState.ContinueWithAsync( + code, + ScriptOptions, + catchException: catchException, + cancellationToken: cancellationToken) + .UntilCancelled(cancellationToken); + } + } + protected override async Task HandleRequestCompletion( RequestCompletion requestCompletion, KernelInvocationContext context) @@ -306,7 +330,6 @@ await _extensionLoader.LoadFromDirectoryAsync( context); } - private Lazy _dependencies; private DependencyProvider GetDependencyProvider() { @@ -321,7 +344,13 @@ private DependencyProvider GetDependencyProvider() throw new ArgumentNullException(nameof(_nativeProbingRoots)); } - return new DependencyProvider(_assemblyProbingPaths, _nativeProbingRoots); + var dependencyProvider = new DependencyProvider( + _assemblyProbingPaths, + _nativeProbingRoots); + + RegisterForDisposal(dependencyProvider); + + return dependencyProvider; } // Set assemblyProbingPaths, nativeProbingRoots for Kernel. @@ -329,16 +358,8 @@ private DependencyProvider GetDependencyProvider() // They are used by the dependecymanager for Assembly and Native dll resolving void ISupportNuget.Initialize(AssemblyResolutionProbe assemblyProbingPaths, NativeResolutionProbe nativeProbingRoots) { - if(assemblyProbingPaths == null) - { - throw new ArgumentNullException(nameof(assemblyProbingPaths)); - } - if (nativeProbingRoots == null) - { - throw new ArgumentNullException(nameof(nativeProbingRoots)); - } - _assemblyProbingPaths = assemblyProbingPaths; - _nativeProbingRoots = nativeProbingRoots; + _assemblyProbingPaths = assemblyProbingPaths ?? throw new ArgumentNullException(nameof(assemblyProbingPaths)); + _nativeProbingRoots = nativeProbingRoots ?? throw new ArgumentNullException(nameof(nativeProbingRoots)); } void ISupportNuget.RegisterResolvedPackageReferences(IReadOnlyList resolvedReferences) diff --git a/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs b/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs index f5584f15b1..009e75cf68 100644 --- a/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs +++ b/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs @@ -14,7 +14,6 @@ open System.Threading.Tasks open Microsoft.CodeAnalysis.Tags open Microsoft.DotNet.Interactive -open Microsoft.DotNet.Interactive open Microsoft.DotNet.Interactive.Commands open Microsoft.DotNet.Interactive.Events open Microsoft.DotNet.Interactive.Extensions @@ -26,7 +25,7 @@ open FSharp.Compiler.Scripting open FSharp.Compiler.SourceCodeServices type FSharpKernel() as this = - inherit KernelBase("fsharp") + inherit LanguageKernel("fsharp") static let lockObj = Object(); @@ -40,14 +39,12 @@ type FSharpKernel() as this = do registerForDisposal(fun () -> script.ValueBound.RemoveHandler valueBoundHandler) script - let extensionLoader: AssemblyBasedExtensionLoader = new AssemblyBasedExtensionLoader() + let extensionLoader: AssemblyBasedExtensionLoader = AssemblyBasedExtensionLoader() let script = lazy createScript this.RegisterForDisposal do base.RegisterForDisposal(fun () -> if script.IsValueCreated then (script.Value :> IDisposable).Dispose()) let mutable cancellationTokenSource = new CancellationTokenSource() - let messageMap = Dictionary() - let getLineAndColumn (text: string) offset = let rec getLineAndColumn' i l c = if i >= offset then l, c @@ -149,10 +146,10 @@ type FSharpKernel() as this = // ISupportNuget.Initialize must be invoked prior to creating the DependencyManager // With non null funcs if isNull _assemblyProbingPaths then - raise (new ArgumentNullException("_assemblyProbingPaths")) + raise (new InvalidOperationException("_assemblyProbingPaths is null")) if isNull _nativeProbingRoots then - raise (new ArgumentNullException("_nativeProbingRoots")) + raise (new InvalidOperationException("_nativeProbingRoots is null")) new DependencyProvider(_assemblyProbingPaths, _nativeProbingRoots) lazy (createDependencyProvider ()) @@ -178,23 +175,26 @@ type FSharpKernel() as this = override _.HandleRequestCompletion(command: RequestCompletion, context: KernelInvocationContext): Task = handleRequestCompletion command context |> Async.StartAsTask :> Task - override this.TryGetVariable(name: string, [] value: Object byref) = + override _.TryGetVariable<'a>(name: string, [] value: 'a byref) = match this.GetCurrentVariable(name) with | Some(cv) -> - value <- cv.Value + value <- cv.Value :?> 'a true | None -> false + override _.SetVariableAsync<'a>(name: string, value: 'a) : Task = + raise (NotImplementedException()) + interface ISupportNuget with member this.Initialize (assemblyProbingPaths: AssemblyResolutionProbe, nativeProbingRoots: NativeResolutionProbe) = // These may not be set to null, if they are it is a product coding error // ISupportNuget.Initialize must be invoked prior to creating the DependencyManager // With non null funcs if isNull assemblyProbingPaths then - raise (new ArgumentNullException("assemblyProbingPaths")) + raise (ArgumentNullException("assemblyProbingPaths")) if isNull nativeProbingRoots then - raise (new ArgumentNullException("nativeProbingRoots")) + raise (ArgumentNullException("nativeProbingRoots")) _assemblyProbingPaths <- assemblyProbingPaths _nativeProbingRoots <- nativeProbingRoots diff --git a/Microsoft.DotNet.Interactive.Formatting/DefaultPlainTextFormatterSet.cs b/Microsoft.DotNet.Interactive.Formatting/DefaultPlainTextFormatterSet.cs index 8b1eaf92f3..7489d3f248 100644 --- a/Microsoft.DotNet.Interactive.Formatting/DefaultPlainTextFormatterSet.cs +++ b/Microsoft.DotNet.Interactive.Formatting/DefaultPlainTextFormatterSet.cs @@ -8,6 +8,7 @@ using System.Dynamic; using System.Linq; using System.Text.Encodings.Web; +using Microsoft.DotNet.Interactive.CSharp; namespace Microsoft.DotNet.Interactive.Formatting { @@ -105,29 +106,7 @@ private static ConcurrentDictionary DefaultFormatters() [typeof(Type)] = new PlainTextFormatter((type, writer) => { - var typeName = type.FullName ?? type.Name; - - if (typeName.Contains("`") && !type.IsAnonymous()) - { - writer.Write(typeName.Remove(typeName.IndexOf('`'))); - writer.Write("<"); - var genericArguments = type.GetGenericArguments(); - - for (var i = 0; i < genericArguments.Length; i++) - { - Formatter.FormatTo(genericArguments[i], writer); - if (i < genericArguments.Length - 1) - { - writer.Write(","); - } - } - - writer.Write(">"); - } - else - { - writer.Write(typeName); - } + type.WriteCSharpDeclarationTo(writer); }), [typeof(DateTime)] = new PlainTextFormatter((value, writer) => writer.Write(value.ToString("u"))), diff --git a/Microsoft.DotNet.Interactive.Formatting/Microsoft.DotNet.Interactive.Formatting.csproj b/Microsoft.DotNet.Interactive.Formatting/Microsoft.DotNet.Interactive.Formatting.csproj index c29492413e..10371a13ef 100644 --- a/Microsoft.DotNet.Interactive.Formatting/Microsoft.DotNet.Interactive.Formatting.csproj +++ b/Microsoft.DotNet.Interactive.Formatting/Microsoft.DotNet.Interactive.Formatting.csproj @@ -11,6 +11,10 @@ interactive formatting Jupyter mime + + + + diff --git a/Microsoft.DotNet.Interactive.Formatting/TypeExtensions.cs b/Microsoft.DotNet.Interactive.Formatting/TypeExtensions.cs index a4e3e108a6..1e62bd10b2 100644 --- a/Microsoft.DotNet.Interactive.Formatting/TypeExtensions.cs +++ b/Microsoft.DotNet.Interactive.Formatting/TypeExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -10,7 +11,7 @@ namespace Microsoft.DotNet.Interactive.Formatting { - internal static class TypeExtensions + internal static partial class TypeExtensions { internal static bool CanBeInstantiated(this Type type) { diff --git a/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs b/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs index e79d34c4e6..ed1ae07a6f 100644 --- a/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs +++ b/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.DotNet.Interactive.PowerShell.Tests { - public class PowerShellKernelTests : LanguageKernelTests + public class PowerShellKernelTests : LanguageKernelTestBase { private readonly string _allUsersCurrentHostProfilePath = Path.Combine(Path.GetDirectoryName(typeof(PSObject).Assembly.Location), "Microsoft.dotnet-interactive_profile.ps1"); @@ -31,7 +31,7 @@ public async Task TryGetVariable_unwraps_PowerShell_object(string code, Type exp await kernel.SubmitCodeAsync(code); - kernel.TryGetVariable("x", out var fi).Should().BeTrue(); + kernel.TryGetVariable("x", out object fi).Should().BeTrue(); fi.Should().BeOfType(expectedType); } diff --git a/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj b/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj index b9eb41f12c..c60c18d89b 100644 --- a/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj +++ b/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj @@ -33,41 +33,7 @@ PackageCopyToOutput="true" CopyToOutputDirectory="PreserveNewest" /> - - - - - - - - - - - + diff --git a/Microsoft.DotNet.Interactive.PowerShell/PowerShellKernel.cs b/Microsoft.DotNet.Interactive.PowerShell/PowerShellKernel.cs index d3138d3e5d..1a2867b669 100644 --- a/Microsoft.DotNet.Interactive.PowerShell/PowerShellKernel.cs +++ b/Microsoft.DotNet.Interactive.PowerShell/PowerShellKernel.cs @@ -19,7 +19,8 @@ namespace Microsoft.DotNet.Interactive.PowerShell { using System.Management.Automation; - public class PowerShellKernel : KernelBase + public class PowerShellKernel : + LanguageKernel { internal const string DefaultKernelName = "powershell"; @@ -112,7 +113,7 @@ private PowerShell CreatePowerShell() return pwsh; } - public override bool TryGetVariable(string name, out object value) + public override bool TryGetVariable(string name, out T value) { var variable = pwsh.Runspace.SessionStateProxy.PSVariable.Get(name); @@ -121,20 +122,26 @@ public override bool TryGetVariable(string name, out object value) switch (variable.Value) { case PSObject psobject: - value = psobject.BaseObject; + value = (T) psobject.BaseObject; break; default: - value = variable.Value; + value = (T) variable.Value; break; } return true; } - value = null; + value = default; return false; } + public override Task SetVariableAsync(string name, T value) + { + _lazyPwsh.Value.Runspace.SessionStateProxy.PSVariable.Set(name, value); + return Task.CompletedTask; + } + protected override async Task HandleSubmitCode( SubmitCode submitCode, KernelInvocationContext context) diff --git a/Microsoft.DotNet.Interactive.Tests/LanguageKernelTestBase.cs b/Microsoft.DotNet.Interactive.Tests/LanguageKernelTestBase.cs index e463600407..44279e1101 100644 --- a/Microsoft.DotNet.Interactive.Tests/LanguageKernelTestBase.cs +++ b/Microsoft.DotNet.Interactive.Tests/LanguageKernelTestBase.cs @@ -74,7 +74,7 @@ public void Dispose() _lockReleaser.Dispose(); } - protected KernelBase CreateKernel(Language language) + protected CompositeKernel CreateKernel(Language language) { var kernelBase = language switch { diff --git a/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs b/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs index d67848b30b..ece5df1d02 100644 --- a/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs +++ b/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs @@ -3,23 +3,21 @@ using System; using System.Linq; -using System.Management.Automation; using System.Reactive.Linq; using System.Threading.Tasks; using FluentAssertions; +using FluentAssertions.Execution; using FluentAssertions.Extensions; using Microsoft.DotNet.Interactive.Commands; -using Microsoft.DotNet.Interactive.CSharp; using Microsoft.DotNet.Interactive.Events; using Microsoft.DotNet.Interactive.Tests.Utility; -using XPlot.Plotly; using Xunit; using Xunit.Abstractions; #pragma warning disable 8509 namespace Microsoft.DotNet.Interactive.Tests { - public class LanguageKernelTests : LanguageKernelTestBase + public sealed class LanguageKernelTests : LanguageKernelTestBase { public LanguageKernelTests(ITestOutputHelper output) : base(output) { @@ -730,7 +728,7 @@ public async Task it_returns_completion_list_for_types(Language language, string .Contain(i => i.DisplayText == expectedCompletion); } - [Theory(Timeout = 45000)] + [Theory] [InlineData(Language.CSharp)] [InlineData(Language.FSharp)] [InlineData(Language.PowerShell)] @@ -778,5 +776,94 @@ public async Task When_submission_is_split_then_CommandHandled_is_published_only .Should() .Be(command); } + + [Theory] + [InlineData(Language.CSharp)] + [InlineData(Language.FSharp)] + [InlineData(Language.PowerShell)] + public async Task TryGetVariable_returns_defined_variable(Language language) + { + var codeToSetVariable = language switch + { + Language.CSharp => "var x = 123;", + Language.FSharp => "let x = 123", + Language.PowerShell => "$x = 123" + }; + + var kernel = CreateKernel(language); + + await kernel.SubmitCodeAsync(codeToSetVariable); + + var languageKernel = kernel.ChildKernels.OfType().Single(); + + var succeeded = languageKernel.TryGetVariable("x", out int x); + + using var _ = new AssertionScope(); + + succeeded.Should().BeTrue(); + x.Should().Be(123); + } + + [Theory] + [InlineData(Language.CSharp)] + [InlineData(Language.FSharp, Skip = "Requires FSI API changes")] + [InlineData(Language.PowerShell)] + public async Task SetVariableAsync_declares_the_specified_variable(Language language) + { + var kernel = CreateKernel(language); + + var languageKernel = kernel.ChildKernels.OfType().Single(); + + await languageKernel.SetVariableAsync("x", 123); + + var succeeded = languageKernel.TryGetVariable("x", out int x); + + using var _ = new AssertionScope(); + + succeeded.Should().BeTrue(); + x.Should().Be(123); + } + + [Theory] + [InlineData(Language.CSharp)] + [InlineData(Language.FSharp, Skip = "Requires FSI API changes")] + [InlineData(Language.PowerShell)] + public async Task SetVariableAsync_overwrites_an_existing_variable_of_the_same_type(Language language) + { + var kernel = CreateKernel(language); + + var languageKernel = kernel.ChildKernels.OfType().Single(); + + await languageKernel.SetVariableAsync("x", 123); + await languageKernel.SetVariableAsync("x", 456); + + var succeeded = languageKernel.TryGetVariable("x", out int x); + + using var _ = new AssertionScope(); + + succeeded.Should().BeTrue(); + x.Should().Be(456); + } + + [Theory] + [InlineData(Language.CSharp)] + [InlineData(Language.FSharp, Skip = "Requires FSI API changes")] + [InlineData(Language.PowerShell)] + public async Task SetVariableAsync_can_redeclare_an_existing_variable_and_change_its_type(Language language) + { + var kernel = CreateKernel(language); + + var languageKernel = kernel.ChildKernels.OfType().Single(); + + await languageKernel.SetVariableAsync("x", 123); + await languageKernel.SetVariableAsync("x", "hello"); + + var succeeded = languageKernel.TryGetVariable("x", out string x); + + using var _ = new AssertionScope(); + + succeeded.Should().BeTrue(); + x.Should().Be("hello"); + } } } diff --git a/Microsoft.DotNet.Interactive.Tests/Utility/FakeKernel.cs b/Microsoft.DotNet.Interactive.Tests/Utility/FakeKernel.cs index eef427072b..049d97066a 100644 --- a/Microsoft.DotNet.Interactive.Tests/Utility/FakeKernel.cs +++ b/Microsoft.DotNet.Interactive.Tests/Utility/FakeKernel.cs @@ -16,12 +16,6 @@ public FakeKernel([CallerMemberName] string name = null) : base(name) public KernelCommandInvocation Handle { get; set; } - public override bool TryGetVariable(string name, out object value) - { - value = null; - return false; - } - protected override Task HandleSubmitCode(SubmitCode command, KernelInvocationContext context) { Handle(command, context); diff --git a/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs b/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs index 3c566dc0e1..6d82081dd0 100644 --- a/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs +++ b/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs @@ -17,10 +17,15 @@ public class VariableSharingTests { [Theory] [InlineData( - "fsharp", + "#!fsharp", "let x = 123", - "csharp", - "GetKernel(\"fsharp\").TryGetVariable(\"x\", out var x);\nx")] + "#!csharp", + "(GetKernel(\"fsharp\") as Microsoft.DotNet.Interactive.LanguageKernel).TryGetVariable(\"x\", out int x);\nx")] + [InlineData( + "#!fsharp", + "let x = 123", + "#!csharp", + "#!SOMETHING\nfsharp.TryGetVariable(\"x\", out int x);\nx")] public async Task Variables_can_be_read_from_other_kernels( string fromLanguage, string codeToWrite, @@ -34,13 +39,13 @@ public async Task Variables_can_be_read_from_other_kernels( new FSharpKernel() .UseKernelHelpers(), new PowerShellKernel() - }; + }.LogEventsToPocketLogger(); using var events = kernel.KernelEvents.ToSubscribedList(); - await kernel.SubmitCodeAsync($"#!{fromLanguage}\n{codeToWrite}"); + await kernel.SubmitCodeAsync($"{fromLanguage}\n{codeToWrite}"); - await kernel.SubmitCodeAsync($"#!{toLanguage}\n{codeToRead}"); + await kernel.SubmitCodeAsync($"{toLanguage}\n{codeToRead}"); events.Should() .ContainSingle() @@ -49,5 +54,13 @@ public async Task Variables_can_be_read_from_other_kernels( .Should() .Be(123); } + + [Fact] + public void Internal_types_cannot_be_shared() + { + + + throw new NotImplementedException("test not written"); + } } } \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive/CompositeKernel.cs b/Microsoft.DotNet.Interactive/CompositeKernel.cs index f8ccb6b22f..fdc7c52c25 100644 --- a/Microsoft.DotNet.Interactive/CompositeKernel.cs +++ b/Microsoft.DotNet.Interactive/CompositeKernel.cs @@ -16,7 +16,7 @@ namespace Microsoft.DotNet.Interactive { public class CompositeKernel : - KernelBase, + KernelBase, IExtensibleKernel, IEnumerable { @@ -44,7 +44,7 @@ public string DefaultKernelName } } - public void Add(IKernel kernel, IEnumerable aliases = null) + public void Add(IKernel kernel, IReadOnlyCollection aliases = null) { if (kernel == null) { @@ -55,13 +55,15 @@ public void Add(IKernel kernel, IEnumerable aliases = null) { if (kernelBase.ParentKernel != null) { - throw new InvalidOperationException("Kernel already has a parent."); + throw new InvalidOperationException($"Kernel \"{kernelBase.Name}\" already has a parent: \"{kernelBase.ParentKernel.Name}\"."); } kernelBase.ParentKernel = this; kernelBase.AddMiddleware(LoadExtensions); } + AddChooseKernelDirective(kernel, aliases); + _childKernels.Add(kernel); if (_childKernels.Count == 1) @@ -69,6 +71,46 @@ public void Add(IKernel kernel, IEnumerable aliases = null) DefaultKernelName = kernel.Name; } + DeclareKernelVariables(kernel, aliases); + + RegisterForDisposal(kernel.KernelEvents.Subscribe(PublishEvent)); + RegisterForDisposal(kernel); + } + + private void DeclareKernelVariables( + IKernel kernel, + IReadOnlyCollection aliases) + { + foreach (var otherKernel in ChildKernels + .OfType() + .Where(k => k != kernel)) + { + otherKernel.DeferCommand(new AnonymousKernelCommand(async (command, context) => + { + try + { + await otherKernel.SetVariableAsync( + kernel.Name, + kernel); + } + catch (Exception exception) + { + // FIX: (DeclareKernelVariables) + + context.Publish(new DiagnosticLogEventProduced(exception.Message)); + + + } + })); + + + } + } + + private void AddChooseKernelDirective( + IKernel kernel, + IEnumerable aliases) + { var chooseKernelCommand = new ChooseKernelDirective(kernel); if (aliases is { }) @@ -80,8 +122,6 @@ public void Add(IKernel kernel, IEnumerable aliases = null) } AddDirective(chooseKernelCommand); - RegisterForDisposal(kernel.KernelEvents.Subscribe(PublishEvent)); - RegisterForDisposal(kernel); } private async Task LoadExtensions( @@ -150,12 +190,6 @@ private IKernel GetHandlingKernel( return kernel ?? this; } - public override bool TryGetVariable(string name, out object value) - { - value = null; - return false; - } - internal override async Task HandleAsync( IKernelCommand command, KernelInvocationContext context) diff --git a/Microsoft.DotNet.Interactive/HtmlKernel.cs b/Microsoft.DotNet.Interactive/HtmlKernel.cs index 9f3c41df43..4389879faa 100644 --- a/Microsoft.DotNet.Interactive/HtmlKernel.cs +++ b/Microsoft.DotNet.Interactive/HtmlKernel.cs @@ -16,12 +16,6 @@ public HtmlKernel() : base(DefaultKernelName) { } - public override bool TryGetVariable(string name, out object value) - { - value = default; - return false; - } - protected override async Task HandleSubmitCode(SubmitCode command, KernelInvocationContext context) { await context.DisplayAsync( diff --git a/Microsoft.DotNet.Interactive/JavaScriptKernel.cs b/Microsoft.DotNet.Interactive/JavaScriptKernel.cs index 8c6738187f..9d61d024b0 100644 --- a/Microsoft.DotNet.Interactive/JavaScriptKernel.cs +++ b/Microsoft.DotNet.Interactive/JavaScriptKernel.cs @@ -14,13 +14,6 @@ public class JavaScriptKernel : KernelBase public JavaScriptKernel() : base(DefaultKernelName) { } - - public override bool TryGetVariable(string name, out object value) - { - value = default; - return false; - } - protected override async Task HandleSubmitCode( SubmitCode command, KernelInvocationContext context) diff --git a/Microsoft.DotNet.Interactive/Kernel.cs b/Microsoft.DotNet.Interactive/Kernel.cs index af52a8be09..1180dc820e 100644 --- a/Microsoft.DotNet.Interactive/Kernel.cs +++ b/Microsoft.DotNet.Interactive/Kernel.cs @@ -46,7 +46,7 @@ public static void Javascript( .Wait(); } - public static KernelBase GetKernel(string name) + public static IKernel GetKernel(string name) { var kernel = KernelInvocationContext.Current.HandlingKernel; @@ -59,14 +59,9 @@ public static KernelBase GetKernel(string name) foundKernel = root switch { CompositeKernel c => c.ChildKernels - .OfType() - .FlattenBreadthFirst( - b => b switch - { - CompositeKernel composite => composite.ChildKernels.OfType(), - _ => Array.Empty() - }) + .OfType() .SingleOrDefault(k => k.Name == name), + LanguageKernel k => k, _ => null }; } diff --git a/Microsoft.DotNet.Interactive/KernelBase.cs b/Microsoft.DotNet.Interactive/KernelBase.cs index 5c582e1225..851670e35a 100644 --- a/Microsoft.DotNet.Interactive/KernelBase.cs +++ b/Microsoft.DotNet.Interactive/KernelBase.cs @@ -193,8 +193,6 @@ public FrontendEnvironment FrontendEnvironment public IReadOnlyCollection Directives => SubmissionParser.Directives; - public abstract bool TryGetVariable(string name, out object value); - public void AddDirective(Command command) => SubmissionParser.AddDirective(command); public virtual Task LspMethod(string methodName, JObject request) diff --git a/Microsoft.DotNet.Interactive/LanguageKernel.cs b/Microsoft.DotNet.Interactive/LanguageKernel.cs new file mode 100644 index 0000000000..2ab8d0fcda --- /dev/null +++ b/Microsoft.DotNet.Interactive/LanguageKernel.cs @@ -0,0 +1,18 @@ +// 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.Threading.Tasks; + +namespace Microsoft.DotNet.Interactive +{ + public abstract class LanguageKernel : KernelBase + { + protected LanguageKernel(string name) : base(name) + { + } + + public abstract bool TryGetVariable(string name, out T value); + + public abstract Task SetVariableAsync(string name, T value); + } +} \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive/TypeExtensions.cs b/Microsoft.DotNet.Interactive/TypeExtensions.cs index b67eaa1a90..5cda4ae103 100644 --- a/Microsoft.DotNet.Interactive/TypeExtensions.cs +++ b/Microsoft.DotNet.Interactive/TypeExtensions.cs @@ -14,4 +14,4 @@ internal static bool CanBeInstantiated(this Type type) && !type.IsInterface; } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/NotebookExamples/Extensions.ipynb b/NotebookExamples/Extensions.ipynb index 80a2c9deb9..cf4893eede 100644 --- a/NotebookExamples/Extensions.ipynb +++ b/NotebookExamples/Extensions.ipynb @@ -2,9 +2,133 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "\r\n", + "
\r\n", + " \r\n", + " \r\n", + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "What is the path to your dotnet/interactive repo?: c:\\dev\\interactive\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + " Directory: C:\\dev\\interactive\\samples\\extensions\\ClockExtension\n", + "\n", + "Mode LastWriteTime Length Name\n", + "---- ------------- ------ ----\n", + "-a--- 2/27/2020 12:25 PM 902 ClockExtension.csproj\n", + "-a--- 2/28/2020 4:53 PM 2191 ClockKernelExtension.cs\n", + "-a--- 2/23/2020 12:59 PM 5172 SvgClock.cs\n", + "\n" + ] + } + ], "source": [ "#!pwsh\n", "\n", @@ -15,9 +139,56 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Microsoft (R) Build Engine version 16.6.0-preview-20162-03+00781ad13 for .NET Core\n", + "Copyright (C) Microsoft Corporation. All rights reserved.\n", + "\n", + " Determining projects to restore...\n", + " Restored C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\ClockExtension.csproj (in 1.74 sec).\n", + " You are using a preview version of .NET Core. See: https://aka.ms/dotnet-core-preview\n", + " ClockExtension -> C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\\netcoreapp3.1\\ClockExtension.dll\n", + "\n", + "Build succeeded.\n", + " 0 Warning(s)\n", + " 0 Error(s)\n", + "\n", + "Time Elapsed 00:00:05.49\n", + "Microsoft (R) Build Engine version 16.6.0-preview-20162-03+00781ad13 for .NET Core\n", + "Copyright (C) Microsoft Corporation. All rights reserved.\n", + "\n", + " Determining projects to restore...\n", + " Restored C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\ClockExtension.csproj (in 455 ms).\n", + " You are using a preview version of .NET Core. See: https://aka.ms/dotnet-core-preview\n", + " ClockExtension -> C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\\netcoreapp3.1\\ClockExtension.dll\n", + " Successfully created package 'C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\\ClockExtension.1.2.8.nupkg'.\n", + "C:\\Program Files\\dotnet\\sdk\\3.1.300-preview-015095\\Sdks\\NuGet.Build.Tasks.Pack\\build\\NuGet.Build.Tasks.Pack.targets(198,5): warning NU5100: The assembly 'interactive-extensions\\dotnet\\ClockExtension.dll' is not inside the 'lib' folder and hence it won't be added as a reference when the package is installed into a project. Move it into the 'lib' folder if it needs to be referenced. [C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\ClockExtension.csproj]\n", + "C:\\Program Files\\dotnet\\sdk\\3.1.300-preview-015095\\Sdks\\NuGet.Build.Tasks.Pack\\build\\NuGet.Build.Tasks.Pack.targets(198,5): warning NU5104: A stable release of a package should not have a prerelease dependency. Either modify the version spec of dependency \"microsoft.dotnet.interactive [1.0.0-beta.20111.6, )\" or update the version field in the nuspec. [C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\ClockExtension.csproj]\n", + "\n", + "\n", + " Directory: C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\n", + "\n", + "Mode LastWriteTime Length Name\n", + "---- ------------- ------ ----\n", + "-a--- 4/21/2020 9:51 AM 17200 ClockExtension.1.2.8.nupkg\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "Wall time: 10121.251ms" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "#!pwsh\n", "#!time\n", @@ -28,9 +199,46 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
Restore sources
  • C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\\
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Installed package clockextension version 1.2.8" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Loaded kernel extension \"ClockKernelExtension\" from assembly C:\\Users\\josequ\\.nuget\\packages\\clockextension\\1.2.8\\interactive-extensions\\dotnet\\ClockExtension.dll" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "`ClockExtension` is loaded. It adds visualizations for `System.DateTime` and `System.DateTimeOffset`. Try it by running: `display(DateTime.Now);` or `#!clock -h`" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "#i nuget:C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\\\n", "#r nuget:clockextension" @@ -38,27 +246,253 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
.NET Interactive
" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "DateTime.UtcNow" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "#!clock:\n", + " Displays a clock showing the current or specified time.\n", + "\n", + "Usage:\n", + " #!clock [options]\n", + "\n", + "Options:\n", + " --hour, -o The position of the hour hand\n", + " -m, --minute The position of the minute hand\n", + " -s, --second The position of the second hand\n", + " -?, -h, --help Show help and usage information\n", + "\n" + ] + } + ], "source": [ "#!clock -h" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
.NET Interactive
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "#!clock --hour 1 -m 2 -s 3" ] diff --git a/dotnet-interactive.Tests/MagicCommandTests.about.cs b/dotnet-interactive.Tests/MagicCommandTests.about.cs index 249c5388b8..ad56b23cfb 100644 --- a/dotnet-interactive.Tests/MagicCommandTests.about.cs +++ b/dotnet-interactive.Tests/MagicCommandTests.about.cs @@ -1,12 +1,9 @@ // 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.CommandLine; -using System.CommandLine.IO; using System.Threading.Tasks; using FluentAssertions; using Microsoft.DotNet.Interactive.Events; -using Microsoft.DotNet.Interactive.Tests; using Microsoft.DotNet.Interactive.Tests.Utility; using Xunit; @@ -38,7 +35,7 @@ public async Task it_shows_the_product_name_and_version_information() .Should() .ContainAll( ".NET Interactive", - "Version", + "Version", "https://github.com/dotnet/interactive"); } } diff --git a/dotnet-interactive/HttpRouting/VariableRouter.cs b/dotnet-interactive/HttpRouting/VariableRouter.cs index bf808eeea5..bf13195e4f 100644 --- a/dotnet-interactive/HttpRouting/VariableRouter.cs +++ b/dotnet-interactive/HttpRouting/VariableRouter.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Routing; using Microsoft.DotNet.Interactive.Formatting; using Newtonsoft.Json; @@ -44,10 +43,10 @@ private async Task BatchVariableRequest(RouteContext context) { var segments = context.HttpContext - .Request - .Path - .Value - .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + .Request + .Path + .Value + .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); if (segments.Length == 1 && segments[0] == "variables") { @@ -61,11 +60,11 @@ private async Task BatchVariableRequest(RouteContext context) var propertyBag = new JObject(); response[kernelName] = propertyBag; var targetKernel = GetKernel(kernelName); - if (targetKernel is KernelBase kernelBase) + if (targetKernel is LanguageKernel languageKernel) { foreach (var variableName in kernelProperty.Value.Values()) { - if (kernelBase.TryGetVariable(variableName, out var value)) + if (languageKernel.TryGetVariable(variableName, out object value)) { if (value is string) { @@ -118,10 +117,10 @@ private void SingleVariableRequest(RouteContext context) { var segments = context.HttpContext - .Request - .Path - .Value - .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + .Request + .Path + .Value + .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); if (segments[0] == "variables") { @@ -130,15 +129,14 @@ private void SingleVariableRequest(RouteContext context) var targetKernel = GetKernel(kernelName); - if (targetKernel is KernelBase kernelBase) + if (targetKernel is LanguageKernel languageKernel) { - if (kernelBase.TryGetVariable(variableName, out var value)) + if (languageKernel.TryGetVariable(variableName, out object value)) { context.Handler = async httpContext => { await using (var writer = new StreamWriter(httpContext.Response.Body)) { - httpContext.Response.ContentType = JsonFormatter.MimeType; if (value is string) { diff --git a/dotnet-interactive/KernelExtensions.cs b/dotnet-interactive/KernelExtensions.cs index 65d3ece40a..277226dcb2 100644 --- a/dotnet-interactive/KernelExtensions.cs +++ b/dotnet-interactive/KernelExtensions.cs @@ -6,7 +6,6 @@ using System.CommandLine.Invocation; using Microsoft.DotNet.Interactive.App.CommandLine; using Microsoft.DotNet.Interactive.Commands; -using Microsoft.DotNet.Interactive.Events; using Microsoft.DotNet.Interactive.Formatting; using Recipes; using XPlot.DotNet.Interactive.KernelExtensions; From 57f506ddb4eed7fb4a35f5722fa03fb708237921 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Wed, 22 Apr 2020 09:26:13 -0700 Subject: [PATCH 4/7] wip --- .../CSharpKernel.cs | 6 ++- .../CSharpKernelExtensions.cs | 6 --- .../FSharpKernel.fs | 4 +- ...osoft.DotNet.Interactive.Formatting.csproj | 2 +- ...osoft.DotNet.Interactive.PowerShell.csproj | 36 +++++++++++++- .../PowerShellKernel.cs | 4 +- ...rosoft.DotNet.Interactive.Telemetry.csproj | 2 +- .../KernelExtensionsTests.cs | 49 +++++++++++++++++++ .../LanguageKernelTests.cs | 8 +-- .../VariableSharingTests.cs | 15 +++--- .../CompositeKernel.cs | 32 ------------ ...guageKernel.cs => DotNetLanguageKernel.cs} | 6 +-- .../AssemblyBasedExtensionLoader.cs | 1 + Microsoft.DotNet.Interactive/Kernel.cs | 15 +----- .../KernelExtensions.cs | 47 +++++++++++++++++- .../Microsoft.DotNet.Interactive.csproj | 2 +- .../HttpRouting/VariableRouter.cs | 4 +- dotnet-interactive/dotnet-interactive.csproj | 2 +- 18 files changed, 162 insertions(+), 79 deletions(-) rename Microsoft.DotNet.Interactive/{LanguageKernel.cs => DotNetLanguageKernel.cs} (64%) diff --git a/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs b/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs index c31a905ad1..5163bfd975 100644 --- a/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs +++ b/Microsoft.DotNet.Interactive.CSharp/CSharpKernel.cs @@ -29,7 +29,7 @@ namespace Microsoft.DotNet.Interactive.CSharp { public class CSharpKernel : - LanguageKernel, + DotNetLanguageKernel, IExtensibleKernel, ISupportNuget { @@ -99,12 +99,14 @@ public override bool TryGetVariable( return false; } - public override async Task SetVariableAsync(string name, T value) + public override async Task SetVariableAsync(string name, object value) { var csharpTypeDeclaration = new StringWriter(); value.GetType().WriteCSharpDeclarationTo(csharpTypeDeclaration); + + await RunAsync($"{csharpTypeDeclaration} {name} = default;"); var scriptVariable = ScriptState.GetVariable(name); diff --git a/Microsoft.DotNet.Interactive.CSharp/CSharpKernelExtensions.cs b/Microsoft.DotNet.Interactive.CSharp/CSharpKernelExtensions.cs index d95e6d0655..661ef4a98d 100644 --- a/Microsoft.DotNet.Interactive.CSharp/CSharpKernelExtensions.cs +++ b/Microsoft.DotNet.Interactive.CSharp/CSharpKernelExtensions.cs @@ -1,20 +1,14 @@ // 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; -using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Invocation; using System.CommandLine.Parsing; -using System.CommandLine.Rendering; -using System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Html; using Microsoft.DotNet.Interactive.Commands; using Microsoft.DotNet.Interactive.Events; using Microsoft.DotNet.Interactive.Formatting; -using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags; namespace Microsoft.DotNet.Interactive.CSharp { diff --git a/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs b/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs index 009e75cf68..8e5886d086 100644 --- a/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs +++ b/Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs @@ -25,7 +25,7 @@ open FSharp.Compiler.Scripting open FSharp.Compiler.SourceCodeServices type FSharpKernel() as this = - inherit LanguageKernel("fsharp") + inherit DotNetLanguageKernel("fsharp") static let lockObj = Object(); @@ -183,7 +183,7 @@ type FSharpKernel() as this = | None -> false - override _.SetVariableAsync<'a>(name: string, value: 'a) : Task = + override _.SetVariableAsync(name: string, value: Object) : Task = raise (NotImplementedException()) interface ISupportNuget with diff --git a/Microsoft.DotNet.Interactive.Formatting/Microsoft.DotNet.Interactive.Formatting.csproj b/Microsoft.DotNet.Interactive.Formatting/Microsoft.DotNet.Interactive.Formatting.csproj index 10371a13ef..924b32781d 100644 --- a/Microsoft.DotNet.Interactive.Formatting/Microsoft.DotNet.Interactive.Formatting.csproj +++ b/Microsoft.DotNet.Interactive.Formatting/Microsoft.DotNet.Interactive.Formatting.csproj @@ -18,7 +18,7 @@ - + diff --git a/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj b/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj index c60c18d89b..b9eb41f12c 100644 --- a/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj +++ b/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj @@ -33,7 +33,41 @@ PackageCopyToOutput="true" CopyToOutputDirectory="PreserveNewest" /> - + + + + + + + + + + + diff --git a/Microsoft.DotNet.Interactive.PowerShell/PowerShellKernel.cs b/Microsoft.DotNet.Interactive.PowerShell/PowerShellKernel.cs index 1a2867b669..094da50fbd 100644 --- a/Microsoft.DotNet.Interactive.PowerShell/PowerShellKernel.cs +++ b/Microsoft.DotNet.Interactive.PowerShell/PowerShellKernel.cs @@ -20,7 +20,7 @@ namespace Microsoft.DotNet.Interactive.PowerShell using System.Management.Automation; public class PowerShellKernel : - LanguageKernel + DotNetLanguageKernel { internal const string DefaultKernelName = "powershell"; @@ -136,7 +136,7 @@ public override bool TryGetVariable(string name, out T value) return false; } - public override Task SetVariableAsync(string name, T value) + public override Task SetVariableAsync(string name, object value) { _lazyPwsh.Value.Runspace.SessionStateProxy.PSVariable.Set(name, value); return Task.CompletedTask; diff --git a/Microsoft.DotNet.Interactive.Telemetry/Microsoft.DotNet.Interactive.Telemetry.csproj b/Microsoft.DotNet.Interactive.Telemetry/Microsoft.DotNet.Interactive.Telemetry.csproj index fbad516926..b257ff61ca 100644 --- a/Microsoft.DotNet.Interactive.Telemetry/Microsoft.DotNet.Interactive.Telemetry.csproj +++ b/Microsoft.DotNet.Interactive.Telemetry/Microsoft.DotNet.Interactive.Telemetry.csproj @@ -9,6 +9,6 @@ - +
diff --git a/Microsoft.DotNet.Interactive.Tests/KernelExtensionsTests.cs b/Microsoft.DotNet.Interactive.Tests/KernelExtensionsTests.cs index 2a41c2deb7..a662a134f0 100644 --- a/Microsoft.DotNet.Interactive.Tests/KernelExtensionsTests.cs +++ b/Microsoft.DotNet.Interactive.Tests/KernelExtensionsTests.cs @@ -5,12 +5,61 @@ using System.Collections.Generic; using System.Threading.Tasks; using FluentAssertions; +using Microsoft.DotNet.Interactive.Tests.Utility; using Xunit; namespace Microsoft.DotNet.Interactive.Tests { public class KernelExtensionsTests { + [Fact] + public void FindKernel_finds_a_subkernel_of_a_composite_kernel_by_name() + { + var one = new FakeKernel("one"); + var two = new FakeKernel("two"); + using var compositeKernel = new CompositeKernel + { + one, + two, + }; + + var found = compositeKernel.FindKernel("two"); + + found.Should().BeSameAs(two); + } + + [Fact] + public void FindKernel_finds_a_subkernel_of_a_parent_composite_kernel_by_name() + { + var one = new FakeKernel("one"); + var two = new FakeKernel("two"); + using var compositeKernel = new CompositeKernel + { + one, + two, + }; + + var found = one.FindKernel("two"); + + found.Should().BeSameAs(two); + } + + [Fact] + public void FindKernel_returns_null_for_unknown_kernel() + { + var one = new FakeKernel("one"); + var two = new FakeKernel("two"); + using var compositeKernel = new CompositeKernel + { + one, + two, + }; + + var found = compositeKernel.FindKernel("three"); + + found.Should().BeNull(); + } + [Fact] public void VisitSubkernels_does_not_recurse_by_default() { diff --git a/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs b/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs index ece5df1d02..bdd716fff4 100644 --- a/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs +++ b/Microsoft.DotNet.Interactive.Tests/LanguageKernelTests.cs @@ -794,7 +794,7 @@ public async Task TryGetVariable_returns_defined_variable(Language language) await kernel.SubmitCodeAsync(codeToSetVariable); - var languageKernel = kernel.ChildKernels.OfType().Single(); + var languageKernel = kernel.ChildKernels.OfType().Single(); var succeeded = languageKernel.TryGetVariable("x", out int x); @@ -812,7 +812,7 @@ public async Task SetVariableAsync_declares_the_specified_variable(Language lang { var kernel = CreateKernel(language); - var languageKernel = kernel.ChildKernels.OfType().Single(); + var languageKernel = kernel.ChildKernels.OfType().Single(); await languageKernel.SetVariableAsync("x", 123); @@ -832,7 +832,7 @@ public async Task SetVariableAsync_overwrites_an_existing_variable_of_the_same_t { var kernel = CreateKernel(language); - var languageKernel = kernel.ChildKernels.OfType().Single(); + var languageKernel = kernel.ChildKernels.OfType().Single(); await languageKernel.SetVariableAsync("x", 123); await languageKernel.SetVariableAsync("x", 456); @@ -853,7 +853,7 @@ public async Task SetVariableAsync_can_redeclare_an_existing_variable_and_change { var kernel = CreateKernel(language); - var languageKernel = kernel.ChildKernels.OfType().Single(); + var languageKernel = kernel.ChildKernels.OfType().Single(); await languageKernel.SetVariableAsync("x", 123); await languageKernel.SetVariableAsync("x", "hello"); diff --git a/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs b/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs index 6d82081dd0..47c40b7b75 100644 --- a/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs +++ b/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs @@ -25,7 +25,7 @@ public class VariableSharingTests "#!fsharp", "let x = 123", "#!csharp", - "#!SOMETHING\nfsharp.TryGetVariable(\"x\", out int x);\nx")] + "#!share --from fsharp x\nfsharp.TryGetVariable(\"x\", out int x);\nx", Skip = "WIP")] public async Task Variables_can_be_read_from_other_kernels( string fromLanguage, string codeToWrite, @@ -35,10 +35,13 @@ public async Task Variables_can_be_read_from_other_kernels( using var kernel = new CompositeKernel { new CSharpKernel() - .UseKernelHelpers(), + .UseKernelHelpers() + .UseDotNetVariableSharing(), new FSharpKernel() - .UseKernelHelpers(), + .UseKernelHelpers() + .UseDotNetVariableSharing(), new PowerShellKernel() + .UseDotNetVariableSharing() }.LogEventsToPocketLogger(); using var events = kernel.KernelEvents.ToSubscribedList(); @@ -55,11 +58,9 @@ public async Task Variables_can_be_read_from_other_kernels( .Be(123); } - [Fact] - public void Internal_types_cannot_be_shared() + [Fact(Skip = "WIP")] + public void Internal_types_are_shared_as_their_most_public_supertype() { - - throw new NotImplementedException("test not written"); } } diff --git a/Microsoft.DotNet.Interactive/CompositeKernel.cs b/Microsoft.DotNet.Interactive/CompositeKernel.cs index fdc7c52c25..1ea4ade58d 100644 --- a/Microsoft.DotNet.Interactive/CompositeKernel.cs +++ b/Microsoft.DotNet.Interactive/CompositeKernel.cs @@ -71,42 +71,10 @@ public void Add(IKernel kernel, IReadOnlyCollection aliases = null) DefaultKernelName = kernel.Name; } - DeclareKernelVariables(kernel, aliases); - RegisterForDisposal(kernel.KernelEvents.Subscribe(PublishEvent)); RegisterForDisposal(kernel); } - private void DeclareKernelVariables( - IKernel kernel, - IReadOnlyCollection aliases) - { - foreach (var otherKernel in ChildKernels - .OfType() - .Where(k => k != kernel)) - { - otherKernel.DeferCommand(new AnonymousKernelCommand(async (command, context) => - { - try - { - await otherKernel.SetVariableAsync( - kernel.Name, - kernel); - } - catch (Exception exception) - { - // FIX: (DeclareKernelVariables) - - context.Publish(new DiagnosticLogEventProduced(exception.Message)); - - - } - })); - - - } - } - private void AddChooseKernelDirective( IKernel kernel, IEnumerable aliases) diff --git a/Microsoft.DotNet.Interactive/LanguageKernel.cs b/Microsoft.DotNet.Interactive/DotNetLanguageKernel.cs similarity index 64% rename from Microsoft.DotNet.Interactive/LanguageKernel.cs rename to Microsoft.DotNet.Interactive/DotNetLanguageKernel.cs index 2ab8d0fcda..9ce96bb23c 100644 --- a/Microsoft.DotNet.Interactive/LanguageKernel.cs +++ b/Microsoft.DotNet.Interactive/DotNetLanguageKernel.cs @@ -5,14 +5,14 @@ namespace Microsoft.DotNet.Interactive { - public abstract class LanguageKernel : KernelBase + public abstract class DotNetLanguageKernel : KernelBase { - protected LanguageKernel(string name) : base(name) + protected DotNetLanguageKernel(string name) : base(name) { } public abstract bool TryGetVariable(string name, out T value); - public abstract Task SetVariableAsync(string name, T value); + public abstract Task SetVariableAsync(string name, object value); } } \ No newline at end of file diff --git a/Microsoft.DotNet.Interactive/Extensions/AssemblyBasedExtensionLoader.cs b/Microsoft.DotNet.Interactive/Extensions/AssemblyBasedExtensionLoader.cs index 842cab950e..7f0c1b8baf 100644 --- a/Microsoft.DotNet.Interactive/Extensions/AssemblyBasedExtensionLoader.cs +++ b/Microsoft.DotNet.Interactive/Extensions/AssemblyBasedExtensionLoader.cs @@ -112,6 +112,7 @@ private async Task LoadFromAssembly( if (loadExtensions) { var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyFile.FullName); + var extensionTypes = assembly .ExportedTypes .Where(t => t.CanBeInstantiated() && typeof(IKernelExtension).IsAssignableFrom(t)) diff --git a/Microsoft.DotNet.Interactive/Kernel.cs b/Microsoft.DotNet.Interactive/Kernel.cs index 1180dc820e..7ba4ad5b2e 100644 --- a/Microsoft.DotNet.Interactive/Kernel.cs +++ b/Microsoft.DotNet.Interactive/Kernel.cs @@ -9,7 +9,6 @@ using Microsoft.DotNet.Interactive.Commands; using Microsoft.DotNet.Interactive.Events; using Microsoft.DotNet.Interactive.Formatting; -using Microsoft.DotNet.Interactive.Utility; using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags; namespace Microsoft.DotNet.Interactive @@ -50,20 +49,10 @@ public static IKernel GetKernel(string name) { var kernel = KernelInvocationContext.Current.HandlingKernel; - KernelBase foundKernel = null; + IKernel foundKernel = null; - if (kernel is KernelBase kernelBase) { - var root = kernelBase.RecurseWhileNotNull(k => k.ParentKernel).Last(); - - foundKernel = root switch - { - CompositeKernel c => c.ChildKernels - .OfType() - .SingleOrDefault(k => k.Name == name), - LanguageKernel k => k, - _ => null - }; + foundKernel = kernel.FindKernel(name); } return foundKernel ?? throw new KeyNotFoundException($"Kernel \"{name}\" was not found."); diff --git a/Microsoft.DotNet.Interactive/KernelExtensions.cs b/Microsoft.DotNet.Interactive/KernelExtensions.cs index 782ca7c59b..09a4e53541 100644 --- a/Microsoft.DotNet.Interactive/KernelExtensions.cs +++ b/Microsoft.DotNet.Interactive/KernelExtensions.cs @@ -6,11 +6,13 @@ using System.CommandLine.Invocation; using System.CommandLine.Rendering; using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.DotNet.Interactive.Commands; using Microsoft.DotNet.Interactive.Events; using Microsoft.DotNet.Interactive.Formatting; +using Microsoft.DotNet.Interactive.Utility; using Pocket; using static System.CommandLine.Rendering.Ansi.Color; using CompositeDisposable = System.Reactive.Disposables.CompositeDisposable; @@ -21,6 +23,25 @@ public static class KernelExtensions { private static readonly TextSpanFormatter _textSpanFormatter = new TextSpanFormatter(); + public static IKernel FindKernel(this IKernel kernelBase, string name) + { + var root = kernelBase + .RecurseWhileNotNull(k => k switch + { + KernelBase kb => kb.ParentKernel, + _ => null + }) + .LastOrDefault(); + + return root switch + { + CompositeKernel c => c.ChildKernels + .SingleOrDefault(k => k.Name == name), + IKernel k when k.Name == name => k, + _ => null + }; + } + public static Task SendAsync( this IKernel kernel, IKernelCommand command) @@ -50,7 +71,6 @@ public static T UseLog(this T kernel) { var command = new Command("#!log", "Enables session logging."); - var logStarted = false; command.Handler = CommandHandler.Create(async context => @@ -102,6 +122,31 @@ public static T UseLog(this T kernel) return kernel; } + public static T UseDotNetVariableSharing(this T kernel) + where T : DotNetLanguageKernel + { + var share = new Command("#!share", "Share a .NET object between subkernels") + { + new Option("--from"), + new Argument("name") + }; + + share.Handler = CommandHandler.Create(async (from, name, context) => + { + if (kernel.FindKernel(from) is DotNetLanguageKernel fromKernel) + { + if (fromKernel.TryGetVariable(name, out object shared)) + { + await kernel.SetVariableAsync(name, shared); + } + } + }); + + kernel.AddDirective(share); + + return kernel; + } + internal static Task DisplayAnsi( this KernelInvocationContext context, FormattableString message) => diff --git a/Microsoft.DotNet.Interactive/Microsoft.DotNet.Interactive.csproj b/Microsoft.DotNet.Interactive/Microsoft.DotNet.Interactive.csproj index 54eb0ffcdc..78f14163a8 100644 --- a/Microsoft.DotNet.Interactive/Microsoft.DotNet.Interactive.csproj +++ b/Microsoft.DotNet.Interactive/Microsoft.DotNet.Interactive.csproj @@ -18,7 +18,7 @@ 2.9.6 4.3.0 4.3.2 - 2.0.0-beta1.20214.1 + 2.0.0-beta1.20219.3 diff --git a/dotnet-interactive/HttpRouting/VariableRouter.cs b/dotnet-interactive/HttpRouting/VariableRouter.cs index bf13195e4f..3aac6ac69f 100644 --- a/dotnet-interactive/HttpRouting/VariableRouter.cs +++ b/dotnet-interactive/HttpRouting/VariableRouter.cs @@ -60,7 +60,7 @@ private async Task BatchVariableRequest(RouteContext context) var propertyBag = new JObject(); response[kernelName] = propertyBag; var targetKernel = GetKernel(kernelName); - if (targetKernel is LanguageKernel languageKernel) + if (targetKernel is DotNetLanguageKernel languageKernel) { foreach (var variableName in kernelProperty.Value.Values()) { @@ -129,7 +129,7 @@ private void SingleVariableRequest(RouteContext context) var targetKernel = GetKernel(kernelName); - if (targetKernel is LanguageKernel languageKernel) + if (targetKernel is DotNetLanguageKernel languageKernel) { if (languageKernel.TryGetVariable(variableName, out object value)) { diff --git a/dotnet-interactive/dotnet-interactive.csproj b/dotnet-interactive/dotnet-interactive.csproj index fda3ab30ce..0923e92678 100644 --- a/dotnet-interactive/dotnet-interactive.csproj +++ b/dotnet-interactive/dotnet-interactive.csproj @@ -68,7 +68,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all From 26616879e09d842ef53f6f990a49a4f3d45a634d Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Wed, 22 Apr 2020 17:14:15 -0700 Subject: [PATCH 5/7] unbreak some merge messes --- .../PowerShellKernelTests.cs | 126 +++++++++++++++++- Microsoft.DotNet.Interactive/Kernel.cs | 9 +- 2 files changed, 124 insertions(+), 11 deletions(-) diff --git a/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs b/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs index ed1ae07a6f..4f1cbefc41 100644 --- a/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs +++ b/Microsoft.DotNet.Interactive.PowerShell.Tests/PowerShellKernelTests.cs @@ -7,8 +7,6 @@ using System.Threading.Tasks; using FluentAssertions; using System.Linq; -using System.Management.Automation; -using System.Threading.Tasks; using Microsoft.DotNet.Interactive.Commands; using Microsoft.DotNet.Interactive.Events; using Microsoft.DotNet.Interactive.Tests; @@ -22,6 +20,10 @@ public class PowerShellKernelTests : LanguageKernelTestBase { private readonly string _allUsersCurrentHostProfilePath = Path.Combine(Path.GetDirectoryName(typeof(PSObject).Assembly.Location), "Microsoft.dotnet-interactive_profile.ps1"); + public PowerShellKernelTests(ITestOutputHelper output) : base(output) + { + } + [Theory] [InlineData(@"$x = New-Object -TypeName System.IO.FileInfo -ArgumentList c:\temp\some.txt", typeof(FileInfo))] [InlineData("$x = \"hello!\"", typeof(string))] @@ -36,6 +38,122 @@ public async Task TryGetVariable_unwraps_PowerShell_object(string code, Type exp fi.Should().BeOfType(expectedType); } + [Fact] + public async Task PowerShell_progress_sends_updated_display_values() + { + var kernel = CreateKernel(Language.PowerShell); + var command = new SubmitCode(@" +for ($j = 0; $j -le 4; $j += 4 ) { + $p = $j * 25 + Write-Progress -Id 1 -Activity 'Search in Progress' -Status ""$p% Complete"" -PercentComplete $p + Start-Sleep -Milliseconds 300 +} +"); + await kernel.SendAsync(command); + + Assert.Collection(KernelEvents, + e => e.Should().BeOfType(), + e => e.Should().BeOfType(), + e => e.Should().BeOfType().Which + .Value.Should().BeOfType().Which + .Should().Match("* Search in Progress* 0% Complete* [ * ] *"), + e => e.Should().BeOfType().Which + .Value.Should().BeOfType().Which + .Should().Match("* Search in Progress* 100% Complete* [ooo*ooo] *"), + e => e.Should().BeOfType().Which + .Value.Should().BeOfType().Which + .Should().Be(string.Empty), + e => e.Should().BeOfType()); + } + + [Fact] + public void PowerShell_type_accelerators_present() + { + CreateKernel(Language.PowerShell); + + var accelerator = typeof(PSObject).Assembly.GetType("System.Management.Automation.TypeAccelerators"); + dynamic typeAccelerators = accelerator.GetProperty("Get").GetValue(null); + Assert.Equal(typeAccelerators["Graph.Scatter"].FullName, $"{typeof(Graph).FullName}+Scatter"); + Assert.Equal(typeAccelerators["Layout"].FullName, $"{typeof(Layout).FullName}+Layout"); + Assert.Equal(typeAccelerators["Chart"].FullName, typeof(Chart).FullName); + } + + [Fact] + public async Task PowerShell_token_variables_work() + { + var kernel = CreateKernel(Language.PowerShell); + + await kernel.SendAsync(new SubmitCode("echo /this/is/a/path")); + await kernel.SendAsync(new SubmitCode("$$; $^")); + + Assert.Collection(KernelEvents, + e => e.Should() + .BeOfType() + .Which.Code + .Should().Be("echo /this/is/a/path"), + e => e.Should() + .BeOfType() + .Which.Code + .Should().Be("echo /this/is/a/path"), + e => e.Should() + .BeOfType() + .Which.Value.ToString() + .Should().Be("/this/is/a/path" + Environment.NewLine), + e => e.Should().BeOfType(), + e => e.Should() + .BeOfType() + .Which.Code + .Should().Be("$$; $^"), + e => e.Should() + .BeOfType() + .Which.Code + .Should().Be("$$; $^"), + e => e.Should() + .BeOfType() + .Which.Value.ToString() + .Should().Be("/this/is/a/path" + Environment.NewLine), + e => e.Should() + .BeOfType() + .Which.Value.ToString() + .Should().Be("echo" + Environment.NewLine), + e => e.Should().BeOfType()); + } + + [Fact] + public async Task PowerShell_get_history_should_work() + { + var kernel = CreateKernel(Language.PowerShell); + + await kernel.SendAsync(new SubmitCode("Get-Verb > $null")); + await kernel.SendAsync(new SubmitCode("echo bar > $null")); + await kernel.SendAsync(new SubmitCode("Get-History | % CommandLine")); + + var outputs = KernelEvents.OfType(); + outputs.Should().HaveCount(2); + Assert.Collection(outputs, + e => e.Value.As().Should().Be("Get-Verb > $null" + Environment.NewLine), + e => e.Value.As().Should().Be("echo bar > $null" + Environment.NewLine)); + } + + [Fact] + public async Task PowerShell_native_executable_output_is_collected() + { + var kernel = CreateKernel(Language.PowerShell); + + var command = Platform.IsWindows + ? new SubmitCode("ping.exe -n 1 localhost") + : new SubmitCode("ping -c 1 localhost"); + + await kernel.SendAsync(command); + + var outputs = KernelEvents.OfType(); + outputs.Should().HaveCountGreaterThan(1); + outputs.Select(e => e.Value.ToString()) + .First(s => s.Trim().Length > 0) + .ToLowerInvariant() + .Should().Match("*ping*data*"); + } + [Fact] public async Task GetCorrectProfilePaths() { @@ -45,7 +163,7 @@ public async Task GetCorrectProfilePaths() await kernel.SubmitCodeAsync("$currentUserCurrentHost = $PROFILE.CurrentUserCurrentHost"); await kernel.SubmitCodeAsync("$allUsersCurrentHost = $PROFILE.AllUsersCurrentHost"); - kernel.TryGetVariable("currentUserCurrentHost", out var profileObj).Should().BeTrue(); + kernel.TryGetVariable("currentUserCurrentHost", out object profileObj).Should().BeTrue(); profileObj.Should().BeOfType(); string currentUserCurrentHost = profileObj.As(); @@ -81,7 +199,7 @@ public async Task VerifyAllUsersProfileRuns() // trigger first time setup. await kernel.SubmitCodeAsync("Get-Date"); - kernel.TryGetVariable(randomVariableName, out var profileObj).Should().BeTrue(); + kernel.TryGetVariable(randomVariableName, out object profileObj).Should().BeTrue(); profileObj.Should().BeOfType(); profileObj.As().Should().BeTrue(); diff --git a/Microsoft.DotNet.Interactive/Kernel.cs b/Microsoft.DotNet.Interactive/Kernel.cs index 7ba4ad5b2e..22a83707d6 100644 --- a/Microsoft.DotNet.Interactive/Kernel.cs +++ b/Microsoft.DotNet.Interactive/Kernel.cs @@ -49,13 +49,8 @@ public static IKernel GetKernel(string name) { var kernel = KernelInvocationContext.Current.HandlingKernel; - IKernel foundKernel = null; - - { - foundKernel = kernel.FindKernel(name); - } - - return foundKernel ?? throw new KeyNotFoundException($"Kernel \"{name}\" was not found."); + return kernel.FindKernel(name) ?? + throw new KeyNotFoundException($"Kernel \"{name}\" was not found."); } } } \ No newline at end of file From 981b56087715e1ff75bacbdbdbfa0565fb3189ec Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Wed, 22 Apr 2020 18:44:35 -0700 Subject: [PATCH 6/7] fix cast --- .../Microsoft.DotNet.Interactive.PowerShell.csproj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj b/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj index b9eb41f12c..f350dcf380 100644 --- a/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj +++ b/Microsoft.DotNet.Interactive.PowerShell/Microsoft.DotNet.Interactive.PowerShell.csproj @@ -33,7 +33,7 @@ PackageCopyToOutput="true" CopyToOutputDirectory="PreserveNewest" /> - + - - +--> From cfc78dc250426c033e7e68133c3871f0ab6dc500 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Wed, 22 Apr 2020 18:47:09 -0700 Subject: [PATCH 7/7] fix cast --- Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs b/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs index 47c40b7b75..299cd791f6 100644 --- a/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs +++ b/Microsoft.DotNet.Interactive.Tests/VariableSharingTests.cs @@ -20,7 +20,7 @@ public class VariableSharingTests "#!fsharp", "let x = 123", "#!csharp", - "(GetKernel(\"fsharp\") as Microsoft.DotNet.Interactive.LanguageKernel).TryGetVariable(\"x\", out int x);\nx")] + "(GetKernel(\"fsharp\") as Microsoft.DotNet.Interactive.DotNetLanguageKernel).TryGetVariable(\"x\", out int x);\nx")] [InlineData( "#!fsharp", "let x = 123",