"""Support for stack-frames. Provides Implements a nearly complete wrapper for a stack frame. """ import pythoncom from . import axdebug, expressions, gateways from .util import RaiseNotImpl, _wrap, trace # def trace(*args): # pass class EnumDebugStackFrames(gateways.EnumDebugStackFrames): """A class that given a debugger object, can return an enumerator of DebugStackFrame objects. """ def __init__(self, debugger): infos = [] frame = debugger.currentframe # print("Stack check") while frame: # print(" Checking frame", frame.f_code.co_filename, frame.f_lineno-1, frame.f_trace) # Get a DebugCodeContext for the stack frame. If we fail, then it # is not debuggable, and therefore not worth displaying. cc = debugger.codeContainerProvider.FromFileName(frame.f_code.co_filename) if cc is not None: try: address = frame.f_locals["__axstack_address__"] except KeyError: # print("Couldn't find stack address for",frame.f_code.co_filename, frame.f_lineno-1) # Use this one, even tho it is wrong :-( address = axdebug.GetStackAddress() frameInfo = ( DebugStackFrame(frame, frame.f_lineno - 1, cc), address, address + 1, 0, None, ) infos.append(frameInfo) # print("- Kept!") # else: # print("- rejected") frame = frame.f_back gateways.EnumDebugStackFrames.__init__(self, infos, 0) # def __del__(self): # print("EnumDebugStackFrames dieing") def Next(self, count): return gateways.EnumDebugStackFrames.Next(self, count) # def _query_interface_(self, iid): # from win32com.util import IIDToInterfaceName # print(f"EnumDebugStackFrames QI with {IIDToInterfaceName(iid)} ({iid})") # return 0 def _wrap(self, obj): # This enum returns a tuple, with 2 com objects in it. obFrame, min, lim, fFinal, obFinal = obj obFrame = _wrap(obFrame, axdebug.IID_IDebugStackFrame) if obFinal: obFinal = _wrap(obFinal, pythoncom.IID_IUnknown) return obFrame, min, lim, fFinal, obFinal class DebugStackFrame(gateways.DebugStackFrame): def __init__(self, frame, lineno, codeContainer): self.frame = frame self.lineno = lineno self.codeContainer = codeContainer self.expressionContext = None # def __del__(self): # print("DSF dieing") def _query_interface_(self, iid): if iid == axdebug.IID_IDebugExpressionContext: if self.expressionContext is None: self.expressionContext = _wrap( expressions.ExpressionContext(self.frame), axdebug.IID_IDebugExpressionContext, ) return self.expressionContext # from win32com.util import IIDToInterfaceName # print(f"DebugStackFrame QI with {IIDToInterfaceName(iid)} ({iid})") return 0 # # The following need implementation def GetThread(self): """Returns the thread associated with this stack frame. Result must be a IDebugApplicationThread """ RaiseNotImpl("GetThread") def GetCodeContext(self): offset = self.codeContainer.GetPositionOfLine(self.lineno) return self.codeContainer.GetCodeContextAtPosition(offset) # # The following are usefully implemented def GetDescriptionString(self, fLong): filename = self.frame.f_code.co_filename s = "" if 0: # fLong: s += filename if self.frame.f_code.co_name: s += self.frame.f_code.co_name else: s += "" return s def GetLanguageString(self, fLong): if fLong: return "Python ActiveX Scripting Engine" else: return "Python" def GetDebugProperty(self): return _wrap(StackFrameDebugProperty(self.frame), axdebug.IID_IDebugProperty) class DebugStackFrameSniffer: _public_methods_ = ["EnumStackFrames"] _com_interfaces_ = [axdebug.IID_IDebugStackFrameSniffer] def __init__(self, debugger): self.debugger = debugger trace("DebugStackFrameSniffer instantiated") # def __del__(self): # print("DSFS dieing") def EnumStackFrames(self): trace("DebugStackFrameSniffer.EnumStackFrames called") return _wrap( EnumDebugStackFrames(self.debugger), axdebug.IID_IEnumDebugStackFrames ) # A DebugProperty for a stack frame. class StackFrameDebugProperty: _com_interfaces_ = [axdebug.IID_IDebugProperty] _public_methods_ = [ "GetPropertyInfo", "GetExtendedInfo", "SetValueAsString", "EnumMembers", "GetParent", ] def __init__(self, frame): self.frame = frame def GetPropertyInfo(self, dwFieldSpec, nRadix): RaiseNotImpl("StackFrameDebugProperty::GetPropertyInfo") def GetExtendedInfo(self): ### Note - not in the framework. RaiseNotImpl("StackFrameDebugProperty::GetExtendedInfo") def SetValueAsString(self, value, radix): # RaiseNotImpl("DebugProperty::SetValueAsString") def EnumMembers(self, dwFieldSpec, nRadix, iid): print("EnumMembers", dwFieldSpec, nRadix, iid) from . import expressions return expressions.MakeEnumDebugProperty( self.frame.f_locals, dwFieldSpec, nRadix, iid, self.frame ) def GetParent(self): # return IDebugProperty RaiseNotImpl("DebugProperty::GetParent")