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
MCPD-EAD, MCSD, MCDBA, MCTS-WPF, MCTS-TFS, MCTS-WSS
Wintellect | 770.617.4016 | kr...@wintellect.com<mailto:r...@wintellect.com>
www.wintellect.com<http://www.wintellect.com/>

_______________________________________________
Ironpython-users mailing list
Ironpython-users@python.org
http://mail.python.org/mailman/listinfo/ironpython-users

Reply via email to