From 179595da567064ea649dc421e2222aecab8bc90f Mon Sep 17 00:00:00 2001 From: "jonathan.buchanan" Date: Thu, 30 Oct 2008 02:17:55 +0000 Subject: [PATCH] Got tests back in working order; documentation updates for Django 1.0 --- docs/overview.txt | 22 ++++----- tagging/forms.py | 24 +++++++--- tagging/models.py | 11 +++-- tagging/tests/tests.py | 103 +++++++++++++---------------------------- tagging/validators.py | 32 ------------- 5 files changed, 68 insertions(+), 124 deletions(-) delete mode 100644 tagging/validators.py diff --git a/docs/overview.txt b/docs/overview.txt index c698290..246e6d9 100644 --- a/docs/overview.txt +++ b/docs/overview.txt @@ -76,7 +76,7 @@ the command ``svn update`` from within the ``tagging-trunk`` directory. copy of the source code. .. _`Subversion`: http://subversion.tigris.org -.. _`PYTHONPATH`: http://docs.python.org/tut/node8.html#SECTION008110000000000000000 +.. _`PYTHONPATH`: http://www.python.org/doc/2.5.2/tut/node8.html#SECTION008120000000000000000 .. _`junction`: http://www.microsoft.com/technet/sysinternals/FileAndDisk/Junction.mspx .. _`CHANGELOG`: http://django-tagging.googlecode.com/svn/trunk/CHANGELOG.txt .. _`backwards-incompatible changes wiki page`: http://code.google.com/p/django-tagging/wiki/BackwardsIncompatibleChanges @@ -119,8 +119,7 @@ Default: ``50`` An integer which specifies the maximum length which any tag is allowed to have. This is used for validation in the ``django.contrib.admin`` -application and in any ``newforms`` forms automatically generated using -``ModelForm``. +application and in any forms automatically generated using ``ModelForm``. Registering your models @@ -453,7 +452,7 @@ greater than 99:: >>> Tag.objects.usage_for_model(Widget, filters=dict(size__gt=99, user__username='Alan')) -.. _`field lookups`: http://www.djangoproject.com/documentation/db-api/#field-lookups +.. _`field lookups`: http://docs.djangoproject.com/en/dev/topics/db/queries/#field-lookups **New in development version** @@ -699,18 +698,17 @@ model:: This field will also validate that it has been given a valid list of tag names, separated by a single comma, a single space or a comma -followed by a space, using the ``is_tag_list`` validator from -``tagging.validators``. +followed by a space. Form fields =========== The ``tagging.forms`` module contains a ``Field`` for use with -Django's `newforms library`_ which takes care of validating tag name +Django's `forms library`_ which takes care of validating tag name input when used in your forms. -.. _`newforms library`: http://www.djangoproject.com/documentation/newforms/ +.. _`forms library`: http://docs.djangoproject.com/en/dev/topics/forms/ Field types ----------- @@ -722,9 +720,9 @@ A form ``Field`` which is displayed as a single-line text input, which validates that the input it receives is a valid list of tag names. When you generate a form for one of your models automatically, using -the ``ModelForm`` class provided by newforms, any -``tagging.fields.TagField`` fields in your model will automatically be -represented by a ``tagging.forms.TagField`` in the generated form. +the ``ModelForm`` class, any ``tagging.fields.TagField`` fields in your +model will automatically be represented by a ``tagging.forms.TagField`` +in the generated form. Generic views @@ -774,7 +772,7 @@ template context variables which may be provided. * ``tag``: The ``Tag`` instance for the given tag. -.. _`object_list documentation`: http://www.djangoproject.com/documentation/generic_views/#django-views-generic-list-detail-object-list +.. _`object_list documentation`: http://docs.djangoproject.com/en/dev/ref/generic-views/#django-views-generic-list-detail-object-list Example usage ~~~~~~~~~~~~~ diff --git a/tagging/forms.py b/tagging/forms.py index 4d4de03..a70ac6b 100644 --- a/tagging/forms.py +++ b/tagging/forms.py @@ -1,22 +1,27 @@ """ -Tagging components for Django's ``newforms`` form library. +Tagging components for Django's form library. """ from django import forms from django.utils.translation import ugettext as _ from tagging import settings from tagging.models import Tag -from tagging.validators import is_tag, is_tag_list from tagging.utils import parse_tag_input class AdminTagForm(forms.ModelForm): class Meta: model = Tag - + def clean_name(self): - value = self.cleaned_data["name"] - return is_tag(value) - + value = self.cleaned_data['name'] + tag_names = parse_tag_input(value) + if len(tag_names) > 1: + raise ValidationError(_('Multiple tags were given.')) + elif len(tag_names[0]) > settings.MAX_TAG_LENGTH: + raise forms.ValidationError( + _('A tag may be no more than %s characters long.') % + settings.MAX_TAG_LENGTH) + return value class TagField(forms.CharField): """ @@ -27,4 +32,9 @@ def clean(self, value): value = super(TagField, self).clean(value) if value == u'': return value - return is_tag_list(value) + for tag_name in parse_tag_input(value): + if len(tag_name) > settings.MAX_TAG_LENGTH: + raise forms.ValidationError( + _('Each tag may be no more than %s characters long.') % + settings.MAX_TAG_LENGTH) + return value diff --git a/tagging/models.py b/tagging/models.py index c0aed46..d43f22d 100644 --- a/tagging/models.py +++ b/tagging/models.py @@ -267,7 +267,7 @@ class TaggedItemManager(models.Manager): objects we're interested in, then use the ORM's ``__in`` lookup to return a ``QuerySet``. - now that the queryset-refactor branch is in the trunk, this can be + Now that the queryset-refactor branch is in the trunk, this can be tidied up significantly. """ def get_by_model(self, queryset_or_model, tags): @@ -419,11 +419,16 @@ def get_related(self, obj, queryset_or_model, num=None): 'tag': qn(self.model._meta.get_field('tag').rel.to._meta.db_table), 'content_type_id': content_type.pk, 'related_content_type_id': related_content_type.pk, - 'limit_offset': num is not None and connection.ops.limit_offset_sql(num) or '', + # Hardcoding this for now just to get tests working again - this + # should now be handled by the query object. + 'limit_offset': num is not None and 'LIMIT %s' or '', } cursor = connection.cursor() - cursor.execute(query, [obj.pk]) + params = [obj.pk] + if num is not None: + params.append(num) + cursor.execute(query, params) object_ids = [row[0] for row in cursor.fetchall()] if len(object_ids) > 0: # Use in_bulk here instead of an id__in lookup, because id__in would diff --git a/tagging/tests/tests.py b/tagging/tests/tests.py index 596e4f0..5d6d8b5 100644 --- a/tagging/tests/tests.py +++ b/tagging/tests/tests.py @@ -1,14 +1,14 @@ # -*- coding: utf-8 -*- -tests = r""" +r""" >>> import os ->>> from django import newforms as forms +>>> from django import forms +>>> from django.db.models import Q >>> from tagging.forms import TagField >>> from tagging import settings >>> from tagging.models import Tag, TaggedItem >>> from tagging.tests.models import Article, Link, Perch, Parrot, FormTest >>> from tagging.utils import calculate_cloud, get_tag_list, get_tag, parse_tag_input >>> from tagging.utils import LINEAR ->>> from tagging.validators import is_tag_list, is_tag ############# # Utilities # @@ -152,24 +152,6 @@ ... ValueError: Invalid distribution algorithm specified: cheese. -# Validators ################################################################## - ->>> is_tag_list('foo qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbn bar', {}) -Traceback (most recent call last): - ... -ValidationError: [u'Each tag may be no more than 50 characters long.'] - ->>> is_tag('"test"', {}) ->>> is_tag(',test', {}) ->>> is_tag('f o o', {}) -Traceback (most recent call last): - ... -ValidationError: [u'Multiple tags were given.'] ->>> is_tag_list('foo qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbn bar', {}) -Traceback (most recent call last): - ... -ValidationError: [u'Each tag may be no more than 50 characters long.'] - ########### # Tagging # ########### @@ -393,6 +375,36 @@ >>> TaggedItem.objects.get_related(a1, Link) [] +# Limiting results to a queryset +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state='no more'), counts=True)] +[(u'foo', 1), (u'ter', 1)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state__startswith='p'), counts=True)] +[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4), counts=True)] +[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), counts=True)] +[(u'bar', 1), (u'foo', 2), (u'ter', 1)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), min_count=2)] +[(u'foo', 2)] +>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4))] +[(u'bar', False), (u'baz', False), (u'foo', False), (u'ter', False)] +>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=99))] +[] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), counts=True)] +[(u'bar', 2), (u'foo', 1), (u'ter', 1)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), min_count=2)] +[(u'bar', 2)] +>>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')))] +[(u'bar', False), (u'foo', False), (u'ter', False)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state='passed on'), counts=True)] +[(u'bar', 2), (u'foo', 2), (u'ter', 2)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state__startswith='p'), min_count=2)] +[(u'ter', 2)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(Q(perch__size__gt=6) | Q(perch__smelly=False)), counts=True)] +[(u'foo', 1), (u'ter', 1)] +>>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(perch__smelly=True).filter(state__startswith='l'), counts=True)] +[(u'bar', 1), (u'ter', 1)] + ################ # Model Fields # ################ @@ -444,52 +456,3 @@ ... ValidationError: [u'Each tag may be no more than 50 characters long.'] """ - -tests_pre_qsrf = tests + r""" -# Limiting results to a queryset ->>> Tag.objects.usage_for_queryset(Parrot.objects.filter()) -Traceback (most recent call last): - ... -AttributeError: 'TagManager.usage_for_queryset' is not compatible with pre-queryset-refactor versions of Django. -""" - -tests_post_qsrf = tests + r""" ->>> from django.db.models import Q - -# Limiting results to a queryset ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state='no more'), counts=True)] -[(u'foo', 1), (u'ter', 1)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(state__startswith='p'), counts=True)] -[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4), counts=True)] -[(u'bar', 2), (u'baz', 1), (u'foo', 1), (u'ter', 1)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), counts=True)] -[(u'bar', 1), (u'foo', 2), (u'ter', 1)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__smelly=True), min_count=2)] -[(u'foo', 2)] ->>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=4))] -[(u'bar', False), (u'baz', False), (u'foo', False), (u'ter', False)] ->>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(perch__size__gt=99))] -[] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), counts=True)] -[(u'bar', 2), (u'foo', 1), (u'ter', 1)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')), min_count=2)] -[(u'bar', 2)] ->>> [(tag.name, hasattr(tag, 'counts')) for tag in Tag.objects.usage_for_queryset(Parrot.objects.filter(Q(perch__size__gt=6) | Q(state__startswith='l')))] -[(u'bar', False), (u'foo', False), (u'ter', False)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state='passed on'), counts=True)] -[(u'bar', 2), (u'foo', 2), (u'ter', 2)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(state__startswith='p'), min_count=2)] -[(u'ter', 2)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(Q(perch__size__gt=6) | Q(perch__smelly=False)), counts=True)] -[(u'foo', 1), (u'ter', 1)] ->>> [(tag.name, tag.count) for tag in Tag.objects.usage_for_queryset(Parrot.objects.exclude(perch__smelly=True).filter(state__startswith='l'), counts=True)] -[(u'bar', 1), (u'ter', 1)] -""" - -try: - from django.db.models.query import parse_lookup -except ImportError: - __test__ = {'post-qsrf': tests_post_qsrf} -else: - __test__ = {'pre-qsrf': tests_pre_qsrf} diff --git a/tagging/validators.py b/tagging/validators.py deleted file mode 100644 index 082f0a5..0000000 --- a/tagging/validators.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Oldforms validators for tagging related fields - these are still -required for basic ``django.contrib.admin`` application field validation -until the ``newforms-admin`` branch lands in trunk. -""" -from django import forms -from django.utils.translation import ugettext as _ - -from tagging import settings -from tagging.utils import parse_tag_input - -def is_tag_list(value): - """ - Validates that ``value`` is a valid list of tags. - """ - for tag_name in parse_tag_input(value): - if len(tag_name) > settings.MAX_TAG_LENGTH: - raise forms.ValidationError( - _('Each tag may be no more than %s characters long.') % settings.MAX_TAG_LENGTH) - return value - -def is_tag(value): - """ - Validates that ``value`` is a valid tag. - """ - tag_names = parse_tag_input(value) - if len(tag_names) > 1: - raise ValidationError(_('Multiple tags were given.')) - elif len(tag_names[0]) > settings.MAX_TAG_LENGTH: - raise forms.ValidationError( - _('A tag may be no more than %s characters long.') % settings.MAX_TAG_LENGTH) - return value