classification
Title: PEP 372 odict.__eq__ behaves incorrectly
Type: behavior Stage:
Components: None Versions: Python 2.5
process
Status: closed Resolution: works for me
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: cegner, rhettinger
Priority: normal Keywords:

Created on 2009-08-19 22:29 by cegner, last changed 2009-08-20 01:25 by rhettinger. This issue is now closed.

Messages (4)
msg91752 - (view) Author: Christopher Egner (cegner) Date: 2009-08-19 22:29
The current definition for odict.__eq__ is
    def __eq__(self, other):
        if isinstance(other, OrderedDict):
            return all(p==q for p, q in  _zip_longest(self.items(),
other.items()))
        return dict.__eq__(self, other)

The current behavior of NotImplemented is:
>>> if( NotImplemented ):
...     print 'foo'
foo
>>> dict.__eq__( {}, None )
NotImplemented
>>> if ( dict.__eq__( {}, None ) ):
...     print 'oops'
oops

The surprising behavior is:
>>> if ( OrderedDict() != None ):
...     print 'okie'
... else:
...     print 'gah!'
gah!

As best I understand it, normally other (in this case None) would be
given the chance to evaluate other.__eq__( OrderedDict() ), but this
doesn't seem to be happening.
msg91754 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-08-19 23:15
I cannot reproduce your final example:

Python 2.7a0 (trunk, Aug  4 2009, 12:07:15)
>>> from collections import OrderedDict
[41375 refs]
>>> if (OrderedDict() != None):
...     print 'okie'
... else:
...     print 'gah'
...
okie

Both are based on OrderedDict.__eq__ defined as:

    def __eq__(self, other):
        '''od.__eq__(y) <==> od==y.  Comparison to another OD is
order-sensitive
        while comparison to a regular mapping is order-insensitive.

        '''
        if isinstance(other, OrderedDict):
            return len(self)==len(other) and \
                   all(p==q for p, q in zip(self.items(), other.items()))
        return dict.__eq__(self, other)

Other questions about your bug report.  
* When you refer to odict, do you mean OrderedDict()?
* Do you understand that NotImplemented only does its magic
  in the context of the == or != operator, and it bypassed
  which you write dict.__eq__ or OrderedDict.__eq__?
* Are you clear that bool(NotImplemented) always evaluates to True?




Python 3.1.1 (r311:74483, Aug 17 2009, 17:02:12) [MSC v.1500 32 bit
(Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> from collections import OrderedDict
>>> if (OrderedDict() != None):
...	print('Okie')
... else:
...	print('Gah')

Okie
	
Okie
msg91755 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-08-19 23:19
If you need an implementation for OrderedDict that runs on Pythons
before 2.7 or 3.1, use the recipe at:

http://code.activestate.com/recipes/576693/

That code matches what was actually added to the language.
msg91756 - (view) Author: Christopher Egner (cegner) Date: 2009-08-19 23:53
I was running the odict.py file from the PEP, figured out that things
were going off the rails at dict.__eq__ and generalised, saw the same
implementation in OrderedDict, I thought the same problem would exist. 
This is what I get for taking a shortcut.

I checked out the activestate recipe mentioned in msg91755 which works.

The odict.py version, here is a literal paste from the pdb prompt (aside
from changing some of the more private data to xxx):
(Pdb) p urlConsolidationArtefact_row_prev
odict.odict([(u'id', 58768L), (u'urlConsolidationRun_id', 22L),
(u'valid', True), (u'validated', False), (u'refererUrl',
u'http://search.yahoo.com/search?y=xxx'), (u'refererUrl_hash',
'\xa60\xe2\xb8D\x7fv\x03\xb1=\xf3{\x15\xc0\xb0)'), (u'url',
u'http://xxx'), (u'url_hash',
'\x00\x00\xc8\xf3\xa3\x0f\x1d\xc2wn\xb4\xc7\xd7\xe1\xca3'),
(u'updatedAt', datetime.datetime(2009, 8, 15, 10, 54, 15)),
(u'createdAt', datetime.datetime(2009, 8, 15, 10, 54, 14))])
(Pdb) p urlConsolidationArtefact_row_prev != None
False
(Pdb) p urlConsolidationArtefact_row_prev == None
False

So there is a problem at least in the odict module provided by 
http://dev.pocoo.org/hg/sandbox/raw-file/tip/odict.py (referenced in the
PEP, once more prominently than now, I think).

Anyhow, I don't really know the details of what python does with
NotImplemented but version you gave doesn't have the same problem, so
I'll gladly use that instead.

If you can confirm that there's no deeper issue here, I'll be glad to
close the bug.

Thanks for the help!
History
Date User Action Args
2009-08-20 01:25:20rhettingersetstatus: open -> closed
resolution: works for me
2009-08-19 23:53:30cegnersetmessages: + msg91756
versions: - Python 2.6, Python 3.0, Python 3.1, Python 2.7, Python 3.2
2009-08-19 23:19:56rhettingersetmessages: + msg91755
2009-08-19 23:15:27rhettingersetmessages: + msg91754
2009-08-19 22:52:24rhettingersetassignee: rhettinger

nosy: + rhettinger
2009-08-19 22:29:13cegnercreate