porting pycxx and pysvn to python 3.0 hit a problem
I have a version of PyCXX ported to python 3.0 rc1 and its passing its tests. I'm porting pysvn to python 3.0 rc1 and hit an odd problem. Given this dict: wc_status_kind_map = { pysvn.wc_status_kind.added: 'A', pysvn.wc_status_kind.replaced: 'R', pysvn.wc_status_kind.unversioned: '?', } This fails: wc_status_kind_map[ pysvn.wc_status_kind.unversioned ] With: KeyError: <wc_status_kind.unversioned> Clearly I have a bug in the implementation of pysvn.wc_status_kind and could do with some suggestions on what to check please. I've assumed that if my objects support tp_hash and tp_compare they can be used as keys to a dictionary. My test scripts shows hash() and cmp() working. Why does "key in wc_status_kind_wc" work when I use an object returned by keys() by not when I use pysvn.wc_status_kind.unversioned? Barry --------- a.py -------- import pysvn wc_status_kind_map = { pysvn.wc_status_kind.replaced: 'R', pysvn.wc_status_kind.unversioned: 'U', } print( 'hash wc_status_kind', hash( "wc_status_kind" ) ) print( 'hash replace', hash( pysvn.wc_status_kind.replaced ) ) print( 'hash unversioned', hash( pysvn.wc_status_kind.unversioned ) ) print( 'cmp unversioned, unversioned', cmp ( pysvn.wc_status_kind.unversioned, pysvn.wc_status_kind.unversioned ) ) print( 'cmp unversioned, replaced', cmp ( pysvn.wc_status_kind.unversioned, pysvn.wc_status_kind.replaced ) ) print( 'cmp replaced, unversioned', cmp ( pysvn.wc_status_kind.replaced, pysvn.wc_status_kind.unversioned ) ) for key in wc_status_kind_map.keys(): print( '1 key', key, key in wc_status_kind_map, cmp( key, pysvn.wc_status_kind.unversioned ), hash( key ) ) try: print( '1 lookup', wc_status_kind_map[ key ] ) except: print( '1 failed' ) for key in [pysvn.wc_status_kind.added, pysvn.wc_status_kind.replaced, pysvn.wc_status_kind.unversioned]: print( '2 key', key, key in wc_status_kind_map, cmp( key, pysvn.wc_status_kind.unversioned ), hash( key ) ) try: print( '2 lookup', wc_status_kind_map[ key ] ) except: print( '2 failed' ) print( wc_status_kind_map[ pysvn.wc_status_kind.unversioned ] ) ------------ Output ------- $ python3.0 a.py hash wc_status_kind -586300918 hash replace -586300911 hash unversioned -586300916 cmp unversioned, unversioned 0 cmp unversioned, replaced -1 cmp replaced, unversioned 1 1 key replaced True 1 -586300911 1 lookup R 1 key unversioned True 0 -586300916 1 lookup U 2 key added False 1 -586300914 2 failed 2 key replaced False 1 -586300911 2 failed 2 key unversioned False 0 -586300916 2 failed Traceback (most recent call last): File "a.py", line 32, in <module> print( wc_status_kind_map[ pysvn.wc_status_kind.unversioned ] ) KeyError: <wc_status_kind.unversioned>
On Oct 5, 2008, at 19:47, Martin v. Löwis wrote:
Why does "key in wc_status_kind_wc" work when I use an object returned by keys() by not when I use pysvn.wc_status_kind.unversioned?
This is too little detail to come up with an explanation. Do your objects support __eq__.
Regards, Martin
I wrote a smaller version of the code that fails and had a session with gdb. My object implements tp_compare but lookdict() uses richcompare. If richcompare is not implemented do_richcompare() falls back to comparing PyObject * pointers - which is cause of the KeyError as the objects cmp() eq but have different PyObect * values. This is a change from V2 python where to be a key implementing tp_hash and tp_compare is sufficient. In V3 is it your intention that to be a key you must implement tp_hash and tp_richcompare? If not I'll raise a bug against 3.0 on this issue. Barry
In V3 is it your intention that to be a key you must implement tp_hash and tp_richcompare? If not I'll raise a bug against 3.0 on this issue.
I believe that cmp/tp_compare are being phased out, although I think there was a heavy debate about this. In any case, I think you really need to implement tp_richcompare. Regards, Martin
On Oct 7, 2008, at 23:31, Martin v. Löwis wrote:
In V3 is it your intention that to be a key you must implement tp_hash and tp_richcompare? If not I'll raise a bug against 3.0 on this issue.
I believe that cmp/tp_compare are being phased out, although I think there was a heavy debate about this.
Given the problems I am seeing with tp_compare I'd advise that you get rid of it for 3.0. The half hearted support is worst then no support. At least if you remove tp_compare it forces a porter to implement tp_richcompare.
In any case, I think you really need to implement tp_richcompare.
I've added support already in PyCXX. I'll now implement tp_richcompare for pysvn and document this in my PyCXX porting guide. Barry
Barry Scott wrote:
for key in [pysvn.wc_status_kind.added, pysvn.wc_status_kind.replaced, pysvn.wc_status_kind.unversioned]: print( '2 key', key, key in wc_status_kind_map, cmp( key, pysvn.wc_status_kind.unversioned ), hash( key ) ) try: print( '2 lookup', wc_status_kind_map[ key ] ) except: print( '2 failed' )
2 key added False 1 -586300914 2 failed 2 key replaced False 1 -586300911 2 failed 2 key unversioned False 0 -586300916 2 failed
Given that p.we.x seems to always return the same object (since the hashes, which which appear to be ids, are the same), an __eq__ method (which gets called in preference to __cmp__), possibly inherited, that always return False is the only thing I can think of. (Hence Martin's question, I presume). I have no idea, however, how porting could make that happen. tjr
On Oct 5, 2008, at 22:49, Terry Reedy wrote:
Barry Scott wrote:
for key in [pysvn.wc_status_kind.added, pysvn.wc_status_kind.replaced, pysvn.wc_status_kind.unversioned]: print( '2 key', key, key in wc_status_kind_map, cmp( key, pysvn.wc_status_kind.unversioned ), hash( key ) ) try: print( '2 lookup', wc_status_kind_map[ key ] ) except: print( '2 failed' )
2 key added False 1 -586300914 2 failed 2 key replaced False 1 -586300911 2 failed 2 key unversioned False 0 -586300916 2 failed
Given that p.we.x seems to always return the same object (since the hashes, which which appear to be ids, are the same), an __eq__ method (which gets called in preference to __cmp__), possibly inherited, that always return False is the only thing I can think of. (Hence Martin's question, I presume). I have no idea, however, how porting could make that happen.
The type is not derived so the __eq__ cannot be happening. I guess I need to use gdb and figure out what is going on. Barry
On Oct 5, 2008, at 22:49, Terry Reedy wrote:
Given that p.we.x seems to always return the same object (since the hashes, which which appear to be ids, are the same), an __eq__ method (which gets called in preference to __cmp__), possibly inherited, that always return False is the only thing I can think of. (Hence Martin's question, I presume). I have no idea, however, how porting could make that happen.
I see no reply from Martin. What was his question? Barry
Given that p.we.x seems to always return the same object (since the hashes, which which appear to be ids, are the same), an __eq__ method (which gets called in preference to __cmp__), possibly inherited, that always return False is the only thing I can think of. (Hence Martin's question, I presume). I have no idea, however, how porting could make that happen.
I see no reply from Martin. What was his question?
Whether __eq__ was implemented for the specific type (and whether that implementation was consistent with __hash__). Regards, Martin
participants (3)
-
"Martin v. Löwis" -
Barry Scott -
Terry Reedy