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:
parent
ddff6522fa
commit
f0c7649b16
|
@ -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__
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue