def test_stdinCache_find(self): stdinCache = StdinCache.StdinCache() stdinCache.refreshFromText( dedentAndStrip(""" x+y z+h def f(): def g(): return 10 return g """)) e1 = compile(ast.parse("x+y"), "<stdin>", 'exec') e2 = compile(ast.parse("z+h"), "<stdin>", 'exec') self.assertEqual(stdinCache.findCodeLineNumberWithinStdin(e1), 0) self.assertEqual(stdinCache.findCodeLineNumberWithinStdin(e2), 2) def f(): def g(): return 10 return g g = f() self.assertEqual(stdinCache.findCodeLineNumberWithinStdin(f.func_code), 4) self.assertEqual(stdinCache.findCodeLineNumberWithinStdin(g.func_code), 5)
def test_stdinCache_trailing_backslash(self): stdinCache = StdinCache.StdinCache() stdinCache.refreshFromText( dedentAndStrip(""" x+\ y """)) self.assertEqual(len(stdinCache.blocks), 1)
def test_stdinCache(self): stdinCache = StdinCache.StdinCache() stdinCache.refreshFromText( dedentAndStrip(""" x y """)) self.assertEqual(len(stdinCache.blocks), 2)
def getframeinfo(frame, context=1): """Get information about a frame or traceback object. A tuple of five things is returned: the filename, the line number of the current line, the function name, a list of lines of context from the source code, and the index of the current line within that list. The optional second argument specifies the number of lines of context to return, which are centered around the current line.""" if istraceback(frame): lineno = frame.tb_lineno frame = frame.tb_frame else: lineno = frame.f_lineno if not isframe(frame): raise TypeError( '{!r} is not a frame or traceback object'.format(frame)) filename = getsourcefile(frame) or getfile(frame) lines = None if filename == "<stdin>": lineno = StdinCache.singleton().refreshFromReadline( ).findCodeLineNumberWithinStdin(frame.f_code) + 1 lines = StdinCache.singleton().getlines() if context > 0: start = lineno - 1 - context // 2 try: if lines is None: lines, _ = findsource(frame) except IOError: if lines is None: lines = index = None else: start = max(start, 1) start = max(0, min(start, len(lines) - context)) lines = lines[start:start + context] index = lineno - 1 - start else: lines = index = None return Traceback(filename, lineno, frame.f_code.co_name, lines, index)
def getframeinfo(frame, context=1): """Get information about a frame or traceback object. A tuple of five things is returned: the filename, the line number of the current line, the function name, a list of lines of context from the source code, and the index of the current line within that list. The optional second argument specifies the number of lines of context to return, which are centered around the current line.""" if istraceback(frame): lineno = frame.tb_lineno frame = frame.tb_frame else: lineno = frame.f_lineno if not isframe(frame): raise TypeError('{!r} is not a frame or traceback object'.format(frame)) filename = getsourcefile(frame) or getfile(frame) lines = None if filename == "<stdin>": lineno = StdinCache.singleton().refreshFromReadline().findCodeLineNumberWithinStdin(frame.f_code) + 1 lines = StdinCache.singleton().getlines() if context > 0: start = lineno - 1 - context//2 try: if lines is None: lines, _ = findsource(frame) except IOError: if lines is None: lines = index = None else: start = max(start, 1) start = max(0, min(start, len(lines) - context)) lines = lines[start:start+context] index = lineno - 1 - start else: lines = index = None return Traceback(filename, lineno, frame.f_code.co_name, lines, index)
def test_stdinCache_2(self): stdinCache = StdinCache.StdinCache() stdinCache.refreshFromText( dedentAndStrip(""" def f(arg): if arg: x.y = 3 return x f() """)) self.assertEqual(len(stdinCache.blocks), 3, stdinCache.blocks) self.assertEqual(len(stdinCache.blocks[0]), 4)
def getlines(path): """return a list of lines for a given path. This override is also careful to map "<stdin>" to the full contents of the readline buffer. """ if path == "<stdin>": return StdinCache.singleton().refreshFromReadline().getlines() if path in linesCache_: return linesCache_[path] if path not in pathExistsOnDiskCache_: pathExistsOnDiskCache_[path] = os.path.exists(path) if pathExistsOnDiskCache_[path]: with open(path, "r") as f: linesCache_[path] = f.readlines() return linesCache_[path] else: return None
def findsource(pyObject): """Return the entire source file and starting line number for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a list of all the lines in the file and the line number indexes a line in that list. An IOError is raised if the source code cannot be retrieved.""" pyFile = getfile(pyObject) sourcefile = getsourcefile(pyObject) if not sourcefile and pyFile[:1] + pyFile[-1:] != '<>': raise IOError('source code not available') pyFile = sourcefile if sourcefile else file module = getmodule(pyObject, pyFile) lines = getlines(pyFile) if not lines: raise IOError('could not get source code') if ismodule(pyObject): return lines, 0 if isclass(pyObject): name = pyObject.__name__ pat = re.compile(r'^(\s*)class\s*' + name + r'\b') # find all matching class definitions and if more than one # is found, raise a PyforaInspectError candidates = [] for i in range(len(lines)): match = pat.match(lines[i]) if match: # add to candidate list candidates.append(i) if not candidates: raise IOError('could not find class definition for %s' % pyObject) elif len(candidates) > 1: raise PyforaInspectError('could not find class unequivocally: class ' + name) else: return lines, candidates[0] if ismethod(pyObject): pyObject = pyObject.im_func if isfunction(pyObject): pyObject = pyObject.func_code if istraceback(pyObject): pyObject = pyObject.tb_frame if isframe(pyObject): pyObject = pyObject.f_code if iscode(pyObject): if pyFile == "<stdin>": #the "co_firstlineno" variable is wrong in this case. #we need to find the actual line number lnum = StdinCache.singleton().refreshFromReadline().findCodeLineNumberWithinStdin(pyObject) else: if not hasattr(pyObject, 'co_firstlineno'): raise IOError('could not find function definition') lnum = pyObject.co_firstlineno - 1 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)') while lnum > 0: if pat.match(lines[lnum]): break lnum = lnum - 1 return lines, lnum raise IOError('could not find code object')