Uploaded Test files

This commit is contained in:
Batuhan Berk Başoğlu 2020-11-12 11:05:57 -05:00
parent f584ad9d97
commit 2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions

View file

@ -0,0 +1,3 @@
# See if we have a special directory for the binaries (for developers)
import win32com
win32com.__PackageSupportBuildPath__(__path__)

View file

@ -0,0 +1,416 @@
"""The glue between the Python debugger interface and the Active Debugger interface
"""
from win32com.axdebug.util import trace, _wrap, _wrap_remove
from win32com.server.util import unwrap
import win32com.client.connect
from . import gateways
import sys, bdb, traceback
from . import axdebug, stackframe
import win32api, pythoncom
import _thread, os
def fnull(*args):
pass
try:
os.environ["DEBUG_AXDEBUG"]
debugging = 1
except KeyError:
debugging = 0
traceenter = fnull # trace enter of functions
tracev = fnull # verbose trace
if debugging:
traceenter = trace # trace enter of functions
tracev = trace # verbose trace
class OutputReflector:
def __init__(self, file, writefunc):
self.writefunc = writefunc
self.file = file
def __getattr__(self,name):
return getattr(self.file, name)
def write(self,message):
self.writefunc(message)
self.file.write(message)
def _dumpf(frame):
if frame is None:
return "<None>"
else:
addn = "(with trace!)"
if frame.f_trace is None:
addn = " **No Trace Set **"
return "Frame at %d, file %s, line: %d%s" % (id(frame), frame.f_code.co_filename, frame.f_lineno, addn)
g_adb = None
def OnSetBreakPoint(codeContext, breakPointState, lineNo):
try:
fileName = codeContext.codeContainer.GetFileName()
# inject the code into linecache.
import linecache
linecache.cache[fileName] = 0, 0, codeContext.codeContainer.GetText(), fileName
g_adb._OnSetBreakPoint(fileName, codeContext, breakPointState, lineNo+1)
except:
traceback.print_exc()
class Adb(bdb.Bdb,gateways.RemoteDebugApplicationEvents):
def __init__(self):
self.debugApplication = None
self.debuggingThread = None
self.debuggingThreadStateHandle = None
self.stackSnifferCookie = self.stackSniffer = None
self.codeContainerProvider = None
self.debuggingThread = None
self.breakFlags = None
self.breakReason = None
self.appDebugger = None
self.appEventConnection = None
self.logicalbotframe = None # Anything at this level or below does not exist!
self.currentframe = None # The frame we are currently in.
self.recursiveData = [] # Data saved for each reentery on this thread.
bdb.Bdb.__init__(self)
self._threadprotectlock = _thread.allocate_lock()
self.reset()
def canonic(self, fname):
if fname[0]=='<':
return fname
return bdb.Bdb.canonic(self, fname)
def reset(self):
traceenter("adb.reset")
bdb.Bdb.reset(self)
def __xxxxx__set_break(self, filename, lineno, cond = None):
# As per standard one, except no linecache checking!
if filename not in self.breaks:
self.breaks[filename] = []
list = self.breaks[filename]
if lineno in list:
return 'There is already a breakpoint there!'
list.append(lineno)
if cond is not None: self.cbreaks[filename, lineno]=cond
def stop_here(self, frame):
traceenter("stop_here", _dumpf(frame), _dumpf(self.stopframe))
# As per bdb.stop_here, except for logicalbotframe
## if self.stopframe is None:
## return 1
if frame is self.stopframe:
return 1
tracev("stop_here said 'No'!")
return 0
def break_here(self, frame):
traceenter("break_here", self.breakFlags, _dumpf(frame))
self.breakReason = None
if self.breakFlags==axdebug.APPBREAKFLAG_DEBUGGER_HALT:
self.breakReason = axdebug.BREAKREASON_DEBUGGER_HALT
elif self.breakFlags==axdebug.APPBREAKFLAG_DEBUGGER_BLOCK:
self.breakReason = axdebug.BREAKREASON_DEBUGGER_BLOCK
elif self.breakFlags==axdebug.APPBREAKFLAG_STEP:
self.breakReason = axdebug.BREAKREASON_STEP
else:
print("Calling base 'break_here' with", self.breaks)
if bdb.Bdb.break_here(self, frame):
self.breakReason = axdebug.BREAKREASON_BREAKPOINT
return self.breakReason is not None
def break_anywhere(self, frame):
traceenter("break_anywhere", _dumpf(frame))
if self.breakFlags==axdebug.APPBREAKFLAG_DEBUGGER_HALT:
self.breakReason = axdebug.BREAKREASON_DEBUGGER_HALT
return 1
rc = bdb.Bdb.break_anywhere(self, frame)
tracev("break_anywhere",_dumpf(frame),"returning",rc)
return rc
def dispatch_return(self, frame, arg):
traceenter("dispatch_return", _dumpf(frame), arg)
if self.logicalbotframe is frame:
# We dont want to debug parent frames.
tracev("dispatch_return resetting sys.trace")
sys.settrace(None)
return
# self.bSetTrace = 0
self.currentframe = frame.f_back
return bdb.Bdb.dispatch_return(self, frame, arg)
def dispatch_line(self, frame):
traceenter("dispatch_line", _dumpf(frame), _dumpf(self.botframe))
# trace("logbotframe is", _dumpf(self.logicalbotframe), "botframe is", self.botframe)
if frame is self.logicalbotframe:
trace("dispatch_line", _dumpf(frame), "for bottom frame returing tracer")
# The next code executed in the frame above may be a builtin (eg, apply())
# in which sys.trace needs to be set.
sys.settrace(self.trace_dispatch)
# And return the tracer incase we are about to execute Python code,
# in which case sys tracer is ignored!
return self.trace_dispatch
if self.codeContainerProvider.FromFileName(frame.f_code.co_filename) is None:
trace("dispatch_line has no document for", _dumpf(frame), "- skipping trace!")
return None
self.currentframe = frame # So the stack sniffer knows our most recent, debuggable code.
return bdb.Bdb.dispatch_line(self, frame)
def dispatch_call(self, frame, arg):
traceenter("dispatch_call",_dumpf(frame))
frame.f_locals['__axstack_address__'] = axdebug.GetStackAddress()
if frame is self.botframe:
trace("dispatch_call is self.botframe - returning tracer")
return self.trace_dispatch
# Not our bottom frame. If we have a document for it,
# then trace it, otherwise run at full speed.
if self.codeContainerProvider.FromFileName(frame.f_code.co_filename) is None:
trace("dispatch_call has no document for", _dumpf(frame), "- skipping trace!")
## sys.settrace(None)
return None
return self.trace_dispatch
# rc = bdb.Bdb.dispatch_call(self, frame, arg)
# trace("dispatch_call", _dumpf(frame),"returned",rc)
# return rc
def trace_dispatch(self, frame, event, arg):
traceenter("trace_dispatch", _dumpf(frame), event, arg)
if self.debugApplication is None:
trace("trace_dispatch has no application!")
return # None
return bdb.Bdb.trace_dispatch(self, frame, event, arg)
#
# The user functions do bugger all!
#
# def user_call(self, frame, argument_list):
# traceenter("user_call",_dumpf(frame))
def user_line(self, frame):
traceenter("user_line",_dumpf(frame))
# Traces at line zero
if frame.f_lineno!=0:
breakReason = self.breakReason
if breakReason is None:
breakReason = axdebug.BREAKREASON_STEP
self._HandleBreakPoint(frame, None, breakReason)
def user_return(self, frame, return_value):
# traceenter("user_return",_dumpf(frame),return_value)
bdb.Bdb.user_return(self, frame, return_value)
def user_exception(self, frame, exc_info):
# traceenter("user_exception")
bdb.Bdb.user_exception(self, frame, exc_info)
def _HandleBreakPoint(self, frame, tb, reason):
traceenter("Calling HandleBreakPoint with reason", reason,"at frame", _dumpf(frame))
traceenter(" Current frame is", _dumpf(self.currentframe))
try:
resumeAction = self.debugApplication.HandleBreakPoint(reason)
tracev("HandleBreakPoint returned with ", resumeAction)
except pythoncom.com_error as details:
# Eeek - the debugger is dead, or something serious is happening.
# Assume we should continue
resumeAction = axdebug.BREAKRESUMEACTION_CONTINUE
trace("HandleBreakPoint FAILED with", details)
self.stack = []
self.curindex = 0
if resumeAction == axdebug.BREAKRESUMEACTION_ABORT:
self.set_quit()
elif resumeAction == axdebug.BREAKRESUMEACTION_CONTINUE:
tracev("resume action is continue")
self.set_continue()
elif resumeAction == axdebug.BREAKRESUMEACTION_STEP_INTO:
tracev("resume action is step")
self.set_step()
elif resumeAction == axdebug.BREAKRESUMEACTION_STEP_OVER:
tracev("resume action is next")
self.set_next(frame)
elif resumeAction == axdebug.BREAKRESUMEACTION_STEP_OUT:
tracev("resume action is stop out")
self.set_return(frame)
else:
raise ValueError("unknown resume action flags")
self.breakReason = None
def set_trace(self):
self.breakReason = axdebug.BREAKREASON_LANGUAGE_INITIATED
bdb.Bdb.set_trace(self)
def CloseApp(self):
traceenter("ClosingApp")
self.reset()
self.logicalbotframe = None
if self.stackSnifferCookie is not None:
try:
self.debugApplication.RemoveStackFrameSniffer(self.stackSnifferCookie)
except pythoncom.com_error:
trace("*** Could not RemoveStackFrameSniffer %d" % (self.stackSnifferCookie))
if self.stackSniffer:
_wrap_remove(self.stackSniffer)
self.stackSnifferCookie = self.stackSniffer = None
if self.appEventConnection is not None:
self.appEventConnection.Disconnect()
self.appEventConnection = None
self.debugApplication = None
self.appDebugger = None
if self.codeContainerProvider is not None:
self.codeContainerProvider.Close()
self.codeContainerProvider = None
def AttachApp(self, debugApplication, codeContainerProvider):
# traceenter("AttachApp", debugApplication, codeContainerProvider)
self.codeContainerProvider = codeContainerProvider
self.debugApplication = debugApplication
self.stackSniffer = _wrap(stackframe.DebugStackFrameSniffer(self), axdebug.IID_IDebugStackFrameSniffer)
self.stackSnifferCookie = debugApplication.AddStackFrameSniffer(self.stackSniffer)
# trace("StackFrameSniffer added (%d)" % self.stackSnifferCookie)
# Connect to the application events.
self.appEventConnection = win32com.client.connect.SimpleConnection(self.debugApplication, self, axdebug.IID_IRemoteDebugApplicationEvents)
def ResetAXDebugging(self):
traceenter("ResetAXDebugging", self, "with refcount", len(self.recursiveData))
if win32api.GetCurrentThreadId()!=self.debuggingThread:
trace("ResetAXDebugging called on other thread")
return
if len(self.recursiveData)==0:
# print "ResetAXDebugging called for final time."
self.logicalbotframe = None
self.debuggingThread = None
self.currentframe = None
self.debuggingThreadStateHandle = None
return
self.logbotframe, self.stopframe, self.currentframe, self.debuggingThreadStateHandle = self.recursiveData[0]
self.recursiveData = self.recursiveData[1:]
def SetupAXDebugging(self, baseFrame = None, userFrame = None):
"""Get ready for potential debugging. Must be called on the thread
that is being debugged.
"""
# userFrame is for non AXScript debugging. This is the first frame of the
# users code.
if userFrame is None:
userFrame = baseFrame
else:
# We have missed the "dispatch_call" function, so set this up now!
userFrame.f_locals['__axstack_address__'] = axdebug.GetStackAddress()
traceenter("SetupAXDebugging", self)
self._threadprotectlock.acquire()
try:
thisThread = win32api.GetCurrentThreadId()
if self.debuggingThread is None:
self.debuggingThread = thisThread
else:
if self.debuggingThread!=thisThread:
trace("SetupAXDebugging called on other thread - ignored!")
return
# push our context.
self.recursiveData.insert(0, (self.logicalbotframe,self.stopframe, self.currentframe,self.debuggingThreadStateHandle))
finally:
self._threadprotectlock.release()
trace("SetupAXDebugging has base frame as", _dumpf(baseFrame))
self.botframe = baseFrame
self.stopframe = userFrame
self.logicalbotframe = baseFrame
self.currentframe = None
self.debuggingThreadStateHandle = axdebug.GetThreadStateHandle()
self._BreakFlagsChanged()
# RemoteDebugApplicationEvents
def OnConnectDebugger(self, appDebugger):
traceenter("OnConnectDebugger", appDebugger)
self.appDebugger = appDebugger
# Reflect output to appDebugger
writefunc = lambda s: appDebugger.onDebugOutput(s)
sys.stdout = OutputReflector(sys.stdout, writefunc)
sys.stderr = OutputReflector(sys.stderr, writefunc)
def OnDisconnectDebugger(self):
traceenter("OnDisconnectDebugger")
# Stop reflecting output
if isinstance(sys.stdout, OutputReflector):
sys.stdout = sys.stdout.file
if isinstance(sys.stderr, OutputReflector):
sys.stderr = sys.stderr.file
self.appDebugger = None
self.set_quit()
def OnSetName(self, name):
traceenter("OnSetName", name)
def OnDebugOutput(self, string):
traceenter("OnDebugOutput", string)
def OnClose(self):
traceenter("OnClose")
def OnEnterBreakPoint(self, rdat):
traceenter("OnEnterBreakPoint", rdat)
def OnLeaveBreakPoint(self, rdat):
traceenter("OnLeaveBreakPoint", rdat)
def OnCreateThread(self, rdat):
traceenter("OnCreateThread", rdat)
def OnDestroyThread(self, rdat):
traceenter("OnDestroyThread", rdat)
def OnBreakFlagChange(self, abf, rdat):
traceenter("Debugger OnBreakFlagChange", abf, rdat)
self.breakFlags = abf
self._BreakFlagsChanged()
def _BreakFlagsChanged(self):
traceenter("_BreakFlagsChanged to %s with our thread = %s, and debugging thread = %s" % (self.breakFlags, self.debuggingThread, win32api.GetCurrentThreadId()))
trace("_BreakFlagsChanged has breaks", self.breaks)
# If a request comes on our debugging thread, then do it now!
# if self.debuggingThread!=win32api.GetCurrentThreadId():
# return
if len(self.breaks) or self.breakFlags:
if self.logicalbotframe:
trace("BreakFlagsChange with bot frame", _dumpf(self.logicalbotframe))
# We have frames not to be debugged (eg, Scripting engine frames
# (sys.settrace will be set when out logicalbotframe is hit -
# this may not be the right thing to do, as it may not cause the
# immediate break we desire.)
self.logicalbotframe.f_trace = self.trace_dispatch
else:
trace("BreakFlagsChanged, but no bottom frame")
if self.stopframe is not None:
self.stopframe.f_trace = self.trace_dispatch
# If we have the thread-state for the thread being debugged, then
# we dynamically set its trace function - it is possible that the thread
# being debugged is in a blocked call (eg, a message box) and we
# want to hit the debugger the instant we return
if self.debuggingThreadStateHandle is not None and \
self.breakFlags and \
self.debuggingThread != win32api.GetCurrentThreadId():
axdebug.SetThreadStateTrace(self.debuggingThreadStateHandle, self.trace_dispatch)
def _OnSetBreakPoint(self, key, codeContext, bps, lineNo):
traceenter("_OnSetBreakPoint", self, key, codeContext, bps, lineNo)
if bps==axdebug.BREAKPOINT_ENABLED:
problem = self.set_break(key, lineNo)
if problem:
print("*** set_break failed -", problem)
trace("_OnSetBreakPoint just set BP and has breaks", self.breaks)
else:
self.clear_break(key, lineNo)
self._BreakFlagsChanged()
trace("_OnSetBreakPoint leaving with breaks", self.breaks)
def Debugger():
global g_adb
if g_adb is None:
g_adb = Adb()
return g_adb

