Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Python 3 #373

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
eb0d02d
Add python 3.3 and 3.2 as allow_failures
graingert Apr 8, 2013
eb53791
add <1.6 to tests_require
graingert Apr 8, 2013
005ca0b
use sqlparse from pypi
graingert Apr 8, 2013
c73c77a
remove support for django <1.4.2
graingert Apr 8, 2013
c58094b
use new style exception in __init__.py
graingert Apr 8, 2013
e749ab1
port imports to py3k in middleware.py
graingert Apr 8, 2013
f6aad29
support new style exceptions in loader.py
graingert Apr 8, 2013
f1d5de5
port imports to py3k in utils/__init__.py
graingert Apr 8, 2013
61d1286
support new style exceptions in utils/tracking/__init__.py
graingert Apr 8, 2013
e4e8388
use force_text instead of force_unicode
graingert Apr 8, 2013
e3723e3
remove use of deprecated sqlparse.filters.Filters
graingert Apr 8, 2013
bab0aee
use thread from six.moves in tests/tests.py
graingert Apr 8, 2013
417c852
use assertEqual instead of assertEquals in tests
graingert Apr 8, 2013
3929d60
use iteritems from six, or items in templates
graingert Apr 8, 2013
068a6c1
use string_types from six instead of basestring
graingert Apr 8, 2013
7cb3cb0
use iterkeys and itervalues from six, or .keys and .values in templates
graingert Apr 8, 2013
c2485f5
deprecate functions unusable on Python3
graingert Apr 9, 2013
61bbd7f
use more simpler, more portable monkey_patch_call func in tracking
graingert Apr 9, 2013
cdfa803
use map from six
graingert Apr 9, 2013
494f421
force more things to bytes before hashing
graingert Apr 9, 2013
a30c83f
use text_type instead of unicode
graingert Apr 9, 2013
6e50c9f
add DJANGO_VERSION=1.5 to allow_failures
graingert Apr 9, 2013
47ea676
fix print function
w-diesel Apr 14, 2013
76a8159
Update profiling.py, attr. "func_closure" ( py2.6)
w-diesel Apr 14, 2013
f5d4cde
remove u'' prefix, import __future__ unicode_lit..
w-diesel Apr 14, 2013
0e6983a
use force_bytes to encode before hashing
graingert Apr 14, 2013
a088ed0
list expected
w-diesel Apr 14, 2013
3aa8c4c
Update middleware.py
w-diesel Apr 14, 2013
7a21c54
cache.py, fix python3.2 support
w-diesel Apr 15, 2013
fa40aa1
Masterbranch can pass all original tests on 1.5ver
w-diesel Apr 16, 2013
ee44437
Update .travis.yml
w-diesel Apr 16, 2013
fd2bb66
use unittest.skipIf to skip tests invalid on PY3
graingert Apr 23, 2013
09203c6
bump django version requirements to 1.4.5
graingert Apr 25, 2013
9a924cd
remove spaces from print functions
graingert Apr 25, 2013
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions .travis.yml
Expand Up @@ -3,9 +3,14 @@ python:
- "2.6"
- "2.7"
env:
- DJANGO_VERSION=1.3.7
- DJANGO_VERSION=1.4.5
- DJANGO_VERSION=1.5
- DJANGO_VERSION=1.5.1
matrix:
include:
- python: 3.2
env: DJANGO_VERSION=1.5.1
- python: 3.3
env: DJANGO_VERSION=1.5.1
install:
- pip install Django==$DJANGO_VERSION
- python setup.py install
Expand Down
2 changes: 1 addition & 1 deletion debug_toolbar/__init__.py
Expand Up @@ -3,5 +3,5 @@
try:
VERSION = __import__('pkg_resources') \
.get_distribution('django-debug-toolbar').version
except Exception, e:
except Exception as e:
VERSION = 'unknown'
10 changes: 6 additions & 4 deletions debug_toolbar/management/commands/debugsqlshell.py
@@ -1,9 +1,11 @@
from __future__ import print_function
from datetime import datetime

from django.db.backends import util
from django.core.management.commands.shell import Command

from debug_toolbar.utils import ms_from_timedelta, sqlparse
from debug_toolbar.utils import ms_from_timedelta
import sqlparse


