Skip to content

Commit

Permalink
Merge branch 'EnTeQuAk-py3k'
Browse files Browse the repository at this point in the history
Conflicts:
	MANIFEST.in
	docs/changelog.txt
	docs/index.txt
	setup.py
	taggit/tests/tests.py
  • Loading branch information
apollo13 committed Mar 25, 2013
2 parents 6f84438 + d9fb9b1 commit 08579a1
Show file tree
Hide file tree
Showing 19 changed files with 206 additions and 133 deletions.
15 changes: 13 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,28 @@ language: python
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"

env:
- DJANGO=https://github.com/django/django/archive/master.tar.gz
- DJANGO=django==1.5 --use-mirrors
- DJANGO=django==1.4.5 --use-mirrors
- DJANGO=django==1.3.7 --use-mirrors

install:
- pip install $DJANGO
- pip install -r requirements/travis-ci.txt --use-mirrors

script:
- python setup.py test
- coverage run --source django_taggit runtests.py
- coverage report

notifications:
email: false

matrix:
exclude:
- python: "3.2"
env: DJANGO=django==1.4.5 --use-mirrors
- python: "3.3"
env: DJANGO=django==1.4.5 --use-mirrors
6 changes: 6 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Changelog
=========

0.11.0 (unreleased)
~~~~~~~~~~~~~~~~~~~

* Python3 support
* *Backwards incompatible* Dropped support for Django < 1.4.5.

0.10.0
~~~~~~

Expand Down
2 changes: 1 addition & 1 deletion docs/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Welcome to django-taggit's documentation!
``django-taggit`` is a reusable Django application designed to making adding
tagging to your project easy and fun.

``django-taggit`` works with Django 1.3.X and newer and Python 2.4-2.X.
``django-taggit`` works with Django 1.4.5+ and Python 2.7-3.X.

.. toctree::
:maxdepth: 2
Expand Down
1 change: 1 addition & 0 deletions requirements/docs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Sphinx
2 changes: 2 additions & 0 deletions requirements/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Django
coverage
1 change: 1 addition & 0 deletions requirements/travis-ci.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
coverage
File renamed without changes.
7 changes: 6 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Framework :: Django',
],
test_suite='taggit.tests.runtests.runtests',
test_suite='runtests.runtests',
include_package_data=True,
zip_safe=False,
)
2 changes: 2 additions & 0 deletions taggit/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import unicode_literals

from django.contrib import admin

from taggit.models import Tag, TaggedItem
Expand Down
5 changes: 4 additions & 1 deletion taggit/forms.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
from __future__ import unicode_literals

from django import forms
from django.utils.translation import ugettext as _
from django.utils import six

from taggit.utils import parse_tags, edit_string_for_tags


class TagWidget(forms.TextInput):
def render(self, name, value, attrs=None):
if value is not None and not isinstance(value, basestring):
if value is not None and not isinstance(value, six.string_types):
value = edit_string_for_tags([o.tag for o in value.select_related("tag")])
return super(TagWidget, self).render(name, value, attrs)

Expand Down
43 changes: 24 additions & 19 deletions taggit/managers.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,19 @@
from __future__ import unicode_literals

from django.contrib.contenttypes.generic import GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models.fields.related import ManyToManyRel, RelatedField, add_lazy_relation
from django.db.models.related import RelatedObject
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
from django.utils import six

from taggit.forms import TagField
from taggit.models import TaggedItem, GenericTaggedItemBase
from taggit.utils import require_instance_manager


try:
all
except NameError:
# 2.4 compat
try:
from django.utils.itercompat import all
except ImportError:
# 1.1.X compat
def all(iterable):
for item in iterable:
if not item:
return False
return True


class TaggableRel(ManyToManyRel):
def __init__(self):
self.related_name = None
Expand Down Expand Up @@ -68,7 +56,7 @@ def contribute_to_class(self, cls, name):
cls._meta.add_field(self)
setattr(cls, name, self)
if not cls._meta.abstract:
if isinstance(self.through, basestring):
if isinstance(self.through, six.string_types):
def resolve_related_class(field, model, cls):
self.through = model
self.post_through_setup(cls)
Expand All @@ -78,6 +66,14 @@ def resolve_related_class(field, model, cls):
else:
self.post_through_setup(cls)

def __lt__(self, other):
"""
Required contribute_to_class as Django uses bisect
for ordered class contribution and bisect requires
a orderable type in py3.
"""
return False

def post_through_setup(self, cls):
self.use_gfk = (
self.through is None or issubclass(self.through, GenericTaggedItemBase)
Expand Down Expand Up @@ -132,7 +128,8 @@ def extra_filters(self, pieces, pos, negate):
if negate or not self.use_gfk:
return []
prefix = "__".join(["tagged_items"] + pieces[:pos-2])
cts = map(ContentType.objects.get_for_model, _get_subclasses(self.model))
get = ContentType.objects.get_for_model
cts = [get(obj) for obj in _get_subclasses(self.model)]
if len(cts) == 1:
return [("%s__content_type" % prefix, cts[0])]
return [("%s__content_type__in" % prefix, cts)]
Expand Down Expand Up @@ -197,7 +194,7 @@ def most_common(self):
def similar_objects(self):
lookup_kwargs = self._lookup_kwargs()
lookup_keys = sorted(lookup_kwargs)
qs = self.through.objects.values(*lookup_kwargs.keys())
qs = self.through.objects.values(*six.iterkeys(lookup_kwargs))
qs = qs.annotate(n=models.Count('pk'))
qs = qs.exclude(**lookup_kwargs)
qs = qs.filter(tag__in=self.all())
Expand All @@ -220,7 +217,7 @@ def similar_objects(self):
preload.setdefault(result['content_type'], set())
preload[result["content_type"]].add(result["object_id"])

for ct, obj_ids in preload.iteritems():
for ct, obj_ids in preload.items():
ct = ContentType.objects.get_for_id(ct)
for obj in ct.model_class()._default_manager.filter(pk__in=obj_ids):
items[(ct.pk, obj.pk)] = obj
Expand All @@ -243,3 +240,11 @@ def _get_subclasses(model):
getattr(field.field.rel, "parent_link", None)):
subclasses.extend(_get_subclasses(field.model))
return subclasses


