diff --git a/categories/__init__.py b/categories/__init__.py index 035da6a..df598df 100644 --- a/categories/__init__.py +++ b/categories/__init__.py @@ -29,4 +29,4 @@ def register(): try: register() except Exception as e: - print e + print(e) diff --git a/categories/admin.py b/categories/admin.py index c61f26f..26b8949 100644 --- a/categories/admin.py +++ b/categories/admin.py @@ -11,7 +11,7 @@ from .settings import MODEL_REGISTRY class NullTreeNodeChoiceField(forms.ModelChoiceField): """A ModelChoiceField for tree nodes.""" - def __init__(self, level_indicator=u'---', *args, **kwargs): + def __init__(self, level_indicator='---', *args, **kwargs): self.level_indicator = level_indicator super(NullTreeNodeChoiceField, self).__init__(*args, **kwargs) @@ -20,7 +20,7 @@ class NullTreeNodeChoiceField(forms.ModelChoiceField): Creates labels which represent the tree level of each node when generating option labels. """ - return u'%s %s' % (self.level_indicator * getattr( + return '%s %s' % (self.level_indicator * getattr( obj, obj._mptt_meta.level_attr), obj) if RELATION_MODELS: from .models import CategoryRelation @@ -68,8 +68,8 @@ class CategoryAdmin(CategoryBaseAdmin): if REGISTER_ADMIN: admin.site.register(Category, CategoryAdmin) -for model, modeladmin in admin.site._registry.items(): - if model in MODEL_REGISTRY.values() and modeladmin.fieldsets: +for model, modeladmin in list(admin.site._registry.items()): + if model in list(MODEL_REGISTRY.values()) and modeladmin.fieldsets: fieldsets = getattr(modeladmin, 'fieldsets', ()) fields = [cat.split('.')[2] for cat in MODEL_REGISTRY if MODEL_REGISTRY[cat] == model] # check each field to see if already defined diff --git a/categories/apps.py b/categories/apps.py index daab55b..02e70e0 100644 --- a/categories/apps.py +++ b/categories/apps.py @@ -26,12 +26,12 @@ def handle_class_prepared(sender, **kwargs): sender_app = sender._meta.app_label sender_name = sender._meta.model_name - for key, val in FK_REGISTRY.items(): + for key, val in list(FK_REGISTRY.items()): app_name, model_name = key.split('.') if app_name == sender_app and sender_name == model_name: registry.register_model(app_name, sender, 'ForeignKey', val) - for key, val in M2M_REGISTRY.items(): + for key, val in list(M2M_REGISTRY.items()): app_name, model_name = key.split('.') if app_name == sender_app and sender_name == model_name: registry.register_model(app_name, sender, 'ManyToManyField', val) diff --git a/categories/editor/templatetags/admin_tree_list_tags.py b/categories/editor/templatetags/admin_tree_list_tags.py index a019b2e..a9f4db5 100644 --- a/categories/editor/templatetags/admin_tree_list_tags.py +++ b/categories/editor/templatetags/admin_tree_list_tags.py @@ -91,10 +91,10 @@ def items_for_tree_result(cl, result, form): result_id = repr(force_unicode(value))[1:] first = False if django.VERSION[1] < 4: - yield mark_safe(u'<%s%s>%s%s' % \ + yield mark_safe('<%s%s>%s%s' % \ (table_tag, row_class, checkbox_value, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag)) else: - yield mark_safe(u'<%s%s>%s' % \ + yield mark_safe('<%s%s>%s' % \ (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag)) else: @@ -106,9 +106,9 @@ def items_for_tree_result(cl, result, form): result_repr = mark_safe(force_unicode(bf.errors) + force_unicode(bf)) else: result_repr = conditional_escape(result_repr) - yield mark_safe(u'%s' % (row_class, result_repr)) + yield mark_safe('%s' % (row_class, result_repr)) if form and not form[cl.model._meta.pk.name].is_hidden: - yield mark_safe(u'%s' % force_unicode(form[cl.model._meta.pk.name])) + yield mark_safe('%s' % force_unicode(form[cl.model._meta.pk.name])) class TreeList(list): diff --git a/categories/editor/tree_editor.py b/categories/editor/tree_editor.py index 7df5732..c2769da 100644 --- a/categories/editor/tree_editor.py +++ b/categories/editor/tree_editor.py @@ -9,7 +9,7 @@ from django.shortcuts import render_to_response import django -import settings +from . import settings class TreeEditorQuerySet(QuerySet): @@ -162,7 +162,7 @@ class TreeEditor(admin.ModelAdmin): # parameter via the query string. If wacky parameters were given and # the 'invalid=1' parameter was already in the query string, something # is screwed up with the database, so display an error page. - if ERROR_FLAG in request.GET.keys(): + if ERROR_FLAG in list(request.GET.keys()): return render_to_response( 'admin/invalid_setup.html', {'title': _('Database error')}) return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1') diff --git a/categories/editor/utils.py b/categories/editor/utils.py index b8d7e78..11871d1 100644 --- a/categories/editor/utils.py +++ b/categories/editor/utils.py @@ -11,6 +11,7 @@ from django.utils.translation import get_date_formats from django.utils.text import capfirst from django.utils import dateformat from django.utils.html import escape +import collections def lookup_field(name, obj, model_admin=None): @@ -20,7 +21,7 @@ def lookup_field(name, obj, model_admin=None): except models.FieldDoesNotExist: # For non-field values, the value is either a method, property or # returned via a callable. - if callable(name): + if isinstance(name, collections.Callable): attr = name value = attr(obj) elif (model_admin is not None and hasattr(model_admin, name) and @@ -29,7 +30,7 @@ def lookup_field(name, obj, model_admin=None): value = attr(obj) else: attr = getattr(obj, name) - if callable(attr): + if isinstance(attr, collections.Callable): value = attr() else: value = attr @@ -57,12 +58,12 @@ def label_for_field(name, model, model_admin=None, return_attr=False): except models.FieldDoesNotExist: if name == "__unicode__": label = force_unicode(model._meta.verbose_name) - attr = unicode + attr = str elif name == "__str__": label = smart_str(model._meta.verbose_name) attr = str else: - if callable(name): + if isinstance(name, collections.Callable): attr = name elif model_admin is not None and hasattr(model_admin, name): attr = getattr(model_admin, name) @@ -76,7 +77,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False): if hasattr(attr, "short_description"): label = attr.short_description - elif callable(attr): + elif isinstance(attr, collections.Callable): if attr.__name__ == "": label = "--" else: diff --git a/categories/management/commands/drop_category_field.py b/categories/management/commands/drop_category_field.py index 3163e01..ed9e710 100644 --- a/categories/management/commands/drop_category_field.py +++ b/categories/management/commands/drop_category_field.py @@ -21,6 +21,6 @@ class Command(BaseCommand): from categories.migration import drop_field if len(args) != 3: - print "You must specify an Application name, a Model name and a Field name" + print("You must specify an Application name, a Model name and a Field name") drop_field(*args) diff --git a/categories/management/commands/import_categories.py b/categories/management/commands/import_categories.py index f0f164e..5599d53 100644 --- a/categories/management/commands/import_categories.py +++ b/categories/management/commands/import_categories.py @@ -81,7 +81,7 @@ class Command(BaseCommand): for file_path in file_paths: if not os.path.isfile(file_path): - print "File %s not found." % file_path + print("File %s not found." % file_path) continue f = file(file_path, 'r') data = f.readlines() diff --git a/categories/migration.py b/categories/migration.py index 77b061b..57b2788 100644 --- a/categories/migration.py +++ b/categories/migration.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import connection, transaction from django.apps import apps @@ -47,7 +47,7 @@ def migrate_app(sender, *args, **kwargs): app_name = app_config.label - fields = [fld for fld in registry._field_registry.keys() if fld.startswith(app_name)] + fields = [fld for fld in list(registry._field_registry.keys()) if fld.startswith(app_name)] sid = transaction.savepoint() for fld in fields: diff --git a/categories/migrations/0001_initial.py b/categories/migrations/0001_initial.py index 207a589..e4e1c59 100644 --- a/categories/migrations/0001_initial.py +++ b/categories/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import django.core.files.storage diff --git a/categories/models.py b/categories/models.py index 7383195..12dfa92 100644 --- a/categories/models.py +++ b/categories/models.py @@ -2,6 +2,7 @@ from django.core.urlresolvers import reverse from django.db import models from django.utils.encoding import force_unicode from django.contrib.contenttypes.models import ContentType +from functools import reduce try: from django.contrib.contenttypes.fields import GenericForeignKey except ImportError: @@ -141,7 +142,7 @@ class CategoryRelation(models.Model): objects = CategoryRelationManager() def __unicode__(self): - return u"CategoryRelation" + return "CategoryRelation" try: from south.db import db # South is required for migrating. Need to check for it diff --git a/categories/registration.py b/categories/registration.py index 6631f70..61cc1d8 100644 --- a/categories/registration.py +++ b/categories/registration.py @@ -2,7 +2,7 @@ These functions handle the adding of fields to other models """ from django.db.models import FieldDoesNotExist, ForeignKey, ManyToManyField -import fields +from . import fields # from settings import self._field_registry, self._model_registry from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ImproperlyConfigured @@ -32,7 +32,7 @@ class Registry(object): app_label = app - if isinstance(field_definitions, basestring): + if isinstance(field_definitions, str): field_definitions = [field_definitions] elif not isinstance(field_definitions, collections.Iterable): raise ImproperlyConfigured(_('Field configuration for %(app)s should ' @@ -64,7 +64,7 @@ class Registry(object): extra_params = {'to': 'categories.Category', 'blank': True} if field_type != 'ManyToManyField': extra_params['null'] = True - if isinstance(fld, basestring): + if isinstance(fld, str): field_name = fld elif isinstance(fld, dict): if 'name' in fld: @@ -121,13 +121,13 @@ def _process_registry(registry, call_func): from django.core.exceptions import ImproperlyConfigured from django.db.models.loading import get_model - for key, value in registry.items(): + for key, value in list(registry.items()): model = get_model(*key.split('.')) if model is None: raise ImproperlyConfigured(_('%(key)s is not a model') % {'key': key}) if isinstance(value, (tuple, list)): for item in value: - if isinstance(item, basestring): + if isinstance(item, str): call_func(model, item) elif isinstance(item, dict): field_name = item.pop('name') @@ -135,7 +135,7 @@ def _process_registry(registry, call_func): else: raise ImproperlyConfigured(_("%(settings)s doesn't recognize the value of %(key)s") % {'settings': 'CATEGORY_SETTINGS', 'key': key}) - elif isinstance(value, basestring): + elif isinstance(value, str): call_func(model, value) elif isinstance(value, dict): field_name = value.pop('name') diff --git a/categories/settings.py b/categories/settings.py index 2d1589d..b3d8d51 100644 --- a/categories/settings.py +++ b/categories/settings.py @@ -1,6 +1,7 @@ from django.conf import settings from django.db.models import Q from django.utils.translation import ugettext_lazy as _ +import collections DEFAULT_SETTINGS = { 'ALLOW_SLUG_CHANGE': False, @@ -18,9 +19,9 @@ DEFAULT_SETTINGS = { DEFAULT_SETTINGS.update(getattr(settings, 'CATEGORIES_SETTINGS', {})) if DEFAULT_SETTINGS['SLUG_TRANSLITERATOR']: - if callable(DEFAULT_SETTINGS['SLUG_TRANSLITERATOR']): + if isinstance(DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'], collections.Callable): pass - elif isinstance(DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'], basestring): + elif isinstance(DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'], str): from django.utils.importlib import import_module bits = DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'].split(".") module = import_module(".".join(bits[:-1])) diff --git a/categories/south_migration.py b/categories/south_migration.py index 431cbe0..9ce9bcf 100644 --- a/categories/south_migration.py +++ b/categories/south_migration.py @@ -11,22 +11,22 @@ def migrate_app(sender, app, created_models=None, verbosity=False, *args, **kwar from .models import Category from .registration import registry import sys - import StringIO + import io org_stderror = sys.stderr - sys.stderr = StringIO.StringIO() # south will print out errors to stderr + sys.stderr = io.StringIO() # south will print out errors to stderr try: from south.db import db except ImportError: raise ImproperlyConfigured(_('%(dependency)s must be installed for this command to work') % {'dependency': 'South'}) # pull the information from the registry - if isinstance(app, basestring): + if isinstance(app, str): app_name = app else: app_name = app.__name__.split('.')[-2] - fields = [fld for fld in registry._field_registry.keys() if fld.startswith(app_name)] + fields = [fld for fld in list(registry._field_registry.keys()) if fld.startswith(app_name)] # call the south commands to add the fields/tables for fld in fields: app_name, model_name, field_name = fld.split('.') @@ -43,14 +43,14 @@ def migrate_app(sender, app, created_models=None, verbosity=False, *args, **kwar db.add_column(table_name, field_name, registry._field_registry[fld], keep_default=False) db.commit_transaction() if verbosity: - print (_('Added ForeignKey %(field_name)s to %(model_name)s') % - {'field_name': field_name, 'model_name': model_name}) - except DatabaseError, e: + print((_('Added ForeignKey %(field_name)s to %(model_name)s') % + {'field_name': field_name, 'model_name': model_name})) + except DatabaseError as e: db.rollback_transaction() if "already exists" in str(e): if verbosity > 1: - print (_('ForeignKey %(field_name)s to %(model_name)s already exists') % - {'field_name': field_name, 'model_name': model_name}) + print((_('ForeignKey %(field_name)s to %(model_name)s already exists') % + {'field_name': field_name, 'model_name': model_name})) else: sys.stderr = org_stderror raise e @@ -66,14 +66,14 @@ def migrate_app(sender, app, created_models=None, verbosity=False, *args, **kwar db.create_unique(table_name, ['%s_id' % model_name, 'category_id']) db.commit_transaction() if verbosity: - print (_('Added Many2Many table between %(model_name)s and %(category_table)s') % - {'model_name': model_name, 'category_table': 'category'}) - except DatabaseError, e: + print((_('Added Many2Many table between %(model_name)s and %(category_table)s') % + {'model_name': model_name, 'category_table': 'category'})) + except DatabaseError as e: db.rollback_transaction() if "already exists" in str(e): if verbosity > 1: - print (_('Many2Many table between %(model_name)s and %(category_table)s already exists') % - {'model_name': model_name, 'category_table': 'category'}) + print((_('Many2Many table between %(model_name)s and %(category_table)s already exists') % + {'model_name': model_name, 'category_table': 'category'})) else: sys.stderr = org_stderror raise e @@ -98,23 +98,23 @@ def drop_field(app_name, model_name, field_name): fld = '%s.%s.%s' % (app_name, model_name, field_name) if isinstance(registry._field_registry[fld], CategoryFKField): - print (_('Dropping ForeignKey %(field_name)s from %(model_name)s') % - {'field_name': field_name, 'model_name': model_name}) + print((_('Dropping ForeignKey %(field_name)s from %(model_name)s') % + {'field_name': field_name, 'model_name': model_name})) try: db.start_transaction() table_name = mdl._meta.db_table db.delete_column(table_name, field_name) db.commit_transaction() - except DatabaseError, e: + except DatabaseError as e: db.rollback_transaction() raise e elif isinstance(registry._field_registry[fld], CategoryM2MField): - print (_('Dropping Many2Many table between %(model_name)s and %(category_table)s') % - {'model_name': model_name, 'category_table': 'category'}) + print((_('Dropping Many2Many table between %(model_name)s and %(category_table)s') % + {'model_name': model_name, 'category_table': 'category'})) try: db.start_transaction() db.delete_table(table_name, cascade=False) db.commit_transaction() - except DatabaseError, e: + except DatabaseError as e: db.rollback_transaction() raise e diff --git a/categories/templatetags/category_tags.py b/categories/templatetags/category_tags.py index f21a42a..8e75f9a 100644 --- a/categories/templatetags/category_tags.py +++ b/categories/templatetags/category_tags.py @@ -30,7 +30,7 @@ def get_cat_model(model): Return a class from a string or class """ try: - if isinstance(model, basestring): + if isinstance(model, str): model_class = get_model(*model.split(".")) elif issubclass(model, CategoryBase): model_class = model @@ -119,13 +119,13 @@ def get_category_drilldown(parser, token): '{%% %(tagname)s category_obj as varname %%}.' if len(bits) == 4: if bits[2] != 'as': - raise template.TemplateSyntaxError, error_str % {'tagname': bits[0]} + raise template.TemplateSyntaxError(error_str % {'tagname': bits[0]}) if bits[2] == 'as': varname = bits[3].strip("'\"") model = "categories.category" if len(bits) == 6: if bits[2] not in ('using', 'as') or bits[4] not in ('using', 'as'): - raise template.TemplateSyntaxError, error_str % {'tagname': bits[0]} + raise template.TemplateSyntaxError(error_str % {'tagname': bits[0]}) if bits[2] == 'as': varname = bits[3].strip("'\"") model = bits[5].strip("'\"") diff --git a/categories/tests/test_templatetags.py b/categories/tests/test_templatetags.py index 1ec8a80..526157f 100644 --- a/categories/tests/test_templatetags.py +++ b/categories/tests/test_templatetags.py @@ -28,40 +28,40 @@ class CategoryTagsTest(TestCase): Test that we can properly retrieve a category. """ # display_path_as_ul - rock_resp = u'' + rock_resp = '' resp = self.render_template('{% load category_tags %}{% display_path_as_ul "/Rock" %}') resp = re.sub(r'\n$', "", resp) self.assertEqual(resp, rock_resp) # display_drilldown_as_ul - expected_resp = u'' + expected_resp = '' resp = self.render_template('{% load category_tags %}' '{% display_drilldown_as_ul "/World/Worldbeat" "categories.category" %}') resp = re.sub(r'\n$', "", resp) self.assertEqual(resp, expected_resp) # breadcrumbs - expected_resp = u'World > Worldbeat' + expected_resp = 'World > Worldbeat' resp = self.render_template('{% load category_tags %}' '{% breadcrumbs "/World/Worldbeat" " > " "categories.category" %}') self.assertEqual(resp, expected_resp) # get_top_level_categories - expected_resp = u'Avant-garde|Blues|Country|Easy listening|Electronic|Hip hop/Rap music|Jazz|Latin|Modern folk|Pop|Reggae|Rhythm and blues|Rock|World|' + expected_resp = 'Avant-garde|Blues|Country|Easy listening|Electronic|Hip hop/Rap music|Jazz|Latin|Modern folk|Pop|Reggae|Rhythm and blues|Rock|World|' resp = self.render_template('{% load category_tags %}' '{% get_top_level_categories using "categories.category" as varname %}' '{% for item in varname %}{{ item }}|{% endfor %}') self.assertEqual(resp, expected_resp) # get_category_drilldown - expected_resp = u"World|World > Worldbeat|" + expected_resp = "World|World > Worldbeat|" resp = self.render_template('{% load category_tags %}' '{% get_category_drilldown "/World" using "categories.category" as var %}' '{% for item in var %}{{ item }}|{% endfor %}') self.assertEqual(resp, expected_resp) # recursetree - expected_resp = u'
  • Country
    • Country pop
      • Urban Cowboy
  • World
    • Worldbeat
    ' + expected_resp = '
    • Country
      • Country pop
        • Urban Cowboy
    • World
      • Worldbeat
      ' ctxt = {'nodes': Category.objects.filter(name__in=("Worldbeat", "Urban Cowboy"))} resp = self.render_template('{% load category_tags %}' '
        {% recursetree nodes|tree_queryset %}
      • {{ node.name }}' diff --git a/categories/views.py b/categories/views.py index 9d5d383..21311d6 100644 --- a/categories/views.py +++ b/categories/views.py @@ -63,14 +63,14 @@ class CategoryDetailView(DetailView): def get_object(self, **kwargs): if self.path_field not in self.kwargs: - raise AttributeError(u"Category detail view %s must be called with " - u"a %s." % self.__class__.__name__, self.path_field) + raise AttributeError("Category detail view %s must be called with " + "a %s." % self.__class__.__name__, self.path_field) if self.queryset is None: queryset = self.get_queryset() try: return get_category_for_path(self.kwargs[self.path_field], self.model.objects.all()) except ObjectDoesNotExist: - raise Http404(_(u"No %(verbose_name)s found matching the query") % + raise Http404(_("No %(verbose_name)s found matching the query") % {'verbose_name': queryset.model._meta.verbose_name}) def get_template_names(self): diff --git a/doc_src/conf.py b/doc_src/conf.py index 51ac114..5773732 100644 --- a/doc_src/conf.py +++ b/doc_src/conf.py @@ -40,8 +40,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'Django Categories' -copyright = u'2010-2012, Corey Oordt' +project = 'Django Categories' +copyright = '2010-2012, Corey Oordt' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -175,8 +175,8 @@ htmlhelp_basename = 'DjangoCategoriesdoc' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'DjangoCategories.tex', u'Django Categories Documentation', - u'CoreyOordt', 'manual'), + ('index', 'DjangoCategories.tex', 'Django Categories Documentation', + 'CoreyOordt', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/example/simpletext/admin.py b/example/simpletext/admin.py index 55a5d73..9060c31 100644 --- a/example/simpletext/admin.py +++ b/example/simpletext/admin.py @@ -1,4 +1,4 @@ -from models import SimpleText, SimpleCategory +from .models import SimpleText, SimpleCategory from django.contrib import admin from categories.admin import CategoryBaseAdmin, CategoryBaseAdminForm diff --git a/example/simpletext/tests.py b/example/simpletext/tests.py index 2247054..c7c4668 100755 --- a/example/simpletext/tests.py +++ b/example/simpletext/tests.py @@ -12,7 +12,7 @@ class SimpleTest(TestCase): """ Tests that 1 + 1 always equals 2. """ - self.failUnlessEqual(1 + 1, 2) + self.assertEqual(1 + 1, 2) __test__ = {"doctest": """ Another way to test that 1 + 1 is equal to 2.