[Ironpython-users] Detecting source code origination in SetTrace() callbacks

Keith Rome rome at Wintellect.com
Fri Mar 30 05:57:24 CEST 2012

In our live debugger implementation, I call SetTrace() to hook a TracebackDelegate for processing breakpoints, updating stack frame UI, inspecting watches, etc. I depend on information such as "(int)frame.f_lineno" to track the current execution pointer (and therefore which line to highlight in the source code), and "result" to determine if this was a stack push/pop or not. This works beautifully as long as execution never leaves the current script source.

However, when a function is called that references code in some other compiled script source, it will report the line_no from the called script. This causes the "current line" indicator to hop around in our source editor UI, seemingly randomly, because those line_no values are only meaningful in the called function's source script.

I do have a solution for this currently. I check the "frame.f_code" on each call to my trace delegate, and compare it to the one that was captured on the very first call of the trace delegate after starting execution of our debugger. This way, I can detect when the runtime is executing a line of code from some other script source (and therefore can know that execution is currently in "external code"). But it isn't as simple as it sounds. I end up casting "frame.f_code" as IronPython.Runtime.FunctionCode, and then I can walk down the property lineage of FunctionCode.PythonCode.GlobalParent.Document. The Document of two compiled scripts will always be different. Note that all of our scripts are compiled from in-memory strings... nothing is ever loaded from .py files. So this was the only way I could find to compare two "frame" values to determine if they originated from the same script.

The gotcha is that FunctionCode.PythonCode, Node.GlobalParent, and PythonAst.Document are all internal properties. I can't get to those properties without using Reflection (which is not possible for our scenario). So I have customized our version of IronPython by adding the following simple class to IronPython.dll:

using IronPython.Runtime;

namespace IronPython
    /// <summary>
    /// Provides Assistance to Runtime Debugger Tools. This class is not a part of the standard Python runtime.
    /// </summary>
    public static class RuntimeDebuggerHelper
        /// <summary>
        /// Compares a function to another, returns true if they originate from the same source code document.
        /// </summary>
        /// <param name="sourceFunction"></param>
        /// <param name="targetFunction"></param>
        /// <returns></returns>
        public static bool CompareCodeOrigination(FunctionCode sourceFunction, FunctionCode targetFunction)
            var sourceDocument = sourceFunction.PythonCode.GlobalParent.Document;
            var targetDocument = targetFunction.PythonCode.GlobalParent.Document;

            return sourceDocument == targetDocument;

This works fine, but I would really prefer to not need to customize our distribution. Is there a better way to solve this problem? Or failing that, is this the type of update that could ever make its way back into the main distribution?

Keith Rome
Senior Consultant and Architect
Wintellect | 770.617.4016 | krome at wintellect.com<mailto:rome at wintellect.com>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20120330/857d74c4/attachment.html>

More information about the Ironpython-users mailing list