From d26c2149aa15388606377f1816bce413f485478b Mon Sep 17 00:00:00 2001 From: Pavel Koneski Date: Mon, 21 Apr 2025 22:06:24 -0700 Subject: [PATCH 1/2] Override console Ctrl+C event handler with handler in module `signal` --- .../IronPython.Modules/signal.SimpleSignalState.cs | 10 ++++++++-- src/core/IronPython/Hosting/PythonCommandLine.cs | 1 + src/core/IronPython/Runtime/PythonContext.cs | 6 ++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/core/IronPython.Modules/signal.SimpleSignalState.cs b/src/core/IronPython.Modules/signal.SimpleSignalState.cs index 473c64151..b9084d6f6 100644 --- a/src/core/IronPython.Modules/signal.SimpleSignalState.cs +++ b/src/core/IronPython.Modules/signal.SimpleSignalState.cs @@ -14,9 +14,15 @@ namespace IronPython.Modules { public static partial class PythonSignal { private class SimpleSignalState : PythonSignalState { + private readonly ConsoleCancelEventHandler? _consoleHandler; public SimpleSignalState(PythonContext pc) : base(pc) { Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress); + if (pc.Console is Microsoft.Scripting.Hosting.Shell.BasicConsole console) { + // in console hosting scenarios, we need to override the console handler of Ctrl+C + _consoleHandler = console.ConsoleCancelEventHandler; + console.ConsoleCancelEventHandler = null; + } } @@ -42,8 +48,8 @@ private void Console_CancelKeyPress(object? sender, ConsoleCancelEventArgs e) { throw new InvalidOperationException("unreachable"); } } else if (ReferenceEquals(handler, default_int_handler) && pySignal == SIGINT) { - // Let the real interrupt handler throw a KeyboardInterrupt for SIGINT. - // It handles this far more gracefully than we can + // Forward the signal to the console handler, if any + _consoleHandler?.Invoke(sender, e); return; } else { CallPythonHandler(pySignal, handler); diff --git a/src/core/IronPython/Hosting/PythonCommandLine.cs b/src/core/IronPython/Hosting/PythonCommandLine.cs index 781836ddd..2fc86f071 100644 --- a/src/core/IronPython/Hosting/PythonCommandLine.cs +++ b/src/core/IronPython/Hosting/PythonCommandLine.cs @@ -145,6 +145,7 @@ protected override void Initialize() { Console.Output = new OutputWriter(PythonContext, false); Console.ErrorOutput = new OutputWriter(PythonContext, true); + Language.Console = Console; // TODO: must precede path initialization! (??? - test test_importpkg.py) int pathIndex = PythonContext.PythonOptions.SearchPaths.Count; diff --git a/src/core/IronPython/Runtime/PythonContext.cs b/src/core/IronPython/Runtime/PythonContext.cs index 23090b46e..4ec56da4d 100644 --- a/src/core/IronPython/Runtime/PythonContext.cs +++ b/src/core/IronPython/Runtime/PythonContext.cs @@ -22,6 +22,7 @@ using Microsoft.Scripting.Actions; using Microsoft.Scripting.Debugging.CompilerServices; using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Hosting.Shell; using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; @@ -684,6 +685,11 @@ internal static Version GetPythonVersion() internal FloatFormat DoubleFormat { get; set; } + /// + /// Not null if the Python context is running in a console host. + /// + internal IConsole/*?*/ Console { get; set; } + /// /// Initializes the sys module on startup. Called both to load and reload sys /// From 59e3b6bbed6295f310de87697facf982fed40ac2 Mon Sep 17 00:00:00 2001 From: Pavel Koneski Date: Fri, 25 Apr 2025 15:17:28 -0700 Subject: [PATCH 2/2] Use nullable annotation --- src/core/IronPython/Runtime/PythonContext.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/IronPython/Runtime/PythonContext.cs b/src/core/IronPython/Runtime/PythonContext.cs index 4ec56da4d..27f563dfb 100644 --- a/src/core/IronPython/Runtime/PythonContext.cs +++ b/src/core/IronPython/Runtime/PythonContext.cs @@ -685,10 +685,14 @@ internal static Version GetPythonVersion() internal FloatFormat DoubleFormat { get; set; } +#nullable enable + /// /// Not null if the Python context is running in a console host. /// - internal IConsole/*?*/ Console { get; set; } + internal IConsole? Console { get; set; } + +#nullable restore /// /// Initializes the sys module on startup. Called both to load and reload sys