Fixed #21198 -- Prevented invalid use of @python_2_unicode_compatible.

Thanks jpic for the report and chmodas for working on a patch.

Reverts 2ea80b94. Refs #19362.

Conflicts:
	tests/utils_tests/test_encoding.py
This commit is contained in:
Aymeric Augustin 2013-10-13 18:06:58 +02:00
parent ddff6522fa
commit f0c7649b16
6 changed files with 14 additions and 28 deletions

View File

@ -427,11 +427,6 @@ class Model(six.with_metaclass(ModelBase)):
def __str__(self): def __str__(self):
if six.PY2 and hasattr(self, '__unicode__'): if six.PY2 and hasattr(self, '__unicode__'):
if type(self).__unicode__ == Model.__str__:
klass_name = type(self).__name__
raise RuntimeError("%s.__unicode__ is aliased to __str__. Did"
" you apply @python_2_unicode_compatible"
" without defining __str__?" % klass_name)
return force_text(self).encode('utf-8') return force_text(self).encode('utf-8')
return '%s object' % self.__class__.__name__ return '%s object' % self.__class__.__name__

View File

@ -52,6 +52,10 @@ def python_2_unicode_compatible(klass):
returning text and apply this decorator to the class. returning text and apply this decorator to the class.
""" """
if six.PY2: if six.PY2:
if '__str__' not in klass.__dict__:
raise ValueError("@python_2_unicode_compatible cannot be applied "
"to %s because it doesn't define __str__()." %
klass.__name__)
klass.__unicode__ = klass.__str__ klass.__unicode__ = klass.__str__
klass.__str__ = lambda self: self.__unicode__().encode('utf-8') klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
return klass return klass

View File

@ -1,13 +1,10 @@
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class Comment(models.Model): class Comment(models.Model):
pass pass
@python_2_unicode_compatible
class Book(models.Model): class Book(models.Model):
title = models.CharField(max_length=100, db_index=True) title = models.CharField(max_length=100, db_index=True)
comments = models.ManyToManyField(Comment) comments = models.ManyToManyField(Comment)

View File

@ -27,14 +27,6 @@ class Article(models.Model):
# in ASCII. # in ASCII.
return self.headline return self.headline
@python_2_unicode_compatible
class BrokenArticle(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateTimeField()
def __unicode__(self): # instead of __str__
return self.headline
@python_2_unicode_compatible @python_2_unicode_compatible
class InternationalArticle(models.Model): class InternationalArticle(models.Model):
headline = models.CharField(max_length=100) headline = models.CharField(max_length=100)

View File

@ -7,7 +7,7 @@ from django.test import TestCase
from django.utils import six from django.utils import six
from django.utils.unittest import skipIf from django.utils.unittest import skipIf
from .models import Article, BrokenArticle, InternationalArticle from .models import Article, InternationalArticle
class SimpleTests(TestCase): class SimpleTests(TestCase):
@ -21,16 +21,6 @@ class SimpleTests(TestCase):
self.assertEqual(str(a), str('Area man programs in Python')) self.assertEqual(str(a), str('Area man programs in Python'))
self.assertEqual(repr(a), str('<Article: Area man programs in Python>')) self.assertEqual(repr(a), str('<Article: Area man programs in Python>'))
@skipIf(six.PY3, "tests Model's default __str__ method under Python 2")
def test_broken(self):
# Regression test for #19362.
a = BrokenArticle.objects.create(
headline='Girl wins €12.500 in lottery',
pub_date=datetime.datetime(2005, 7, 28)
)
six.assertRaisesRegex(self, RuntimeError, "Did you apply "
"@python_2_unicode_compatible without defining __str__\?", str, a)
def test_international(self): def test_international(self):
a = InternationalArticle.objects.create( a = InternationalArticle.objects.create(
headline='Girl wins €12.500 in lottery', headline='Girl wins €12.500 in lottery',

View File

@ -2,7 +2,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.utils import unittest from django.utils import unittest
from django.utils.encoding import force_bytes, filepath_to_uri from django.utils.encoding import force_bytes, filepath_to_uri, python_2_unicode_compatible
from django.utils import six
class TestEncodingUtils(unittest.TestCase): class TestEncodingUtils(unittest.TestCase):
@ -21,3 +22,10 @@ class TestEncodingUtils(unittest.TestCase):
'upload/%D1%87%D1%83%D0%B1%D0%B0%D0%BA%D0%B0.mp4') 'upload/%D1%87%D1%83%D0%B1%D0%B0%D0%BA%D0%B0.mp4')
self.assertEqual(filepath_to_uri('upload\\чубака.mp4'.encode('utf-8')), self.assertEqual(filepath_to_uri('upload\\чубака.mp4'.encode('utf-8')),
'upload/%D1%87%D1%83%D0%B1%D0%B0%D0%BA%D0%B0.mp4') 'upload/%D1%87%D1%83%D0%B1%D0%B0%D0%BA%D0%B0.mp4')
@unittest.skipIf(six.PY3, "tests a class not defining __str__ under Python 2")
def test_decorated_class_without_str(self):
with self.assertRaises(ValueError):
@python_2_unicode_compatible
class NoStr(object):
pass