Trigger the Panel.process_view by monkey-patching the Flask.dispatch_request method. Use this for the profiling panel to make it threadsafe

This commit is contained in:
mvantellingen
2011-02-06 20:44:15 +01:00
parent 59c0b19387
commit 9e17f76c3e
4 changed files with 49 additions and 17 deletions
+42 -5
View File
@@ -1,10 +1,10 @@
import os
from flask import request
from flask import signals
from flask import current_app, request, signals
from flask.globals import _request_ctx_stack
from flask.helpers import send_from_directory
from jinja2 import Environment, PackageLoader
from werkzeug.routing import Rule, Submount
from werkzeug.exceptions import HTTPException
from flaskext.debugtoolbar.toolbar import DebugToolbar
@@ -34,6 +34,9 @@ class DebugToolbarExtension(object):
signals.request_started.connect(self.process_request, app)
signals.request_finished.connect(self.process_response, app)
# Monkey-patch the Flask.dispatch_request method
app.dispatch_request = self.dispatch_request
# Configure jinja for the internal templates and add url rules
# for static data
self.jinja_env = Environment(
@@ -43,6 +46,37 @@ class DebugToolbarExtension(object):
app.add_url_rule('/_debug_toolbar/static/<path:filename>',
'_debug_toolbar.static', self.send_static_file)
def dispatch_request(self):
"""Does the request dispatching. Matches the URL and returns the
return value of the view or error handler. This does not have to
be a response object. In order to convert the return value to a
proper response object, call :func:`make_response`.
This is a modified version of the default Flask.dispatch_request
"""
req = _request_ctx_stack.top.request
app = current_app
try:
if req.routing_exception is not None:
raise req.routing_exception
rule = req.url_rule
# if we provide automatic options for this URL and the
# request came with the OPTIONS method, reply automatically
if getattr(rule, 'provide_automatic_options', False) \
and req.method == 'OPTIONS':
return app.make_default_options_response()
# otherwise dispatch to the handler for that endpoint, give the
# panels the ability to wrap the view_func
view_func = app.view_functions[rule.endpoint]
view_func = self.process_view(app, view_func, req.view_args)
return view_func(**req.view_args)
except HTTPException, e:
return app.handle_http_exception(e)
def _show_toolbar(self):
if request.path.startswith('/_debug_toolbar/'):
return False
@@ -60,10 +94,13 @@ class DebugToolbarExtension(object):
for panel in self.debug_toolbars[request].panels:
panel.process_request(request)
def process_view(self, app, template, context):
def process_view(self, app, view_func, view_kwargs):
if request in self.debug_toolbars:
for panel in self.debug_toolbars[request].panels:
panel.process_view(request, template, [], context)
new_view = panel.process_view(request, view_func, view_kwargs)
if new_view:
view_func = new_view
return view_func
def process_response(self, sender, response):
if request not in self.debug_toolbars:
+1 -1
View File
@@ -52,7 +52,7 @@ class DebugPanel(object):
def process_request(self, request):
pass
def process_view(self, request, view_func, view_args, view_kwargs):
def process_view(self, request, view_func, view_kwargs):
pass
def process_response(self, request, response):
+4 -8
View File
@@ -2,6 +2,7 @@ try:
import cProfile as profile
except ImportError:
import profile
import functools
import pstats
from flask import current_app
@@ -25,13 +26,9 @@ class ProfilerDebugPanel(DebugPanel):
self.profiler = profile.Profile()
self.stats = None
# Monkey-patch Flask.dispatch_request for profiling
org_dispatch_request = current_app.dispatch_request
def dispatch_request():
content = self.profiler.runcall(org_dispatch_request)
current_app.dispatch_request = org_dispatch_request
return content
current_app.dispatch_request = dispatch_request
def process_view(self, request, view_func, view_kwargs):
if self.is_active:
return functools.partial(self.profiler.runcall, view_func)
def process_response(self, request, response):
if not self.is_active:
@@ -64,7 +61,6 @@ class ProfilerDebugPanel(DebugPanel):
# destroy the profiler just in case
return response
def title(self):
if not self.is_active:
return "Profiler not active"
+2 -3
View File
@@ -22,11 +22,10 @@ class RequestVarsDebugPanel(DebugPanel):
self.request = request
self.view_func = None
self.view_args = []
self.view_kwargs = request.view_args
self.view_kwargs = {}
def process_view(self, request, view_func, view_args, view_kwargs):
def process_view(self, request, view_func, view_kwargs):
self.view_func = view_func
self.view_args = view_args
self.view_kwargs = view_kwargs
def content(self):