Binary file not shown.

View file

@ -0,0 +1,254 @@
"""A utility class for a code container.
A code container is a class which holds source code for a debugger. It knows how
to color the text, and also how to translate lines into offsets, and back.
"""
import sys
from win32com.axdebug import axdebug
import tokenize
from .util import RaiseNotImpl, _wrap
from win32com.server.exception import Exception
import win32api, winerror
from . import contexts
_keywords = {} # set of Python keywords
for name in """
and assert break class continue def del elif else except exec
finally for from global if import in is lambda not
or pass print raise return try while
""".split():
_keywords[name] = 1
class SourceCodeContainer:
def __init__(self, text, fileName = "<Remove Me!>", sourceContext = 0, startLineNumber = 0, site = None, debugDocument = None):
self.sourceContext = sourceContext # The source context added by a smart host.
self.text = text
if text:
self._buildlines()
self.nextLineNo = 0
self.fileName = fileName
self.codeContexts = {}
self.site = site
self.startLineNumber = startLineNumber
self.debugDocument = None
def _Close(self):
self.text = self.lines = self.lineOffsets = None
self.codeContexts = None
self.debugDocument = None
self.site = None
self.sourceContext = None
def GetText(self):
return self.text
def GetName(self, dnt):
assert 0, "You must subclass this"
def GetFileName(self):
return self.fileName
def GetPositionOfLine(self, cLineNumber):
self.GetText() # Prime us.
try:
return self.lineOffsets[cLineNumber]
except IndexError:
raise Exception(scode=winerror.S_FALSE)
def GetLineOfPosition(self, charPos):
self.GetText() # Prime us.
lastOffset = 0
lineNo = 0
for lineOffset in self.lineOffsets[1:]:
if lineOffset > charPos:
break
lastOffset = lineOffset
lineNo = lineNo + 1
else: # for not broken.
# print "Cant find", charPos, "in", self.lineOffsets
raise Exception(scode=winerror.S_FALSE)
# print "GLOP ret=",lineNo, (charPos-lastOffset)
return lineNo, (charPos-lastOffset)
def GetNextLine(self):
if self.nextLineNo>=len(self.lines):
self.nextLineNo = 0 # auto-reset.
return ""
rc = self.lines[self.nextLineNo]
self.nextLineNo = self.nextLineNo + 1
return rc
def GetLine(self, num):
self.GetText() # Prime us.
return self.lines[num]
def GetNumChars(self):
return len(self.GetText())
def GetNumLines(self):
self.GetText() # Prime us.
return len(self.lines)
def _buildline(self, pos):
i = self.text.find('\n', pos)
if i < 0:
newpos = len(self.text)
else:
newpos = i+1
r = self.text[pos:newpos]
return r, newpos
def _buildlines(self):
self.lines = []
self.lineOffsets = [0]
line, pos = self._buildline(0)
while line:
self.lines.append(line)
self.lineOffsets.append(pos)
line, pos = self._buildline(pos)
def _ProcessToken(self, type, token, spos, epos, line):
srow, scol = spos
erow, ecol = epos
self.GetText() # Prime us.
linenum = srow - 1 # Lines zero based for us too.
realCharPos = self.lineOffsets[linenum] + scol
numskipped = realCharPos - self.lastPos
if numskipped==0:
pass
elif numskipped==1:
self.attrs.append(axdebug.SOURCETEXT_ATTR_COMMENT)
else:
self.attrs.append((axdebug.SOURCETEXT_ATTR_COMMENT, numskipped))
kwSize = len(token)
self.lastPos = realCharPos + kwSize
attr = 0
if type==tokenize.NAME:
if token in _keywords:
attr = axdebug.SOURCETEXT_ATTR_KEYWORD
elif type==tokenize.STRING:
attr = axdebug.SOURCETEXT_ATTR_STRING
elif type==tokenize.NUMBER:
attr = axdebug.SOURCETEXT_ATTR_NUMBER
elif type==tokenize.OP:
attr = axdebug.SOURCETEXT_ATTR_OPERATOR
elif type==tokenize.COMMENT:
attr = axdebug.SOURCETEXT_ATTR_COMMENT
# else attr remains zero...
if kwSize==0:
pass
elif kwSize==1:
self.attrs.append(attr)
else:
self.attrs.append((attr, kwSize))
def GetSyntaxColorAttributes(self):
self.lastPos = 0
self.attrs = []
try:
tokenize.tokenize(self.GetNextLine, self._ProcessToken)
except tokenize.TokenError:
pass # Ignore - will cause all subsequent text to be commented.
numAtEnd = len(self.GetText()) - self.lastPos
if numAtEnd:
self.attrs.append((axdebug.SOURCETEXT_ATTR_COMMENT, numAtEnd))
return self.attrs
# We also provide and manage DebugDocumentContext objects
def _MakeDebugCodeContext(self, lineNo, charPos, len):
return _wrap(contexts.DebugCodeContext(lineNo, charPos, len, self, self.site), axdebug.IID_IDebugCodeContext)
# Make a context at the given position. It should take up the entire context.
def _MakeContextAtPosition(self, charPos):
lineNo, offset = self.GetLineOfPosition(charPos)
try:
endPos = self.GetPositionOfLine(lineNo+1)
except:
endPos = charPos
codecontext = self._MakeDebugCodeContext(lineNo, charPos, endPos-charPos)
return codecontext
# Returns a DebugCodeContext. debugDocument can be None for smart hosts.
def GetCodeContextAtPosition(self, charPos):
# trace("GetContextOfPos", charPos, maxChars)
# Convert to line number.
lineNo, offset = self.GetLineOfPosition(charPos)
charPos = self.GetPositionOfLine(lineNo)
try:
cc = self.codeContexts[charPos]
# trace(" GetContextOfPos using existing")
except KeyError:
cc = self._MakeContextAtPosition(charPos)
self.codeContexts[charPos] = cc
return cc
class SourceModuleContainer(SourceCodeContainer):
def __init__(self, module):
self.module = module
if hasattr(module, '__file__'):
fname = self.module.__file__
# Check for .pyc or .pyo or even .pys!
if fname[-1] in ['O','o','C','c', 'S', 's']: fname = fname[:-1]
try:
fname = win32api.GetFullPathName(fname)
except win32api.error:
pass
else:
if module.__name__=='__main__' and len(sys.argv)>0:
fname = sys.argv[0]
else:
fname = "<Unknown!>"
SourceCodeContainer.__init__(self, None, fname)
def GetText(self):
if self.text is None:
fname = self.GetFileName()
if fname:
try:
self.text = open(fname, "r").read()
except IOError as details:
self.text = "# Exception opening file\n# %s" % (repr(details))
else:
self.text = "# No file available for module '%s'" % (self.module)
self._buildlines()
return self.text
def GetName(self, dnt):
name = self.module.__name__
try:
fname = win32api.GetFullPathName(self.module.__file__)
except win32api.error:
fname = self.module.__file__
except AttributeError:
fname = name
if dnt==axdebug.DOCUMENTNAMETYPE_APPNODE:
return name.split(".")[-1]
elif dnt==axdebug.DOCUMENTNAMETYPE_TITLE:
return fname
elif dnt==axdebug.DOCUMENTNAMETYPE_FILE_TAIL:
return os.path.split(fname)[1]
elif dnt==axdebug.DOCUMENTNAMETYPE_URL:
return "file:%s" % fname
else:
raise Exception(scode=winerror.E_UNEXPECTED)
if __name__=='__main__':
import sys
sys.path.append(".")
import ttest
sc = SourceModuleContainer(ttest)
# sc = SourceCodeContainer(open(sys.argv[1], "rb").read(), sys.argv[1])
attrs = sc.GetSyntaxColorAttributes()
attrlen = 0
for attr in attrs:
if type(attr)==type(()):
attrlen = attrlen + attr[1]
else:
attrlen = attrlen + 1
text = sc.GetText()
if attrlen!=len(text):
print("Lengths dont match!!! (%d/%d)" % (attrlen, len(text)))
# print "Attributes:"
# print attrs
print("GetLineOfPos=", sc.GetLineOfPosition(0))
print("GetLineOfPos=", sc.GetLineOfPosition(4))
print("GetLineOfPos=", sc.GetLineOfPosition(10))

