Skip to content

Commit

Permalink
Merge pull request #318 from mmerickel/fix-tracebacks
Browse files Browse the repository at this point in the history
Fix tracebacks
  • Loading branch information
mmerickel committed Jun 21, 2017
2 parents e1265d4 + e7c9dcb commit 9f6448b
Show file tree
Hide file tree
Showing 15 changed files with 224 additions and 272 deletions.
20 changes: 14 additions & 6 deletions demo/demo.py
Expand Up @@ -36,10 +36,23 @@ def text_(s, encoding='latin-1', errors='strict'):

here = os.path.dirname(os.path.abspath(__file__))

@view_config(route_name='test_exc')
def exc(request):
raise RuntimeError

@view_config(route_name='test_squashed_exc')
def squashed_exc(request):
raise RuntimeError

@view_config(
route_name='test_squashed_exc',
context=RuntimeError,
renderer='notfound.mako',
)
def notfound_view(request):
request.response.status_code = 404
return {}

@view_config(route_name='test_notfound')
def notfound(request):
raise HTTPNotFound()
Expand All @@ -57,11 +70,6 @@ def notfound_view(request):
request.response.status_code = 404
return {}

@view_config(context=RuntimeError, renderer='notfound.mako')
def notfound_view(request):
request.response.status_code = 404
return {}

@view_config(renderer='index.mako') # found via traversal
def test_page(request):
title = 'Pyramid Debugtoolbar'
Expand Down Expand Up @@ -113,7 +121,7 @@ def make_app():
settings['debugtoolbar.reload_templates'] = True
settings['debugtoolbar.hosts'] = ['127.0.0.1']
settings['debugtoolbar.intercept_redirects'] = True
settings['debugtoolbar.exclude_prefixes'] = ['/static']
settings['debugtoolbar.exclude_prefixes'] = ['/static', '/favicon.ico']

# session factory
session_factory = SignedCookieSessionFactory('itsaseekreet')
Expand Down
16 changes: 4 additions & 12 deletions docs/index.rst
Expand Up @@ -124,16 +124,6 @@ file.
handler. Note that, for backwards compatibility purposes, the value
``true`` provided to this setting is interpreted as ``debug``.

``debugtoolbar.eval_exc``

``true`` if real-time exception debugging is enabled when
``intercept_exc`` is true; ``false`` if real-time exception debugging is
disabled. Default is ``true``. This differs from
``debugtoolbar.intercept_exc``: it only controls whether the pretty
exception rendering displays real-time in-browser debugging controls. The
real-time in-browser debugging controls allow you to evaluate arbitrary
Python expresssions in the context of a stack frame via a browser control.

``debugtoolbar.show_on_exc_only``

Default is ``false``. If set to ``true`` the debugtoolbar will only be
Expand Down Expand Up @@ -216,11 +206,13 @@ file.
by carriage returns. For example::

debugtoolbar.exclude_prefixes =
/favicon.ico
/settings
/static

If configuration is done via Python, the setting should be a list. This
setting was added in debugtoolbar version 1.0.4.
If configuration is done via Python, the setting should be a list.

By default, the setting is ``['/favicon.ico']``.

``debugtoolbar.active_panels``

Expand Down
2 changes: 1 addition & 1 deletion pyramid_debugtoolbar/__init__.py
Expand Up @@ -33,7 +33,7 @@
('global_panels', as_list, ()),
('extra_global_panels', as_list, ()),
('hosts', as_list, default_hosts),
('exclude_prefixes', as_cr_separated_list, ()),
('exclude_prefixes', as_cr_separated_list, ('/favicon.ico',)),
('active_panels', as_list, ()),
('includes', as_list, ()),
('button_style', None, ''),
Expand Down
9 changes: 4 additions & 5 deletions pyramid_debugtoolbar/panels/sqla.py
Expand Up @@ -9,7 +9,6 @@
from pyramid_debugtoolbar.compat import json
from pyramid_debugtoolbar.compat import url_quote
from pyramid_debugtoolbar.panels import DebugPanel
from pyramid_debugtoolbar.utils import find_request_history
from pyramid_debugtoolbar.utils import format_sql
from pyramid_debugtoolbar.utils import text_
from pyramid_debugtoolbar.utils import STATIC_PATH
Expand Down Expand Up @@ -67,7 +66,6 @@ def __init__(self, request):
self.engines = request.registry.pdtb_sqla_engines
else:
self.engines = request.registry.pdtb_sqla_engines = {}
self.token = request.registry.pdtb_token
self.pdtb_id = request.pdtb_id