class PrintQueryWrapper(util.CursorDebugWrapper):
Expand All @@ -14,8 +16,8 @@ def execute(self, sql, params=()):
finally:
raw_sql = self.db.ops.last_executed_query(self.cursor, sql, params)
execution_time = datetime.now() - starttime
print sqlparse.format(raw_sql, reindent=True),
print ' [%.2fms]' % (ms_from_timedelta(execution_time),)
print
print( sqlparse.format(raw_sql, reindent=True),)
print( ' [%.2fms]' % (ms_from_timedelta(execution_time),))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could remove the extra spacing after the print( in the above 2 lines.

print()

util.CursorDebugWrapper = PrintQueryWrapper
26 changes: 14 additions & 12 deletions debug_toolbar/middleware.py
@@ -1,14 +1,16 @@
from __future__ import unicode_literals
"""
Debug Toolbar middleware
"""
import imp
import thread
from django.utils.six.moves import _thread

from django.conf import settings
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.utils.encoding import smart_unicode
from django.utils.encoding import smart_text
from django.utils.importlib import import_module
from django.utils.six import string_types

import debug_toolbar.urls
from debug_toolbar.toolbar.loader import DebugToolbar
Expand Down Expand Up @@ -38,7 +40,7 @@ class DebugToolbarMiddleware(object):

@classmethod
def get_current(cls):
return cls.debug_toolbars.get(thread.get_ident())
return cls.debug_toolbars.get(_thread.get_ident())

def __init__(self):
self._urlconfs = {}
Expand All @@ -47,7 +49,7 @@ def __init__(self):
self.show_toolbar = self._show_toolbar # default

# The tag to attach the toolbar to
self.tag = u'</body>'
self.tag = '</body>'

if hasattr(settings, 'DEBUG_TOOLBAR_CONFIG'):
show_toolbar_callback = settings.DEBUG_TOOLBAR_CONFIG.get(
Expand All @@ -57,7 +59,7 @@ def __init__(self):

tag = settings.DEBUG_TOOLBAR_CONFIG.get('TAG', None)
if tag:
self.tag = u'</' + tag + u'>'
self.tag = '</' + tag + '>'

def _show_toolbar(self, request):
if getattr(settings, 'TEST', False):
Expand All @@ -76,13 +78,13 @@ def process_request(self, request):
__traceback_hide__ = True
if self.show_toolbar(request):
urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF)
if isinstance(urlconf, basestring):
if isinstance(urlconf, string_types):
urlconf = import_module(getattr(request, 'urlconf', settings.ROOT_URLCONF))

if urlconf not in self._urlconfs:
new_urlconf = imp.new_module('urlconf')
new_urlconf.urlpatterns = debug_toolbar.urls.urlpatterns + \
list(urlconf.urlpatterns)
list(urlconf.urlpatterns)

if hasattr(urlconf, 'handler403'):
new_urlconf.handler403 = urlconf.handler403
Expand All @@ -98,11 +100,11 @@ def process_request(self, request):
toolbar = DebugToolbar(request)
for panel in toolbar.panels:
panel.process_request(request)
self.__class__.debug_toolbars[thread.get_ident()] = toolbar
self.__class__.debug_toolbars[_thread.get_ident()] = toolbar

def process_view(self, request, view_func, view_args, view_kwargs):
__traceback_hide__ = True
toolbar = self.__class__.debug_toolbars.get(thread.get_ident())
toolbar = self.__class__.debug_toolbars.get(_thread.get_ident())
if not toolbar:
return
result = None
Expand All @@ -114,7 +116,7 @@ def process_view(self, request, view_func, view_args, view_kwargs):

def process_response(self, request, response):
__traceback_hide__ = True
ident = thread.get_ident()
ident = _thread.get_ident()
toolbar = self.__class__.debug_toolbars.get(ident)
if not toolbar or request.is_ajax():
return response
Expand All @@ -134,9 +136,9 @@ def process_response(self, request, response):
for panel in toolbar.panels:
panel.process_response(request, response)
response.content = replace_insensitive(
smart_unicode(response.content),
smart_text(response.content),
self.tag,
smart_unicode(toolbar.render_toolbar() + self.tag))
smart_text(toolbar.render_toolbar() + self.tag))
if response.get('Content-Length', None):
response['Content-Length'] = len(response.content)
del self.__class__.debug_toolbars[ident]
Expand Down
6 changes: 4 additions & 2 deletions debug_toolbar/panels/cache.py
@@ -1,3 +1,4 @@
from __future__ import unicode_literals
import inspect
import sys
import time
Expand All @@ -10,6 +11,7 @@
from django.template import Node
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext_lazy as _, ungettext
from django.utils.six import iteritems