View file

@ -0,0 +1,56 @@
""" A module for managing the AXDebug I*Contexts
"""
from . import gateways, axdebug
import pythoncom, win32com.server.util
# Utility function for wrapping object created by this module.
from .util import _wrap, _wrap_remove, trace
from . import adb
class DebugCodeContext(gateways.DebugCodeContext, gateways.DebugDocumentContext):
# NOTE: We also implement the IDebugDocumentContext interface for Simple Hosts.
# Thus, debugDocument may be NULL when we have smart hosts - but in that case, we
# wont be called upon to provide it.
_public_methods_ = gateways.DebugCodeContext._public_methods_ + \
gateways.DebugDocumentContext._public_methods_
_com_interfaces_ = gateways.DebugCodeContext._com_interfaces_ + \
gateways.DebugDocumentContext._com_interfaces_
def __init__(self, lineNo, charPos, len, codeContainer, debugSite):
self.debugSite = debugSite
self.offset = charPos
self.length = len
self.breakPointState = 0
self.lineno = lineNo
gateways.DebugCodeContext.__init__(self)
self.codeContainer = codeContainer
def _Close(self):
self.debugSite = None
def GetDocumentContext(self):
if self.debugSite is not None:
# We have a smart host - let him give it to us.
return self.debugSite.GetDocumentContextFromPosition(
self.codeContainer.sourceContext,
self.offset,
self.length)
else:
# Simple host - Fine - Ill do it myself!
return _wrap(self, axdebug.IID_IDebugDocumentContext)
def SetBreakPoint(self, bps):
self.breakPointState = bps
adb.OnSetBreakPoint(self, bps, self.lineno)
# The DebugDocumentContext methods for simple hosts.
def GetDocument(self):
return self.codeContainer.debugDocument
def EnumCodeContexts(self):
return _wrap(EnumDebugCodeContexts([self]), axdebug.IID_IEnumDebugCodeContexts)
class EnumDebugCodeContexts(gateways.EnumDebugCodeContexts):
def _wrap(self, obj):
return _wrap(obj, axdebug.IID_IDebugCodeContext)

