From be29baba7b41754eb9bd4e67d940c7b5525ab401 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sat, 24 Oct 2026 16:22:10 +0000 Subject: [PATCH] Build the F# packages against the host's FSharp.Core, and reopen the namespaces in a C# notebook AngouriMath.FSharp and AngouriMath.Interactive were built against the SDK's FSharp.Core, 10.1, and a notebook host runs its own: dotnet-interactive 1.0.712001 carries 10.0. A C# kernel never finished loading the kernel extension, and an F# kernel failed its first call into the wrappers unless the extension had loaded first. Both now ask for 8.0.403, which is Plotly.NET's floor. Measured in the Binder image: a C# kernel loads AngouriMath.Interactive in 12 s where the same build at 10.1 times out, and the F# kernel renders LaTeX and Plotly charts. A test fails when a wrapper asks for a newer FSharp.Core than the F# kernel is built against. extension.dib opened AngouriMath and AngouriMath.Extensions in 2.6.0, and C# notebooks rely on it; #2111 dropped the usings because they do not compile in an F# notebook. A second cell defers them to the C# kernel's next submission when its references include AngouriMath, so they are opened exactly when the C# kernel loaded the package. Both sample notebooks run with no error against a local build, the C# one with either package. Fixes https://github.com/asc-community/AngouriMath/issues/2108 Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura --- Sources/AngouriMath/extension.dib | 13 +++++++++ .../HostCompatibility.fs | 28 +++++++++++++++++++ .../InteractiveWrapperUnitTests.fsproj | 1 + .../AngouriMath.FSharp.fsproj | 7 +++++ .../AngouriMath.Interactive.fsproj | 4 +++ 5 files changed, 53 insertions(+) create mode 100644 Sources/Tests/InteractiveWrapperUnitTests/HostCompatibility.fs diff --git a/Sources/AngouriMath/extension.dib b/Sources/AngouriMath/extension.dib index 20b1d6e95..ee0154644 100644 --- a/Sources/AngouriMath/extension.dib +++ b/Sources/AngouriMath/extension.dib @@ -34,3 +34,16 @@ if (FindType("Numbers", "PeterO.Numbers.ERational") is { } rational) RegisterLatex(rational, o => $@"\frac{{{rational.GetProperty("Numerator").GetValue(o)}}}{{{rational.GetProperty("Denominator").GetValue(o)}}}"); "Extensions for LaTeX loaded!" + +#!csharp + +// The namespaces a C# notebook writes without opening: `AngouriMath` and `AngouriMath.Extensions` are opened only +// when the cell above was compiled against AngouriMath, which is when this kernel loaded the package rather than +// another kernel of the same notebook, and the opening is deferred to this kernel's next submission. +static object PropertyOf(object o, string name) => o?.GetType().GetProperty(name)?.GetValue(o); + +if (PropertyOf(PropertyOf(PropertyOf(Microsoft.DotNet.Interactive.Kernel.Current, "ScriptState"), "Script"), "Options") is { } options + && PropertyOf(options, "MetadataReferences") is System.Collections.IEnumerable references + && references.Cast().Any(r => PropertyOf(r, "Display") is string path && System.IO.Path.GetFileName(path) == "AngouriMath.dll")) + Microsoft.DotNet.Interactive.Kernel.Current.DeferCommand( + new Microsoft.DotNet.Interactive.Commands.SubmitCode("using AngouriMath;\nusing AngouriMath.Extensions;")); diff --git a/Sources/Tests/InteractiveWrapperUnitTests/HostCompatibility.fs b/Sources/Tests/InteractiveWrapperUnitTests/HostCompatibility.fs new file mode 100644 index 000000000..d548dc03b --- /dev/null +++ b/Sources/Tests/InteractiveWrapperUnitTests/HostCompatibility.fs @@ -0,0 +1,28 @@ +// +// Copyright (c) 2019-2026 Angouri. +// AngouriMath is licensed under MIT. +// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md. +// Website: https://am.angouri.org. +// + +module AngouriMath.Interactive.Tests.HostCompatibility + +open System.Reflection +open Xunit + +let private fsharpCoreReferencedBy (assembly : Assembly) = + assembly.GetReferencedAssemblies() + |> Array.find (fun name -> name.Name = "FSharp.Core") + |> fun name -> name.Version + +// A notebook host runs its own FSharp.Core and cannot give a package a newer one. Built against +// FSharp.Core 10.1 under a host carrying 10.0, the kernel extension hung a C# kernel as it loaded, +// and an F# kernel failed its first call into the wrappers unless the extension had loaded first: +// https://github.com/asc-community/AngouriMath/issues/2108 +[] +let ``The wrappers ask for no newer FSharp.Core than the F# kernel is built against`` () = + let kernel = fsharpCoreReferencedBy typeof.Assembly + for wrapper in [ typeof.Assembly + Assembly.Load "AngouriMath.FSharp" ] do + let asked = fsharpCoreReferencedBy wrapper + Assert.True(asked <= kernel, $"{wrapper.GetName().Name} asks for FSharp.Core {asked}, the F# kernel is built against {kernel}") diff --git a/Sources/Tests/InteractiveWrapperUnitTests/InteractiveWrapperUnitTests.fsproj b/Sources/Tests/InteractiveWrapperUnitTests/InteractiveWrapperUnitTests.fsproj index d64e56be4..a726b5225 100644 --- a/Sources/Tests/InteractiveWrapperUnitTests/InteractiveWrapperUnitTests.fsproj +++ b/Sources/Tests/InteractiveWrapperUnitTests/InteractiveWrapperUnitTests.fsproj @@ -10,6 +10,7 @@ + diff --git a/Sources/Wrappers/AngouriMath.FSharp/AngouriMath.FSharp.fsproj b/Sources/Wrappers/AngouriMath.FSharp/AngouriMath.FSharp.fsproj index 4c82eb5e4..2e79661e6 100644 --- a/Sources/Wrappers/AngouriMath.FSharp/AngouriMath.FSharp.fsproj +++ b/Sources/Wrappers/AngouriMath.FSharp/AngouriMath.FSharp.fsproj @@ -27,6 +27,13 @@ + + + + + diff --git a/Sources/Wrappers/AngouriMath.Interactive/AngouriMath.Interactive.fsproj b/Sources/Wrappers/AngouriMath.Interactive/AngouriMath.Interactive.fsproj index af93108b7..c256984fd 100644 --- a/Sources/Wrappers/AngouriMath.Interactive/AngouriMath.Interactive.fsproj +++ b/Sources/Wrappers/AngouriMath.Interactive/AngouriMath.Interactive.fsproj @@ -47,6 +47,10 @@ + +