import inspect import os.path import django import SocketServer import sys from django.conf import settings from django.views.debug import linebreak_iter from django.utils.html import escape from django.utils.safestring import mark_safe # Figure out some paths django_path = os.path.realpath(os.path.dirname(django.__file__)) socketserver_path = os.path.realpath(os.path.dirname(SocketServer.__file__)) def ms_from_timedelta(td): """ Given a timedelta object, returns a float representing milliseconds """ return (td.seconds * 1000) + (td.microseconds / 1000.0) hide_django_sql = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}).get('HIDE_DJANGO_SQL', True) def tidy_stacktrace(stack): """ Clean up stacktrace and remove all entries that: 1. Are part of Django (except contrib apps) 2. Are part of SocketServer (used by Django's dev server) 3. Are the last entry (which is part of our stacktracing code) ``stack`` should be a list of frame tuples from ``inspect.stack()`` """ trace = [] for frame, path, line_no, func_name, text in (f[:5] for f in stack): s_path = os.path.realpath(path) # Support hiding of frames -- used in various utilities that provide # inspection. if '__traceback_hide__' in frame.f_locals: continue if hide_django_sql and django_path in s_path and not 'django/contrib' in s_path: continue if socketserver_path in s_path: continue if not text: text = '' else: text = (''.join(text)).strip() trace.append((path, line_no, func_name, text)) return trace def render_stacktrace(trace): stacktrace = [] for frame in trace: params = map(escape, frame[0].rsplit(os.path.sep, 1) + list(frame[1:])) try: stacktrace.append(u'{0}/{1} in {3}({2})\n {4}'.format(*params)) except IndexError: # This frame doesn't have the expected format, so skip it and move on to the next one continue return mark_safe('\n'.join(stacktrace)) def get_template_info(source, context_lines=3): line = 0 upto = 0 source_lines = [] # before = during = after = "" origin, (start, end) = source template_source = origin.reload() for num, next in enumerate(linebreak_iter(template_source)): if start >= upto and end <= next: line = num # before = template_source[upto:start] # during = template_source[start:end] # after = template_source[end:next] source_lines.append((num, template_source[upto:next])) upto = next top = max(1, line - context_lines) bottom = min(len(source_lines), line + 1 + context_lines) context = [] for num, content in source_lines[top:bottom]: context.append({ 'num': num, 'content': content, 'highlight': (num == line), }) return { 'name': origin.name, 'context': context, } def get_name_from_obj(obj): if hasattr(obj, '__name__'): name = obj.__name__ elif hasattr(obj, '__class__') and hasattr(obj.__class__, '__name__'): name = obj.__class__.__name__ else: name = '' if hasattr(obj, '__module__'): module = obj.__module__ name = '%s.%s' % (module, name) return name 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. This originally comes from ``inspect`` but is modified to handle issues with ``findsource()``. """ if inspect.istraceback(frame): lineno = frame.tb_lineno frame = frame.tb_frame else: lineno = frame.f_lineno if not inspect.isframe(frame): raise TypeError('arg is not a frame or traceback object') filename = inspect.getsourcefile(frame) or inspect.getfile(frame) if context > 0: start = lineno - 1 - context // 2 try: lines, lnum = inspect.findsource(frame) except (IOError, IndexError): 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 if hasattr(inspect, 'Traceback'): return inspect.Traceback(filename, lineno, frame.f_code.co_name, lines, index) else: return (filename, lineno, frame.f_code.co_name, lines, index) def get_stack(context=1): """ Get a list of records for a frame and all higher (calling) frames. Each record contains a frame object, filename, line number, function name, a list of lines of context, and index within the context. Modified version of ``inspect.stack()`` which calls our own ``getframeinfo()`` """ frame = sys._getframe(1) framelist = [] while frame: framelist.append((frame,) + getframeinfo(frame, context)) frame = frame.f_back return framelist