View file

@ -0,0 +1,203 @@
import sys, traceback, string
from win32com.axscript import axscript
from win32com.axdebug import codecontainer, axdebug, gateways, documents, contexts, adb, expressions
from win32com.axdebug.util import trace, _wrap, _wrap_remove
import pythoncom
import win32api, winerror
import os
currentDebugger = None
class ModuleTreeNode:
"""Helper class for building a module tree
"""
def __init__(self, module):
modName = module.__name__
self.moduleName = modName
self.module = module
self.realNode = None
self.cont = codecontainer.SourceModuleContainer(module)
def __repr__(self):
return "<ModuleTreeNode wrapping %s>" % (self.module)
def Attach(self, parentRealNode):
self.realNode.Attach(parentRealNode)
def Close(self):
self.module = None
self.cont = None
self.realNode = None
def BuildModule(module, built_nodes, rootNode, create_node_fn, create_node_args ):
if module:
keep = module.__name__
keep = keep and (built_nodes.get(module) is None)
if keep and hasattr(module, '__file__'):
keep = string.lower(os.path.splitext(module.__file__)[1]) not in [".pyd", ".dll"]
# keep = keep and module.__name__=='__main__'
if module and keep:
# print "keeping", module.__name__
node = ModuleTreeNode(module)
built_nodes[module] = node
realNode = create_node_fn(*(node,)+create_node_args)
node.realNode = realNode
# Split into parent nodes.
parts = string.split(module.__name__, '.')
if parts[-1][:8]=='__init__': parts = parts[:-1]
parent = string.join(parts[:-1], '.')
parentNode = rootNode
if parent:
parentModule = sys.modules[parent]
BuildModule(parentModule, built_nodes, rootNode, create_node_fn, create_node_args)
if parentModule in built_nodes:
parentNode = built_nodes[parentModule].realNode
node.Attach(parentNode)
def RefreshAllModules(builtItems, rootNode, create_node, create_node_args):
for module in list(sys.modules.values()):
BuildModule(module, builtItems, rootNode, create_node, create_node_args)
# realNode = pdm.CreateDebugDocumentHelper(None) # DebugDocumentHelper node?
# app.CreateApplicationNode() # doc provider node.
class CodeContainerProvider(documents.CodeContainerProvider):
def __init__(self, axdebugger):
self.axdebugger = axdebugger
documents.CodeContainerProvider.__init__(self)
self.currentNumModules = len(sys.modules)
self.nodes = {}
self.axdebugger.RefreshAllModules(self.nodes, self)
def FromFileName(self, fname):
### It appears we cant add modules during a debug session!
# if self.currentNumModules != len(sys.modules):
# self.axdebugger.RefreshAllModules(self.nodes, self)
# self.currentNumModules = len(sys.modules)
# for key in self.ccsAndNodes.keys():
# print "File:", key
return documents.CodeContainerProvider.FromFileName(self, fname)
def Close(self):
documents.CodeContainerProvider.Close(self)
self.axdebugger = None
print("Closing %d nodes" % (len(self.nodes)))
for node in self.nodes.values():
node.Close()
self.nodes = {}
class OriginalInterfaceMaker:
def MakeInterfaces(self, pdm):
app = self.pdm.CreateApplication()
self.cookie = pdm.AddApplication(app)
root = app.GetRootNode()
return app, root
def CloseInterfaces(self, pdm):
pdm.RemoveApplication(self.cookie)
class SimpleHostStyleInterfaceMaker:
def MakeInterfaces(self, pdm):
app = pdm.GetDefaultApplication()
root = app.GetRootNode()
return app, root
def CloseInterfaces(self, pdm):
pass
class AXDebugger:
def __init__(self, interfaceMaker = None, processName = None):
if processName is None: processName = "Python Process"
if interfaceMaker is None: interfaceMaker = SimpleHostStyleInterfaceMaker()
self.pydebugger = adb.Debugger()
self.pdm=pythoncom.CoCreateInstance(axdebug.CLSID_ProcessDebugManager,None,pythoncom.CLSCTX_ALL, axdebug.IID_IProcessDebugManager)
self.app, self.root = interfaceMaker.MakeInterfaces(self.pdm)
self.app.SetName(processName)
self.interfaceMaker = interfaceMaker
expressionProvider = _wrap(expressions.ProvideExpressionContexts(), axdebug.IID_IProvideExpressionContexts)
self.expressionCookie = self.app.AddGlobalExpressionContextProvider(expressionProvider)
contProvider = CodeContainerProvider(self)
self.pydebugger.AttachApp(self.app, contProvider)
def Break(self):
# Get the frame we start debugging from - this is the frame 1 level up
try:
1 + ''
except:
frame = sys.exc_info()[2].tb_frame.f_back
# Get/create the debugger, and tell it to break.
self.app.StartDebugSession()
# self.app.CauseBreak()
self.pydebugger.SetupAXDebugging(None, frame)
self.pydebugger.set_trace()
def Close(self):
self.pydebugger.ResetAXDebugging()
self.interfaceMaker.CloseInterfaces(self.pdm)
self.pydebugger.CloseApp()
self.app.RemoveGlobalExpressionContextProvider(self.expressionCookie)
self.expressionCookie = None
self.pdm = None
self.app = None
self.pydebugger = None
self.root = None
def RefreshAllModules(self, nodes, containerProvider):
RefreshAllModules(nodes, self.root, self.CreateApplicationNode, (containerProvider,))
def CreateApplicationNode(self, node, containerProvider):
realNode = self.app.CreateApplicationNode()
document = documents.DebugDocumentText(node.cont)
document = _wrap(document, axdebug.IID_IDebugDocument)
node.cont.debugDocument = document
provider = documents.DebugDocumentProvider(document)
provider = _wrap(provider, axdebug.IID_IDebugDocumentProvider)
realNode.SetDocumentProvider(provider)
containerProvider.AddCodeContainer(node.cont, realNode)
return realNode
def _GetCurrentDebugger():
global currentDebugger
if currentDebugger is None:
currentDebugger = AXDebugger()
return currentDebugger
def Break():
_GetCurrentDebugger().Break()
brk = Break
set_trace = Break
def dosomethingelse():
a=2
b = "Hi there"
def dosomething():
a=1
b=2
dosomethingelse()
def test():
Break()
input("Waiting...")
dosomething()
print("Done")
if __name__=='__main__':
print("About to test the debugging interfaces!")
test()
print(" %d/%d com objects still alive" % (pythoncom._GetInterfaceCount(), pythoncom._GetGatewayCount()))

View file

