Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dict's __repr__() in python2 and python3

I'm porting a python library from python 2 only to python 2 and 3 in one codebase (2.6, 2.7 and 3.3+). The main problem left is that a lot of tests use something like this:

def test(self):
 example = {u'foo': u'bar'}
 self.assertEqual(str(example), "{u'foo': u'bar'}")

which works in python 2, but raises an exception in python3:

 AssertionError: "{'foo': 'bar'}" != "{u'foo': u'bar'}"

Is there a standard way of dealing with these problems apart from 'test different'? overloading__repr__?

like image 484
Christian Geier Avatar asked Dec 19 '22 22:12

Christian Geier


2 Answers

Get rid of those tests; they are next to useless:

  • This tests if the Python implementation of dict.__repr__ is working. Python itself already tests for this; focus on the project codebase instead. If Python fails to render a dictionary representation correctly it's not your project's job to fix that.

  • Python dictionaries have no fixed ordering; testing if their representation matches a given string is not going to be stable.

    Moreover, Python 3.3 introduces hash randomization, meaning that the order of a given dictionary will change from invocation to invocation. See PYTHONHASHSEED.

If you are testing the result of a project API calll, test for dictionary equality using self.assertEqual() instead; it'll use assertDictEqual() to give you meaningful error messages if the two dictionaries do not match.

Since Python 3.3 interprets u'foo' as a literal for type str, comparing output against {u'foo': u'bar} will work across Python 2.6, 2.7 and 3.3 and newer.

like image 69
Martijn Pieters Avatar answered Dec 30 '22 19:12

Martijn Pieters


I suspect that this isn't your real code, and your real code is doing something slightly less silly: trying to verify that a dictionary matches some expected result.

The way to do this is to compare the dictionaries directly, instead of comparing their string representations:

self.assertEqual(example, {u'foo': u'bar'})

This will work in both 2.x and 3.x (since you're requiring 3.3+, which means the u prefixes are legal, if unnecessary).

like image 32
abarnert Avatar answered Dec 30 '22 18:12

abarnert