# `total_ordering` does not exist in Django 1.4, as such
# we special case this import to be py3k specific which
# is not supported by Django 1.4
if six.PY3:
from django.utils.functional import total_ordering
TaggableManager = total_ordering(TaggableManager)
40 changes: 21 additions & 19 deletions taggit/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import datetime
from south.db import db
from south.v2 import SchemaMigration
Expand All @@ -9,52 +11,52 @@ class Migration(SchemaMigration):

def forwards(self, orm):
# Adding model 'Tag'
db.create_table(u'taggit_tag', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
db.create_table('taggit_tag', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=100)),
('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=100)),
))
db.send_create_signal(u'taggit', ['Tag'])
db.send_create_signal('taggit', ['Tag'])

# Adding model 'TaggedItem'
db.create_table(u'taggit_taggeditem', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('tag', self.gf('django.db.models.fields.related.ForeignKey')(related_name=u'taggit_taggeditem_items', to=orm['taggit.Tag'])),
db.create_table('taggit_taggeditem', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('tag', self.gf('django.db.models.fields.related.ForeignKey')(related_name='taggit_taggeditem_items', to=orm['taggit.Tag'])),
('object_id', self.gf('django.db.models.fields.IntegerField')(db_index=True)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name=u'taggit_taggeditem_tagged_items', to=orm['contenttypes.ContentType'])),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='taggit_taggeditem_tagged_items', to=orm['contenttypes.ContentType'])),
))
db.send_create_signal(u'taggit', ['TaggedItem'])
db.send_create_signal('taggit', ['TaggedItem'])


def backwards(self, orm):
# Deleting model 'Tag'
db.delete_table(u'taggit_tag')
db.delete_table('taggit_tag')

# Deleting model 'TaggedItem'
db.delete_table(u'taggit_taggeditem')
db.delete_table('taggit_taggeditem')


models = {
u'contenttypes.contenttype': {
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'taggit.tag': {
'taggit.tag': {
'Meta': {'object_name': 'Tag'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'})
},
u'taggit.taggeditem': {
'taggit.taggeditem': {
'Meta': {'object_name': 'TaggedItem'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'taggit_taggeditem_tagged_items'", 'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'taggit_taggeditem_items'", 'to': u"orm['taggit.Tag']"})
'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"})
}
}

complete_apps = ['taggit']
complete_apps = ['taggit']
24 changes: 13 additions & 11 deletions taggit/migrations/0002_unique_tagnames.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import datetime
from south.db import db
from south.v2 import SchemaMigration
Expand All @@ -9,35 +11,35 @@ class Migration(SchemaMigration):

def forwards(self, orm):
# Adding unique constraint on 'Tag', fields ['name']
db.create_unique(u'taggit_tag', ['name'])
db.create_unique('taggit_tag', ['name'])


def backwards(self, orm):
# Removing unique constraint on 'Tag', fields ['name']
db.delete_unique(u'taggit_tag', ['name'])
db.delete_unique('taggit_tag', ['name'])


models = {
u'contenttypes.contenttype': {
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'taggit.tag': {
'taggit.tag': {
'Meta': {'object_name': 'Tag'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'})
},
u'taggit.taggeditem': {
'taggit.taggeditem': {
'Meta': {'object_name': 'TaggedItem'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'taggit_taggeditem_tagged_items'", 'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'taggit_taggeditem_items'", 'to': u"orm['taggit.Tag']"})
'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"})
}
}

complete_apps = ['taggit']
complete_apps = ['taggit']
15 changes: 8 additions & 7 deletions taggit/models.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
from __future__ import unicode_literals

import django
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey
from django.db import models, IntegrityError, transaction
from django.template.defaultfilters import slugify as default_slugify
from django.utils.translation import ugettext_lazy as _, ugettext
from django.utils.encoding import python_2_unicode_compatible


@python_2_unicode_compatible
class TagBase(models.Model):
name = models.CharField(verbose_name=_('Name'), unique=True, max_length=100)
slug = models.SlugField(verbose_name=_('Slug'), unique=True, max_length=100)

def __unicode__(self):
def __str__(self):
return self.name

class Meta:
Expand Down Expand Up @@ -57,9 +61,9 @@ class Meta:
verbose_name_plural = _("Tags")



@python_2_unicode_compatible
class ItemBase(models.Model):
def __unicode__(self):
def __str__(self):
return ugettext("%(object)s tagged with %(tag)s") % {
"object": self.content_object,
"tag": self.tag
Expand Down Expand Up @@ -90,10 +94,7 @@ def bulk_lookup_kwargs(cls, instances):


class TaggedItemBase(ItemBase):
if django.VERSION < (1, 2):
tag = models.ForeignKey(Tag, related_name="%(class)s_items")
else:
tag = models.ForeignKey(Tag, related_name="%(app_label)s_%(class)s_items")
tag = models.ForeignKey(Tag, related_name="%(app_label)s_%(class)s_items")

class Meta:
abstract = True
Expand Down
2 changes: 2 additions & 0 deletions taggit/tests/forms.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import unicode_literals

from django import forms

from taggit.tests.models import Food, DirectFood, CustomPKFood, OfficialFood
Expand Down
Loading

0 comments on commit 08579a1

Please sign in to comment.