@ -0,0 +1,124 @@
""" Management of documents for AXDebugging.
"""
from . import axdebug, gateways
import pythoncom
from .util import _wrap, _wrap_remove, RaiseNotImpl, trace
from win32com.server.util import unwrap
from . import codecontainer
from . import contexts
from win32com.server.exception import Exception
import win32api, winerror, os, string, sys
#def trace(*args):
# pass
def GetGoodFileName(fname):
if fname[0] != "<":
return win32api.GetFullPathName(fname)
return fname
class DebugDocumentProvider(gateways.DebugDocumentProvider):
def __init__(self, doc):
self.doc = doc
def GetName(self, dnt):
return self.doc.GetName(dnt)
def GetDocumentClassId(self):
return self.doc.GetDocumentClassId()
def GetDocument(self):
return self.doc
class DebugDocumentText(gateways.DebugDocumentInfo, gateways.DebugDocumentText, gateways.DebugDocument):
_com_interfaces_ = gateways.DebugDocumentInfo._com_interfaces_ + \
gateways.DebugDocumentText._com_interfaces_ + \
gateways.DebugDocument._com_interfaces_
_public_methods_ = gateways.DebugDocumentInfo._public_methods_ + \
gateways.DebugDocumentText._public_methods_ + \
gateways.DebugDocument._public_methods_
# A class which implements a DebugDocumentText, using the functionality
# provided by a codeContainer
def __init__(self, codeContainer):
gateways.DebugDocumentText.__init__(self)
gateways.DebugDocumentInfo.__init__(self)
gateways.DebugDocument.__init__(self)
self.codeContainer = codeContainer
def _Close(self):
self.docContexts = None
# self.codeContainer._Close()
self.codeContainer = None
# IDebugDocumentInfo
def GetName(self, dnt):
return self.codeContainer.GetName(dnt)
def GetDocumentClassId(self):
return "{DF630910-1C1D-11d0-AE36-8C0F5E000000}"
# IDebugDocument has no methods!
#
# IDebugDocumentText methods.
# def GetDocumentAttributes
def GetSize(self):
# trace("GetSize")
return self.codeContainer.GetNumLines(), self.codeContainer.GetNumChars()
def GetPositionOfLine(self, cLineNumber):
return self.codeContainer.GetPositionOfLine(cLineNumber)
def GetLineOfPosition(self, charPos):
return self.codeContainer.GetLineOfPosition(charPos)
def GetText(self, charPos, maxChars, wantAttr):
# Get all the attributes, else the tokenizer will get upset.
# XXX - not yet!
# trace("GetText", charPos, maxChars, wantAttr)
cont = self.codeContainer
attr = cont.GetSyntaxColorAttributes()
return cont.GetText(), attr
def GetPositionOfContext(self, context):
trace("GetPositionOfContext", context)
context = unwrap(context)
return context.offset, context.length
# Return a DebugDocumentContext.
def GetContextOfPosition(self, charPos, maxChars):
# Make one
doc = _wrap(self, axdebug.IID_IDebugDocument)
rc = self.codeContainer.GetCodeContextAtPosition(charPos)
return rc.QueryInterface(axdebug.IID_IDebugDocumentContext)
class CodeContainerProvider:
"""An abstract Python class which provides code containers!
Given a Python file name (as the debugger knows it by) this will
return a CodeContainer interface suitable for use.
This provides a simple base imlpementation that simply supports
a dictionary of nodes and providers.
"""
def __init__(self):
self.ccsAndNodes = {}
def AddCodeContainer(self, cc, node = None):
fname = GetGoodFileName(cc.fileName)
self.ccsAndNodes[fname] = cc, node
def FromFileName(self, fname):
cc, node = self.ccsAndNodes.get(GetGoodFileName(fname), (None, None))
# if cc is None:
# print "FromFileName for %s returning None" % fname
return cc
def Close(self):
for cc, node in self.ccsAndNodes.values():
try:
# Must close the node before closing the provider
# as node may make calls on provider (eg Reset breakpoints etc)
if node is not None:
node.Close()
cc._Close()
except pythoncom.com_error:
pass
self.ccsAndNodes = {}

View file

@ -0,0 +1,48 @@
import sys, string
import traceback
from win32com.axdebug import axdebug
from win32com.client.util import Enumerator
import pythoncom
def DumpDebugApplicationNode(node, level = 0):
# Recursive dump of a DebugApplicationNode
spacer = " " * level
for desc, attr in [("Node Name", axdebug.DOCUMENTNAMETYPE_APPNODE),
("Title", axdebug.DOCUMENTNAMETYPE_TITLE),
("Filename", axdebug.DOCUMENTNAMETYPE_FILE_TAIL),
("URL", axdebug.DOCUMENTNAMETYPE_URL),
]:
try:
info = node.GetName(attr)
except pythoncom.com_error:
info = "<N/A>"
print("%s%s: %s" % (spacer, desc, info))
try:
doc = node.GetDocument()
except pythoncom.com_error:
doc = None
if doc:
doctext = doc.QueryInterface(axdebug.IID_IDebugDocumentText)
numLines, numChars = doctext.GetSize()
# text, attr = doctext.GetText(0, 20, 1)
text, attr = doctext.GetText(0, numChars, 1)
print("%sText is %s, %d bytes long" % (spacer, repr(text[:40]+"..."), len(text)))
else:
print("%s%s" % (spacer, "<No document available>"))
for child in Enumerator(node.EnumChildren()):
DumpDebugApplicationNode(child, level+1)
def dumpall():
dm=pythoncom.CoCreateInstance(axdebug.CLSID_MachineDebugManager,None,pythoncom.CLSCTX_ALL, axdebug.IID_IMachineDebugManager)
e=Enumerator(dm.EnumApplications())
for app in e:
print("Application: %s" % app.GetName())
node = app.GetRootNode() # of type PyIDebugApplicationNode->PyIDebugDocumentProvider->PyIDebugDocumentInfo
DumpDebugApplicationNode(node)
if __name__=='__main__':
try:
dumpall()
except:
traceback.print_exc()

View file

