From b6e8595c20003272d730a01efc86ed90d6a9ed55 Mon Sep 17 00:00:00 2001 From: slozier Date: Sat, 4 Jan 2025 22:31:00 -0500 Subject: [PATCH] Exceptions cleanup (#1862) --- .../Runtime/Exceptions/PythonExceptions.cs | 2 +- .../Runtime/Exceptions/SystemExitException.cs | 41 ++++++++++--------- .../Runtime/Exceptions/TraceBack.cs | 25 +++++------ .../Runtime/Operations/PythonOps.cs | 17 ++------ Src/IronPython/Runtime/PythonContext.cs | 23 ++++------- 5 files changed, 46 insertions(+), 62 deletions(-) diff --git a/Src/IronPython/Runtime/Exceptions/PythonExceptions.cs b/Src/IronPython/Runtime/Exceptions/PythonExceptions.cs index 97dc38f98..81753a7bf 100644 --- a/Src/IronPython/Runtime/Exceptions/PythonExceptions.cs +++ b/Src/IronPython/Runtime/Exceptions/PythonExceptions.cs @@ -719,7 +719,7 @@ internal static BaseException CreateBaseExceptionForRaise(CodeContext/*!*/ conte /// /// Given a CLR exception returns the Python exception which most closely maps to the CLR exception. /// - public static object ToPython(System.Exception/*!*/ clrException) { + public static BaseException ToPython(System.Exception/*!*/ clrException) { var res = clrException.GetPythonException(); if (res is null) { // explicit extra conversions that need a special transformation diff --git a/Src/IronPython/Runtime/Exceptions/SystemExitException.cs b/Src/IronPython/Runtime/Exceptions/SystemExitException.cs index 6444bb4c6..992193951 100644 --- a/Src/IronPython/Runtime/Exceptions/SystemExitException.cs +++ b/Src/IronPython/Runtime/Exceptions/SystemExitException.cs @@ -2,8 +2,11 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. +#nullable enable + using System; using System.Runtime.Serialization; + using IronPython.Modules; using IronPython.Runtime.Operations; using IronPython.Runtime.Types; @@ -15,15 +18,19 @@ namespace IronPython.Runtime.Exceptions { [Serializable] public sealed class SystemExitException : Exception { public SystemExitException() : base() { } + public SystemExitException(string msg) : base(msg) { } + public SystemExitException(string message, Exception innerException) : base(message, innerException) { } + #if FEATURE_SERIALIZATION private SystemExitException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endif + /// /// Result of sys.exit(n) /// @@ -36,30 +43,26 @@ private SystemExitException(SerializationInfo info, StreamingContext context) : /// int_value if the script exited using "sys.exit(int_value)" /// 1 otherwise /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")] [PythonHidden] - public int GetExitCode(out object otherCode) { + public int GetExitCode(out object? otherCode) { otherCode = null; - object pyObj = PythonExceptions.ToPython(this); + var pyObj = PythonExceptions.ToPython(this); - object args; - PythonTuple t; - - if (!PythonOps.TryGetBoundAttr(pyObj, "args", out args) || - (t = args as PythonTuple) == null || - t.__len__() == 0) { - return 0; - } else if (Builtin.isinstance(t[0], TypeCache.Int32)) { - return Converter.ConvertToInt32(t[0]); - } else if (Builtin.isinstance(t[0], TypeCache.BigInteger)) { - var b = Converter.ConvertToBigInteger(t[0]); - if (b > int.MaxValue || b < int.MinValue) { - return -1; + if (PythonOps.TryGetBoundAttr(pyObj, "code", out object? code)) { + if (code is null) { + return 0; + } else if (Builtin.isinstance(code, TypeCache.Int32)) { + return Converter.ConvertToInt32(code); + } else if (Builtin.isinstance(code, TypeCache.BigInteger)) { + var b = Converter.ConvertToBigInteger(code); + if (b > int.MaxValue || b < int.MinValue) { + return -1; + } + return (int)b; + } else { + otherCode = code; } - return (int)b; } - - otherCode = t[0]; return 1; } } diff --git a/Src/IronPython/Runtime/Exceptions/TraceBack.cs b/Src/IronPython/Runtime/Exceptions/TraceBack.cs index 49f1bb208..5125e115e 100644 --- a/Src/IronPython/Runtime/Exceptions/TraceBack.cs +++ b/Src/IronPython/Runtime/Exceptions/TraceBack.cs @@ -8,18 +8,15 @@ using System.Runtime.CompilerServices; using System.Text; -using Microsoft.Scripting; -using Microsoft.Scripting.Runtime; - using IronPython.Runtime.Operations; -[module: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope = "member", Target = "IronPython.Runtime.Exceptions.TraceBackFrame..ctor(System.Object,System.Object,System.Object)", MessageId = "0#globals")] -[module: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope = "member", Target = "IronPython.Runtime.Exceptions.TraceBackFrame.Globals", MessageId = "Globals")] +using Microsoft.Scripting; +using Microsoft.Scripting.Runtime; namespace IronPython.Runtime.Exceptions { [PythonType("traceback")] [Serializable] - public class TraceBack { + public sealed class TraceBack { private readonly TraceBack _next; private readonly TraceBackFrame _frame; private int _line; @@ -79,7 +76,7 @@ internal string Extract() { [PythonType("frame")] [DebuggerDisplay("Code = {f_code.co_name}, Line = {f_lineno}")] [Serializable] - public class TraceBackFrame { + public sealed class TraceBackFrame { private readonly PythonTracebackListener _traceAdapter; private TracebackDelegate _trace; private object _traceObject; @@ -118,11 +115,11 @@ internal TraceBackFrame(PythonTracebackListener traceAdapter, FunctionCode code, [SpecialName, PropertyMethod] public object Getf_trace() { - if (_traceAdapter != null) { - return _traceObject; - } else { - return null; - } + if (_traceAdapter != null) { + return _traceObject; + } else { + return null; + } } [SpecialName, PropertyMethod] @@ -230,7 +227,7 @@ private void SetLineNumber(int newLineNum) { Dictionary currentLoopIds = null; bool inForLoopOrFinally = loopAndFinallyLocations != null && loopAndFinallyLocations.TryGetValue(_lineNo, out currentLoopIds); - + int originalNewLine = newLineNum; if (newLineNum < funcCode.Span.Start.Line) { @@ -246,7 +243,7 @@ private void SetLineNumber(int newLineNum) { // Check if we're jumping onto a handler bool handlerIsFinally; if (handlerLocations != null && handlerLocations.TryGetValue(newLineNum, out handlerIsFinally)) { - throw PythonOps.ValueError("can't jump to 'except' line"); + throw PythonOps.ValueError("can't jump to 'except' line"); } // Check if we're jumping into a for-loop diff --git a/Src/IronPython/Runtime/Operations/PythonOps.cs b/Src/IronPython/Runtime/Operations/PythonOps.cs index f95fd6acf..82f0f75be 100644 --- a/Src/IronPython/Runtime/Operations/PythonOps.cs +++ b/Src/IronPython/Runtime/Operations/PythonOps.cs @@ -2457,20 +2457,9 @@ public static PythonTuple GetExceptionInfo(CodeContext/*!*/ context) { return PythonTuple.MakeTuple(null, null, null); } - PythonContext pc = context.LanguageContext; - - object pyExcep = PythonExceptions.ToPython(ex); - TraceBack? tb = CreateTraceBack(pc, ex); - - object excType; - if (pyExcep is IPythonObject pyObj) { - // class is always the Python type for new-style types (this is also the common case) - excType = pyObj.PythonType; - } else { - excType = PythonOps.GetBoundAttr(context, pyExcep, "__class__"); - } - - return PythonTuple.MakeTuple(excType, pyExcep, tb); + var pyExcep = PythonExceptions.ToPython(ex); + TraceBack? tb = CreateTraceBack(context.LanguageContext, ex); + return PythonTuple.MakeTuple(((IPythonObject)pyExcep).PythonType, pyExcep, tb); } /// diff --git a/Src/IronPython/Runtime/PythonContext.cs b/Src/IronPython/Runtime/PythonContext.cs index d13d72a75..751ac78dd 100644 --- a/Src/IronPython/Runtime/PythonContext.cs +++ b/Src/IronPython/Runtime/PythonContext.cs @@ -1332,7 +1332,7 @@ public override string FormatException(Exception exception) { StringBuilder result = new StringBuilder(); - object pythonEx = PythonExceptions.ToPython(exception); + var pythonEx = PythonExceptions.ToPython(exception); if (exception.InnerException != null) { if (exception.InnerException.GetPythonException() is PythonExceptions.BaseException pythonInnerException) { @@ -1438,28 +1438,24 @@ private static string FormatCLSException(Exception e) { return result.ToString(); } - internal static string FormatPythonException(object pythonException) { + internal static string FormatPythonException(PythonExceptions.BaseException pythonException) { string result = ""; // dump the python exception. if (pythonException != null) { - if (pythonException is string str) { - result += str; - } else { - result += GetPythonExceptionClassName(pythonException); + result += GetPythonExceptionClassName(pythonException); - string excepStr = PythonOps.ToString(pythonException); + string excepStr = PythonOps.ToString(pythonException); - if (!string.IsNullOrEmpty(excepStr)) { - result += ": " + excepStr; - } + if (!string.IsNullOrEmpty(excepStr)) { + result += ": " + excepStr; } } return result; } - private static string GetPythonExceptionClassName(object pythonException) { + private static string GetPythonExceptionClassName(PythonExceptions.BaseException pythonException) { string className = string.Empty; if (PythonOps.TryGetBoundAttr(pythonException, "__class__", out object val)) { if (PythonOps.TryGetBoundAttr(val, "__name__", out val)) { @@ -1644,9 +1640,8 @@ public override CompilerOptions GetCompilerOptions() } public override void GetExceptionMessage(Exception exception, out string message, out string typeName) { - object pythonEx = PythonExceptions.ToPython(exception); - - message = FormatPythonException(PythonExceptions.ToPython(exception)); + var pythonEx = PythonExceptions.ToPython(exception); + message = FormatPythonException(pythonEx); typeName = GetPythonExceptionClassName(pythonEx); }