Repository: jazzband/django-debug-toolbar

Issue:
python 2.5 compatibility ('unicode' object has no attribute 'format')
``` python
Traceback (most recent call last):
  File "/home/etarasenko/projects/frobbit/env/lib/python2.5/site-packages/django/core/servers/basehttp.py", line 280, in run
    self.result = application(self.environ, self.start_response)
  File "/home/etarasenko/projects/frobbit/env/lib/python2.5/site-packages/django/core/servers/basehttp.py", line 674, in __call__
    return self.application(environ, start_response)
  File "/home/etarasenko/projects/frobbit/env/lib/python2.5/site-packages/django/core/handlers/wsgi.py", line 245, in __call__
    response = middleware_method(request, response)
  File "/home/etarasenko/projects/frobbit/env/lib/python2.5/site-packages/debug_toolbar/middleware.py", line 129, in process_response
    panel.process_response(request, response)
  File "/home/etarasenko/projects/frobbit/env/lib/python2.5/site-packages/debug_toolbar/panels/sql.py", line 197, in process_response
    stacktrace.append(u'<span class="path">{0}/</span><span class="file">{1}</span> in <span class="func">{3}</span>(<span class="lineno">{2}</span>)\n  <span class="code">{4}</span>'.format(*params))
AttributeError: 'unicode' object has no attribute 'format'
```



Discussion:
I got similar error.

I think it's reasonable to assume that the toolbar only supports Python >= 2.6 as the newstyle formatting is used in other places as well. Any objections with making that official, @dcramer, @robhudson? 

It may be better to make next requirements:
v0.9.x supports python >= 2.6
v0.8.x supports python >= 2.5

Because django-debug-toolbar==0.8.5 works correctly with python2.5

@etarasenko Agreed, I was refering to master (0.9.X) when I said Python >= 2.6 support.

I have no objections, but if it's only a couple of small fixes it might be reasonable to support 2.5 still (since 1.2 supports 2.5, and we could just follow the Django 2 version deprecation plan, assuming I remember it correctly)

@dcramer yeah, it's mostly a bunch of `format()` calls AFAIK. I don't mind supporting it, FWIW.


Resolving patch:
diff --git a/debug_toolbar/utils/__init__.py b/debug_toolbar/utils/__init__.py
--- a/debug_toolbar/utils/__init__.py
+++ b/debug_toolbar/utils/__init__.py
@@ -56,9 +56,15 @@ def render_stacktrace(trace):
     stacktrace = []
     for frame in trace:
         params = map(escape, frame[0].rsplit(os.path.sep, 1) + list(frame[1:]))
+        params_dict = dict((unicode(idx), v) for idx, v in enumerate(params))
         try:
-            stacktrace.append(u'<span class="path">{0}/</span><span class="file">{1}</span> in <span class="func">{3}</span>(<span class="lineno">{2}</span>)\n  <span class="code">{4}</span>'.format(*params))
-        except IndexError:
+            stacktrace.append(u'<span class="path">%(0)s/</span>'
+                              u'<span class="file">%(1)s</span>'
+                              u' in <span class="func">%(3)s</span>'
+                              u'(<span class="lineno">%(2)s</span>)\n'
+                              u'  <span class="code">%(4)s</span>'
+                              % params_dict)
+        except KeyError:
             # This frame doesn't have the expected format, so skip it and move on to the next one
             continue
     return mark_safe('\n'.join(stacktrace))


Test patch:
diff --git a/tests/tests.py b/tests/tests.py
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
 import thread
 
 from django.conf import settings