The model class should have default ``__cmp__`` method.

54 views
Skip to first unread message

Λlisue

unread,
Mar 9, 2012, 12:15:05 AM3/9/12
to django-d...@googlegroups.com
I have the following codes for testing model and it's works correctly in
Django 1.3 + Python 2.7 without unittest2::

# in method of TestCase subclass -----------------------------------
user1 = User.objects.create_user(username='user1',
email='us...@test.com', password='password')
user2 = User.objects.create_user(username='user2',
email='us...@test.com', password='password')

self.assertItemsEqual(User.objects.all(), [user1, user2])
#-------------------------------------------------------------------

However the code raise ``AssertionError: Sequences differ: ...`` in
Django 1.3 + Python 2.6 or Django 1.3 + Python 2.7 + unittest2. (well
but I have no idea why the code above works with Django 1.3 + Python 2.7
without unittest2)

This happen because unittest2 or whatever does ``sorted(expected_seq)``
in ``assertItemsEqual`` method but they don't know how to sort the
instances of model class. To solve this problem, I simply add
``__cmp__`` method to Model class like::

# somewhere but called after Django has correctly configured -------
from django.db.models import Model

if not hasattr(Model, '__cmp__'):
Model.__cmp__ = lambda self, other: cmp(self._get_pk_val(),
other._get_pk_val())
#-------------------------------------------------------------------

But it is too annoying to call this patch in every library which use
``assertItemsEqual`` for testing. So I wander if official django's model
class has ``__cmp__`` method in default.

Thanks.

Łukasz Rekucki

unread,
Mar 9, 2012, 4:02:36 AM3/9/12
to django-d...@googlegroups.com
On 9 March 2012 06:15, Λlisue <lambd...@hashnote.net> wrote:
> I have the following codes for testing model and it's works correctly in
> Django 1.3 + Python 2.7 without unittest2::
>
> # in method of TestCase subclass -----------------------------------
> user1 = User.objects.create_user(username='user1',
> email='us...@test.com', password='password')
> user2 = User.objects.create_user(username='user2',
> email='us...@test.com', password='password')
>
> self.assertItemsEqual(User.objects.all(), [user1, user2])
> #-------------------------------------------------------------------
>
> However the code raise ``AssertionError: Sequences differ: ...`` in
> Django 1.3 + Python 2.6 or Django 1.3 + Python 2.7 + unittest2. (well
> but I have no idea why the code above works with Django 1.3 + Python 2.7
> without unittest2)

Since 1.3 Django ships with unittest2 library (see
django.utils.unittest), so if there are no
other versions of unittest2 installed, it will use that (which is a
verbatim copy of unittest2==0.5.1).

Python 2.7 seems to have a bit different implementation of that
method, but it uses things like Counter.

>
> This happen because unittest2 or whatever does ``sorted(expected_seq)``
> in ``assertItemsEqual`` method but they don't know how to sort the
> instances of model class.

Actually, assertItemsEqual handles unorderable and unhashable items,
if you take a look at it's source code. The py2.7 version should too.
Didn't have time to check this, but it looks like a bug in unittest2.

> To solve this problem, I simply add
> ``__cmp__`` method to Model class like::
>
> # somewhere but called after Django has correctly configured -------
> from django.db.models import Model
>
> if not hasattr(Model, '__cmp__'):
>    Model.__cmp__ = lambda self, other: cmp(self._get_pk_val(),
> other._get_pk_val())
> #-------------------------------------------------------------------
>

Apart from __cmp__ being deprecated, this isn't really correct even
for testing (the model can have an UUIDField as it's pk instead of a
sequential integer).

For making assertions about QuerySets, there already is
assertQuerysetEqual(), so -1 on adding __cmp__ to Model.

--
Łukasz Rekucki

Reply all
Reply to author
Forward
0 new messages