From patchwork Sun Nov 29 22:10:47 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 549833 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id F0CF11401E7 for ; Mon, 30 Nov 2015 09:12:19 +1100 (AEDT) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id D73031A0B63 for ; Mon, 30 Nov 2015 09:12:19 +1100 (AEDT) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by lists.ozlabs.org (Postfix) with ESMTP id 958531A0935 for ; Mon, 30 Nov 2015 09:11:13 +1100 (AEDT) Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP; 29 Nov 2015 14:11:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,360,1444719600"; d="scan'208";a="4368089" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by fmsmga004.fm.intel.com with ESMTP; 29 Nov 2015 14:11:10 -0800 Received: from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com [10.237.217.45]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id tATMBAQ3024155; Sun, 29 Nov 2015 22:11:10 GMT Received: from sivswdev01.ir.intel.com (localhost [127.0.0.1]) by sivswdev01.ir.intel.com with ESMTP id tATMB9Hh004897; Sun, 29 Nov 2015 22:11:09 GMT Received: (from sfinucan@localhost) by sivswdev01.ir.intel.com with id tATMB9PP004893; Sun, 29 Nov 2015 22:11:09 GMT From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 6/9] py3: Fix Django models Python3 compatibility Date: Sun, 29 Nov 2015 22:10:47 +0000 Message-Id: <1448835050-1572-7-git-send-email-stephen.finucane@intel.com> X-Mailer: git-send-email 2.0.0 In-Reply-To: <1448835050-1572-1-git-send-email-stephen.finucane@intel.com> References: <1448835050-1572-1-git-send-email-stephen.finucane@intel.com> X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Per suggestions from the Django porting guide: https://docs.djangoproject.com/en/1.8/topics/python3/ Signed-off-by: Stephen Finucane --- patchwork/admin.py | 2 +- patchwork/models.py | 74 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/patchwork/admin.py b/patchwork/admin.py index bada5a6..082885b 100644 --- a/patchwork/admin.py +++ b/patchwork/admin.py @@ -31,7 +31,7 @@ admin.site.register(Project, ProjectAdmin) class PersonAdmin(admin.ModelAdmin): - list_display = ('__unicode__', 'has_account') + list_display = ('__str__', 'has_account') search_fields = ('name', 'email') def has_account(self, person): diff --git a/patchwork/models.py b/patchwork/models.py index a2b9498..ecfd986 100644 --- a/patchwork/models.py +++ b/patchwork/models.py @@ -18,6 +18,8 @@ # along with Patchwork; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +from __future__ import absolute_import + from collections import Counter, OrderedDict import datetime import random @@ -29,31 +31,37 @@ from django.contrib.sites.models import Site from django.core.urlresolvers import reverse from django.db import models from django.db.models import Q +from django.utils.encoding import python_2_unicode_compatible from django.utils.functional import cached_property +from django.utils import six +from django.utils.six import add_metaclass +from django.utils.six.moves import filter from patchwork.parser import extract_tags, hash_patch +@python_2_unicode_compatible class Person(models.Model): email = models.CharField(max_length=255, unique=True) name = models.CharField(max_length=255, null=True, blank=True) user = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) - def __unicode__(self): - if self.name: - return u'%s <%s>' % (self.name, self.email) - else: - return self.email - def link_to_user(self, user): self.name = user.profile.name() self.user = user + def __str__(self): + if self.name: + return '%s <%s>' % (self.name, self.email) + else: + return self.email + class Meta: verbose_name_plural = 'People' +@python_2_unicode_compatible class Project(models.Model): linkname = models.CharField(max_length=255, unique=True) name = models.CharField(max_length=255, unique=True) @@ -65,9 +73,6 @@ class Project(models.Model): send_notifications = models.BooleanField(default=False) use_tags = models.BooleanField(default=True) - def __unicode__(self): - return self.name - def is_editable(self, user): if not user.is_authenticated(): return False @@ -79,10 +84,14 @@ class Project(models.Model): return [] return list(Tag.objects.all()) + def __str__(self): + return self.name + class Meta: ordering = ['linkname'] +@python_2_unicode_compatible class UserProfile(models.Model): user = models.OneToOneField(User, unique=True, related_name='profile') primary_project = models.ForeignKey(Project, null=True, blank=True) @@ -98,8 +107,9 @@ class UserProfile(models.Model): def name(self): if self.user.first_name or self.user.last_name: - names = filter(bool, [self.user.first_name, self.user.last_name]) - return u' '.join(names) + names = list(filter( + bool, [self.user.first_name, self.user.last_name])) + return ' '.join(names) return self.user.username def contributor_projects(self): @@ -126,7 +136,7 @@ class UserProfile(models.Model): action_required=True).values('pk').query) return qs - def __unicode__(self): + def __str__(self): return self.name() @@ -140,20 +150,21 @@ def _user_saved_callback(sender, created, instance, **kwargs): models.signals.post_save.connect(_user_saved_callback, sender=User) +@python_2_unicode_compatible class State(models.Model): name = models.CharField(max_length=100) ordering = models.IntegerField(unique=True) action_required = models.BooleanField(default=True) - def __unicode__(self): + def __str__(self): return self.name class Meta: ordering = ['ordering'] +@add_metaclass(models.SubfieldBase) class HashField(models.CharField): - __metaclass__ = models.SubfieldBase def __init__(self, algorithm='sha1', *args, **kwargs): self.algorithm = algorithm @@ -161,13 +172,15 @@ class HashField(models.CharField): import hashlib def _construct(string=''): + if isinstance(string, six.text_type): + string = string.encode('utf-8') return hashlib.new(self.algorithm, string) self.construct = _construct self.n_bytes = len(hashlib.new(self.algorithm).hexdigest()) except ImportError: modules = {'sha1': 'sha', 'md5': 'md5'} - if algorithm not in modules.keys(): + if algorithm not in modules: raise NameError("Unknown algorithm '%s'" % algorithm) self.construct = __import__(modules[algorithm]).new @@ -181,6 +194,7 @@ class HashField(models.CharField): return 'char(%d)' % self.n_bytes +@python_2_unicode_compatible class Tag(models.Model): name = models.CharField(max_length=20) pattern = models.CharField( @@ -191,13 +205,13 @@ class Tag(models.Model): max_length=2, unique=True, help_text='Short (one-or-two letter)' ' abbreviation for the tag, used in table column headers') - def __unicode__(self): - return self.name - @property def attr_name(self): return 'tag_%d_count' % self.id + def __str__(self): + return self.name + class Meta: ordering = ['abbrev'] @@ -249,6 +263,7 @@ class PatchManager(models.Manager): return self.get_queryset().with_tag_counts(project) +@python_2_unicode_compatible class Patch(models.Model): project = models.ForeignKey(Project) msgid = models.CharField(max_length=255) @@ -267,9 +282,6 @@ class Patch(models.Model): objects = PatchManager() - def __unicode__(self): - return self.name - def commit_message(self): """Retrieve the commit message.""" return Comment.objects.filter(patch=self, msgid=self.msgid) @@ -379,7 +391,7 @@ class Patch(models.Model): unique[ctx] = check - return unique.values() + return list(unique.values()) @property def check_count(self): @@ -403,6 +415,9 @@ class Patch(models.Model): def get_absolute_url(self): return ('patchwork.views.patch.patch', (), {'patch_id': self.id}) + def __str__(self): + return self.name + class Meta: verbose_name_plural = 'Patches' ordering = ['date'] @@ -469,9 +484,6 @@ class Bundle(models.Model): order=max_order + 1) bp.save() - class Meta: - unique_together = [('owner', 'name')] - def public_url(self): if not self.public: return None @@ -490,6 +502,9 @@ class Bundle(models.Model): 'bundlename': self.name, }) + class Meta: + unique_together = [('owner', 'name')] + class BundlePatch(models.Model): patch = models.ForeignKey(Patch) @@ -542,7 +557,7 @@ class Check(models.Model): self.id, self.context, self.get_state_display()) def __unicode__(self): - return ('%s (%s)' % (self.context, self.get_state_display())) + return '%s (%s)' % (self.context, self.get_state_display()) class EmailConfirmation(models.Model): @@ -573,17 +588,18 @@ class EmailConfirmation(models.Model): super(EmailConfirmation, self).save() +@python_2_unicode_compatible class EmailOptout(models.Model): email = models.CharField(max_length=200, primary_key=True) - def __unicode__(self): - return self.email - @classmethod def is_optout(cls, email): email = email.lower().strip() return cls.objects.filter(email=email).count() > 0 + def __str__(self): + return self.email + class PatchChangeNotification(models.Model): patch = models.OneToOneField(Patch, primary_key=True)