@ -0,0 +1,156 @@
from . import axdebug, gateways
from .util import _wrap, _wrap_remove, RaiseNotImpl
import io, traceback
from pprint import pprint
from win32com.server.exception import COMException
import winerror
import string
import sys
# Given an object, return a nice string
def MakeNiceString(ob):
stream = io.StringIO()
pprint(ob, stream)
return string.strip(stream.getvalue())
class ProvideExpressionContexts(gateways.ProvideExpressionContexts):
pass
class ExpressionContext(gateways.DebugExpressionContext):
def __init__(self, frame):
self.frame = frame
def ParseLanguageText(self, code, radix, delim, flags):
return _wrap(Expression(self.frame, code, radix, delim, flags), axdebug.IID_IDebugExpression)
def GetLanguageInfo(self):
# print "GetLanguageInfo"
return "Python", "{DF630910-1C1D-11d0-AE36-8C0F5E000000}"
class Expression(gateways.DebugExpression):
def __init__(self, frame, code, radix, delim, flags):
self.callback = None
self.frame = frame
self.code = code
self.radix = radix
self.delim = delim
self.flags = flags
self.isComplete = 0
self.result=None
self.hresult = winerror.E_UNEXPECTED
def Start(self, callback):
try:
try:
try:
self.result = eval(self.code, self.frame.f_globals, self.frame.f_locals)
except SyntaxError:
exec(self.code, self.frame.f_globals, self.frame.f_locals)
self.result = ""
self.hresult = 0
except:
l = traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])
# l is a list of strings with trailing "\n"
self.result = string.join(map(lambda s:s[:-1], l), "\n")
self.hresult = winerror.E_FAIL
finally:
self.isComplete = 1
callback.onComplete()
def Abort(self):
print("** ABORT **")
def QueryIsComplete(self):
return self.isComplete
def GetResultAsString(self):
# print "GetStrAsResult returning", self.result
return self.hresult, MakeNiceString(self.result)
def GetResultAsDebugProperty(self):
result = _wrap(DebugProperty(self.code, self.result, None, self.hresult), axdebug.IID_IDebugProperty)
return self.hresult, result
def MakeEnumDebugProperty(object, dwFieldSpec, nRadix, iid, stackFrame = None):
name_vals = []
if hasattr(object, "items") and hasattr(object, "keys"): # If it is a dict.
name_vals = iter(object.items())
dictionary = object
elif hasattr(object, "__dict__"): #object with dictionary, module
name_vals = iter(object.__dict__.items())
dictionary = object.__dict__
infos = []
for name, val in name_vals:
infos.append(GetPropertyInfo(name, val, dwFieldSpec, nRadix, 0, dictionary, stackFrame))
return _wrap(EnumDebugPropertyInfo(infos), axdebug.IID_IEnumDebugPropertyInfo)
def GetPropertyInfo(obname, obvalue, dwFieldSpec, nRadix, hresult=0, dictionary = None, stackFrame = None):
# returns a tuple
name = typ = value = fullname = attrib = dbgprop = None
if dwFieldSpec & axdebug.DBGPROP_INFO_VALUE:
value = MakeNiceString(obvalue)
if dwFieldSpec & axdebug.DBGPROP_INFO_NAME:
name = obname
if dwFieldSpec & axdebug.DBGPROP_INFO_TYPE:
if hresult:
typ = "Error"
else:
try:
typ = type(obvalue).__name__
except AttributeError:
typ = str(type(obvalue))
if dwFieldSpec & axdebug.DBGPROP_INFO_FULLNAME:
fullname = obname
if dwFieldSpec & axdebug.DBGPROP_INFO_ATTRIBUTES:
if hasattr(obvalue, "has_key") or hasattr(obvalue, "__dict__"): # If it is a dict or object
attrib = axdebug.DBGPROP_ATTRIB_VALUE_IS_EXPANDABLE
else:
attrib = 0
if dwFieldSpec & axdebug.DBGPROP_INFO_DEBUGPROP:
dbgprop = _wrap(DebugProperty(name, obvalue, None, hresult, dictionary, stackFrame), axdebug.IID_IDebugProperty)
return name, typ, value, fullname, attrib, dbgprop
from win32com.server.util import ListEnumeratorGateway
class EnumDebugPropertyInfo(ListEnumeratorGateway):
"""A class to expose a Python sequence as an EnumDebugCodeContexts
Create an instance of this class passing a sequence (list, tuple, or
any sequence protocol supporting object) and it will automatically
support the EnumDebugCodeContexts interface for the object.
"""
_public_methods_ = ListEnumeratorGateway._public_methods_ + ["GetCount"]
_com_interfaces_ = [ axdebug.IID_IEnumDebugPropertyInfo]
def GetCount(self):
return len(self._list_)
def _wrap(self, ob):
return ob
class DebugProperty:
_com_interfaces_ = [axdebug.IID_IDebugProperty]
_public_methods_ = ['GetPropertyInfo', 'GetExtendedInfo', 'SetValueAsString',
'EnumMembers', 'GetParent'
]
def __init__(self, name, value, parent = None, hresult = 0, dictionary = None, stackFrame = None):
self.name = name
self.value = value
self.parent = parent
self.hresult = hresult
self.dictionary = dictionary
self.stackFrame = stackFrame
def GetPropertyInfo(self, dwFieldSpec, nRadix):
return GetPropertyInfo(self.name, self.value, dwFieldSpec, nRadix, self.hresult, dictionary, stackFrame)
def GetExtendedInfo(self): ### Note - not in the framework.
RaiseNotImpl("DebugProperty::GetExtendedInfo")
def SetValueAsString(self, value, radix):
if self.stackFrame and self.dictionary:
self.dictionary[self.name]= eval(value,self.stackFrame.f_globals, self.stackFrame.f_locals)
else:
RaiseNotImpl("DebugProperty::SetValueAsString")
def EnumMembers(self, dwFieldSpec, nRadix, iid):
# Returns IEnumDebugPropertyInfo
return MakeEnumDebugProperty(self.value, dwFieldSpec, nRadix, iid, self.stackFrame)
def GetParent(self):
# return IDebugProperty
RaiseNotImpl("DebugProperty::GetParent")

View file

