diff --git a/.travis.yml b/.travis.yml index 8310e44..8bd20d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ branches: - master env: + - TOXENV=py27-lint - TOXENV=py27-django18 - TOXENV=py27-django19 - TOXENV=py34-django18 diff --git a/categories/__init__.py b/categories/__init__.py index df598df..be4f387 100644 --- a/categories/__init__.py +++ b/categories/__init__.py @@ -21,6 +21,7 @@ __version__ = get_version() default_app_config = 'categories.apps.CategoriesConfig' + def register(): from categories import settings from categories.registration import (_process_registry, registry) diff --git a/categories/admin.py b/categories/admin.py index 26b8949..1789150 100644 --- a/categories/admin.py +++ b/categories/admin.py @@ -20,8 +20,8 @@ class NullTreeNodeChoiceField(forms.ModelChoiceField): Creates labels which represent the tree level of each node when generating option labels. """ - return '%s %s' % (self.level_indicator * getattr( - obj, obj._mptt_meta.level_attr), obj) + return '%s %s' % (self.level_indicator * getattr(obj, obj._mptt_meta.level_attr), obj) + if RELATION_MODELS: from .models import CategoryRelation @@ -50,7 +50,7 @@ class CategoryAdmin(CategoryBaseAdmin): }), (_('Meta Data'), { 'fields': ('alternate_title', 'alternate_url', 'description', - 'meta_keywords', 'meta_extra'), + 'meta_keywords', 'meta_extra'), 'classes': ('collapse',), }), (_('Advanced'), { diff --git a/categories/base.py b/categories/base.py index ff16f8e..7305cf8 100644 --- a/categories/base.py +++ b/categories/base.py @@ -35,7 +35,8 @@ class CategoryBase(MPTTModel): This base model includes the absolute bare bones fields and methods. One could simply subclass this model and do nothing else and it should work. """ - parent = TreeForeignKey('self', + parent = TreeForeignKey( + 'self', blank=True, null=True, related_name='children', @@ -99,9 +100,7 @@ class CategoryBaseAdminForm(forms.ModelForm): kwargs['parent__isnull'] = True else: kwargs['parent__pk'] = int(self.cleaned_data['parent'].id) - this_level_slugs = [c['slug'] for c in opts.model.objects.filter( - **kwargs).values('id', 'slug' - ) if c['id'] != self.instance.id] + this_level_slugs = [c['slug'] for c in opts.model.objects.filter(**kwargs).values('id', 'slug') if c['id'] != self.instance.id] if self.cleaned_data['slug'] in this_level_slugs: raise forms.ValidationError(_('The slug must be unique among ' 'the items at its level.')) diff --git a/categories/editor/models.py b/categories/editor/models.py index 8a93c30..3542496 100644 --- a/categories/editor/models.py +++ b/categories/editor/models.py @@ -1 +1 @@ -# Placeholder for Django \ No newline at end of file +# Placeholder for Django diff --git a/categories/editor/settings.py b/categories/editor/settings.py index 399142b..af293e5 100644 --- a/categories/editor/settings.py +++ b/categories/editor/settings.py @@ -4,7 +4,7 @@ import django DJANGO10_COMPAT = django.VERSION[0] < 1 or (django.VERSION[0] == 1 and django.VERSION[1] < 1) STATIC_URL = getattr(settings, 'STATIC_URL', settings.MEDIA_URL) -if STATIC_URL == None: +if STATIC_URL is None: STATIC_URL = settings.MEDIA_URL MEDIA_PATH = getattr(settings, 'EDITOR_MEDIA_PATH', '%seditor/' % STATIC_URL) diff --git a/categories/editor/templatetags/admin_tree_list_tags.py b/categories/editor/templatetags/admin_tree_list_tags.py index efd29f3..0e9a245 100644 --- a/categories/editor/templatetags/admin_tree_list_tags.py +++ b/categories/editor/templatetags/admin_tree_list_tags.py @@ -3,9 +3,9 @@ from django.db import models from django.template import Library from django.contrib.admin.templatetags.admin_list import result_headers, _boolean_icon try: - from django.contrib.admin.utils import lookup_field, display_for_field, label_for_field + from django.contrib.admin.utils import lookup_field, display_for_field except ImportError: - from categories.editor.utils import lookup_field, display_for_field, label_for_field + from categories.editor.utils import lookup_field, display_for_field from django.core.exceptions import ObjectDoesNotExist from django.utils.encoding import smart_text, force_text from django.utils.html import escape, conditional_escape @@ -99,10 +99,12 @@ def items_for_tree_result(cl, result, form): result_id = repr(force_text(value))[1:] first = False if django.VERSION[1] < 4: - yield mark_safe('<%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('<%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: @@ -151,9 +153,11 @@ def result_tree_list(cl): Displays the headers and data list together """ import django - result = {'cl': cl, - 'result_headers': list(result_headers(cl)), - 'results': list(tree_results(cl))} + result = { + 'cl': cl, + 'result_headers': list(result_headers(cl)), + 'results': list(tree_results(cl)) + } if django.VERSION[1] > 2: from django.contrib.admin.templatetags.admin_list import result_hidden_fields result['result_hidden_fields'] = list(result_hidden_fields(cl)) diff --git a/categories/editor/tree_editor.py b/categories/editor/tree_editor.py index 821f6a6..a450977 100644 --- a/categories/editor/tree_editor.py +++ b/categories/editor/tree_editor.py @@ -38,8 +38,7 @@ class TreeEditorQuerySet(QuerySet): # will already be in include_pages when they are checked, thus not # trigger additional queries. for p in super(TreeEditorQuerySet, self.order_by('rght')).iterator(): - if p.parent_id and p.parent_id not in include_pages and \ - p.id not in include_pages: + if p.parent_id and p.parent_id not in include_pages and p.id not in include_pages: ancestor_id_list = p.get_ancestors().values_list('id', flat=True) include_pages.update(ancestor_id_list) @@ -145,12 +144,14 @@ class TreeEditor(admin.ModelAdmin): try: if django.VERSION[1] < 4: - params = (request, self.model, list_display, + params = ( + request, self.model, list_display, self.list_display_links, self.list_filter, self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_editable, self) else: - params = (request, self.model, list_display, + params = ( + request, self.model, list_display, self.list_display_links, self.list_filter, self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self.list_max_show_all, @@ -244,8 +245,7 @@ class TreeEditor(admin.ModelAdmin): if django.VERSION[1] < 4: context['root_path'] = self.admin_site.root_path else: - selection_note_all = ungettext('%(total_count)s selected', - 'All %(total_count)s selected', cl.result_count) + selection_note_all = ungettext('%(total_count)s selected', 'All %(total_count)s selected', cl.result_count) context.update({ 'module_name': force_text(opts.verbose_name_plural), diff --git a/categories/editor/utils.py b/categories/editor/utils.py index 6664c65..c4c8ba4 100644 --- a/categories/editor/utils.py +++ b/categories/editor/utils.py @@ -24,8 +24,7 @@ def lookup_field(name, obj, model_admin=None): if isinstance(name, collections.Callable): attr = name value = attr(obj) - elif (model_admin is not None and hasattr(model_admin, name) and - not name == '__str__' and not name == '__unicode__'): + elif (model_admin is not None and hasattr(model_admin, name) and not name == '__str__' and not name == '__unicode__'): attr = getattr(model_admin, name) value = attr(obj) else: diff --git a/categories/genericcollection.py b/categories/genericcollection.py index 88eb416..daa03dc 100644 --- a/categories/genericcollection.py +++ b/categories/genericcollection.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.contrib.contenttypes.models import ContentType + class GenericCollectionInlineModelAdmin(admin.options.InlineModelAdmin): ct_field = "content_type" ct_fk_field = "object_id" @@ -17,6 +18,7 @@ class GenericCollectionInlineModelAdmin(admin.options.InlineModelAdmin): result.ct_fk_field = self.ct_fk_field return result + class GenericCollectionTabularInline(GenericCollectionInlineModelAdmin): template = 'admin/edit_inline/gen_coll_tabular.html' diff --git a/categories/management/commands/__init__.py b/categories/management/commands/__init__.py index 0721d7c..6b58348 100644 --- a/categories/management/commands/__init__.py +++ b/categories/management/commands/__init__.py @@ -1,7 +1,7 @@ try: - from south.db import db - from django.db.models.signals import post_syncdb - from categories.migration import migrate_app + from south.db import db # noqa + from django.db.models.signals import post_syncdb # noqa + from categories.migration import migrate_app # noqa post_syncdb.connect(migrate_app) except ImportError: diff --git a/categories/management/commands/add_category_fields.py b/categories/management/commands/add_category_fields.py index 2ef3070..53daf58 100644 --- a/categories/management/commands/add_category_fields.py +++ b/categories/management/commands/add_category_fields.py @@ -14,11 +14,6 @@ class Command(BaseCommand): """ Alter the tables """ - from django.core.exceptions import ImproperlyConfigured - try: - from south.db import db - except ImportError: - raise ImproperlyConfigured("South must be installed for this command to work") from categories.migration import migrate_app from categories.settings import MODEL_REGISTRY diff --git a/categories/management/commands/drop_category_field.py b/categories/management/commands/drop_category_field.py index ed9e710..c9adddb 100644 --- a/categories/management/commands/drop_category_field.py +++ b/categories/management/commands/drop_category_field.py @@ -14,10 +14,6 @@ class Command(BaseCommand): """ Alter the tables """ - try: - from south.db import db - except ImportError: - raise ImproperlyConfigured("South must be installed for this command to work") from categories.migration import drop_field if len(args) != 3: diff --git a/categories/management/commands/import_categories.py b/categories/management/commands/import_categories.py index fe75b23..a899e50 100644 --- a/categories/management/commands/import_categories.py +++ b/categories/management/commands/import_categories.py @@ -35,7 +35,7 @@ class Command(BaseCommand): cat = Category( name=string.strip(), slug=slugify(SLUG_TRANSLITERATOR(string.strip()))[:49], - #parent=parent, + # arent=parent, order=order ) cat._tree_manager.insert_node(cat, parent, 'last-child', True) diff --git a/categories/models.py b/categories/models.py index 1921cfe..a10675c 100644 --- a/categories/models.py +++ b/categories/models.py @@ -11,8 +11,7 @@ from django.core.files.storage import get_storage_class from django.utils.translation import ugettext_lazy as _ -from .settings import (RELATION_MODELS, RELATIONS, THUMBNAIL_UPLOAD_PATH, - THUMBNAIL_STORAGE) +from .settings import (RELATION_MODELS, RELATIONS, THUMBNAIL_UPLOAD_PATH, THUMBNAIL_STORAGE) from .base import CategoryBase @@ -133,7 +132,8 @@ class CategoryRelation(models.Model): ContentType, limit_choices_to=CATEGORY_RELATION_LIMITS, verbose_name=_('content type')) object_id = models.PositiveIntegerField(verbose_name=_('object id')) content_object = GenericForeignKey('content_type', 'object_id') - relation_type = models.CharField(verbose_name=_('relation type'), + relation_type = models.CharField( + verbose_name=_('relation type'), max_length=200, blank=True, null=True, @@ -145,7 +145,7 @@ class CategoryRelation(models.Model): return "CategoryRelation" try: - from south.db import db # South is required for migrating. Need to check for it + from south.db import db # noqa, South is required for migrating. Need to check for it from django.db.models.signals import post_syncdb from categories.migration import migrate_app post_syncdb.connect(migrate_app) diff --git a/categories/registration.py b/categories/registration.py index ad307cd..5eb8105 100644 --- a/categories/registration.py +++ b/categories/registration.py @@ -35,8 +35,7 @@ class Registry(object): if isinstance(field_definitions, str): field_definitions = [field_definitions] elif not isinstance(field_definitions, collections.Iterable): - raise ImproperlyConfigured(_('Field configuration for %(app)s should ' - 'be a string or iterable') % {'app': app}) + raise ImproperlyConfigured(_('Field configuration for %(app)s should be a string or iterable') % {'app': app}) if field_type not in ('ForeignKey', 'ManyToManyField'): raise ImproperlyConfigured(_('`field_type` must be either `"ForeignKey"` or `"ManyToManyField"`.')) @@ -73,8 +72,8 @@ class Registry(object): continue extra_params.update(fld) else: - raise ImproperlyConfigured(_("%(settings)s doesn't recognize the " - "value of %(app)s.%(model)s") % { + raise ImproperlyConfigured( + _("%(settings)s doesn't recognize the value of %(app)s.%(model)s") % { 'settings': 'CATEGORY_SETTINGS', 'app': app, 'model': model_name}) diff --git a/categories/settings.py b/categories/settings.py index b3d8d51..bf77d66 100644 --- a/categories/settings.py +++ b/categories/settings.py @@ -5,7 +5,6 @@ import collections DEFAULT_SETTINGS = { 'ALLOW_SLUG_CHANGE': False, - 'RELATION_MODELS': [], 'M2M_REGISTRY': {}, 'FK_REGISTRY': {}, 'THUMBNAIL_UPLOAD_PATH': 'uploads/categories/thumbnails', @@ -37,7 +36,7 @@ else: # Add all the keys/values to the module's namespace globals().update(DEFAULT_SETTINGS) -RELATIONS = [Q(app_label=al, model=m) for al, m in [x.split('.') for x in RELATION_MODELS]] +RELATIONS = [Q(app_label=al, model=m) for al, m in [x.split('.') for x in DEFAULT_SETTINGS['RELATION_MODELS']]] # The field registry keeps track of the individual fields created. # {'app.model.field': Field(**extra_params)} diff --git a/categories/templatetags/category_tags.py b/categories/templatetags/category_tags.py index 1617b26..1db869f 100644 --- a/categories/templatetags/category_tags.py +++ b/categories/templatetags/category_tags.py @@ -54,8 +54,7 @@ def get_category(category_string, model=Category): if len(cat_list) == 0: return None try: - categories = model_class.objects.filter(name=cat_list[-1], - level=len(cat_list) - 1) + categories = model_class.objects.filter(name=cat_list[-1], level=len(cat_list) - 1) if len(cat_list) == 1 and len(categories) > 1: return None # If there is only one, use it. If there is more than one, check @@ -265,8 +264,7 @@ def get_top_level_categories(parser, token): return TopLevelCategoriesNode(varname, model) -def get_latest_objects_by_category(category, app_label, model_name, set_name, - date_field='pub_date', num=15): +def get_latest_objects_by_category(category, app_label, model_name, set_name, date_field='pub_date', num=15): m = apps.get_model(app_label, model_name) if not isinstance(category, CategoryBase): category = Category.objects.get(slug=str(category)) @@ -304,8 +302,7 @@ class LatestObjectsNode(Node): date_field = resolve(self.date_field, context) num = resolve(self.num, context) - result = get_latest_objects_by_category(category, app_label, model_name, - set_name, date_field, num) + result = get_latest_objects_by_category(category, app_label, model_name, set_name, date_field, num) context[self.var_name] = result return '' @@ -339,8 +336,7 @@ def do_get_latest_objects_by_category(parser, token): num = FilterExpression(bits[6], parser) else: num = FilterExpression(None, parser) - return LatestObjectsNode(var_name, category, app_label, model_name, set_name, - date_field, num) + return LatestObjectsNode(var_name, category, app_label, model_name, set_name, date_field, num) register.tag("get_latest_objects_by_category", do_get_latest_objects_by_category) @@ -369,8 +365,7 @@ def tree_queryset(value): # will already be in include_pages when they are checked, thus not # trigger additional queries. for p in qs2.order_by('rght').iterator(): - if p.parent_id and p.parent_id not in include_pages and \ - p.id not in include_pages: + if p.parent_id and p.parent_id not in include_pages and p.id not in include_pages: ancestor_id_list = p.get_ancestors().values_list('id', flat=True) include_pages.update(ancestor_id_list) diff --git a/categories/tests/test_category_import.py b/categories/tests/test_category_import.py index 8384add..4ecde46 100644 --- a/categories/tests/test_category_import.py +++ b/categories/tests/test_category_import.py @@ -9,8 +9,6 @@ from categories.models import Category from categories.management.commands.import_categories import Command from django.core.management.base import CommandError -from categories.registration import _process_registry, registry - @override_settings(INSTALLED_APPS=(app for app in settings.INSTALLED_APPS if app != 'django.contrib.flatpages')) class CategoryImportTest(TestCase): diff --git a/categories/tests/test_registration.py b/categories/tests/test_registration.py index c4259d0..842baec 100644 --- a/categories/tests/test_registration.py +++ b/categories/tests/test_registration.py @@ -54,5 +54,3 @@ class Categorym2mTest(TestCase): _process_registry(M2M_REGISTRY, registry.register_m2m) from django.contrib.flatpages.models import FlatPage self.assertTrue('category' in [f.name for f in FlatPage()._meta.get_fields()]) - - diff --git a/categories/tests/test_templatetags.py b/categories/tests/test_templatetags.py index 526157f..f099715 100644 --- a/categories/tests/test_templatetags.py +++ b/categories/tests/test_templatetags.py @@ -35,27 +35,31 @@ class CategoryTagsTest(TestCase): # display_drilldown_as_ul expected_resp = '' - resp = self.render_template('{% load category_tags %}' + 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 = 'World > Worldbeat' - resp = self.render_template('{% load category_tags %}' + resp = self.render_template( + '{% load category_tags %}' '{% breadcrumbs "/World/Worldbeat" " > " "categories.category" %}') self.assertEqual(resp, expected_resp) # get_top_level_categories 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 %}' + 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 = "World|World > Worldbeat|" - resp = self.render_template('{% load category_tags %}' + 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) @@ -63,7 +67,8 @@ class CategoryTagsTest(TestCase): # recursetree expected_resp = '' ctxt = {'nodes': Category.objects.filter(name__in=("Worldbeat", "Urban Cowboy"))} - resp = self.render_template('{% load category_tags %}' + resp = self.render_template( + '{% load category_tags %}' '', ctxt) diff --git a/categories/urls.py b/categories/urls.py index c666c62..986df79 100644 --- a/categories/urls.py +++ b/categories/urls.py @@ -1,16 +1,8 @@ from django.conf.urls import url +from django.views.generic import ListView from .models import Category from . import views -try: - from django.views.generic import DetailView, ListView -except ImportError: - try: - from cbv import DetailView, ListView - except ImportError: - from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured("For older versions of Django, you need django-cbv.") - categorytree_dict = { 'queryset': Category.objects.filter(level=0) diff --git a/categories/views.py b/categories/views.py index 21311d6..e844b48 100644 --- a/categories/views.py +++ b/categories/views.py @@ -17,16 +17,17 @@ except ImportError: from .models import Category -def category_detail(request, path, - template_name='categories/category_detail.html', extra_context={}): +def category_detail(request, path, template_name='categories/category_detail.html', extra_context={}): path_items = path.strip('/').split('/') if len(path_items) >= 2: - category = get_object_or_404(Category, + category = get_object_or_404( + Category, slug__iexact=path_items[-1], level=len(path_items) - 1, parent__slug__iexact=path_items[-2]) else: - category = get_object_or_404(Category, + category = get_object_or_404( + Category, slug__iexact=path_items[-1], level=len(path_items) - 1) diff --git a/doc_src/code_examples/custom_categories1.py b/doc_src/code_examples/custom_categories1.py index 72eb2ca..c8d4652 100644 --- a/doc_src/code_examples/custom_categories1.py +++ b/doc_src/code_examples/custom_categories1.py @@ -1,9 +1,10 @@ from categories.models import CategoryBase + class SimpleCategory(CategoryBase): """ A simple of catgorizing example """ - + class Meta: verbose_name_plural = 'simple categories' diff --git a/doc_src/code_examples/custom_categories2.py b/doc_src/code_examples/custom_categories2.py index 4a81b6d..53cf264 100644 --- a/doc_src/code_examples/custom_categories2.py +++ b/doc_src/code_examples/custom_categories2.py @@ -4,7 +4,8 @@ from categories.admin import CategoryBaseAdmin from .models import SimpleCategory + class SimpleCategoryAdmin(CategoryBaseAdmin): pass -admin.site.register(SimpleCategory, SimpleCategoryAdmin) \ No newline at end of file +admin.site.register(SimpleCategory, SimpleCategoryAdmin) diff --git a/doc_src/code_examples/custom_categories3.py b/doc_src/code_examples/custom_categories3.py index 57907e2..d2aaa6f 100644 --- a/doc_src/code_examples/custom_categories3.py +++ b/doc_src/code_examples/custom_categories3.py @@ -1,8 +1,12 @@ +from categories import models, settings +from categories.base import CategoryBase + + class Category(CategoryBase): thumbnail = models.FileField( - upload_to=THUMBNAIL_UPLOAD_PATH, + upload_to=settings.THUMBNAIL_UPLOAD_PATH, null=True, blank=True, - storage=STORAGE(),) + storage=settings.THUMBNAIL_STORAGE,) thumbnail_width = models.IntegerField(blank=True, null=True) thumbnail_height = models.IntegerField(blank=True, null=True) order = models.IntegerField(default=0) @@ -12,8 +16,8 @@ class Category(CategoryBase): max_length=100, help_text="An alternative title to use on pages with this category.") alternate_url = models.CharField( - blank=True, - max_length=200, + blank=True, + max_length=200, help_text="An alternative URL to use instead of the one derived from " "the category hierarchy.") description = models.TextField(blank=True, null=True) @@ -26,4 +30,4 @@ class Category(CategoryBase): blank=True, default="", help_text="(Advanced) Any additional HTML to be placed verbatim " - "in the <head>") \ No newline at end of file + "in the <head>") diff --git a/doc_src/code_examples/custom_categories4.py b/doc_src/code_examples/custom_categories4.py index 4a4fa65..87e1d3a 100644 --- a/doc_src/code_examples/custom_categories4.py +++ b/doc_src/code_examples/custom_categories4.py @@ -1,3 +1,6 @@ +from categories.models import Category + + def save(self, *args, **kwargs): if self.thumbnail: from django.core.files.images import get_image_dimensions @@ -8,8 +11,8 @@ def save(self, *args, **kwargs): width, height = get_image_dimensions(self.thumbnail.file, close=True) else: width, height = None, None - + self.thumbnail_width = width self.thumbnail_height = height - - super(Category, self).save(*args, **kwargs) \ No newline at end of file + + super(Category, self).save(*args, **kwargs) diff --git a/doc_src/code_examples/custom_categories5.py b/doc_src/code_examples/custom_categories5.py index 2dfc16f..67109c6 100644 --- a/doc_src/code_examples/custom_categories5.py +++ b/doc_src/code_examples/custom_categories5.py @@ -1,5 +1,9 @@ +from categories.base import CategoryBase + + class Meta(CategoryBase.Meta): verbose_name_plural = 'categories' + class MPTTMeta: order_insertion_by = ('order', 'name') diff --git a/doc_src/code_examples/custom_categories6.py b/doc_src/code_examples/custom_categories6.py index c649ab7..3c09f03 100644 --- a/doc_src/code_examples/custom_categories6.py +++ b/doc_src/code_examples/custom_categories6.py @@ -1,9 +1,13 @@ +from categories.base import CategoryBaseAdminForm +from categories.models import Category + + class CategoryAdminForm(CategoryBaseAdminForm): class Meta: model = Category - + def clean_alternate_title(self): if self.instance is None or not self.cleaned_data['alternate_title']: return self.cleaned_data['name'] else: - return self.cleaned_data['alternate_title'] \ No newline at end of file + return self.cleaned_data['alternate_title'] diff --git a/doc_src/code_examples/custom_categories7.py b/doc_src/code_examples/custom_categories7.py index dc48499..4fcc1a2 100644 --- a/doc_src/code_examples/custom_categories7.py +++ b/doc_src/code_examples/custom_categories7.py @@ -1,3 +1,7 @@ +from categories.admin import CategoryAdminForm +from categories.base import CategoryBaseAdmin + + class CategoryAdmin(CategoryBaseAdmin): form = CategoryAdminForm list_display = ('name', 'alternate_title', 'active') @@ -6,12 +10,12 @@ class CategoryAdmin(CategoryBaseAdmin): 'fields': ('parent', 'name', 'thumbnail', 'active') }), ('Meta Data', { - 'fields': ('alternate_title', 'alternate_url', 'description', - 'meta_keywords', 'meta_extra'), + 'fields': ('alternate_title', 'alternate_url', 'description', + 'meta_keywords', 'meta_extra'), 'classes': ('collapse',), }), ('Advanced', { 'fields': ('order', 'slug'), 'classes': ('collapse',), }), - ) \ No newline at end of file + ) diff --git a/doc_src/conf.py b/doc_src/conf.py index 5773732..0ffb72f 100644 --- a/doc_src/conf.py +++ b/doc_src/conf.py @@ -11,7 +11,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import sys +import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -19,7 +20,7 @@ import sys, os sys.path.append(os.path.abspath('..')) os.environ['DJANGO_SETTINGS_MODULE'] = 'example.settings' -import categories +import categories # noqa # -- General configuration ----------------------------------------------------- @@ -34,7 +35,7 @@ templates_path = ['_templates'] source_suffix = '.rst' # The encoding of source files. -#source_encoding = 'utf-8' +# ource_encoding = 'utf-8' # The master toctree document. master_doc = 'index' @@ -54,40 +55,40 @@ release = categories.get_version() # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# anguage = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# oday = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# oday_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. -#unused_docs = [] +# nused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# efault_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# dd_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# dd_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# how_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# odindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- @@ -99,26 +100,26 @@ html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# tml_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# tml_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# tml_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# tml_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# tml_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# tml_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -127,38 +128,38 @@ html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# tml_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# tml_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# tml_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# tml_additional_pages = {} # If false, no module index is generated. -#html_use_modindex = True +# tml_use_modindex = True # If false, no index is generated. -#html_use_index = True +# tml_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# tml_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# tml_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# tml_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' +# tml_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'DjangoCategoriesdoc' @@ -167,31 +168,30 @@ htmlhelp_basename = 'DjangoCategoriesdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' +# atex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' +# atex_font_size = '10pt' # 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', 'Django Categories Documentation', - '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 # the title page. -#latex_logo = None +# atex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# atex_use_parts = False # Additional stuff for the LaTeX preamble. -#latex_preamble = '' +# atex_preamble = '' # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# atex_appendices = [] # If false, no module index is generated. -#latex_use_modindex = True +# atex_use_modindex = True diff --git a/example/simpletext/admin.py b/example/simpletext/admin.py index 9060c31..573370d 100644 --- a/example/simpletext/admin.py +++ b/example/simpletext/admin.py @@ -3,6 +3,7 @@ from django.contrib import admin from categories.admin import CategoryBaseAdmin, CategoryBaseAdminForm + class SimpleTextAdmin(admin.ModelAdmin): fieldsets = ( (None, { @@ -16,8 +17,9 @@ class SimpleCategoryAdminForm(CategoryBaseAdminForm): model = SimpleCategory fields = '__all__' + class SimpleCategoryAdmin(CategoryBaseAdmin): form = SimpleCategoryAdminForm admin.site.register(SimpleText, SimpleTextAdmin) -admin.site.register(SimpleCategory, SimpleCategoryAdmin) \ No newline at end of file +admin.site.register(SimpleCategory, SimpleCategoryAdmin) diff --git a/example/simpletext/models.py b/example/simpletext/models.py index ea5e81d..28aca89 100755 --- a/example/simpletext/models.py +++ b/example/simpletext/models.py @@ -2,15 +2,16 @@ from django.db import models from categories.base import CategoryBase + class SimpleText(models.Model): """ (SimpleText description) """ - name = models.CharField(max_length=255) + name = models.CharField(max_length=255) description = models.TextField(blank=True) - created = models.DateTimeField(auto_now_add=True) - updated = models.DateTimeField(auto_now=True) + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) class Meta: verbose_name_plural = 'Simple Text' @@ -27,13 +28,14 @@ class SimpleText(models.Model): def get_absolute_url(self): return ('simpletext_detail_view_name', [str(self.id)]) + class SimpleCategory(CategoryBase): """A Test of catgorizing""" class Meta: verbose_name_plural = 'simple categories' -#import categories +# mport categories -#categories.register_fk(SimpleText, 'primary_category', {'related_name':'simpletext_primary_set'}) -#categories.register_m2m(SimpleText, 'cats', ) +# ategories.register_fk(SimpleText, 'primary_category', {'related_name':'simpletext_primary_set'}) +# ategories.register_m2m(SimpleText, 'cats', ) diff --git a/example/simpletext/tests.py b/example/simpletext/tests.py index c7c4668..f54e74f 100755 --- a/example/simpletext/tests.py +++ b/example/simpletext/tests.py @@ -7,6 +7,7 @@ Replace these with more appropriate tests for your application. from django.test import TestCase + class SimpleTest(TestCase): def test_basic_addition(self): """ @@ -20,4 +21,3 @@ Another way to test that 1 + 1 is equal to 2. >>> 1 + 1 == 2 True """} - diff --git a/example/urls.py b/example/urls.py index d19d430..5c660e4 100644 --- a/example/urls.py +++ b/example/urls.py @@ -1,14 +1,12 @@ -from django.conf.urls import include, url +import os -# Uncomment the next two lines to enable the admin: +from django.conf.urls import include, url from django.contrib import admin from django.views.static import serve admin.autodiscover() -import os - ROOT_PATH = os.path.dirname(os.path.dirname(__file__)) urlpatterns = ( @@ -22,7 +20,7 @@ urlpatterns = ( # Uncomment the next line to enable the admin: url(r'^admin/', include(admin.site.urls)), url(r'^categories/', include('categories.urls')), - #(r'^cats/', include('categories.urls')), + # r'^cats/', include('categories.urls')), url(r'^static/categories/(?P.*)$', serve, {'document_root': ROOT_PATH + '/categories/media/categories/'}), @@ -31,7 +29,6 @@ urlpatterns = ( # {'document_root': ROOT_PATH + '/editor/media/editor/', # 'show_indexes':True}), - url(r'^static/(?P.*)$', serve, - {'document_root': os.path.join(ROOT_PATH, 'example', 'static')}), + url(r'^static/(?P.*)$', serve, {'document_root': os.path.join(ROOT_PATH, 'example', 'static')}), ) diff --git a/setup.py b/setup.py index c2165fe..0422ff8 100644 --- a/setup.py +++ b/setup.py @@ -25,6 +25,6 @@ setup( classifiers=[ 'Framework :: Django', ], - install_requires = reqs, - dependency_links = [] + install_requires=reqs, + dependency_links=[] ) diff --git a/tox.ini b/tox.ini index 32fb129..df93f7b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,6 @@ [tox] envlist = + py27-lint py27-django{18,19}, py34-django{18,19}, py35-django{18,19}, @@ -12,3 +13,10 @@ deps= commands= {toxinidir}/example/manage.py test --settings='settings-testing' categories + +[testenv:py27-lint] +deps= + flake8 + +commands= + flake8 . --ignore=E501 --exclude=categories/south_migrations/