@property
Expand Down Expand Up @@ -133,9 +131,10 @@ def __init__(self, request):

def find_query(self):
request_id = self.request.matchdict['request_id']
all_history = find_request_history(self.request)
history = all_history.get(request_id)
sqlapanel = [p for p in history.panels if p.name == 'sqlalchemy'][0]
toolbar = self.request.pdtb_history.get(request_id)
if toolbar is None:
raise HTTPBadRequest('No history found for request.')
sqlapanel = [p for p in toolbar.panels if p.name == 'sqlalchemy'][0]
query_index = int(self.request.matchdict['query_index'])
return sqlapanel.queries[query_index]

Expand Down
4 changes: 2 additions & 2 deletions pyramid_debugtoolbar/panels/templates/traceback.dbtmako
Expand Up @@ -67,8 +67,8 @@
-->

<script type="text/javascript">
var TRACEBACK = ${str(traceback_id)},
DEBUGGER_TOKEN = "${token}",
var DEBUGGER_TOKEN = "${pdtb_token}",
REQUEST_ID = "${request_id}",
CONSOLE_MODE = ${console},
EVALEX = ${evalex},
DEBUG_TOOLBAR_STATIC_PATH = "${static_path}",
Expand Down
108 changes: 58 additions & 50 deletions pyramid_debugtoolbar/panels/traceback.py
Expand Up @@ -21,19 +21,17 @@ class TracebackPanel(DebugPanel):
def __init__(self, request):
self.request = request
self.traceback = None
self.exc_history = request.exc_history

@property
def has_content(self):
return self.traceback is not None

def process_response(self, response):
self.traceback = traceback = getattr(self.request, 'pdbt_tb', None)
self.traceback = traceback = getattr(
self.request.debug_toolbar, 'traceback', None)
if self.traceback is not None:
exc = escape(traceback.exception)
token = self.request.registry.pdtb_token
url = '' # self.request.route_url(EXC_ROUTE_NAME, _query=qs)
evalex = self.exc_history.eval_exc
evalex = self.request.registry.pdtb_eval_exc

self.data = {
'evalex': evalex and 'true' or 'false',
Expand All @@ -44,79 +42,89 @@ def process_response(self, response):
'exception_type': escape(traceback.exception_type),
'plaintext': traceback.plaintext,
'plaintext_cs': re.sub('-{2,}', '-', traceback.plaintext),
'traceback_id': traceback.id,
'token': token,
'url': url,
'pdtb_token': self.request.registry.pdtb_token,
'request_id': self.request.pdtb_id,
}

# stop hanging onto the request after the response is processed
del self.request

def render_vars(self, request):
return {
vars = self.data.copy()
vars.update({
'static_path': request.static_url(STATIC_PATH),
'root_path': request.route_url(ROOT_ROUTE_NAME),
'url': request.route_url(
EXC_ROUTE_NAME, request_id=request.pdtb_id),

# render the summary using the toolbar's request object, not
# the original request that generated the traceback!
'summary': self.traceback.render_summary(
include_title=False, request=request),
}
})
return vars

class ExceptionDebugView(object):
def __init__(self, request):
self.request = request
exc_history = request.exc_history
if exc_history is None:
raise HTTPBadRequest('No exception history')
self.exc_history = exc_history
token = self.request.matchdict.get('token')
if not token:
raise HTTPBadRequest('No token in request')
if not token == request.registry.parent_registry.pdtb_token:
raise HTTPBadRequest('Bad token in request')
self.token = token
frm = self.request.params.get('frm')
if frm is not None:
frm = int(frm)
self.frame = frm
cmd = self.request.params.get('cmd')
self.cmd = cmd
tb = self.request.params.get('tb')
if tb is not None:
tb = int(tb)
self.tb = tb

@property
def history(self):
request_id = self.request.matchdict['request_id']
history = self.request.pdtb_history.get(request_id)
if history is None:
raise HTTPBadRequest('No history found for request.')
return history

@property
def traceback(self):
tb = getattr(self.history, 'traceback', None)
if tb is None:
raise HTTPBadRequest('No traceback found for request.')
return tb

@property
def frame(self):
frame_id = self.request.matchdict['frame_id']
for frame in self.traceback.frames:
if frame.id == frame_id:
return frame
raise HTTPBadRequest('Invalid traceback frame.')

@view_config(route_name='debugtoolbar.exception')
def exception(self):
tb = self.exc_history.tracebacks[self.tb]
tb = self.traceback
body = tb.render_full(self.request).encode('utf-8', 'replace')
response = Response(body, status=500)
return response
return Response(body, content_type='text/html', status=500)

