# -*- coding: utf-8 -*- """ werkzeug.debug.tbtools ~~~~~~~~~~~~~~~~~~~~~~ This module provides various traceback related utility functions. :copyright: (c) 2010 by the Werkzeug Team, see AUTHORS for more details. :license: BSD. """ import re import os import sys import inspect import traceback import codecs from tokenize import TokenError from werkzeug.utils import cached_property from werkzeug.debug.console import Console from werkzeug.debug.utils import render_template _coding_re = re.compile(r'coding[:=]\s*([-\w.]+)') _line_re = re.compile(r'^(.*?)$(?m)') _funcdef_re = re.compile(r'^(\s*def\s)|(.*(? 0: if _funcdef_re.match(lines[lineno].code): break lineno -= 1 try: offset = len(inspect.getblock([x.code + '\n' for x in lines[lineno:]])) except TokenError: offset = 0 for line in lines[lineno:lineno + offset]: line.in_frame = True # mark current line try: lines[self.lineno - 1].current = True except IndexError: pass return render_template('source.html', frame=self, lines=lines) def eval(self, code, mode='single'): """Evaluate code in the context of the frame.""" if isinstance(code, basestring): if isinstance(code, unicode): code = UTF8_COOKIE + code.encode('utf-8') code = compile(code, '', mode) if mode != 'exec': return eval(code, self.globals, self.locals) exec code in self.globals, self.locals @cached_property def sourcelines(self): """The sourcecode of the file as list of unicode strings.""" # get sourcecode from loader or file source = None if self.loader is not None: try: if hasattr(self.loader, 'get_source'): source = self.loader.get_source(self.module) elif hasattr(self.loader, 'get_source_by_code'): source = self.loader.get_source_by_code(self.code) except: # we munch the exception so that we don't cause troubles # if the loader is broken. pass if source is None: try: f = file(self.filename) except IOError: return [] try: source = f.read() finally: f.close() # already unicode? return right away if isinstance(source, unicode): return source.splitlines() # yes. it should be ascii, but we don't want to reject too many # characters in the debugger if something breaks charset = 'utf-8' if source.startswith(UTF8_COOKIE): source = source[3:] else: for idx, match in enumerate(_line_re.finditer(source)): match = _line_re.search(match.group()) if match is not None: charset = match.group(1) break if idx > 1: break # on broken cookies we fall back to utf-8 too try: codecs.lookup(charset) except LookupError: charset = 'utf-8' return source.decode(charset, 'replace').splitlines() @property def current_line(self): try: return self.sourcelines[self.lineno - 1] except IndexError: return u'' @cached_property def console(self): return Console(self.globals, self.locals) id = property(lambda x: id(x))