473,770 Members | 4,558 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Why are there no ordered dictionaries?

This is probably a FAQ, but I dare to ask it nevertheless since I
haven't found a satisfying answer yet: Why isn't there an "ordered
dictionary" class at least in the standard list? Time and again I am
missing that feature. Maybe there is something wrong with my programming
style, but I rather think it is generally useful.

I fully agree with the following posting where somebody complains why so
very basic and useful things are not part of the standard library:
http://groups.google.com/group/comp....52d2f771a49857

Are there plans to get it into the standard lib sometime?

-- Christoph
Nov 22 '05
210 10547
Christoph Zwerschke wrote:
I will assume that d has is a Foord/Larosa ordered dict with "sequence"
attribute in the following.

Then, with other words,

d.keys[:] = newkeyseq

should do the same as:

d.sequence = newkeyseq


At least in the case where newkeyseq is a permutation of d.sequence.

Otherwise, it should behave like the given implementation for setting
slices, i.e.

- if newkeyseq has duplicate elements, an exception should be raised.
- if newkeyseq has elements not in d.sequence, then the dictionary
should be updated with corresponding None values
- if d.sequence has elements not in newkeyseq then these elements should
be deleted from the dictionary

-- Christoph
Nov 27 '05 #201
Bengt Richter schrieb:
OTOH,
>>> {}[:]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unhashable type
I.e., slices are not valid keys for ordinary dicts, and slices tie in
very well with the ordered aspect of ordered dicts, so that's an
argument for permitting it via the indexing syntax, not just items[:]
or items()[:] which have related but not identical semantics.


I see it like that. BTW, the above error message is pretty bad.
I wonder who is going to use it for what.


I think re-ordering will be a very rare use case anyway and slicing even
more. As a use case, I think of something like mixing different
configuration files and default configuration parameters, while trying
to keep a certain order of parameters and parameters blocks.

-- Christoph
Nov 27 '05 #202
Note that I've done two things with the Foord/Larosa dict. ;-)

I've implemented slicing, including slice assignment and deletion. I've
also 'hidden' ``sequence``, but you can pass arguments to keys, values
and items.

I've done a second (experimental) implementation of a custom keys
object. This is effectively the managed list - which you can call as a
method or mutate in place. You can't delete members from 'keys' but you
can do slice assignment so long as the sequence you're replacing is the
same length (and is a re -ordering of the set being replaced).

I'll post it on Monday, and if people like it I'll complete it.

All the best,
Fuzzyman
http://www.voidspace.org.uk/python/index.shtml

Nov 27 '05 #203
On Sun, 27 Nov 2005 12:00:23 +0100, Christoph Zwerschke <ci**@online.de > wrote:
Bengt Richter wrote:
d.keys[:] = newkeyseq
Do you really mean just re-ordering the keys without a corresponding reording of values??
That would be a weird renaming of all values. Or do you means that any key should still
retrieve the same value as before if used as d[key]? In which case the values must undergo
the same permutation as the keys. I.e., you are assuming key->value pairings remain stable
through any key reorderings?


Since it is considered as being a dictionary in the first place, the
key->value pairings should of course stay stable. In the usual
implementati on based on an ordinary dictionary with an additional key
list ("sequence" in the Foord/Larosa and "_keys" in the Bejamin/Winter
implementation ), you would only set the key list, since the value list
is generated dynamically. But if your implementation keeps internal
values or items lists, these need to be adjusted as well.

I will assume that d has is a Foord/Larosa ordered dict with "sequence"
attribute in the following.

Then, with other words,

d.keys[:] = newkeyseq

should do the same as:

d.sequence = newkeyseq
Exactly what, though? should e.g.
d.keys[3] = newk3
mean (not a suggested implementation, just to define semantics)
keys = d.keys()
if newk3 in keys and keys.index(newk 3)!=3:
raise ValueError,'Att empt to introduce duplicate key'
items = d.items()
items[3] = (newk3, items[3][1])
d.clear()
d.update(items)


