Permalink
Please sign in to comment.
Showing
with
216 additions
and 213 deletions.
- +5 −117 pyramid_debugtoolbar/__init__.py
- +210 −0 pyramid_debugtoolbar/toolbar_app.py
- +0 −95 pyramid_debugtoolbar/views.py
- +1 −1 tests/test_toolbar.py
| @@ -0,0 +1,210 @@ | ||
| from collections import OrderedDict | ||
| from pyramid.config import Configurator | ||
| from pyramid.interfaces import Interface | ||
| from pyramid.view import view_config | ||
| from pyramid_debugtoolbar.compat import json | ||
| from pyramid_debugtoolbar.compat import text_ | ||
| from pyramid_debugtoolbar.toolbar import IPanelMap | ||
| from pyramid_debugtoolbar.utils import ( | ||
| find_request_history, | ||
| get_setting, | ||
| ROOT_ROUTE_NAME, | ||
| SETTINGS_PREFIX, | ||
| STATIC_PATH, | ||
| ) | ||
| bundled_includes = ( | ||
| 'pyramid_debugtoolbar.panels.headers', | ||
| 'pyramid_debugtoolbar.panels.introspection', | ||
| 'pyramid_debugtoolbar.panels.logger', | ||
| 'pyramid_debugtoolbar.panels.performance', | ||
| 'pyramid_debugtoolbar.panels.renderings', | ||
| 'pyramid_debugtoolbar.panels.request_vars', | ||
| 'pyramid_debugtoolbar.panels.routes', | ||
| 'pyramid_debugtoolbar.panels.settings', | ||
| 'pyramid_debugtoolbar.panels.sqla', | ||
| 'pyramid_debugtoolbar.panels.traceback', | ||
| 'pyramid_debugtoolbar.panels.tweens', | ||
| 'pyramid_debugtoolbar.panels.versions', | ||
| ) | ||
| class IParentActions(Interface): | ||
| """ Marker interface for registered parent actions in the toolbar app.""" | ||
| def make_toolbar_app(settings, parent_registry): | ||
| """ WSGI application for rendering the debug toolbar.""" | ||
| config = Configurator(settings=settings) | ||
| config.registry.parent_registry = parent_registry | ||
| config.registry.registerUtility(OrderedDict(), IPanelMap) | ||
| config.add_directive('add_debugtoolbar_panel', add_debugtoolbar_panel) | ||
| config.add_directive('inject_parent_action', inject_parent_action) | ||
| config.include('pyramid_mako') | ||
| config.add_mako_renderer('.dbtmako', settings_prefix='dbtmako.') | ||
| config.add_route_predicate('history_request', HistoryRequestRoutePredicate) | ||
| config.add_request_method( | ||
| lambda r: r.registry.parent_registry.exc_history, | ||
| 'exc_history', reify=True) | ||
| config.add_static_view('static', STATIC_PATH) | ||
| config.add_route(ROOT_ROUTE_NAME, '/', static=True) | ||
| config.add_route('debugtoolbar.sse', '/sse') | ||
| config.add_route('debugtoolbar.redirect', '/redirect') | ||
| config.add_route('debugtoolbar.request', '/{request_id}', | ||
| history_request=True) | ||
| config.add_route('debugtoolbar.main', '/') | ||
| config.scan(__name__) | ||
| for include in bundled_includes: | ||
| config.include(include) | ||
| # commit the toolbar config and include any user-defined includes | ||
| config.commit() | ||
| includes = settings.get(SETTINGS_PREFIX + 'includes', ()) | ||
| for include in includes: | ||
| config.include(include) | ||
| return config.make_wsgi_app() | ||
| class HistoryRequestRoutePredicate(object): | ||
| def __init__(self, val, config): | ||
| assert isinstance(val, bool), 'must be a bool' | ||
| self.val = val | ||
| def text(self): | ||
| return 'tbhistory = %s' % self.val | ||
| phash = text | ||
| def __call__(self, info, request): | ||
| match = info['match'] | ||
| history = find_request_history(request) | ||
| is_historical = bool(history.get(match.get('request_id'))) | ||
| return not (is_historical ^ self.val) | ||
| def add_debugtoolbar_panel(config, panel_class, is_global=False): | ||
| """ | ||
| Register a new panel into the debugtoolbar. | ||
| This is a Pyramid config directive that is accessible as | ||
| ``config.add_debugtoolbar_panel`` within the debugtoolbar application. | ||
| It should be used from ``includeme`` functions via the | ||
| ``debugtoolbar.includes`` setting. | ||
| The ``panel_class`` should be a subclass of | ||
| :class:`pyramid_debugtoolbar.panels.DebugPanel`. | ||
| If ``is_global`` is ``True`` then the panel will be added to the global | ||
| panel list which includes application-wide panels that do not depend | ||
| on per-request data to operate. | ||
| """ | ||
| panel_class = config.maybe_dotted(panel_class) | ||
| name = panel_class.name | ||
| panel_map = config.registry.getUtility(IPanelMap) | ||
| panel_map[(name, is_global)] = panel_class | ||
| def inject_parent_action(config, action): | ||
| """ | ||
| Inject an action into the parent application. | ||
| This is a Pyramid config directive that is accessible as | ||
| ``config.inject_parent_action`` within the debugtoolbar application. | ||
| It should be used from ``includeme`` functions via the | ||
| ``debugtoolbar.includes`` setting. | ||
| The ``action`` should be a callable that accepts the parent app's | ||
| ``config`` object. It will be executed after the parent app is created | ||
| to ensure that configuration is set prior to the actions being executed. | ||
| """ | ||
| actions = config.registry.queryUtility(IParentActions) | ||
| if actions is None: | ||
| actions = [] | ||
| config.registry.registerUtility(actions, IParentActions) | ||
| actions.append(action) | ||
| @view_config( | ||
| route_name='debugtoolbar.redirect', | ||
| renderer='pyramid_debugtoolbar:templates/redirect.dbtmako', | ||
| ) | ||
| def redirect_view(request): | ||
| return { | ||
| 'redirect_to': request.params.get('redirect_to'), | ||
| 'redirect_code': request.params.get('redirect_code'), | ||
| } | ||
| @view_config( | ||
| route_name='debugtoolbar.main', | ||
| renderer='pyramid_debugtoolbar:templates/toolbar.dbtmako' | ||
| ) | ||
| @view_config( | ||
| route_name='debugtoolbar.request', | ||
| renderer='pyramid_debugtoolbar:templates/toolbar.dbtmako' | ||
| ) | ||
| def request_view(request): | ||
| history = find_request_history(request) | ||
| try: | ||
| last_request_pair = history.last(1)[0] | ||
| except IndexError: | ||
| last_request_pair = None | ||
| last_request_id = None | ||
| else: | ||
| last_request_id = last_request_pair[0] | ||
| request_id = request.matchdict.get('request_id', last_request_id) | ||
| toolbar = history.get(request_id, None) | ||
| static_path = request.static_url(STATIC_PATH) | ||
| root_path = request.route_url(ROOT_ROUTE_NAME) | ||
| button_style = get_setting(request.registry.settings, 'button_style') | ||
| max_visible_requests = get_setting(request.registry.settings, | ||
| 'max_visible_requests') | ||
| hist_toolbars = history.last(max_visible_requests) | ||
| return {'panels': toolbar.panels if toolbar else [], | ||
| 'static_path': static_path, | ||
| 'root_path': root_path, | ||
| 'button_style': button_style, | ||
| 'history': hist_toolbars, | ||
| 'default_active_panels': ( | ||
| toolbar.default_active_panels if toolbar else []), | ||
| 'global_panels': toolbar.global_panels if toolbar else [], | ||
| 'request_id': request_id | ||
| } | ||
| U_BLANK = text_("") | ||
| U_SSE_PAYLOAD = text_("id:{0}\nevent: new_request\ndata:{1}\n\n") | ||
| @view_config(route_name='debugtoolbar.sse') | ||
| def sse(request): | ||
| response = request.response | ||
| response.content_type = 'text/event-stream' | ||
| history = find_request_history(request) | ||
| response.text = U_BLANK | ||
| active_request_id = text_(request.GET.get('request_id')) | ||
| client_last_request_id = text_(request.headers.get('Last-Event-Id', 0)) | ||
| max_visible_requests = get_setting(request.registry.settings, | ||
| 'max_visible_requests') | ||
| if history: | ||
| last_request_pair = history.last(1)[0] | ||
| last_request_id = last_request_pair[0] | ||
| if not last_request_id == client_last_request_id: | ||
| data = [[ | ||
| _id, | ||
| toolbar.json, | ||
| 'active' if active_request_id == _id else '' | ||
| ] for _id, toolbar in history.last(max_visible_requests)] | ||
| if data: | ||
| response.text = U_SSE_PAYLOAD.format(last_request_id, | ||
| json.dumps(data)) | ||
| return response |
Oops, something went wrong.
0 comments on commit
a22d2cf