|
@@ -0,0 +1,530 @@
|
|
|
|
|
+
|
|
|
|
|
+import inspect
|
|
|
|
|
+import pdb
|
|
|
|
|
+import sys
|
|
|
|
|
+
|
|
|
|
|
+#Bpdb - breakpoint debugging system (kanpatel - 04/2010)
|
|
|
|
|
+class BpMan:
|
|
|
|
|
+ def __init__(self):
|
|
|
|
|
+ self.bpInfos = {}
|
|
|
|
|
+
|
|
|
|
|
+ def partsToPath(self, parts):
|
|
|
|
|
+ cfg = parts.get('cfg')
|
|
|
|
|
+ grp = parts.get('grp')
|
|
|
|
|
+ id = parts.get('id','*')
|
|
|
|
|
+ path = ''
|
|
|
|
|
+ if cfg:
|
|
|
|
|
+ path += '%s'%(cfg,)
|
|
|
|
|
+ if grp or id:
|
|
|
|
|
+ path += '::'
|
|
|
|
|
+ if grp:
|
|
|
|
|
+ path += '%s'%(grp,)
|
|
|
|
|
+ if isinstance(id, int):
|
|
|
|
|
+ path += '(%s)'%(id,)
|
|
|
|
|
+ elif grp:
|
|
|
|
|
+ path += '.%s'%(id,)
|
|
|
|
|
+ else:
|
|
|
|
|
+ path += '%s'%(id,)
|
|
|
|
|
+ return path
|
|
|
|
|
+
|
|
|
|
|
+ def pathToParts(self, path=None):
|
|
|
|
|
+ parts = {'cfg':None, 'grp':None, 'id':None}
|
|
|
|
|
+
|
|
|
|
|
+ #verify input
|
|
|
|
|
+ if not isinstance(path, type('')):
|
|
|
|
|
+ assert not "error: argument must be string of form '[cfg::][grp.]id'"
|
|
|
|
|
+ return parts
|
|
|
|
|
+
|
|
|
|
|
+ #parse cfg
|
|
|
|
|
+ tokens = path.split('::')
|
|
|
|
|
+ if (len(tokens) > 1) and (len(tokens[0]) > 0):
|
|
|
|
|
+ parts['cfg'] = tokens[0]
|
|
|
|
|
+ path = tokens[1]
|
|
|
|
|
+
|
|
|
|
|
+ #parse grp
|
|
|
|
|
+ tokens = path.split('.')
|
|
|
|
|
+ if (len(tokens) > 1) and (len(tokens[0]) > 0):
|
|
|
|
|
+ parts['grp'] = tokens[0]
|
|
|
|
|
+ path = tokens[1]
|
|
|
|
|
+
|
|
|
|
|
+ #parse id
|
|
|
|
|
+ if (len(path) > 0):
|
|
|
|
|
+ parts['id'] = path
|
|
|
|
|
+ if parts['id'] == '*':
|
|
|
|
|
+ parts['id'] = None
|
|
|
|
|
+
|
|
|
|
|
+ #done
|
|
|
|
|
+ return parts
|
|
|
|
|
+
|
|
|
|
|
+ def bpToPath(self, bp):
|
|
|
|
|
+ if type(bp) is type(''):
|
|
|
|
|
+ bp = self.pathToParts(bp)
|
|
|
|
|
+ return self.partsToPath(bp)
|
|
|
|
|
+
|
|
|
|
|
+ def bpToParts(self, bp):
|
|
|
|
|
+ if type(bp) is type({}):
|
|
|
|
|
+ bp = self.partsToPath(bp)
|
|
|
|
|
+ return self.pathToParts(bp)
|
|
|
|
|
+
|
|
|
|
|
+ def makeBpInfo(self, grp, id):
|
|
|
|
|
+ self.bpInfos.setdefault(grp, {None:{},})
|
|
|
|
|
+ self.bpInfos[grp].setdefault(id, {})
|
|
|
|
|
+
|
|
|
|
|
+ def getEnabled(self, bp):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(parts['grp'], parts['id'])
|
|
|
|
|
+ if not self.bpInfos[grp][None].get('enabled', True):
|
|
|
|
|
+ return False
|
|
|
|
|
+ if not self.bpInfos[grp][id].get('enabled', True):
|
|
|
|
|
+ return False
|
|
|
|
|
+ return True
|
|
|
|
|
+
|
|
|
|
|
+ def setEnabled(self, bp, enabled=True):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ self.bpInfos[grp][id]['enabled'] = enabled
|
|
|
|
|
+ return enabled
|
|
|
|
|
+
|
|
|
|
|
+ def toggleEnabled(self, bp):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ newEnabled = not self.bpInfos[grp][id].get('enabled', True)
|
|
|
|
|
+ self.bpInfos[grp][id]['enabled'] = newEnabled
|
|
|
|
|
+ return newEnabled
|
|
|
|
|
+
|
|
|
|
|
+ def getIgnoreCount(self, bp, decrement=False):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ ignoreCount = self.bpInfos[grp][id].get('ignoreCount', 0)
|
|
|
|
|
+ if ignoreCount > 0 and decrement:
|
|
|
|
|
+ self.bpInfos[grp][id]['ignoreCount'] = ignoreCount - 1
|
|
|
|
|
+ return ignoreCount
|
|
|
|
|
+
|
|
|
|
|
+ def setIgnoreCount(self, bp, ignoreCount=0):
|
|
|
|
|
+ if not isinstance(ignoreCount, int):
|
|
|
|
|
+ print 'error: first argument should be integer ignoreCount'
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ self.bpInfos[grp][id]['ignoreCount'] = ignoreCount
|
|
|
|
|
+ return ignoreCount
|
|
|
|
|
+
|
|
|
|
|
+ def getLifetime(self, bp):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ lifetime = self.bpInfos[grp][id].get('lifetime', -1)
|
|
|
|
|
+ return lifetime
|
|
|
|
|
+
|
|
|
|
|
+ def setLifetime(self, bp, newLifetime):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ self.bpInfos[grp][id]['lifetime'] = newLifetime
|
|
|
|
|
+ return lifetime
|
|
|
|
|
+
|
|
|
|
|
+ def decLifetime(self, bp):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ lifetime = self.bpInfos[grp][id].get('lifetime', -1)
|
|
|
|
|
+ if lifetime > 0:
|
|
|
|
|
+ lifetime = lifetime - 1
|
|
|
|
|
+ self.bpInfos[grp][id]['lifetime'] = lifetime
|
|
|
|
|
+ return lifetime
|
|
|
|
|
+
|
|
|
|
|
+ def getHitCount(self, bp):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ return self.bpInfos[grp][id].get('count', 0)
|
|
|
|
|
+
|
|
|
|
|
+ def setHitCount(self, bp, newHitCount):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ self.bpInfos[grp][id]['count'] = newHitCount
|
|
|
|
|
+
|
|
|
|
|
+ def incHitCount(self, bp):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ self.bpInfos[grp][id]['count'] = self.bpInfos[grp][id].get('count', 0) + 1
|
|
|
|
|
+
|
|
|
|
|
+ def resetBp(self, bp):
|
|
|
|
|
+ parts = self.bpToParts(bp)
|
|
|
|
|
+ grp, id = parts['grp'], parts['id']
|
|
|
|
|
+ self.makeBpInfo(grp, id)
|
|
|
|
|
+ self.bpInfos[grp][id] = {}
|
|
|
|
|
+ if id is None:
|
|
|
|
|
+ del self.bpInfos[grp]
|
|
|
|
|
+
|
|
|
|
|
+class BpDb:
|
|
|
|
|
+ def __init__(self):
|
|
|
|
|
+ self.enabled = True
|
|
|
|
|
+ self.cfgInfos = { None:True }
|
|
|
|
|
+ self.codeInfoCache = {}
|
|
|
|
|
+ self.bpMan = BpMan()
|
|
|
|
|
+ self.lastBp = None
|
|
|
|
|
+ self.pdbAliases = {}
|
|
|
|
|
+ self.configCallback = None
|
|
|
|
|
+
|
|
|
|
|
+ def setEnabledCallback(self, callback):
|
|
|
|
|
+ self.enabledCallback = callback
|
|
|
|
|
+
|
|
|
|
|
+ def verifyEnabled(self):
|
|
|
|
|
+ if self.enabledCallback:
|
|
|
|
|
+ return self.enabledCallback()
|
|
|
|
|
+ return True
|
|
|
|
|
+
|
|
|
|
|
+ def setConfigCallback(self, callback):
|
|
|
|
|
+ self.configCallback = callback
|
|
|
|
|
+
|
|
|
|
|
+ def verifySingleConfig(self, cfg):
|
|
|
|
|
+ if cfg not in self.cfgInfos:
|
|
|
|
|
+ self.cfgInfos[cfg] = not self.configCallback or self.configCallback(cfg)
|
|
|
|
|
+ return self.cfgInfos[cfg]
|
|
|
|
|
+
|
|
|
|
|
+ def verifyConfig(self, cfg):
|
|
|
|
|
+ cfgList = choice(isinstance(cfg, tuple), cfg, (cfg,))
|
|
|
|
|
+ passedCfgs = [c for c in cfgList if self.verifySingleConfig(c)]
|
|
|
|
|
+ return (len(passedCfgs) > 0)
|
|
|
|
|
+
|
|
|
|
|
+ def toggleConfig(self, cfg):
|
|
|
|
|
+ newEnabled = not self.verifyConfig(cfg)
|
|
|
|
|
+ self.cfgInfos[cfg] = newEnabled
|
|
|
|
|
+ return self.cfgInfos[cfg]
|
|
|
|
|
+
|
|
|
|
|
+ def resetConfig(self, cfg):
|
|
|
|
|
+ self.cfgInfos.pop(cfg, None)
|
|
|
|
|
+
|
|
|
|
|
+ #setup bpdb prompt commands
|
|
|
|
|
+ def displayHelp(self):
|
|
|
|
|
+ print 'You may use normal pdb commands plus the following:'
|
|
|
|
|
+ #print ' cmd [param <def>] [cmd] does )this( with [param] (default is def)'
|
|
|
|
|
+ #print ' -----------------------------------------------------------------------'
|
|
|
|
|
+ print ' _i [n <0> [, path=<curr>]] set ignore count for bp [path] to [n]'
|
|
|
|
|
+ print ' _t [path <curr>] toggle bp [path]'
|
|
|
|
|
+ print ' _tg [grp <curr>] toggle grp'
|
|
|
|
|
+ print ' _tc [cfg <curr>] toggle cfg'
|
|
|
|
|
+ print ' _z [path <curr>] clear all settings for bp [path]'
|
|
|
|
|
+ print ' _zg [grp <curr>] clear all settings for grp'
|
|
|
|
|
+ print ' _zc [cfg <curr>] clear all settings for cfg (restore .prc setting)'
|
|
|
|
|
+ print ' _h displays this usage help'
|
|
|
|
|
+ print ' _ua unalias these commands from pdb'
|
|
|
|
|
+
|
|
|
|
|
+ def addPdbAliases(self):
|
|
|
|
|
+ self.makePdbAlias('_i', 'bpdb._i(%*)')
|
|
|
|
|
+ self.makePdbAlias('_t', 'bpdb._t(%*)')
|
|
|
|
|
+ self.makePdbAlias('_tg', 'bpdb._tg(%*)')
|
|
|
|
|
+ self.makePdbAlias('_tc', 'bpdb._tc(%*)')
|
|
|
|
|
+ self.makePdbAlias('_z', 'bpdb._z(%*)')
|
|
|
|
|
+ self.makePdbAlias('_zg', 'bpdb._zg(%*)')
|
|
|
|
|
+ self.makePdbAlias('_zc', 'bpdb._zc(%*)')
|
|
|
|
|
+ self.makePdbAlias('_h', 'bpdb.displayHelp()')
|
|
|
|
|
+ self.makePdbAlias('_ua', 'bpdb.removePdbAliases()')
|
|
|
|
|
+
|
|
|
|
|
+ def makePdbAlias(self, aliasName, aliasCmd):
|
|
|
|
|
+ self.pdbAliases[aliasName] = aliasCmd
|
|
|
|
|
+ self.pdb.do_alias('%s %s'%(aliasName,aliasCmd))
|
|
|
|
|
+
|
|
|
|
|
+ def removePdbAliases(self):
|
|
|
|
|
+ for aliasName in self.pdbAliases.iterkeys():
|
|
|
|
|
+ self.pdb.do_unalias(aliasName)
|
|
|
|
|
+ self.pdbAliases = {}
|
|
|
|
|
+ print '(bpdb aliases removed)'
|
|
|
|
|
+
|
|
|
|
|
+ #handle bpdb prompt commands by forwarding to bpMan
|
|
|
|
|
+ def _e(self, *args, **kwargs):
|
|
|
|
|
+ bp = self._getArg(args, [type(''),type({}),], kwargs, ['path','bp','name',], self.lastBp)
|
|
|
|
|
+ enabled = self._getArg(args, [type(True),type(1),], kwargs, ['enabled','on',], True)
|
|
|
|
|
+ newEnabled = self.bpMan.setEnabled(bp, enabled)
|
|
|
|
|
+ print "'%s' is now %s."%(self.bpMan.bpToPath(bp),choice(newEnabled,'enabled','disabled'),)
|
|
|
|
|
+
|
|
|
|
|
+ def _i(self, *args, **kwargs):
|
|
|
|
|
+ bp = self._getArg(args, [type(''),type({}),], kwargs, ['path','bp','name',], self.lastBp)
|
|
|
|
|
+ count = self._getArg(args, [type(1),], kwargs, ['ignoreCount','count','n',], 0)
|
|
|
|
|
+ newCount = self.bpMan.setIgnoreCount(bp, count)
|
|
|
|
|
+ print "'%s' will ignored %s times."%(self.bpMan.bpToPath(bp),newCount,)
|
|
|
|
|
+
|
|
|
|
|
+ def _t(self, *args, **kwargs):
|
|
|
|
|
+ bp = self._getArg(args, [type(''),type({}),], kwargs, ['path','bp','name',], self.lastBp)
|
|
|
|
|
+ newEnabled = self.bpMan.toggleEnabled(bp)
|
|
|
|
|
+ print "'%s' is now %s."%(self.bpMan.bpToPath(bp),choice(newEnabled,'enabled','disabled'),)
|
|
|
|
|
+
|
|
|
|
|
+ def _tg(self, *args, **kwargs):
|
|
|
|
|
+ bp = self._getArg(args, [type(''),type({}),], kwargs, ['grp',], self.lastBp)
|
|
|
|
|
+ if type(bp) == type(''):
|
|
|
|
|
+ bp = {'grp':bp}
|
|
|
|
|
+ bp = {'grp':bp.get('grp')}
|
|
|
|
|
+ newEnabled = self.bpMan.toggleEnabled(bp)
|
|
|
|
|
+ print "'%s' is now %s."%(self.bpMan.bpToPath(bp),choice(newEnabled,'enabled','disabled'),)
|
|
|
|
|
+
|
|
|
|
|
+ def _tc(self, *args, **kwargs):
|
|
|
|
|
+ bp = self._getArg(args, [type(''),type({}),], kwargs, ['cfg',], self.lastBp)
|
|
|
|
|
+ if type(bp) == type(''):
|
|
|
|
|
+ bp = {'cfg':bp}
|
|
|
|
|
+ bp = {'cfg':bp.get('cfg')}
|
|
|
|
|
+ newEnabled = self.toggleConfig(bp['cfg'])
|
|
|
|
|
+ print "'%s' is now %s."%(self.bpMan.bpToPath(bp),choice(newEnabled,'enabled','disabled'),)
|
|
|
|
|
+
|
|
|
|
|
+ def _z(self, *args, **kwargs):
|
|
|
|
|
+ bp = self._getArg(args, [type(''),type({}),], kwargs, ['path','bp','name',], self.lastBp)
|
|
|
|
|
+ self.bpMan.resetBp(bp)
|
|
|
|
|
+ print "'%s' has been reset."%(self.bpMan.partsToPath(bp),)
|
|
|
|
|
+
|
|
|
|
|
+ def _zg(self, *args, **kwargs):
|
|
|
|
|
+ bp = self._getArg(args, [type(''),type({}),], kwargs, ['grp',], self.lastBp)
|
|
|
|
|
+ if type(bp) == type(''):
|
|
|
|
|
+ bp = {'grp':bp}
|
|
|
|
|
+ bp = {'grp':bp.get('grp')}
|
|
|
|
|
+ self.bpMan.resetBp(bp)
|
|
|
|
|
+ print "'%s' has been reset."%(self.bpMan.partsToPath(bp),)
|
|
|
|
|
+
|
|
|
|
|
+ def _zc(self, *args, **kwargs):
|
|
|
|
|
+ bp = self._getArg(args, [type(''),type({}),], kwargs, ['cfg',], self.lastBp)
|
|
|
|
|
+ if type(bp) == type(''):
|
|
|
|
|
+ bp = {'cfg':bp}
|
|
|
|
|
+ bp = {'cfg':bp.get('cfg')}
|
|
|
|
|
+ self.resetConfig(bp['cfg'])
|
|
|
|
|
+ print "'%s' has been reset."%(self.bpMan.bpToPath(bp),)
|
|
|
|
|
+
|
|
|
|
|
+ def _getArg(self, args, goodTypes, kwargs, goodKeys, default = None):
|
|
|
|
|
+ #look for desired arg in args and kwargs lists
|
|
|
|
|
+ argVal = default
|
|
|
|
|
+ for val in args:
|
|
|
|
|
+ if type(val) in goodTypes:
|
|
|
|
|
+ argVal = val
|
|
|
|
|
+ for key in goodKeys:
|
|
|
|
|
+ if key in kwargs:
|
|
|
|
|
+ argVal = kwargs[key]
|
|
|
|
|
+ return argVal
|
|
|
|
|
+
|
|
|
|
|
+ #code for automatically determining param vals
|
|
|
|
|
+ def getFrameCodeInfo(self, frameCount=1):
|
|
|
|
|
+ #get main bits
|
|
|
|
|
+ stack = inspect.stack()
|
|
|
|
|
+ primaryFrame = stack[frameCount][0]
|
|
|
|
|
+
|
|
|
|
|
+ #todo:
|
|
|
|
|
+ #frameInfo is inadequate as a unique marker for this code location
|
|
|
|
|
+ #caching disabled until suitable replacement is found
|
|
|
|
|
+ #
|
|
|
|
|
+ #frameInfo = inspect.getframeinfo(primaryFrame)
|
|
|
|
|
+ #frameInfo = (frameInfo[0], frameInfo[1])
|
|
|
|
|
+ #check cache
|
|
|
|
|
+ #codeInfo = self.codeInfoCache.get(frameInfo)
|
|
|
|
|
+ #if codeInfo:
|
|
|
|
|
+ # return codeInfo
|
|
|
|
|
+
|
|
|
|
|
+ #look for module name
|
|
|
|
|
+ moduleName = None
|
|
|
|
|
+ callingModule = inspect.getmodule(primaryFrame)
|
|
|
|
|
+ if callingModule and callingModule.__name__ != '__main__':
|
|
|
|
|
+ moduleName = callingModule.__name__.split()[-1] #get only leaf module name
|
|
|
|
|
+
|
|
|
|
|
+ #look for class name
|
|
|
|
|
+ className = None
|
|
|
|
|
+ for i in range(frameCount, len(stack)):
|
|
|
|
|
+ callingContexts = stack[i][4]
|
|
|
|
|
+ if callingContexts:
|
|
|
|
|
+ contextTokens = callingContexts[0].split()
|
|
|
|
|
+ if contextTokens[0] in ['class','def'] and len(contextTokens) > 1:
|
|
|
|
|
+ callingContexts[0] = callingContexts[0].replace('(',' ').replace(':',' ')
|
|
|
|
|
+ contextTokens = callingContexts[0].split()
|
|
|
|
|
+ className = contextTokens[1]
|
|
|
|
|
+ break
|
|
|
|
|
+ if className is None:
|
|
|
|
|
+ #look for self (this functions inappropriately for inherited classes)
|
|
|
|
|
+ slf = primaryFrame.f_locals.get('self')
|
|
|
|
|
+ try:
|
|
|
|
|
+ if slf:
|
|
|
|
|
+ className = slf.__class__.__name__
|
|
|
|
|
+ except:
|
|
|
|
|
+ #in __init__ 'self' exists but 'if slf' will crash
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ #get line number
|
|
|
|
|
+ def byteOffsetToLineno(code, byte):
|
|
|
|
|
+ # Returns the source line number corresponding to the given byte
|
|
|
|
|
+ # offset into the indicated Python code module.
|
|
|
|
|
+ import array
|
|
|
|
|
+ lnotab = array.array('B', code.co_lnotab)
|
|
|
|
|
+ line = code.co_firstlineno
|
|
|
|
|
+ for i in range(0, len(lnotab), 2):
|
|
|
|
|
+ byte -= lnotab[i]
|
|
|
|
|
+ if byte <= 0:
|
|
|
|
|
+ return line
|
|
|
|
|
+ line += lnotab[i+1]
|
|
|
|
|
+ return line
|
|
|
|
|
+
|
|
|
|
|
+ lineNumber = byteOffsetToLineno(primaryFrame.f_code, primaryFrame.f_lasti)
|
|
|
|
|
+ #frame = inspect.stack()[frameCount][0]
|
|
|
|
|
+ #lineno = byteOffsetToLineno(frame.f_code, frame.f_lasti)
|
|
|
|
|
+
|
|
|
|
|
+ codeInfo = (moduleName, className, lineNumber)
|
|
|
|
|
+ #self.codeInfoCache[frameInfo] = codeInfo
|
|
|
|
|
+ return codeInfo
|
|
|
|
|
+
|
|
|
|
|
+ #actually deliver the user a prompt
|
|
|
|
|
+ def set_trace(self, bp, frameCount=1):
|
|
|
|
|
+ #find useful frame
|
|
|
|
|
+ self.currFrame = sys._getframe()
|
|
|
|
|
+ interactFrame = self.currFrame
|
|
|
|
|
+ while frameCount > 0:
|
|
|
|
|
+ interactFrame = interactFrame.f_back
|
|
|
|
|
+ frameCount -= 1
|
|
|
|
|
+
|
|
|
|
|
+ #cache this as the latest bp
|
|
|
|
|
+ self.lastBp = bp.getParts()
|
|
|
|
|
+ #set up and start debuggger
|
|
|
|
|
+ self.pdb = pdb.Pdb()
|
|
|
|
|
+ #self.pdb.do_alias('aa bpdb.addPdbAliases()')
|
|
|
|
|
+ self.addPdbAliases()
|
|
|
|
|
+ self.pdb.set_trace(interactFrame);
|
|
|
|
|
+
|
|
|
|
|
+ #bp invoke methods
|
|
|
|
|
+ def bp(self, id=None, grp=None, cfg=None, iff=True, enabled=True, test=None, frameCount=1):
|
|
|
|
|
+ if not (self.enabled and self.verifyEnabled()):
|
|
|
|
|
+ return
|
|
|
|
|
+ if not (enabled and iff):
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ bpi = bp(id=id, grp=grp, cfg=cfg, frameCount=frameCount+1)
|
|
|
|
|
+ bpi.maybeBreak(test=test, frameCount=frameCount+1)
|
|
|
|
|
+
|
|
|
|
|
+ def bpCall(self,id=None,grp=None,cfg=None,iff=True,enabled=True,test=None,frameCount=1,onEnter=1,onExit=0):
|
|
|
|
|
+ def decorator(f):
|
|
|
|
|
+ return f
|
|
|
|
|
+
|
|
|
|
|
+ if not (self.enabled and self.verifyEnabled()):
|
|
|
|
|
+ return decorator
|
|
|
|
|
+ if not (enabled and iff):
|
|
|
|
|
+ return decorator
|
|
|
|
|
+
|
|
|
|
|
+ bpi = bp(id=id, grp=grp, cfg=cfg, frameCount=frameCount+1)
|
|
|
|
|
+ if bpi.disabled:
|
|
|
|
|
+ return decorator
|
|
|
|
|
+
|
|
|
|
|
+ def decorator(f):
|
|
|
|
|
+ def wrap(*args, **kwds):
|
|
|
|
|
+ #create our bp object
|
|
|
|
|
+ dbp = bp(id=id or f.__name__, grp=bpi.grp, cfg=bpi.cfg, frameCount=frameCount+1)
|
|
|
|
|
+ if onEnter:
|
|
|
|
|
+ dbp.maybeBreak(test=test,frameCount=frameCount+1,displayPrefix='Calling ')
|
|
|
|
|
+ f_result = f(*args, **kwds)
|
|
|
|
|
+ if onExit:
|
|
|
|
|
+ dbp.maybeBreak(test=test,frameCount=frameCount+1,displayPrefix='Exited ')
|
|
|
|
|
+ return f_result
|
|
|
|
|
+
|
|
|
|
|
+ wrap.func_name = f.func_name
|
|
|
|
|
+ wrap.func_dict = f.func_dict
|
|
|
|
|
+ wrap.func_doc = f.func_doc
|
|
|
|
|
+ wrap.__module__ = f.__module__
|
|
|
|
|
+ return wrap
|
|
|
|
|
+
|
|
|
|
|
+ return decorator
|
|
|
|
|
+
|
|
|
|
|
+ def bpPreset(self, *args, **kArgs):
|
|
|
|
|
+ def functor(*cArgs, **ckArgs):
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ if self.enabled and self.verifyEnabled():
|
|
|
|
|
+ argsCopy = args[:]
|
|
|
|
|
+ def functor(*cArgs, **ckArgs):
|
|
|
|
|
+ kwArgs = kArgs
|
|
|
|
|
+ kwArgs.update(ckArgs)
|
|
|
|
|
+ kwArgs.pop('static', None)
|
|
|
|
|
+ kwArgs['frameCount'] = ckArgs.get('frameCount',1)+1
|
|
|
|
|
+ return self.bp(*(cArgs), **kwArgs)
|
|
|
|
|
+
|
|
|
|
|
+ if kArgs.get('static'):
|
|
|
|
|
+ return staticmethod(functor)
|
|
|
|
|
+ else:
|
|
|
|
|
+ return functor
|
|
|
|
|
+
|
|
|
|
|
+ #deprecated:
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def bpGroup(*args, **kArgs):
|
|
|
|
|
+ print "BpDb.bpGroup is deprecated, use bpdb.bpPreset instead"
|
|
|
|
|
+ return bpdb.bpPreset(*(args), **(kArgs))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class bp:
|
|
|
|
|
+ def __init__(self, id=None, grp=None, cfg=None, frameCount=1):
|
|
|
|
|
+ #check early out conditions
|
|
|
|
|
+ self.disabled = False
|
|
|
|
|
+ if not bpdb.enabled:
|
|
|
|
|
+ self.disabled = True
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ #default cfg, grp, id from calling code info
|
|
|
|
|
+ moduleName, className, lineNumber = bpdb.getFrameCodeInfo(frameCount=frameCount+1)
|
|
|
|
|
+ self.grp = grp or className or moduleName
|
|
|
|
|
+ self.id = id or lineNumber
|
|
|
|
|
+
|
|
|
|
|
+ #default cfg to stripped module name
|
|
|
|
|
+ if cfg is None and moduleName:
|
|
|
|
|
+ cfg = moduleName
|
|
|
|
|
+ if cfg.find("Distributed") != -1: #prune leading 'Distributed'
|
|
|
|
|
+ cfg = cfg[len("Distributed"):]
|
|
|
|
|
+
|
|
|
|
|
+ # check cfgs
|
|
|
|
|
+ self.cfg = cfg
|
|
|
|
|
+ if not bpdb.verifyConfig(self.cfg):
|
|
|
|
|
+ self.disabled = True
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ def getParts(self):
|
|
|
|
|
+ return {'id':self.id,'grp':self.grp,'cfg':self.cfg}
|
|
|
|
|
+
|
|
|
|
|
+ def displayContextHint(self, displayPrefix=''):
|
|
|
|
|
+ contextString = displayPrefix + bpdb.bpMan.partsToPath({'id':self.id,'grp':self.grp,'cfg':self.cfg})
|
|
|
|
|
+ dashes = '-'*max(0, (80 - len(contextString) - 4) / 2)
|
|
|
|
|
+ print '<%s %s %s>'%(dashes,contextString,dashes)
|
|
|
|
|
+
|
|
|
|
|
+ def maybeBreak(self, test=None, frameCount=1, displayPrefix=''):
|
|
|
|
|
+ if self.shouldBreak(test=test):
|
|
|
|
|
+ self.doBreak(frameCount=frameCount+1,displayPrefix=displayPrefix)
|
|
|
|
|
+
|
|
|
|
|
+ def shouldBreak(self, test=None):
|
|
|
|
|
+ #check easy early out
|
|
|
|
|
+ if self.disabled:
|
|
|
|
|
+ return False
|
|
|
|
|
+ if test:
|
|
|
|
|
+ if not isinstance(test, (list, tuple)):
|
|
|
|
|
+ test = (test,)
|
|
|
|
|
+ for atest in test:
|
|
|
|
|
+ if not atest():
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ #check disabled conditions
|
|
|
|
|
+ if not bpdb.bpMan.getEnabled({'grp':self.grp,'id':self.id}):
|
|
|
|
|
+ return False
|
|
|
|
|
+ if not bpdb.verifyConfig(self.cfg):
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ #check skip conditions
|
|
|
|
|
+ if bpdb.bpMan.getIgnoreCount({'grp':self.grp,'id':self.id},decrement=True):
|
|
|
|
|
+ return False
|
|
|
|
|
+ if bpdb.bpMan.getLifetime({'grp':self.grp,'id':self.id}) == 0:
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ #all conditions go
|
|
|
|
|
+ return True
|
|
|
|
|
+
|
|
|
|
|
+ def doBreak(self, frameCount=1,displayPrefix=''):
|
|
|
|
|
+ #accumulate hit count
|
|
|
|
|
+ bpdb.bpMan.decLifetime({'grp':self.grp,'id':self.id})
|
|
|
|
|
+ bpdb.bpMan.incHitCount({'grp':self.grp,'id':self.id})
|
|
|
|
|
+
|
|
|
|
|
+ #setup debugger
|
|
|
|
|
+ self.displayContextHint(displayPrefix=displayPrefix)
|
|
|
|
|
+ bpdb.set_trace(self, frameCount=frameCount+1)
|
|
|
|
|
+
|