Yes, that would be the correct semantics. Of course this should not be
the real implementation and use KeyError instead of ValueError. With
other words,

d.keys[i] = newkey

sould be the same as:

if d.sequence[i] != newkey:
if newkey in d.sequence:
raise KeyError,'Attem pt to introduce duplicate key'
else:
d.sequence[i] = newkey
This would allow what you might call renaming in place.
Similarly
d.keys[i:j] = newkeysij
might have the semantics of
keys = d.keys()
outside = set(keys[:i])+set(keys[j:])
if outside & set(newkeysij) or len(newkeysij) != len(set(newkeys ij)):
raise ValueError,'Att empt to introduce duplicate key(s)'
items = d.items()
items[i:j] = [(k, items[kx+i][1]) for kx,k in enumerate(newke ysij)]
d.clear()
d.update(items)

Is this what is desired?


Not quite, because it does not preserve the key->value pairings (see
above) and it would behave strangely or raise an exception if the new
slice is larger. The following code would do:


keys = d.keys()
outside = set(keys[:i])|set(keys[j:])
if outside & set(newkeysij) or len(newkeysij) != len(set(newkeys ij)):
raise ValueError,'Att empt to introduce duplicate key(s)'
items = d.items()
items[i:j] = [(k, d.get(k, None)) for k in newkeysij]
d.clear()
d.update(items )

(Note that there was a bug in the second line. You cannot add sets.) Oops, thinking about adding dicts ;-)

Again, this would be equivalent to:

seq = d.sequence
newseq = seq[:]
newseq[i:j] = newkeysij
if len(newseq) != len(set(newseq) ):
raise KeyError,'Attem pt to introduce duplicate key(s)'
for k in set(seq[i:j]) - set(newkeysij):
del d[k]
for k in set(newkeysij) - set(seq[i:j]):
d[k] = None
d.sequence = newseq
You don't keep track of the item lists, they need to be built on every
occasion.


That depends on how you implement ;-)


Ok, I was thinking of the usual implementations .
Back from holiday, so maybe I'll hack something out.


Let us know when you have something to check out.

Maybe Fuzzyman can make some moderate improvements to the existing
odict.py, and you can do something more "radical". Then we have two
"reference implementations " and can compare how they prove regarding
performance and usability.

My code so far is a kludge to get functionality. Perhaps we can arrive at
a spec by doing some TDD. My current kludge passes these tests
(run by py.test which I downloaded from the pypy project site and made
work (apparanently ;-) with IIRC a .pth file to point to py where I
expanded the zip, and a cmd file to kick of python running py.test,
and I think that was all there was. As you can see, it is super easy to define
tests. If you want to try it, I think I can retrace my steps and describe
the way I set it up (for windows NT) in a few turgid run-on paragraphs ;-)
Maybe I'll get around to writing a downloading/checking/installing script
for it, with a few interactive are-you-sure?'s and file tree placement options etc.

I'm calling it a Creordict for now -- Created-order-dict.
Here are the tests so far. Do you want to add some to refine what's supposed to
happen. You may want to look at test_items, test_keys, test_values
as those are the ones that provide d.items(), d.items[i], d.items[i:j]
style accesses, with assign, eval, and del available for the latter two.
also test___getitem_ _ for d[i] => value normal key access vs
d[i:j] => another Creordict instance. Let me know what's missing.
I'm not sure how this list-based dict object will work out, but it's
a subclass of list, not of dict. ;-)

Some def test_usecase_xx (): ... definitions might be nice.
I am running py.test on windows NT. I din't compile anything,
I just cobbled afew things together.

----< test_creordict. py >----------------------------------------------
# test_creordict. py
# XXX assoclist.py ?? cf. scheme assv using == (eq<->is, eqv<->==, equal<->deep== ???)
# Tests for creordict.py -- a dictionary object which keeps items in creation time order.
#
# XXX boilerplate bokr AT oz DOT net
from py.test import raises
import py

