Permalink
Browse files

Port the rest of the django-debug-toolbar to flask. Only the logging …

…panel is currently working
  • Loading branch information...
1 parent a060d30 commit 8342799d2e57c65f43fd054951a2a8722ad7706b @mvantellingen committed Feb 2, 2011
View
@@ -0,0 +1,27 @@
+Copyright (c) Rob Hudson and individual contributors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of Django nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1,11 +1,11 @@
import os
-from flask import request_finished
+from flask import request_finished, url_for, request_started, request
from flask.helpers import send_from_directory
from jinja2 import Environment, PackageLoader
from werkzeug.routing import Rule, Submount
-from .panels.logger import handler
+from .toolbar import DebugToolbar
from .views import views_module
@@ -22,36 +22,51 @@ def replace_insensitive(string, target, replacement):
return string
-class DebugToolbar(object):
+class DebugToolbarExtension(object):
_static_dir = os.path.join(os.path.dirname(__file__), 'static')
def __init__(self, app):
- self.jinja_env = Environment(loader=PackageLoader(__name__, 'templates'))
+ self.app = app
+ self.debug_toolbars = {}
+
+ request_started.connect(self.process_request, app)
request_finished.connect(self.process_response, app)
+ # Configure jinja for the internal templates and add url rules
+ # for static data
+ self.jinja_env = Environment(loader=PackageLoader(__name__, 'templates'))
app.url_map.add(Submount('/_debug_toolbar', [
Rule('/static/<path:filename>', endpoint='_debug_toolbar.static'),
Rule('/css/main.css', endpoint='_debug_toolbar.example')
]))
-
app.register_module(views_module)
app.view_functions['_debug_toolbar.static'] = self.send_static_file
+ self.panels = []
+
def send_static_file(self, filename):
return send_from_directory(self._static_dir, filename)
- def render_toolbar(self):
- template = self.jinja_env.get_template('base.html')
- content = template.render()
- return content
+
+ def process_request(self, app):
+ self.debug_toolbars[request] = DebugToolbar(request, self.jinja_env)
+ for panel in self.debug_toolbars[request].panels:
+ panel.process_request(request)
def process_response(self, sender, response):
- if response.is_sequence:
- response_html = response.data
- toolbar_html = self.render_toolbar()
-
- response.response = [
- replace_insensitive(
- response_html,
- '</body>',
- toolbar_html + '</body>')]
+ if request not in self.debug_toolbars:
+ return response
+
+ if response.status_code == 200:
+ for panel in self.debug_toolbars[request].panels:
+ panel.process_response(request, response)
+
+ if response.is_sequence:
+ response_html = response.data
+ toolbar_html = self.debug_toolbars[request].render_toolbar()
+ response.response = [
+ replace_insensitive(
+ response_html,
+ '</body>',
+ toolbar_html + '</body>')]
+
@@ -0,0 +1,54 @@
+"""Base DebugPanel class"""
+
+class DebugPanel(object):
+ """
+ Base class for debug panels.
+ """
+ # name = Base
+ has_content = False # If content returns something, set to true in subclass
+
+ # We'll maintain a local context instance so we can expose our template
+ # context variables to panels which need them:
+ context = {}
+
+ # Panel methods
+ def __init__(self, jinja_env, context={}):
+ self.context.update(context)
+ self.jinja_env = jinja_env
+
+ def render(self, template_name, context):
+ template = self.jinja_env.get_template(template_name)
+ return template.render(**context)
+
+ def dom_id(self):
+ return 'flDebug%sPanel' % (self.name.replace(' ', ''))
+
+ def nav_title(self):
+ """Title showing in toolbar"""
+ raise NotImplementedError
+
+ def nav_subtitle(self):
+ """Subtitle showing until title in toolbar"""
+ return ''
+
+ def title(self):
+ """Title showing in panel"""
+ raise NotImplementedError
+
+ def url(self):
+ raise NotImplementedError
+
+ def content(self):
+ raise NotImplementedError
+
+ # Standard middleware methods
+ def process_request(self, request):
+ pass
+
+ def process_view(self, request, view_func, view_args, view_kwargs):
+ pass
+
+ def process_response(self, request, response):
+ pass
+
+
@@ -1,12 +1,16 @@
-"""
-Logger panel (taken from django-debug-toolbar)
-
-"""
-import threading
+import datetime
import logging
+try:
+ import threading
+except ImportError:
+ threading = None
+from . import DebugPanel
class ThreadTrackingHandler(logging.Handler):
def __init__(self):
+ if threading is None:
+ raise NotImplementedError("threading module is not available, \
+ the logging panel cannot be used without it")
logging.Handler.__init__(self)
self.records = {} # a dictionary that maps threads to log records
@@ -33,3 +37,46 @@ def clear_records(self, thread=None):
handler = ThreadTrackingHandler()
logging.root.setLevel(logging.NOTSET)
logging.root.addHandler(handler)
+
+class LoggingPanel(DebugPanel):
+ name = 'Logging'
+ has_content = True
+
+ def process_request(self, request):
+ handler.clear_records()
+
+ def get_and_delete(self):
+ records = handler.get_records()
+ handler.clear_records()
+ return records
+
+ def nav_title(self):
+ return "Logging"
+
+ def nav_subtitle(self):
+ # FIXME l10n: use ngettext
+ return "%s message%s" % (len(handler.get_records()), (len(handler.get_records()) == 1) and '' or 's')
+
+ def title(self):
+ return 'Log Messages'
+
+ def url(self):
+ return ''
+
+ def content(self):
+ records = []
+ for record in self.get_and_delete():
+ records.append({
+ 'message': record.getMessage(),
+ 'time': datetime.datetime.fromtimestamp(record.created),
+ 'level': record.levelname,
+ 'file': record.pathname,
+ 'line': record.lineno,
+ })
+
+ context = self.context.copy()
+ context.update({'records': records})
+
+ return self.render('panels/logger.html', context)
+
+
Oops, something went wrong. Retry.

0 comments on commit 8342799

Please sign in to comment.