Skip to content

Commit a765206

Browse files
committed
Add support for Python 3.3 (successfully run the testsuite at least)
1 parent 83d4fbf commit a765206

File tree

32 files changed

+187
-136
lines changed

32 files changed

+187
-136
lines changed

docs/admin.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ All standard :class:`~django.contrib.admin.options.ModelAdmin` attributes such a
5151
:attr:`ModelAdmin.list_display`, :attr:`ModelAdmin.list_editable`,
5252
:attr:`ModelAdmin.list_filter` work as normally. The only exception to this
5353
rule is the column showing the tree structure (the second column in the image).
54-
There, we always show the value of :attr:`Model.__unicode__` currently.
54+
There, we always show the value of :attr:`Model.__str__` currently.
5555

5656

5757
AJAX checkboxes
@@ -83,7 +83,7 @@ Usage::
8383
mptt.register(Category)
8484

8585
class CategoryAdmin(tree_editor.TreeEditor):
86-
list_display = ('__unicode__', 'active_toggle')
86+
list_display = ('__str__', 'active_toggle')
8787
active_toggle = tree_editor.ajax_editable_boolean('active', _('active'))
8888

8989

docs/integration.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ Django's standard functionality::
150150
class Meta:
151151
ordering = ['-id']
152152

153-
def __unicode__(self):
153+
def __str__(self):
154154
return self.title
155155

156156
@app_models.permalink

example/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from django import forms
22
from django.db import models
3+
from django.utils.encoding import python_2_unicode_compatible
34
from django.utils.text import capfirst
45
from django.utils.translation import ugettext_lazy as _
56

@@ -78,6 +79,7 @@ def children(self, page, **kwargs):
7879
)
7980

8081

82+
@python_2_unicode_compatible
8183
class Category(MPTTModel):
8284
name = models.CharField(max_length=20)
8385
slug = models.SlugField()
@@ -88,12 +90,10 @@ class Meta:
8890
verbose_name = 'category'
8991
verbose_name_plural = 'categories'
9092

91-
def __unicode__(self):
93+
def __str__(self):
9294
return self.name
9395

9496

9597
# add m2m field to entry so it shows up in entry admin
9698
Entry.add_to_class('categories', models.ManyToManyField(Category, blank=True, null=True))
9799
EntryAdmin.list_filter += ('categories',)
98-
99-

feincms/admin/item_editor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from django.forms.models import modelform_factory
1515
from django.http import Http404
1616
from django.shortcuts import render_to_response
17-
from django.utils.encoding import force_unicode
17+
from django.utils.encoding import force_text
1818
from django.utils.functional import curry
1919
from django.utils.translation import ugettext as _
2020