from creordict import Creordict

def test_sanity():
d = Creordict()
assert d.keys() == []
assert d.values() == []
assert d.items() == []
assert d == d
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert repr(d) == "Creordict([('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)])"
assert d.keys() == ['a', 'b', 'c', 'd', 'e']
assert d.values() == [0, 100, 200, 300, 400]
assert d.items() == [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)]
def test___init__() :
d = Creordict()
assert d.keys() == []
assert d.values() == []
assert d.items() == []
assert d == d
assert d._index == {}
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert repr(d) == "Creordict(%r)" % d.items()
assert d.keys() == ['a', 'b', 'c', 'd', 'e']
assert d.values() == [0, 100, 200, 300, 400]
assert d.items() == [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)]
assert d._index == {'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3}

def test___contains __():
d = Creordict([('a', 1)])
assert 'a' in d
assert (4 in d) == False

def test___eq__():
d = Creordict([('a', 1)])
assert d == d
raises(TypeErro r, "d == {}")
assert d != Creordict([('b', 1)])

def test___cmp__():
d = Creordict([('a', 1)])
assert cmp(d, d) == 0
raises(TypeErro r, "cmp(d, {})")

def mkresult(s, **kw):
return Creordict((k, kw.get(k, k in 'abcdef' and 'abcdef'.index( k)*100)) for k in s)

def test___delitem_ _():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
print mkresult('abcde ')
assert d == mkresult('abcde ')
ditems = d.items()
print d['b']
print d.items()
print d._index
print d._index['b']
del d['b']
assert d == mkresult('acde' )
del d['a']
assert d == mkresult('cde')
del d['e']
assert d == mkresult('cd')
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
del d[1:3]
assert d == mkresult('ade')
del d[:1]
assert d == mkresult('de')
del d[-1:]
assert d == mkresult('d')

def test___repr__() :
assert repr(Creordict( )) == 'Creordict([])'
raises(TypeErro r, "Creordict( {1: 1})")
d = Creordict(((1, 3), (3, 2), (2, 1)))
assert repr(d) =='Creordict([(1, 3), (3, 2), (2, 1)])'

def test___setitem_ _():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
print mkresult('abcde ')
assert d == mkresult('abcde ')
d['b'] = 101
assert d == mkresult('abcde ', b=101)
d['e'] = 401
assert d == mkresult('abcde ', b=101, e=401)

def test___getitem_ _():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d == mkresult('abcde ')
items = d.items()
for k,v in items:
assert d[k]==v
raises(KeyError , "d['f']")

def test___getslice __():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d[2:4] == mkresult('cd')
assert d[ :4] == mkresult('abcd' )
assert d[2: ] == mkresult('cde')
assert d[ : ] == mkresult('abcde ')
assert d[0:0] == mkresult('')

def test___add__():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d+d == d
assert d + Creordict([('f', 500)]) == mkresult('abcde f')

def test_reverse():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
d.reverse()
assert d == mkresult('edcba ')

def test_insert():
d = Creordict([(k,i*100) for i,k in enumerate('abc' )])
d.insert(1, ('x', 101))
assert d == mkresult('axbc' , x=101, b=100, c=200)

def test_get():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d == mkresult('abcde ')
items = d.items()
for k,v in items:
assert d.get(k)==v
assert d.get(k+'1') is None
assert d.get(k+'1', v) == v
raises(KeyError , "d['f']")

def test_copy():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d == d.copy()

def test_items():
assert Creordict().ite ms() == []
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.items() == [(k,i*100) for i,k in enumerate('abcd e')]
assert d.items[:] == [(k,i*100) for i,k in enumerate('abcd e')]
assert d.items[2:4] == [(k,i*100) for i,k in enumerate('abcd e')][2:4]
d.items[2:4] = []
assert d == mkresult('abe')
d.items[1] = ('x', 'replaces b')
assert d == mkresult('axe', x='replaces b')
def test_keys():
assert Creordict().key s() == []
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.keys() == list('abcde')
assert d.keys[:] == list('abcde')
assert d.keys[2:4] == list('cd')
assert d.keys[1] == 'b'
assert d.keys[-1] == 'e'
d.keys[2:4] = ['x', 'y']
assert d == mkresult('abxye ', x=200, y=300)
del d.keys[-1]
assert d == mkresult('abxy' , x=200, y=300)
keys = d.keys()
keys[0], keys[-1] = keys[-1], keys[0] # swap end keys
d.keys[:]=keys
assert d == mkresult('ybxa' , x=200, y=0, a=300) # a and y value associations swapped ;-)

def test_values():
assert Creordict().val ues() == []
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.values() == [i*100 for i,k in enumerate('abcd e')]
assert d.values[:] == [i*100 for i,k in enumerate('abcd e')]
assert d.values[2:4] == d[2:4].values()
assert d.values[1] == d.values()[1]
assert d.values[-1] == d.values()[-1]
d.values[2:4] = ['v2', 'v3']
assert d == mkresult('abcde ', c='v2', d='v3')
del d.values[-1]
assert d == mkresult('abcd' , c='v2', d='v3')
values = d.values()
values[0], values[-1] = values[-1], values[0] # swap end values
d.values[:]=values
assert d == mkresult('abcd' , c='v2', d=0, a='v3') # a and y value associations swapped ;-)

def test_iteritems( ):
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
itd = d.iteritems()
assert type(itd) == type(iter([]))
assert list(itd) == d.items()

def test_len():
d = Creordict()
assert len(d) == 0
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert len(d) == 5

def test_has_key():
d = Creordict(((1, 3), (3, 2), (2, 1)))
assert d.has_key(1) is True
assert d.has_key(4) is False

def test_iterkeys() :
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
itd = d.iterkeys()
assert type(itd) == type(x for x in [])
assert list(itd) == d.keys()

def test_itervalues ():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
itd = d.itervalues()
assert type(itd) == type(x for x in [])
assert list(itd) == d.values()

def test_clear():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
d.clear()
assert d.items() == []
assert d.keys() == []
assert d.values() == []

def test_pop():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.pop('e') == 400
assert d.pop('b') == 100
assert d.pop('a') == 0
assert d == mkresult('cd')

def test_popitem():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.popitem() == ('e', 400)
assert d.popitem() == ('d', 300)
assert d.popitem() == ('c', 200)
assert d == mkresult('ab')

def test_setdefault ():
d = Creordict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.setdefault('c ', 'cee') == 200
assert d.setdefault('g ') is None
assert d == mkresult('abcde g', g=None)
assert d.setdefault('h ', 'eightch') == 'eightch'
assert d == mkresult('abcde gh', g=None, h='eightch')

def test_update():
d = Creordict()
assert d == mkresult('')
d.update([(k,i*100) for i,k in enumerate('abcd e')])
assert d == mkresult('abcde ')
raises(TypeErro r, "d.update({ 'f': 500})")
d.update([('f', 500), ('b',101)])
assert d == mkresult('abcde f', b=101)
raises(ValueErr or, "d.update([('broken',)])")

-----------------------------------------------------------------------

Regards,
Bengt Richter
Nov 29 '05 #204
I had the same idea to create a py.test to verify and compare various
implementations . The doctests in odict.py are nice, but you can't use
them for this purpose and they may not test enough. It would be also
good to have something for testing and comparing performance.

-- Christoph
Nov 29 '05 #205
On Tue, 29 Nov 2005 23:30:45 +0100, Christoph Zwerschke <ci**@online.de > wrote:
I had the same idea to create a py.test to verify and compare various
implementation s. The doctests in odict.py are nice, but you can't use
them for this purpose and they may not test enough. It would be also
good to have something for testing and comparing performance.

Well, the previous post test file just grew to make a simple check for various
aspects, so it's not super clean. I just grepped for defs in the implementation
and bulk appended "test_" to make an empty starting point. Then I just filled
in tests after a preliminary sanity check test. But there are some things
that could still accidentally be inherited from the base class when builtin
utility functions are called on the dict object. Also there's a lot of cut-paste
duplication an no full explorations of corner cases. There's neat generator-based
test driving with different parameters that I didn't take advantage of,
etc. etc.

I should really read the py test docs and learn to use it
better if I am going to use it. But anyway, it's a q&d hack to show and
sanity-check different usages. The semantics of assigning slices
to d.keys[i:j] and d.values[i:j] are kind of tricky when the size changes
and/or key names match or don't match in various ways, or the incoming
data represents collapsing redundant keys that are legal sequential assignment
overrides but change the size, etc.

One could add keyword args to the constructor to vary key eq and cmp used
on keys to determine "key collisions" between e.g. tuple keys and also for
sort. You could even allow partially non-hashable keys that way if you got tricky.
But maybe this is getting too tricky ;-)