from debug_toolbar.panels import DebugPanel
from debug_toolbar.utils import (tidy_stacktrace, render_stacktrace,
Expand Down Expand Up @@ -59,7 +61,7 @@ def __init__(self, cache):
self.cache = cache

def __repr__(self):
return u"<CacheStatTracker for %s>" % self.cache.__repr__()
return "<CacheStatTracker for %s>" % self.cache.__repr__()

def _get_func_info(self):
frame = sys._getframe(3)
Expand Down Expand Up @@ -166,7 +168,7 @@ def _store_call_info(self, sender, name=None, time_taken=0,
else:
self.hits += 1
elif name == 'get_many':
for key, value in return_value.iteritems():
for key, value in iteritems(return_value):
if value is None:
self.misses += 1
else:
Expand Down
14 changes: 8 additions & 6 deletions debug_toolbar/panels/profiling.py
@@ -1,5 +1,7 @@
from __future__ import unicode_literals
from __future__ import division

from django.utils.six import iteritems
from django.utils.translation import ugettext_lazy as _
from django.utils.safestring import mark_safe
from debug_toolbar.panels import DebugPanel
Expand All @@ -23,7 +25,7 @@ class DjangoDebugToolbarStats(Stats):

def get_root_func(self):
if self.__root is None:
for func, (cc, nc, tt, ct, callers) in self.stats.iteritems():
for func, (cc, nc, tt, ct, callers) in iteritems(self.stats):
if len(callers) == 0:
self.__root = func
break
Expand Down Expand Up @@ -80,7 +82,7 @@ def subfuncs(self):
i = 0
h, s, v = self.hsv
count = len(self.statobj.all_callees[self.func])
for func, stats in self.statobj.all_callees[self.func].iteritems():
for func, stats in iteritems(self.statobj.all_callees[self.func]):
i += 1
h1 = h + (i / count) / (self.depth + 1)
if stats[3] == 0:
Expand Down Expand Up @@ -155,12 +157,12 @@ def title(self):
return _('Profiling')

def _unwrap_closure_and_profile(self, func):
if not hasattr(func, 'func_code'):
if not hasattr(func, '__code__'):
return
self.line_profiler.add_function(func)
if func.func_closure:
for cell in func.func_closure:
if hasattr(cell.cell_contents, 'func_code'):
if func.__closure__:
for cell in func.__closure__:
if hasattr(cell.cell_contents, '__code__'):
self._unwrap_closure_and_profile(cell.cell_contents)

def process_view(self, request, view_func, view_args, view_kwargs):
Expand Down
3 changes: 2 additions & 1 deletion debug_toolbar/panels/request_vars.py
@@ -1,6 +1,7 @@
from django.core.urlresolvers import resolve
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
from django.utils.six import iterkeys

from debug_toolbar.panels import DebugPanel
from debug_toolbar.utils import get_name_from_obj
Expand Down Expand Up @@ -53,5 +54,5 @@ def process_response(self, request, response):
if hasattr(self.request, 'session'):
self.record_stats({
'session': [(k, self.request.session.get(k))
for k in self.request.session.iterkeys()]
for k in iterkeys(self.request.session)]
})
14 changes: 9 additions & 5 deletions debug_toolbar/panels/sql.py
@@ -1,20 +1,22 @@
import re
import uuid
import sqlparse

from django.db.backends import BaseDatabaseWrapper
from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _, ungettext_lazy as __
from django.utils.six import itervalues

from debug_toolbar.utils.compat.db import connections
from debug_toolbar.middleware import DebugToolbarMiddleware
from debug_toolbar.panels import DebugPanel
from debug_toolbar.utils import sqlparse, render_stacktrace
from debug_toolbar.utils import render_stacktrace
from debug_toolbar.utils.tracking.db import CursorWrapper
from debug_toolbar.utils.tracking import replace_call
from debug_toolbar.utils.tracking import monkey_patch_call


# Inject our tracking cursor
@replace_call(BaseDatabaseWrapper.cursor)
@monkey_patch_call(BaseDatabaseWrapper, 'cursor')
def cursor(func, self):
result = func(self)

Expand All @@ -25,6 +27,8 @@ def cursor(func, self):

return CursorWrapper(result, self, logger=logger)

BaseDatabaseWrapper.cursor = cursor


def get_isolation_level_display(engine, level):
if engine == 'psycopg2':
Expand Down Expand Up @@ -134,7 +138,7 @@ def process_response(self, request, response):
if self._queries:
width_ratio_tally = 0
factor = int(256.0 / (len(self._databases) * 2.5))
for n, db in enumerate(self._databases.itervalues()):
for n, db in enumerate(itervalues(self._databases)):
rgb = [0, 0, 0]
color = n % 3
rgb[color] = 256 - n / 3 * factor
Expand Down Expand Up @@ -195,7 +199,7 @@ def process_response(self, request, response):
})


