diff options
Diffstat (limited to 'debug_toolbar/panels')
| -rw-r--r-- | debug_toolbar/panels/cache.py | 7 | ||||
| -rw-r--r-- | debug_toolbar/panels/logging.py | 41 | ||||
| -rw-r--r-- | debug_toolbar/panels/settings.py | 8 | ||||
| -rw-r--r-- | debug_toolbar/panels/staticfiles.py | 179 | ||||
| -rw-r--r-- | debug_toolbar/panels/templates/panel.py | 10 | ||||
| -rw-r--r-- | debug_toolbar/panels/versions.py | 9 | 
6 files changed, 211 insertions, 43 deletions
| diff --git a/debug_toolbar/panels/cache.py b/debug_toolbar/panels/cache.py index 1c37c6b..bdc8a4d 100644 --- a/debug_toolbar/panels/cache.py +++ b/debug_toolbar/panels/cache.py @@ -10,8 +10,11 @@ from django.core.cache import cache as original_cache, get_cache as original_get  from django.core.cache.backends.base import BaseCache  from django.dispatch import Signal  from django.template import Node -from django.utils.datastructures import SortedDict  from django.utils.translation import ugettext_lazy as _, ungettext +try: +    from collections import OrderedDict +except ImportError: +    from django.utils.datastructures import SortedDict as OrderedDict  from debug_toolbar.panels import Panel  from debug_toolbar.utils import (tidy_stacktrace, render_stacktrace, @@ -139,7 +142,7 @@ class CachePanel(Panel):          self.hits = 0          self.misses = 0          self.calls = [] -        self.counts = SortedDict(( +        self.counts = OrderedDict((              ('add', 0),              ('get', 0),              ('set', 0), diff --git a/debug_toolbar/panels/logging.py b/debug_toolbar/panels/logging.py index 051d5a3..1ee19ce 100644 --- a/debug_toolbar/panels/logging.py +++ b/debug_toolbar/panels/logging.py @@ -8,42 +8,19 @@ except ImportError:      threading = None  from django.utils.translation import ungettext, ugettext_lazy as _  from debug_toolbar.panels import Panel +from debug_toolbar.utils import ThreadCollector  MESSAGE_IF_STRING_REPRESENTATION_INVALID = '[Could not get log message]' -class LogCollector(object): -    def __init__(self): -        if threading is None: -            raise NotImplementedError( -                "threading module is not available, " -                "the logging panel cannot be used without it") -        self.records = {}  # a dictionary that maps threads to log records +class LogCollector(ThreadCollector): -    def add_record(self, record, thread=None): +    def collect(self, item, thread=None):          # Avoid logging SQL queries since they are already in the SQL panel          # TODO: Make this check whether SQL panel is enabled -        if record.get('channel', '') == 'django.db.backends': +        if item.get('channel', '') == 'django.db.backends':              return - -        self.get_records(thread).append(record) - -    def get_records(self, thread=None): -        """ -        Returns a list of records for the provided thread, of if none is provided, -        returns a list for the current thread. -        """ -        if thread is None: -            thread = threading.currentThread() -        if thread not in self.records: -            self.records[thread] = [] -        return self.records[thread] - -    def clear_records(self, thread=None): -        if thread is None: -            thread = threading.currentThread() -        if thread in self.records: -            del self.records[thread] +        super(LogCollector, self).collect(item, thread)  class ThreadTrackingHandler(logging.Handler): @@ -65,7 +42,7 @@ class ThreadTrackingHandler(logging.Handler):              'line': record.lineno,              'channel': record.name,          } -        self.collector.add_record(record) +        self.collector.collect(record)  # We don't use enable/disable_instrumentation because logging is global. @@ -96,10 +73,10 @@ class LoggingPanel(Panel):      title = _("Log messages")      def process_request(self, request): -        collector.clear_records() +        collector.clear_collection()      def process_response(self, request, response): -        records = collector.get_records() +        records = collector.get_collection()          self._records[threading.currentThread()] = records -        collector.clear_records() +        collector.clear_collection()          self.record_stats({'records': records}) diff --git a/debug_toolbar/panels/settings.py b/debug_toolbar/panels/settings.py index c59d1d1..b054f8b 100644 --- a/debug_toolbar/panels/settings.py +++ b/debug_toolbar/panels/settings.py @@ -3,7 +3,10 @@ from __future__ import absolute_import, unicode_literals  from django.conf import settings  from django.views.debug import get_safe_settings  from django.utils.translation import ugettext_lazy as _ -from django.utils.datastructures import SortedDict +try: +    from collections import OrderedDict +except ImportError: +    from django.utils.datastructures import SortedDict as OrderedDict  from debug_toolbar.panels import Panel @@ -21,5 +24,6 @@ class SettingsPanel(Panel):      def process_response(self, request, response):          self.record_stats({ -            'settings': SortedDict(sorted(get_safe_settings().items(), key=lambda s: s[0])), +            'settings': OrderedDict(sorted(get_safe_settings().items(), +                                           key=lambda s: s[0])),          }) diff --git a/debug_toolbar/panels/staticfiles.py b/debug_toolbar/panels/staticfiles.py new file mode 100644 index 0000000..f212f2b --- /dev/null +++ b/debug_toolbar/panels/staticfiles.py @@ -0,0 +1,179 @@ +from __future__ import absolute_import, unicode_literals +from os.path import normpath, join +try: +    import threading +except ImportError: +    threading = None + +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.core.files.storage import get_storage_class +from django.contrib.staticfiles import finders, storage +from django.contrib.staticfiles.templatetags import staticfiles + +from django.utils.encoding import python_2_unicode_compatible +from django.utils.functional import LazyObject +from django.utils.translation import ungettext, ugettext_lazy as _ +try: +    from collections import OrderedDict +except ImportError: +    from django.utils.datastructures import SortedDict as OrderedDict + +from debug_toolbar import panels +from debug_toolbar.utils import ThreadCollector + + +@python_2_unicode_compatible +class StaticFile(object): +    """ +    Representing the different properties of a static file. +    """ +    def __init__(self, path): +        self.path = path + +    def __str__(self): +        return self.path + +    def real_path(self): +        return finders.find(self.path) + +    def url(self): +        return storage.staticfiles_storage.url(self.path) + + +class FileCollector(ThreadCollector): + +    def collect(self, path, thread=None): +        # handle the case of {% static "admin/" %} +        if path.endswith('/'): +            return +        super(FileCollector, self).collect(StaticFile(path), thread) + + +collector = FileCollector() + + +class DebugConfiguredStorage(LazyObject): +    """ +    A staticfiles storage class to be used for collecting which paths +    are resolved by using the {% static %} template tag (which uses the +    `url` method). +    """ +    def _setup(self): + +        configured_storage_cls = get_storage_class(settings.STATICFILES_STORAGE) + +        class DebugStaticFilesStorage(configured_storage_cls): + +            def __init__(self, collector, *args, **kwargs): +                super(DebugStaticFilesStorage, self).__init__(*args, **kwargs) +                self.collector = collector + +            def url(self, path): +                self.collector.collect(path) +                return super(DebugStaticFilesStorage, self).url(path) + +        self._wrapped = DebugStaticFilesStorage(collector) + +_original_storage = storage.staticfiles_storage + + +class StaticFilesPanel(panels.Panel): +    """ +    A panel to display the found staticfiles. +    """ +    name = 'Static files' +    template = 'debug_toolbar/panels/staticfiles.html' + +    @property +    def title(self): +        return (_("Static files (%(num_found)s found, %(num_used)s used)") % +                {'num_found': self.num_found, 'num_used': self.num_used}) + +    def __init__(self, *args, **kwargs): +        super(StaticFilesPanel, self).__init__(*args, **kwargs) +        self.num_found = 0 +        self._paths = {} + +    def enable_instrumentation(self): +        storage.staticfiles_storage = staticfiles.staticfiles_storage = DebugConfiguredStorage() + +    def disable_instrumentation(self): +        storage.staticfiles_storage = staticfiles.staticfiles_storage = _original_storage + +    @property +    def has_content(self): +        if "django.contrib.staticfiles" not in settings.INSTALLED_APPS: +            raise ImproperlyConfigured("Could not find staticfiles in " +                                       "INSTALLED_APPS setting.") +        return True + +    @property +    def num_used(self): +        return len(self._paths[threading.currentThread()]) + +    nav_title = _('Static files') + +    @property +    def nav_subtitle(self): +        num_used = self.num_used +        return ungettext("%(num_used)s file used", +                         "%(num_used)s files used", +                         num_used) % {'num_used': num_used} + +    def process_request(self, request): +        collector.clear_collection() + +    def process_response(self, request, response): +        used_paths = collector.get_collection() +        self._paths[threading.currentThread()] = used_paths + +        self.record_stats({ +            'num_found': self.num_found, +            'num_used': self.num_used, +            'staticfiles': used_paths, +            'staticfiles_apps': self.get_staticfiles_apps(), +            'staticfiles_dirs': self.get_staticfiles_dirs(), +            'staticfiles_finders': self.get_staticfiles_finders(), +        }) + +    def get_staticfiles_finders(self): +        """ +        Returns a sorted mapping between the finder path and the list +        of relative and file system paths which that finder was able +        to find. +        """ +        finders_mapping = OrderedDict() +        for finder in finders.get_finders(): +            for path, finder_storage in finder.list([]): +                if getattr(finder_storage, 'prefix', None): +                    prefixed_path = join(finder_storage.prefix, path) +                else: +                    prefixed_path = path +                finder_cls = finder.__class__ +                finder_path = '.'.join([finder_cls.__module__, +                                        finder_cls.__name__]) +                real_path = finder_storage.path(path) +                payload = (prefixed_path, real_path) +                finders_mapping.setdefault(finder_path, []).append(payload) +                self.num_found += 1 +        return finders_mapping + +    def get_staticfiles_dirs(self): +        """ +        Returns a list of paths to inspect for additional static files +        """ +        dirs = getattr(settings, 'STATICFILES_DIRS', ()) +        return [normpath(d) for d in dirs] + +    def get_staticfiles_apps(self): +        """ +        Returns a list of app paths that have a static directory +        """ +        apps = [] +        for finder in finders.get_finders(): +            if isinstance(finder, finders.AppDirectoriesFinder): +                for app in finder.apps: +                    if app not in apps: +                        apps.append(app) +        return apps diff --git a/debug_toolbar/panels/templates/panel.py b/debug_toolbar/panels/templates/panel.py index df39804..74f28b0 100644 --- a/debug_toolbar/panels/templates/panel.py +++ b/debug_toolbar/panels/templates/panel.py @@ -81,12 +81,8 @@ class TemplatesPanel(Panel):      def __init__(self, *args, **kwargs):          super(TemplatesPanel, self).__init__(*args, **kwargs)          self.templates = [] -        template_rendered.connect(self._store_template_info)      def _store_template_info(self, sender, **kwargs): -        if not self.enabled: -            return -          template, context = kwargs['template'], kwargs['context']          # Skip templates that we are generating through the debug toolbar. @@ -157,6 +153,12 @@ class TemplatesPanel(Panel):              url(r'^template_source/$', 'template_source', name='template_source'),          ) +    def enable_instrumentation(self): +        template_rendered.connect(self._store_template_info) + +    def disable_instrumentation(self): +        template_rendered.disconnect(self._store_template_info) +      def process_response(self, request, response):          template_context = []          for template_data in self.templates: diff --git a/debug_toolbar/panels/versions.py b/debug_toolbar/panels/versions.py index 85672b8..321ba6e 100644 --- a/debug_toolbar/panels/versions.py +++ b/debug_toolbar/panels/versions.py @@ -4,9 +4,12 @@ import sys  import django  from django.conf import settings -from django.utils.translation import ugettext_lazy as _ -from django.utils.datastructures import SortedDict  from django.utils.importlib import import_module +from django.utils.translation import ugettext_lazy as _ +try: +    from collections import OrderedDict +except ImportError: +    from django.utils.datastructures import SortedDict as OrderedDict  from debug_toolbar.panels import Panel @@ -46,6 +49,6 @@ class VersionsPanel(Panel):              versions = sorted(versions, key=lambda version: version[0])          self.record_stats({ -            'versions': SortedDict(versions), +            'versions': OrderedDict(versions),              'paths': sys.path,          }) | 