I'll make some simple mods to the test to allow applying it to arbitrary
candidate implementations with different names and directory locations, so
I can try it on odict.py and other versions. But are the semantics right?

Doctest is handy, and in some ways I like examples showing up in the help docs,
but maybe help should take a keyword arg to select showing them (and some other
things too perhaps. A brief version excluding a lot of inheritance for classes
might be nice. Or a pattern for method and class var inclusion.

But I like the separation of the py.test tests with no need to mod the original.
Where next? This ordered dict thing is kind of a side-track from a side-track for me ;-)

Regards,
Bengt Richter
Nov 30 '05 #206

Christoph Zwerschke wrote:

Hello Christoph,
I think re-ordering will be a very rare use case anyway and slicing even
more. As a use case, I think of something like mixing different
configuration files and default configuration parameters, while trying
to keep a certain order of parameters and parameters blocks.

In actual fact - being able to *reorder* the dictionary is the main way
I use this dictionary.

All the best,

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml
-- Christoph


Dec 1 '05 #207
Hmmm... it would be interesting to see if these tests can be used with
odict.

The odict implementation now has full functionality by the way.

Optimisations to follow and maybe a few *minor* changes.

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml

Dec 1 '05 #208
> The semantics of assigning slices
to d.keys[i:j] and d.values[i:j] are kind of tricky when the size changes
and/or key names match or don't match in various ways, or the incoming
data represents collapsing redundant keys that are legal sequential assignment
overrides but change the size, etc.