@view_config(route_name='debugtoolbar.source')
def source(self):
exc_history = self.exc_history
if self.frame is not None:
frame = exc_history.frames.get(self.frame)
if frame is not None:
return Response(frame.render_source(), content_type='text/html')
return HTTPBadRequest()
frame = self.frame
body = frame.render_source()
return Response(body, content_type='text/html')

@view_config(route_name='debugtoolbar.execute')
def execute(self):
if self.request.exc_history.eval_exc:
exc_history = self.exc_history
if self.frame is not None and self.cmd is not None:
frame = exc_history.frames.get(self.frame)
if frame is not None:
result = frame.console.eval(self.cmd)
return Response(result, content_type='text/html')
return HTTPBadRequest()
if not self.request.registry.parent_registry.pdtb_eval_exc:
raise HTTPBadRequest(
'Evaluating code in stack frames is not allowed.')
frame = self.frame
cmd = self.request.params.get('cmd')
if cmd is None:
raise HTTPBadRequest('Missing command.')
body = frame.console.eval(cmd)
return Response(body, content_type='text/html')

def includeme(config):
config.add_route(EXC_ROUTE_NAME, '/exception/{token}')
config.add_route('debugtoolbar.source', '/source/{token}')
config.add_route('debugtoolbar.execute', '/execute/{token}')
config.add_route(EXC_ROUTE_NAME, '/{request_id}/exception')
config.add_route(
'debugtoolbar.source',
'{request_id}/exception/source/{frame_id}',
)
config.add_route(
'debugtoolbar.execute',
'/{request_id}/exception/execute/{frame_id}',
)

config.add_debugtoolbar_panel(TracebackPanel)
config.scan(__name__)
52 changes: 28 additions & 24 deletions pyramid_debugtoolbar/static/debugger/debugger.js
Expand Up @@ -45,17 +45,19 @@ $(function() {
.click(function() {
sourceView.slideUp('fast');
});
$.get(window.DEBUG_TOOLBAR_ROOT_PATH + 'source',
{frm: frameID, token: window.DEBUGGER_TOKEN}, function(data) {
$('table', sourceView)
.replaceWith(data);
if (!sourceView.is(':visible'))
sourceView.slideDown('fast', function() {
$.get(
window.DEBUG_TOOLBAR_ROOT_PATH + window.REQUEST_ID + '/exception/source/' + frameID,
function(data) {
$('table', sourceView)
.replaceWith(data);
if (!sourceView.is(':visible'))
sourceView.slideDown('fast', function() {
focusSourceBlock();
});
else
focusSourceBlock();
});
else
focusSourceBlock();
});
},
);
return false;
})
.prependTo(target);
Expand Down Expand Up @@ -96,8 +98,7 @@ $(function() {
label.val('submitting...');
$.ajax({
dataType: 'json',
url: window.DEBUG_TOOLBAR_ROOT_PATH + 'paste',
data: {tb: window.TRACEBACK, token: window.DEBUGGER_TOKEN},
url: window.DEBUG_TOOLBAR_ROOT_PATH + window.REQUEST_ID + '/exception/paste',
success: function(data) {
$('div.plain span.pastemessage')
.removeClass('pastemessage')
Expand Down Expand Up @@ -132,18 +133,21 @@ $(function() {
var form = $('<form>&gt;&gt;&gt; </form>')
.submit(function() {
var cmd = command.val();
$.get(window.DEBUG_TOOLBAR_ROOT_PATH + 'execute', {
cmd: cmd, frm: frameID, token:window.DEBUGGER_TOKEN}, function(data) {
var tmp = $('<div>').html(data);
output.append(tmp);
command.focus();
consoleNode.scrollTop(command.position().top);
var old = history.pop();
history.push(cmd);
if (typeof old != 'undefined')
history.push(old);
historyPos = history.length - 1;
});
$.get(
window.DEBUG_TOOLBAR_ROOT_PATH + window.REQUEST_ID + '/exception/execute/' + frameID,
{cmd: cmd},
function(data) {
var tmp = $('<div>').html(data);
output.append(tmp);
command.focus();
consoleNode.scrollTop(command.position().top);
var old = history.pop();
history.push(cmd);
if (typeof old != 'undefined')
history.push(old);
historyPos = history.length - 1;
},
);
command.val('');
return false;
}).
Expand Down

0 comments on commit 9f6448b

Please sign in to comment.