Search code examples
c#ironpython

How to get a Python Style Traceback in Ironpython3?


I have a script that can run a python string but if there is an error I want to be able to get a string formatted like a standard python error. I'm using IronPython 3.4

This is the C# code I currently have:

using UnityEngine;
using IronPython.Hosting;
using System.IO;

public class test : MonoBehaviour
{
void Start()
{
var memoryStream = new MemoryStream();
var engine = Python.CreateEngine();
engine.Runtime.IO.SetOutput(memoryStream, System.Text.Encoding.Default);
var scope = engine.CreateScope();

        string code = @"print(var)";
        try {
            var source = engine.CreateScriptSourceFromString(code);
            source.Execute(scope);
        }
        catch(System.Exception e)
        {
            Debug.Log(e);
        }
    
        Debug.Log(System.Text.Encoding.ASCII.GetString(memoryStream.ToArray()));
    }

}

What I want to be output is something like this:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'var' is not defined

I tried using engine.Runtime.IO.SetErrorOutput but that didn't do anything.


Solution

  • After more digging I found pythonContext.FormatException(e) which gave me exactly what I needed. To get the Python context I used PythonContext context = (PythonContext)Microsoft.Scripting.Hosting.Providers.HostingHelpers.GetLanguageContext(engine);

    So in the end I got this code:

    using UnityEngine;
    using IronPython.Hosting;
    using IronPython.Runtime;
    using System.IO;
    
    public class test : MonoBehaviour
    {
        void Start()
        {
            var memoryStream = new MemoryStream();
            var engine = Python.CreateEngine();
            PythonContext context = (PythonContext)Microsoft.Scripting.Hosting.Providers.HostingHelpers.GetLanguageContext(engine);
            engine.Runtime.IO.SetErrorOutput(memoryStream, System.Text.Encoding.Default);
            var scope = engine.CreateScope();
    
            string code = @"print(var)";
            try {
                var source = engine.CreateScriptSourceFromString(code);
                source.Execute(scope);
            }
            catch(System.Exception e)
            {
                Debug.Log(context.FormatException(e));
            }
    
            Debug.Log(System.Text.Encoding.ASCII.GetString(memoryStream.ToArray()));
        }
    
    }