Skip to content

Commit e692ed8

Browse files
committed
Python 3 - properly handle __str__ vs __unicode__ .
Also test for it, which increases test coverage to 100%.
1 parent b9292c4 commit e692ed8

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

embedly/models.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
from __future__ import unicode_literals
2-
3-
try: # pragma: no cover
4-
from collections import UserDict as IterableUserDict # pragma: no cover
5-
except ImportError: # Python 2 # pragma: no cover
6-
from UserDict import IterableUserDict # pragma: no cover
1+
from __future__ import absolute_import, unicode_literals
2+
from .py3_utils import python_2_unicode_compatible, IterableUserDict
73

84

5+
@python_2_unicode_compatible
96
class Url(IterableUserDict, object):
107
"""
118
A dictionary with two additional attributes for the method and url.
@@ -19,7 +16,4 @@ def __init__(self, data=None, method=None, original_url=None, **kwargs):
1916
self.original_url = original_url
2017

2118
def __str__(self):
22-
return self.__unicode__().encode("utf-8")
23-
24-
def __unicode__(self):
2519
return '<%s %s>' % (self.method.title(), self.original_url or "")

embedly/py3_utils.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import sys
2+
3+
# 2to3 doesn't handle the UserDict relocation
4+
# put the import logic here for cleaner usage
5+
try:
6+
from collections import UserDict as IterableUserDict
7+
except ImportError: # Python 2
8+
from UserDict import IterableUserDict
9+
10+
11+
def python_2_unicode_compatible(klass):
12+
"""
13+
A decorator that defines __unicode__ and __str__ methods under Python 2.
14+
Under Python 3 it does nothing.
15+
16+
From django.utils.encoding.py in 1.4.2+, minus the dependency on Six.
17+
18+
To support Python 2 and 3 with a single code base, define a __str__ method
19+
returning text and apply this decorator to the class.
20+
"""
21+
if sys.version_info[0] == 2:
22+
if '__str__' not in klass.__dict__:
23+
raise ValueError("@python_2_unicode_compatible cannot be applied "
24+
"to %s because it doesn't define __str__()." %
25+
klass.__name__)
26+
klass.__unicode__ = klass.__str__
27+
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
28+
return klass

embedly/tests.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import unicode_literals
22
import re
3+
import sys
34
import json
45

56
try: # pragma: no cover
@@ -78,6 +79,18 @@ def test_model_data_can_serialize(self):
7879
unserialzed = json.loads(json.dumps(obj.data))
7980
self.assertDictEqual(obj.data, unserialzed)
8081

82+
def test_str_representation(self):
83+
unistr = 'I\xf1t\xebrn\xe2ti\xf4n\xe0liz\xe6tion'
84+
url = "http://test.com"
85+
obj = Url(method=unistr, original_url=url)
86+
87+
if sys.version_info[0] == 2:
88+
self.assertTrue(unistr.encode('utf-8') in str(obj))
89+
self.assertTrue(url.encode('utf-8') in str(obj))
90+
else:
91+
self.assertTrue(unistr in str(obj))
92+
self.assertTrue(url in str(obj))
93+
8194

8295
class EmbedlyTestCase(unittest.TestCase):
8396
def setUp(self):

0 commit comments

Comments
 (0)