@ -0,0 +1,452 @@
# Classes which describe interfaces.
from win32com.server.exception import Exception
from win32com.server.util import ListEnumeratorGateway
from win32com.axdebug import axdebug
from win32com.axdebug.util import RaiseNotImpl, _wrap
import pythoncom
import win32com.server.connect
import winerror
class EnumDebugCodeContexts(ListEnumeratorGateway):
"""A class to expose a Python sequence as an EnumDebugCodeContexts
Create an instance of this class passing a sequence (list, tuple, or
any sequence protocol supporting object) and it will automatically
support the EnumDebugCodeContexts interface for the object.
"""
_com_interfaces_ = [ axdebug.IID_IEnumDebugCodeContexts ]
class EnumDebugStackFrames(ListEnumeratorGateway):
"""A class to expose a Python sequence as an EnumDebugStackFrames
Create an instance of this class passing a sequence (list, tuple, or
any sequence protocol supporting object) and it will automatically
support the EnumDebugStackFrames interface for the object.
"""
_com_interfaces_ = [ axdebug.IID_IEnumDebugStackFrames ]
class EnumDebugApplicationNodes(ListEnumeratorGateway):
"""A class to expose a Python sequence as an EnumDebugStackFrames
Create an instance of this class passing a sequence (list, tuple, or
any sequence protocol supporting object) and it will automatically
support the EnumDebugApplicationNodes interface for the object.
"""
_com_interfaces_ = [ axdebug.IID_IEnumDebugApplicationNodes ]
class EnumRemoteDebugApplications(ListEnumeratorGateway):
_com_interfaces_ = [ axdebug.IID_IEnumRemoteDebugApplications ]
class EnumRemoteDebugApplicationThreads(ListEnumeratorGateway):
_com_interfaces_ = [ axdebug.IID_IEnumRemoteDebugApplicationThreads ]
class DebugDocumentInfo:
_public_methods_ = ["GetName", "GetDocumentClassId"]
_com_interfaces_ = [axdebug.IID_IDebugDocumentInfo]
def __init__(self):
pass
def GetName(self, dnt):
""" Get the one of the name of the document
dnt -- int DOCUMENTNAMETYPE
"""
RaiseNotImpl("GetName")
def GetDocumentClassId(self):
"""
Result must be an IID object (or string representing one).
"""
RaiseNotImpl("GetDocumentClassId")
class DebugDocumentProvider(DebugDocumentInfo):
_public_methods_ = DebugDocumentInfo._public_methods_ + ["GetDocument"]
_com_interfaces_ = DebugDocumentInfo._com_interfaces_ + [axdebug.IID_IDebugDocumentProvider]
def GetDocument(self):
RaiseNotImpl("GetDocument")
class DebugApplicationNode(DebugDocumentProvider):
"""Provides the functionality of IDebugDocumentProvider, plus a context within a project tree.
"""
_public_methods_ = """EnumChildren GetParent SetDocumentProvider
Close Attach Detach""".split() + \
DebugDocumentProvider._public_methods_
_com_interfaces_ = [axdebug.IID_IDebugDocumentProvider] + \
DebugDocumentProvider._com_interfaces_
def __init__(self):
DebugDocumentProvider.__init__(self)
def EnumChildren(self):
# Result is type PyIEnumDebugApplicationNodes
RaiseNotImpl("EnumChildren")
def GetParent(self):
# result is type PyIDebugApplicationNode
RaiseNotImpl("GetParent")
def SetDocumentProvider(self, pddp): # PyIDebugDocumentProvider pddp
# void result.
RaiseNotImpl("SetDocumentProvider")
def Close(self):
# void result.
RaiseNotImpl("Close")
def Attach(self, parent): # PyIDebugApplicationNode
# void result.
RaiseNotImpl("Attach")
def Detach(self):
# void result.
RaiseNotImpl("Detach")
class DebugApplicationNodeEvents:
"""Event interface for DebugApplicationNode object.
"""
_public_methods_ = "onAddChild onRemoveChild onDetach".split()
_com_interfaces_ = [axdebug.IID_IDebugApplicationNodeEvents]
def __init__(self):
pass
def onAddChild(self, child): # PyIDebugApplicationNode
# void result.
RaiseNotImpl("onAddChild")
def onRemoveChild(self, child): # PyIDebugApplicationNode
# void result.
RaiseNotImpl("onRemoveChild")
def onDetach(self):
# void result.
RaiseNotImpl("onDetach")
def onAttach(self, parent): # PyIDebugApplicationNode
# void result.
RaiseNotImpl("onAttach")
class DebugDocument(DebugDocumentInfo):
"""The base interface to all debug documents.
"""
_public_methods_ = DebugDocumentInfo._public_methods_
_com_interfaces_ = [axdebug.IID_IDebugDocument] + DebugDocumentInfo._com_interfaces_
class DebugDocumentText(DebugDocument):
"""The interface to a text only debug document.
"""
_com_interfaces_ = [axdebug.IID_IDebugDocumentText] + \
DebugDocument._com_interfaces_
_public_methods_ = ["GetDocumentAttributes", "GetSize",
"GetPositionOfLine", "GetLineOfPosition", "GetText",
"GetPositionOfContext", "GetContextOfPosition"] + \
DebugDocument._public_methods_
def __init__(self):
pass
# IDebugDocumentText
def GetDocumentAttributes(self):
# Result is int (TEXT_DOC_ATTR)
RaiseNotImpl("GetDocumentAttributes")
def GetSize(self):
# Result is (numLines, numChars)
RaiseNotImpl("GetSize")
def GetPositionOfLine(self, cLineNumber):
# Result is int char position
RaiseNotImpl("GetPositionOfLine")
def GetLineOfPosition(self, charPos):
# Result is int, int (lineNo, offset)
RaiseNotImpl("GetLineOfPosition")
def GetText(self, charPos, maxChars, wantAttr):
"""Params
charPos -- integer
maxChars -- integer
wantAttr -- Should the function compute attributes.
Return value must be (string, attribtues). attributes may be
None if(not wantAttr)
"""
RaiseNotImpl("GetText")
def GetPositionOfContext(self, debugDocumentContext):
"""Params
debugDocumentContext -- a PyIDebugDocumentContext object.
Return value must be (charPos, numChars)
"""
RaiseNotImpl("GetPositionOfContext")
def GetContextOfPosition(self, charPos, maxChars):
"""Params are integers.
Return value must be PyIDebugDocumentContext object
"""
print(self)
RaiseNotImpl("GetContextOfPosition")
class DebugDocumentTextExternalAuthor:
"""Allow external editors to edit file-based debugger documents, and to notify the document when the source file has been changed.
"""
_public_methods_ = ["GetPathName", "GetFileName", "NotifyChanged"]
_com_interfaces_ = [axdebug.IID_IDebugDocumentTextExternalAuthor]
def __init__(self):
pass
def GetPathName(self):
"""Return the full path (including file name) to the document's source file.
Result must be (filename, fIsOriginal), where
- if fIsOriginalPath is TRUE if the path refers to the original file for the document.
- if fIsOriginalPath is FALSE if the path refers to a newly created temporary file.
raise Exception(winerror.E_FAIL) if no source file can be created/determined.
"""
RaiseNotImpl("GetPathName")
def GetFileName(self):
"""Return just the name of the document, with no path information. (Used for "Save As...")
Result is a string
"""
RaiseNotImpl("GetFileName")
def NotifyChanged(self):
""" Notify the host that the document's source file has been saved and
that its contents should be refreshed.
"""
RaiseNotImpl("NotifyChanged")
class DebugDocumentTextEvents:
_public_methods_ = """onDestroy onInsertText onRemoveText
onReplaceText onUpdateTextAttributes
onUpdateDocumentAttributes""".split()
_com_interfaces_ = [ axdebug.IID_IDebugDocumentTextEvents ]
def __init__(self):
pass
def onDestroy(self):
# Result is void.
RaiseNotImpl("onDestroy")
def onInsertText(self, cCharacterPosition, cNumToInsert):
# Result is void.
RaiseNotImpl("onInsertText")
def onRemoveText(self, cCharacterPosition, cNumToRemove):
# Result is void.
RaiseNotImpl("onRemoveText")
def onReplaceText(self, cCharacterPosition, cNumToReplace):
# Result is void.
RaiseNotImpl("onReplaceText")
def onUpdateTextAttributes(self, cCharacterPosition, cNumToUpdate):
# Result is void.
RaiseNotImpl("onUpdateTextAttributes")
def onUpdateDocumentAttributes(self,textdocattr): # TEXT_DOC_ATTR
# Result is void.
RaiseNotImpl("onUpdateDocumentAttributes")
class DebugDocumentContext:
_public_methods_ = [ 'GetDocument', 'EnumCodeContexts']
_com_interfaces_ = [ axdebug.IID_IDebugDocumentContext ]
def __init__(self):
pass
def GetDocument(self):
"""Return value must be a PyIDebugDocument object
"""
RaiseNotImpl("GetDocument")
def EnumCodeContexts(self):
"""Return value must be a PyIEnumDebugCodeContexts object
"""
RaiseNotImpl("EnumCodeContexts")
class DebugCodeContext:
_public_methods_ = [ 'GetDocumentContext', 'SetBreakPoint']
_com_interfaces_ = [ axdebug.IID_IDebugCodeContext ]
def __init__(self):
pass
def GetDocumentContext(self):
"""Return value must be a PyIDebugDocumentContext object
"""
RaiseNotImpl("GetDocumentContext")
def SetBreakPoint(self, bps):
"""bps -- an integer with flags.
"""
RaiseNotImpl("SetBreakPoint")
class DebugStackFrame:
"""Abstraction representing a logical stack frame on the stack of a thread."""
_public_methods_ = [ 'GetCodeContext', 'GetDescriptionString', 'GetLanguageString', 'GetThread', 'GetDebugProperty']
_com_interfaces_ = [ axdebug.IID_IDebugStackFrame ]
def __init__(self):
pass
def GetCodeContext(self):
"""Returns the current code context associated with the stack frame.
Return value must be a IDebugCodeContext object
"""
RaiseNotImpl("GetCodeContext")
def GetDescriptionString(self, fLong):
"""Returns a textual description of the stack frame.
fLong -- A flag indicating if the long name is requested.
"""
RaiseNotImpl("GetDescriptionString")
def GetLanguageString(self):
"""Returns a short or long textual description of the language.
fLong -- A flag indicating if the long name is requested.
"""
RaiseNotImpl("GetLanguageString")
def GetThread(self):
""" Returns the thread associated with this stack frame.
Result must be a IDebugApplicationThread
"""
RaiseNotImpl("GetThread")
def GetDebugProperty(self):
RaiseNotImpl("GetDebugProperty")
class DebugDocumentHost:
"""The interface from the IDebugDocumentHelper back to
the smart host or language engine. This interface
exposes host specific functionality such as syntax coloring.
"""
_public_methods_ = [ 'GetDeferredText', 'GetScriptTextAttributes', 'OnCreateDocumentContext', 'GetPathName', 'GetFileName', 'NotifyChanged']
_com_interfaces_ = [ axdebug.IID_IDebugDocumentHost ]
def __init__(self):
pass
def GetDeferredText(self, dwTextStartCookie, maxChars, bWantAttr):
RaiseNotImpl("GetDeferredText")
def GetScriptTextAttributes(self, codeText, delimterText, flags):
# Result must be an attribute sequence of same "length" as the code.
RaiseNotImpl("GetScriptTextAttributes")
def OnCreateDocumentContext(self):
# Result must be a PyIUnknown
RaiseNotImpl("OnCreateDocumentContext")
def GetPathName(self):
# Result must be (string, int) where the int is a BOOL
# - TRUE if the path refers to the original file for the document.
# - FALSE if the path refers to a newly created temporary file.
# - raise Exception(scode=E_FAIL) if no source file can be created/determined.
RaiseNotImpl("GetPathName")
def GetFileName(self):
# Result is a string with just the name of the document, no path information.
RaiseNotImpl("GetFileName")
def NotifyChanged(self):
RaiseNotImpl("NotifyChanged")
# Additional gateway related functions.
class DebugDocumentTextConnectServer:
_public_methods_ = win32com.server.connect.IConnectionPointContainer_methods + win32com.server.connect.IConnectionPoint_methods
_com_interfaces_ = [pythoncom.IID_IConnectionPoint, pythoncom.IID_IConnectionPointContainer]
# IConnectionPoint interfaces
def __init__(self):
self.cookieNo = -1
self.connections = {}
def EnumConnections(self):
RaiseNotImpl("EnumConnections")
def GetConnectionInterface(self):
RaiseNotImpl("GetConnectionInterface")
def GetConnectionPointContainer(self):
return _wrap(self)
def Advise(self, pUnk):
# Creates a connection to the client. Simply allocate a new cookie,
# find the clients interface, and store it in a dictionary.
interface = pUnk.QueryInterface(axdebug.IID_IDebugDocumentTextEvents,1)
self.cookieNo = self.cookieNo + 1
self.connections[self.cookieNo] = interface
return self.cookieNo
def Unadvise(self, cookie):
# Destroy a connection - simply delete interface from the map.
try:
del self.connections[cookie]
except KeyError:
return Exception(scode=winerror.E_UNEXPECTED)
# IConnectionPointContainer interfaces
def EnumConnectionPoints(self):
RaiseNotImpl("EnumConnectionPoints")
def FindConnectionPoint(self, iid):
# Find a connection we support. Only support the single event interface.
if iid==axdebug.IID_IDebugDocumentTextEvents:
return _wrap(self)
raise Exception(scode=winerror.E_NOINTERFACE) # ??
class RemoteDebugApplicationEvents:
_public_methods_ = ["OnConnectDebugger","OnDisconnectDebugger","OnSetName","OnDebugOutput","OnClose","OnEnterBreakPoint","OnLeaveBreakPoint","OnCreateThread","OnDestroyThread","OnBreakFlagChange"]
_com_interfaces_ = [axdebug.IID_IRemoteDebugApplicationEvents]
def OnConnectDebugger(self, appDebugger):
"""appDebugger -- a PyIApplicationDebugger
"""
RaiseNotImpl("OnConnectDebugger")
def OnDisconnectDebugger(self):
RaiseNotImpl("OnDisconnectDebugger")
def OnSetName(self, name):
RaiseNotImpl("OnSetName")
def OnDebugOutput(self, string):
RaiseNotImpl("OnDebugOutput")
def OnClose(self):
RaiseNotImpl("OnClose")
def OnEnterBreakPoint(self, rdat):
"""rdat -- PyIRemoteDebugApplicationThread
"""
RaiseNotImpl("OnEnterBreakPoint")
def OnLeaveBreakPoint(self, rdat):
"""rdat -- PyIRemoteDebugApplicationThread
"""
RaiseNotImpl("OnLeaveBreakPoint")
def OnCreateThread(self, rdat):
"""rdat -- PyIRemoteDebugApplicationThread
"""
RaiseNotImpl("OnCreateThread")
def OnDestroyThread(self, rdat):
"""rdat -- PyIRemoteDebugApplicationThread
"""
RaiseNotImpl("OnDestroyThread")
def OnBreakFlagChange(self, abf, rdat):
"""abf -- int - one of the axdebug.APPBREAKFLAGS constants
rdat -- PyIRemoteDebugApplicationThread
RaiseNotImpl("OnBreakFlagChange")
"""
class DebugExpressionContext:
_public_methods_ = ["ParseLanguageText", "GetLanguageInfo"]
_com_interfaces_ = [axdebug.IID_IDebugExpressionContext]
def __init__(self):
pass
def ParseLanguageText(self, code, radix, delim, flags):
"""
result is IDebugExpression
"""
RaiseNotImpl("ParseLanguageText")
def GetLanguageInfo(self):
"""
result is (string langName, iid langId)
"""
RaiseNotImpl("GetLanguageInfo")
class DebugExpression:
_public_methods_ = ["Start", "Abort", "QueryIsComplete", "GetResultAsString", "GetResultAsDebugProperty"]
_com_interfaces_ = [axdebug.IID_IDebugExpression]
def Start(self, callback):
"""
callback -- an IDebugExpressionCallback
result - void
"""
RaiseNotImpl("Start")
def Abort(self):
"""
no params
result -- void
"""
RaiseNotImpl("Abort")
def QueryIsComplete(self):
"""
no params
result -- void
"""
RaiseNotImpl("QueryIsComplete")
def GetResultAsString(self):
RaiseNotImpl("GetResultAsString")
def GetResultAsDebugProperty(self):
RaiseNotImpl("GetResultAsDebugProperty")
class ProvideExpressionContexts:
_public_methods_ = ["EnumExpressionContexts"]
_com_interfaces_ = [axdebug.IID_IProvideExpressionContexts]
def EnumExpressionContexts(self):
RaiseNotImpl("EnumExpressionContexts")

View file

@ -0,0 +1,146 @@
"""Support for stack-frames.
Provides Implements a nearly complete wrapper for a stack frame.
"""
import sys
from .util import _wrap, RaiseNotImpl
import expressions, gateways, axdebug, winerror
import pythoncom
from win32com.server.exception import COMException
from .util import 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 "Couldnt 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 "EnumDebugStackFrames QI with %s (%s)" % (IIDToInterfaceName(iid), str(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 "DebugStackFrame QI with %s (%s)" % (IIDToInterfaceName(iid), str(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 = s + filename
if self.frame.f_code.co_name:
s = s + self.frame.f_code.co_name
else:
s = s + "<lambda>"
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")

View file

@ -0,0 +1,114 @@
# Utility function for wrapping objects. Centralising allows me to turn
# debugging on and off for the entire package in a single spot.
import sys
import win32com.server.util
from win32com.server.exception import Exception
import winerror
import win32api
import os
try:
os.environ["DEBUG_AXDEBUG"]
debugging = 1
except KeyError:
debugging = 0
def trace(*args):
if not debugging: return
print(str(win32api.GetCurrentThreadId()) + ":", end=' ')
for arg in args:
print(arg, end=' ')
print()
# The AXDebugging implementation assumes that the returned COM pointers are in
# some cases identical. Eg, from a C++ perspective:
# p->GetSomeInterface( &p1 );
# p->GetSomeInterface( &p2 );
# p1==p2
# By default, this is _not_ true for Python.
# (Now this is only true for Document objects, and Python
# now does ensure this.
all_wrapped = {}
def _wrap_nodebug(object, iid):
return win32com.server.util.wrap(object, iid)
def _wrap_debug(object, iid):
import win32com.server.policy
dispatcher = win32com.server.policy.DispatcherWin32trace
return win32com.server.util.wrap(object, iid, useDispatcher = dispatcher)
if debugging:
_wrap = _wrap_debug
else:
_wrap = _wrap_nodebug
def _wrap_remove(object, iid = None):
# Old - no longer used or necessary!
return
def _dump_wrapped():
from win32com.server.util import unwrap
print("Wrapped items:")
for key, items in all_wrapped.items():
print(key, end=' ')
try:
ob = unwrap(key)
print(ob, sys.getrefcount(ob))
except:
print("<error>")
def RaiseNotImpl(who = None):
if who is not None:
print("********* Function %s Raising E_NOTIMPL ************" % (who))
# Print a sort-of "traceback", dumping all the frames leading to here.
try:
1/0
except:
frame = sys.exc_info()[2].tb_frame
while frame:
print("File: %s, Line: %d" % (frame.f_code.co_filename, frame.f_lineno))
frame = frame.f_back
# and raise the exception for COM
raise Exception(scode=winerror.E_NOTIMPL)
import win32com.server.policy
class Dispatcher(win32com.server.policy.DispatcherWin32trace):
def __init__(self, policyClass, object):
win32com.server.policy.DispatcherTrace.__init__(self, policyClass, object)
import win32traceutil # Sets up everything.
# print "Object with win32trace dispatcher created (object=%s)" % `object`
def _QueryInterface_(self, iid):
rc = win32com.server.policy.DispatcherBase._QueryInterface_(self, iid)
# if not rc:
# self._trace_("in _QueryInterface_ with unsupported IID %s (%s)\n" % (IIDToInterfaceName(iid),iid))
return rc
def _Invoke_(self, dispid, lcid, wFlags, args):
print("In Invoke with", dispid, lcid, wFlags, args, "with object",self.policy._obj_)
try:
rc = win32com.server.policy.DispatcherBase._Invoke_(self, dispid, lcid, wFlags, args)
# print "Invoke of", dispid, "returning", rc
return rc
except Exception:
t, v, tb = sys.exc_info()
tb = None # A cycle
scode = v.scode
try:
desc = " (" + str(v.description) + ")"
except AttributeError:
desc = ""
print("*** Invoke of %s raised COM exception 0x%x%s" % (dispid, scode, desc))
except:
print("*** Invoke of %s failed:" % dispid)
typ, val, tb = sys.exc_info()
import traceback
traceback.print_exception(typ, val, tb)
raise