I have come against the same problem with slice assignment, when doing
odict. :-)
Allowing the size to change prevents a useful optimisation - but I
dislike *preventing* programmers from doing things.

All the best,

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml

Regards,
Bengt Richter


Dec 1 '05 #209
On 1 Dec 2005 03:53:27 -0800, "Fuzzyman" <fu******@gmail .com> wrote:
Hmmm... it would be interesting to see if these tests can be used with
odict. I assume you are referring to the pytest tests I posted, though I would
need some of the context you snipped to me more sure ;-)

Anyway, with some changes[1], they can.

The odict implementation now has full functionality by the way.
The one at
http://www.voidspace.org.uk/cgi-bin/...?file=odict.py
? It seems to be unchanged.

Optimisation s to follow and maybe a few *minor* changes.

Anyway, test of the above results in:

C:\UTIL\\..\py. test test
=============== ============== test process starts =============== ==============
testing-mode: inprocess
executable: d:\python-2.4b1\mingw\pyt hon24.exe (2.4.0-beta-1)
using py lib: D:\bpy24\py-0.8.0-alpha2\py <rev unknown>

test\test_odict s.py[28] FF...FF..FFFF.. FFF..........
test\test_odict s_candidate.py[0]

_______________ _______________ _______________ _______________ _______________ ____
_______________ ____________ entrypoint: test_sanity _______________ ____________