class BoldKeywordFilter(sqlparse.filters.Filter):
class BoldKeywordFilter():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize the Filter class has process as its only method, but it still seems reasonable to subclass it IMO. Did this cause a Python 3 problem?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filter no longer exists in sqlparse
On Apr 25, 2013 7:29 PM, "Rob Hudson" notifications@github.com wrote:

In debug_toolbar/panels/sql.py:

@@ -195,7 +199,7 @@ def process_response(self, request, response):
})

-class BoldKeywordFilter(sqlparse.filters.Filter):
+class BoldKeywordFilter():

I realize the Filter class has process as its only method, but it still
seems reasonable to subclass it IMO. Did this cause a Python 3 problem?


Reply to this email directly or view it on GitHubhttps://github.com//pull/373/files#r3963165
.

"""sqlparse filter to bold SQL keywords"""
def process(self, stack, stream):
"""Process the token stream"""
Expand Down
4 changes: 2 additions & 2 deletions debug_toolbar/templates/debug_toolbar/panels/cache.html
Expand Up @@ -22,14 +22,14 @@ <h3>{% trans "Commands" %}</h3>
<table>
<thead>
<tr>
{% for name in counts.iterkeys %}
{% for name in counts.keys %}
<th>{{ name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr>
{% for value in counts.itervalues %}
{% for value in counts.values %}
<td>{{ value }}</td>
{% endfor %}
</tr>
Expand Down
2 changes: 1 addition & 1 deletion debug_toolbar/templates/debug_toolbar/panels/headers.html
Expand Up @@ -7,7 +7,7 @@
</tr>
</thead>
<tbody>
{% for key, value in headers.iteritems %}
{% for key, value in headers.items %}
<tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ key|escape }}</td>
<td>{{ value|escape }}</td>
Expand Down
Expand Up @@ -31,7 +31,7 @@ <h4>{% blocktrans count templates|length as template_count %}Template{% plural %
<h4>{% blocktrans count context_processors|length as context_processors_count %}Context processor{% plural %}Context processors{% endblocktrans %}</h4>
{% if context_processors %}
<dl>
{% for key, value in context_processors.iteritems %}
{% for key, value in context_processors.items %}
<dt><strong>{{ key|escape }}</strong></dt>
<dd>
<div class="djTemplateShowContextDiv"><a class="djTemplateShowContext"><span class="toggleArrow">&#x25B6;</span> {% trans 'Toggle Context' %}</a></div>
Expand Down
2 changes: 1 addition & 1 deletion debug_toolbar/templates/debug_toolbar/panels/versions.html
Expand Up @@ -7,7 +7,7 @@
</tr>
</thead>
<tbody>
{% for package, version in versions.iteritems %}
{% for package, version in versions.items %}
<tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ package }}</td>
<td>{{ version }}</td>
Expand Down
7 changes: 4 additions & 3 deletions debug_toolbar/toolbar/loader.py
@@ -1,3 +1,4 @@
from __future__ import unicode_literals
"""
The main DebugToolbar class that loads and renders the Toolbar.
"""
Expand All @@ -19,7 +20,7 @@ def __init__(self, request):
base_url = self.request.META.get('SCRIPT_NAME', '')
self.config = {
'INTERCEPT_REDIRECTS': True,
'MEDIA_URL': u'%s/__debug__/m/' % base_url
'MEDIA_URL': '%s/__debug__/m/' % base_url
}
# Check if settings has a DEBUG_TOOLBAR_CONFIG and updated config
self.config.update(getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}))
Expand All @@ -33,7 +34,7 @@ def __init__(self, request):
self.stats = {}

def _get_panels(self):
return self._panels.values()
return list(self._panels.values())
panels = property(_get_panels)

def get_panel(self, cls):
Expand Down Expand Up @@ -93,7 +94,7 @@ def load_panel_classes():
panel_module, panel_classname = panel_path[:dot], panel_path[dot + 1:]
try:
mod = import_module(panel_module)
except ImportError, e:
except ImportError as e:
raise ImproperlyConfigured(
'Error importing debug panel %s: "%s"' %
(panel_module, e))
Expand Down