4π
tl; dr ) Use the same type on both sides of assertEqual.
The best code, universal for Python 3 and 2 is possible without adding symbols like u'', unicode, foo.__str__()
etc. Less code should be written and more thought about both what type is expected where in Python 2/3.
part A) fix the test
A short (ugly) solution is to use text_type on the left side if you use the same explicit type u'...'
on the right side. Avoid to use functions with underscores due to better readability. You can convert a value to text_type by several ways:
Replace the line in test by
self.assertEqual(u'%s' % self.cat1, cat_result1)
or
self.assertEqual(u'{}'.format(self.cat1), cat_result1)
or
from django.utils.six import text_type
self.assertEqual(text_type(self.cat1), cat_result1)
A nicer solution is to unify the type in your module and to use from __future__ import unicode_literals
at the beginning of your module because you work mostly with texts not with binary data. Than you can remove all u'
, but it is still useful until everything works in both versions.
part B) fix the __str__
method
Your code would fail if both the parent category name and the current name are not in ASCII. Fix:
from __future__ import unicode_literals
# ... many lines
def __str__(self):
if self.parent is None:
return ('{}'.format(self.name))
else:
return ('%s%s%s' % (
self.parent,
settings.PARENT_DELIMITER,
self.name)
)
I only removed the __str__()
call and added the future directive because the models.py is the first module where it is especially useful. Otherwise you should add u'
to both format strings here.
It is useful to know what the python_2_unicode_compatible decorator does. The result of __str__
method should be text_type
(unicode in Python 2), but if you call it directly in Python 2 you get bytes
type. The formatting operator selects the matching method but any explicit method is invalid either in Python 3 or in 2. Non ascii values of different types can not be combined.
1π
have you tried using six.text_type?
six.text_type
Type for representing (Unicode) textual data. This is
unicode()
in Python 2 andstr
in Python 3.
edit: you donβt have to install six
, as the needed methods are present in django.utils.six
β thanks @hynekcer for pointing it out
Six provides simple utilities for wrapping over differences between Python 2 and Python 3. It is intended to support codebases that work on both Python 2 and 3 without modification. six consists of only one Python file, so it is painless to copy into a project.~
0π
According to error message test tries to compare str
and unicode
objects. Thatβs not good generally.
AssertionError: 'Category 1->Category \xc3\xbc' != u'Category 1->Category \xfc'
Try to:
- compare unicode objects:
self.assertEqual(self.cat1, cat_result1)
- always work with unicode locale even if at a moment you are using only latin1-symbols
- [Django]-Make Django not lazy-load module, for development convenience
- [Django]-How to use enumerate(zip(seq1,seq2)) in jinja2?
- [Django]-Formating Django Datetime objects outside template