def test_sanity():
d = CandidateDict()
assert d.keys() == []
assert d.values() == []
assert d.items() == []
assert d == d
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
E assert repr(d) == "%s([('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)])"%Can
dateDict.__name __ assert "{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}" == ("%s([('a', 0), ('b', 100 ('c', 200), ('d', 300), ('e', 400)])" % CandidateDict._ _name__)
+ where "{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}" = repr({'a': 0, 'b': 100,
c': 200, 'd': 300, 'e': 400})

[C:\pywk\ut\test \test_odicts.py :19]
_______________ _______________ _______________ _______________ _______________ ____
Apparently you are still using plain dict repr format, not a format that could (ideally) be exec'd
to reconstitute the thing repr'd.
from clp.odict import OrderedDict as CandidateDict
CandidateDict._ _name__ 'OrderedDict' repr(CandidateD ict()) '{}'

vs
from ut.creordict import Creordict as CandidateDict
CandidateDict._ _name__ 'Creordict' repr(CandidateD ict()) 'Creordict([])'

Since the test uses CandidateDict._ _name__, it should work either way.

_______________ ___________ entrypoint: test___init__ _______________ ___________

def test___init__() :
d = CandidateDict()
assert d.keys() == []
assert d.values() == []
assert d.items() == []
assert d == d
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
E assert repr(d) == "%s(%r)"% (CandidateDict. __name__, d.items()) assert "{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}" == ('%s(%r)' % ('OrderedDict [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)]))
+ where "{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}" = repr({'a': 0, 'b': 100,
c': 200, 'd': 300, 'e': 400})

[C:\pywk\ut\test \test_odicts.py :32]
_______________ _______________ _______________ _______________ _______________ ____
(Duplicate from test_sanity)

_______________ _________ entrypoint: test___delitem_ _ _______________ __________

def test___delitem_ _():
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
print mkresult('abcde ')
assert d == mkresult('abcde ')
ditems = d.items()
print d['b']
print d.items()
del d['b']
assert d == mkresult('acde' )
del d['a']
assert d == mkresult('cde')
del d['e']
assert d == mkresult('cd')
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')]) del d[1:3]
[C:\pywk\ut\test \test_odicts.py :70]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

def __delitem__(sel f, key):
""" d = OrderedDict(((1 , 3), (3, 2), (2, 1)))
del d[3]
d {1: 3, 2: 1} del d[3]

Traceback (most recent call last):
KeyError: 3
"""
# do the dict.__delitem_ _ *first* as it raises
# the more appropriate error
E dict.__delitem_ _(self, key) TypeError: unhashable type
[c:\pywk\clp\odi ct.py:137]
- - - - - - - - - - - test___delitem_ _: recorded stdout - - - - - - - - - - -
{'a': 0, 'b': 100, 'c': 200, 'd': 300, 'e': 400}
100
[('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400)]

_______________ _______________ _______________ _______________ _______________ ____
You don't appear to accept slice operation syntax directly on the instance

_______________ ___________ entrypoint: test___repr__ _______________ ___________

def test___repr__() :
E assert repr(CandidateD ict()) == '%s([])'%CandidateDic t.__name__ assert '{}' == ('%s([])' % CandidateDict._ _name__) + where '{}' = repr({})
+ where {} = CandidateDict()

[C:\pywk\ut\test \test_odicts.py :78]
_______________ _______________ _______________ _______________ _______________ ____
_______________ _________ entrypoint: test___getslice __ _______________ _________

def test___getslice __():
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
E assert d[2:4] == mkresult('cd') TypeError: unhashable type
[C:\pywk\ut\test \test_odicts.py :102]
_______________ _______________ _______________ _______________ _______________ ____
Again, no slice op

_______________ ___________ entrypoint: test___add__ _______________ ____________

def test___add__():
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
E assert d+d == d TypeError: unsupported operand type(s) for +: 'OrderedDict' and 'OrderedDict'
[C:\pywk\ut\test \test_odicts.py :110]
_______________ _______________ _______________ _______________ _______________ ____
No addition defined on OrderedDicts?

_______________ ___________ entrypoint: test_reverse _______________ ____________

def test_reverse():
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
E d.reverse() AttributeError: 'OrderedDict' object has no attribute 'reverse'
[C:\pywk\ut\test \test_odicts.py :115]
_______________ _______________ _______________ _______________ _______________ ____
No reverse

_______________ ____________ entrypoint: test_insert _______________ ____________

def test_insert():
d = CandidateDict([(k,i*100) for i,k in enumerate('abc' )])
E d.insert(1, ('x', 101)) AttributeError: 'OrderedDict' object has no attribute 'insert'
[C:\pywk\ut\test \test_odicts.py :120]
_______________ _______________ _______________ _______________ _______________ ____
No insert

_______________ ____________ entrypoint: test_items _______________ _____________

def test_items():
assert CandidateDict() .items() == []
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.items() == [(k,i*100) for i,k in enumerate('abcd e')]
E assert d.items[:] == [(k,i*100) for i,k in enumerate('abcd e')] TypeError: unsubscriptable object
[C:\pywk\ut\test \test_odicts.py :141]
_______________ _______________ _______________ _______________ _______________ ____
Only d.items() ?

_______________ _____________ entrypoint: test_keys _______________ _____________

def test_keys():
assert CandidateDict() .keys() == []
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.keys() == list('abcde')
E assert d.keys[:] == list('abcde') TypeError: unsubscriptable object
[C:\pywk\ut\test \test_odicts.py :153]
_______________ _______________ _______________ _______________ _______________ ____
Only d.keys() ?

_______________ ____________ entrypoint: test_values _______________ ____________

def test_values():
assert CandidateDict() .values() == []
d = CandidateDict([(k,i*100) for i,k in enumerate('abcd e')])
assert d.values() == [i*100 for i,k in enumerate('abcd e')]
E assert d.values[:] == [i*100 for i,k in enumerate('abcd e')] TypeError: unsubscriptable object
[C:\pywk\ut\test \test_odicts.py :170]
_______________ _______________ _______________ _______________ _______________ ____
Only d.values() ?

============ tests finished: 17 passed, 11 failed in 1.36 seconds =============
[1] I changed the tests to use a CandidateDict alias, and eliminated a couple of checks
on internal state, so as to allow different implementations to be tested, using
CandidateDict._ _name__ to synthesize alternate expected representation strings.

I made the test selectable if run interactively instead of directly via pytest:

[17:43] C:\pywk\ut>py24 test\test_odict s.py
Enter selection [1..2] (q to do nothing)
for importing candidate odicts
1: from ut.creordict import Creordict as CandidateDict
2: from clp.odict import OrderedDict as CandidateDict 1


"from ut.creordict import Creordict as CandidateDict"

is selected. Type "Yes" exactly (w/o quotes) to accept: Yes
=============== ============== test process starts =============== ==============
testing-mode: inprocess
executable: d:\python-2.4b1\mingw\pyt hon24.exe (2.4.0-beta-1)
using py lib: D:\bpy24\py-0.8.0-alpha2\py <rev unknown>

test\test_odict s.py[28] ............... .............

=============== === tests finished: 28 passed in 1.03 seconds =============== ===

Not sure they way I did it is a good idea, but anyway I can just add a little
boilerplate at the bottom of a test and a text file with the choices (which are
one-line sources that get written to test_... so the test can do from test_... import CandidateDict
and have the chosen class by the name it uses for both.

Regards,
Bengt Richter
Dec 2 '05 #210

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.