@@ -166,7 +166,7 @@ def _frontend_editing_view(self, request, cms_id, content_type, content_id):
166166
context = self.get_extra_context(request)
167167
context.update({
168168
'frontend_editing': True,
169-
'title': _('Change %s') % force_unicode(model_cls._meta.verbose_name),
169+
'title': _('Change %s') % force_text(model_cls._meta.verbose_name),
170170
'object': obj,
171171
'form': form,
172172
'is_popup': True,

feincms/admin/tree_editor.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# coding=utf-8
33
# ------------------------------------------------------------------------
44

5+
from functools import reduce
56
import json
67
import logging
78

@@ -16,7 +17,7 @@
1617
from django.utils.html import escape
1718
from django.utils.safestring import mark_safe
1819
from django.utils.translation import ugettext_lazy as _, ugettext
19-
from django.utils.encoding import force_unicode
20+
from django.utils.encoding import force_text
2021

2122
from mptt.exceptions import InvalidMove
2223
from mptt.forms import MPTTAdminForm
@@ -92,7 +93,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None):
9293
(useful for "disabled and you can't change it" situations).
9394
"""
9495
if text:
95-
text = ' (%s)' % unicode(text)
96+
text = u' (%s)' % text
9697

9798
if override is not None:
9899
a = [ django_boolean_icon(override, text), text ]
@@ -108,7 +109,7 @@ def ajax_editable_boolean_cell(item, attr, text='', override=None):
108109

109110
a.insert(0, '<div id="wrap_%s_%d">' % ( attr, item.pk ))
110111
a.append('</div>')
111-
return unicode(''.join(a))
112+
return u''.join(a)
112113

113114
# ------------------------------------------------------------------------
114115
def ajax_editable_boolean(attr, short_description):
@@ -119,7 +120,7 @@ def ajax_editable_boolean(attr, short_description):
119120
Example::
120121
121122
class MyTreeEditor(TreeEditor):
122-
list_display = ('__unicode__', 'active_toggle')
123+
list_display = ('__str__', 'active_toggle')
123124
124125
active_toggle = ajax_editable_boolean('active', _('is active'))
125126
"""
@@ -247,7 +248,7 @@ def indented_short_title(self, item):
247248
if hasattr(item, 'short_title') and callable(item.short_title):
248249
r += escape(item.short_title())
249250
else:
250-
r += escape(unicode(item))
251+
r += escape(u'%s' % item)
251252
# r += '</span>'
252253
return mark_safe(r)
253254
indented_short_title.short_description = _('title')
@@ -432,8 +433,8 @@ def _move_node(self, request):
432433
if position in ('last-child', 'left', 'right'):
433434
try:
434435
tree_manager.move_node(cut_item, pasted_on, position)
435-
except InvalidMove, e:
436-
self.message_user(request, unicode(e))
436+
except InvalidMove as e:
437+
self.message_user(request, u'%s' % e)
437438
return HttpResponse('FAIL')
438439

439440
# Ensure that model save has been run
@@ -470,7 +471,7 @@ def delete_selected_tree(self, modeladmin, request, queryset):
470471
if self.has_delete_permission(request, obj):
471472
obj.delete()
472473
n += 1
473-
obj_display = force_unicode(obj)
474+
obj_display = force_text(obj)
474475
self.log_deletion(request, obj, obj_display)
475476
else:
476477
logger.warning(

feincms/content/richtext/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,5 @@ def func_im(self, *args, **kwargs):
114114
# Make sure we can load the tidy function without dependency failures:
115115
try:
116116
get_object(settings.FEINCMS_TIDY_FUNCTION)
117-
except ImportError, e:
117+
except ImportError as e:
118118
raise ImproperlyConfigured("FEINCMS_TIDY_HTML is enabled but the HTML tidy function %s could not be imported: %s" % (settings.FEINCMS_TIDY_FUNCTION, e))

feincms/contrib/fields.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,39 @@
44
from django import forms
55
from django.db import models
66
from django.core.serializers.json import DjangoJSONEncoder
7+
from django.utils import six
78

89

910
class JSONFormField(forms.fields.CharField):
1011
def clean(self, value, *args, **kwargs):
1112
if value:
1213
try:
13-
# Run the value through JSON so we can normalize formatting and at least learn about malformed data:
14+
# Run the value through JSON so we can normalize formatting
15+
# and at least learn about malformed data:
1416
value = json.dumps(json.loads(value), cls=DjangoJSONEncoder)
1517
except ValueError:
1618
raise forms.ValidationError("Invalid JSON data!")
1719

1820
return super(JSONFormField, self).clean(value, *args, **kwargs)
1921

20-
class JSONField(models.TextField):
22+
23+
class JSONField(six.with_metaclass(models.SubfieldBase, models.TextField)):
2124
"""
2225
TextField which transparently serializes/unserializes JSON objects
2326
2427
See:
2528
http://www.djangosnippets.org/snippets/1478/
2629
"""
2730

28-
# Used so to_python() is called
29-
__metaclass__ = models.SubfieldBase
30-
3131
formfield = JSONFormField
3232

3333
def to_python(self, value):
3434
"""Convert our string value to JSON after we load it from the DB"""
3535

3636
if isinstance(value, dict):
3737
return value
38-
elif isinstance(value, basestring):
38+
elif (isinstance(value, six.string_types)
39+
or isinstance(value, six.binary_type)):
3940
# Avoid asking the JSON decoder to handle empty values:
4041
if not value:
4142
return {}
@@ -72,15 +73,18 @@ def _flatten_value(self, value):
7273
if isinstance(value, dict):
7374
value = json.dumps(value, cls=DjangoJSONEncoder)
7475

75-
assert isinstance(value, basestring)
76+
assert isinstance(value, six.string_types)
7677

7778
return value
7879

80+
7981
try:
8082
from south.modelsinspector import add_introspection_rules
8183

82-
JSONField_introspection_rule = ( (JSONField,), [], {}, )
84+
JSONField_introspection_rule = ((JSONField,), [], {},)
8385

84-
add_introspection_rules(rules=[JSONField_introspection_rule], patterns=["^feincms\.contrib\.fields"])
86+
add_introspection_rules(
87+
rules=[JSONField_introspection_rule],
88+
patterns=["^feincms\.contrib\.fields"])
8589
except ImportError:
8690
pass

feincms/extensions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from django.contrib import admin
99
from django.core.exceptions import ImproperlyConfigured
10+
from django.utils import six
1011

1112
from feincms.utils import get_object
1213

@@ -43,7 +44,7 @@ def register_extensions(cls, *extensions):
4344

4445
extension = None
4546

46-
if isinstance(ext, basestring):
47+
if isinstance(ext, six.string_types):
4748
try:
4849
extension = get_object(ext)
4950
except (AttributeError, ImportError, ValueError):

feincms/management/checker.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import print_function
2+
13
from django.core.management.color import color_style
24
from django.db import connection
35

@@ -39,17 +41,17 @@ def _fn(sender, **kwargs):
3941

4042
style = color_style()
4143

42-
print style.ERROR('The following columns seem to be missing in the database table %s:' % cls._meta.db_table)
44+
print(style.ERROR('The following columns seem to be missing in the database table %s:' % cls._meta.db_table))
4345
for field in missing_columns:
44-
print u'%s:%s%s' % (
46+
print(u'%s:%s%s' % (
4547
style.SQL_KEYWORD(field.column),
4648
' ' * (25 - len(field.column)),
4749
u'%s.%s' % (field.__class__.__module__, field.__class__.__name__),
48-
)
50+
))
4951

50-
print style.NOTICE('\nPlease consult the output of `python manage.py sql %s` to'
52+
print(style.NOTICE('\nPlease consult the output of `python manage.py sql %s` to'
5153
' find out what the correct column types are. (Or use south, which is what'
5254
' you should be doing anyway.)\n' % (
5355
cls._meta.app_label,
54-
))
56+
)))
5557
return _fn

feincms/management/commands/medialibrary_orphans.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22

33
from django.core.management.base import NoArgsCommand
4-
from django.utils.encoding import force_unicode
4+
from django.utils.encoding import force_text
55

66
from feincms.module.medialibrary.models import MediaFile
77

@@ -16,5 +16,5 @@ def handle_noargs(self, **options):
1616
for base, dirs, files in os.walk('media/medialibrary'):
1717
for f in files:
1818
full = os.path.join(base[6:], f)
19-
if force_unicode(full) not in mediafiles:
19+
if force_text(full) not in mediafiles:
2020
print os.path.join(base, f)

0 commit comments

Comments
 (0)