pax_global_header 0000666 0000000 0000000 00000000064 13307624441 0014516 g ustar 00root root 0000000 0000000 52 comment=a36afca2865d396026d98374f19e8ed042b0c3ae
python-orderedmultidict-1.0/ 0000775 0000000 0000000 00000000000 13307624441 0016240 5 ustar 00root root 0000000 0000000 python-orderedmultidict-1.0/.gitignore 0000664 0000000 0000000 00000000102 13307624441 0020221 0 ustar 00root root 0000000 0000000 *~
.#*
\#*
.tox/
dist/
.eggs/
build/
*.pyc
*.pyo
*.egg
*.egg-info
python-orderedmultidict-1.0/.travis.yml 0000664 0000000 0000000 00000000556 13307624441 0020357 0 ustar 00root root 0000000 0000000 language: python
sudo: false
matrix:
include:
- env: TOXENV=codestyle
- python: 2.6
env: TOXENV=py26
- python: 2.7
env: TOXENV=py27
- python: 3.4
env: TOXENV=py34
- python: 3.5
env: TOXENV=py35
- python: pypy
env: TOXENV=pypy
install: travis_retry pip install tox
script: tox
notifications:
email: false
python-orderedmultidict-1.0/API.md 0000664 0000000 0000000 00000031631 13307624441 0017177 0 ustar 00root root 0000000 0000000 # omdict API
### Nomenclature
Many of omdict's methods contain the word __list__ or __all__. __list__ in a method\
name indicates that method interacts with a list of values instead of a\
single value. __all__ in a method name indicates that method interacts with\
the ordered list of all items, including multiple items with the same key.
Here's an example illustrating __getlist(key, default=[])__, a __list__ method, and\
__allitems()__, an __all__ method.
```python
>>> from orderedmultidict import omdict
>>> omd = omdict([(1,1), (2,2), (1,11)])
>>> omd.items()
[(1, 1), (2, 2)]
>>> omd.allitems()
[(1, 1), (2, 2), (1, 11)]
>>> omd.get(1)
1
>>> omd.getlist(1)
[1, 11]
```
So __list__ denotes a list of values, and __all__ denotes all items.
Simple.
### Method parity with dict
All [dict](http://docs.python.org/library/stdtypes.html#dict) methods behave identically on omdict objects (__pop()__,\
__setdefault()__, __clear()__, etc)
### Initialization and Updates
omdict objects can be initialized from a dictionary or a list of key:value\
items.
```python
>>> omd = omdict()
>>> omd.allitems()
[]
>>> omd = omdict({1:1, 2:2, 3:3})
>>> omd.allitems()
[(1, 1), (2, 2), (3, 3)]
>>> omd = omdict([(1,1), (2,2), (3,3), (1,1)])
>>> omd.allitems()
[(1, 1), (2, 2), (3, 3), (1, 1)]
```
__load(mapping)__ can be used at any time to reinitialize an omdict.
```python
>>> omd.load({4:4, 5:5})
>>> omd.allitems()
[(4, 4), (5, 5)]
>>> omd = omdict([(1,1), (2,2), (3,3)])
>>> omd.allitems()
[(1, 1), (2, 2), (3, 3)]
>>> omd.load([(6,6), (6,6)])
>>> omd.allitems()
[(6, 6), (6, 6)]
```
__update([mapping])__ updates the dictionary with items from __mapping__, one\
item per key like [dict.update([mapping])](http://docs.python.org/library/stdtypes.html#dict.update). __updateall([mapping])__ updates\
the dictionary with all items from __mapping__. Key order is preserved -\
existing keys are updated with values from __mapping__ before any new\
items are added.
```python
>>> omd = omdict()
>>> omd.update([(1,1), (2,2), (1,11), (2,22)])
>>> omd.items()
[(1, 11), (2, 22)]
>>> omd.allitems()
[(1, 11), (2, 22)]
>>> omd.updateall([(2,'replaced'), (1,'replaced'), (2,'added'), (1,'added')])
>>> omd.allitems()
[(1, 'replaced'), (2, 'replaced'), (2, 'added'), (1, 'added')]
```
### Getters, Setters, and Adders
__omd[key]__ behaves identically to [dict[key]](http://docs.python.org/library/stdtypes.html#dict). If __key__ has multiple values, only\
its first value is returned.
```python
>>> omd = omdict([(1,1), (1,'not me')])
>>> omd[1]
1
```
__omd[key] = value__ behaves identically to [dict[key] =
value](http://docs.python.org/library/stdtypes.html#dict). If __key__ has\
multiple values, they will all be deleted and replaced with __value__.
```python
>>> omd = omdict([(1,'deleted'), (1,'deleted')])
>>> omd[1] = 1
>>> omd[1]
1
```
__del omd[key]__ behaves identically to [del
dict[key]](http://docs.python.org/library/stdtypes.html#dict). If __key__ has multiple\
values, all of them will be deleted.
```python
>>> omd = omdict([(1,1), (1,11)])
>>> del omd[1]
>>> omd.allitems()
[]
```
__get(key, default=None)__ behaves identically to\
[dict.get(key,
default=None)](http://docs.python.org/library/stdtypes.html#dict.get). If __key__ has multiple values, only its first value\
is returned.
```python
>>> omd = omdict([(1,1), (1,2)])
>>> omd.get(1)
1
>>> omd.get(404, 'sup')
'sup'
```
__getlist(key, default=[])__ is like __get(key, default=None)__ except it returns the\
list of values assocaited with __key__.
```python
>>> omd = omdict([(1,1), (1,11), (2,2)])
>>> omd.getlist(1)
[1, 11]
>>> omd.getlist(2)
[2]
>>> omd.getlist(404, 'sup')
'sup'
```
__set(key, value=None)__ sets __key__'s value to __value__. Identical in function to\
`omd[key] = value`. Returns the omdict object for method chaining.
```python
>>> omd = omdict([(1,1), (1,11), (1,111)])
>>> omd.set(1, 1)
>>> omd.getlist(1)
[1]
>>> omd.set(1, 11).set(2, 2)
>>> omd.allitems()
[(1, 11), (2, 2)]
```
__setlist(key, values=[])__ sets __key__'s list of values to __values__. Returns the\
omdict object for method chaining.
```python
>>> omd = omdict([(1,1), (2,2)])
>>> omd.setlist(1, ['replaced', 'appended'])
>>> omd.allitems()
[(1, 'replaced'), (2, 2), (1, 'appended')]
>>> omd.setlist(1, ['onlyme'])
>>> omd.allitems()
[(1, 'onlyme'), (2, 2)]
```
__setdefault(key, default=None)__ behaves identically to\
[dict.setdefault(key,
default=None)](http://docs.python.org/library/stdtypes.html#dict.setdefault).
```python
>>> omd = omdict([(1,1)])
>>> omd.setdefault(1)
1
>>> omd.setdefault(2, None)
>>> omd.allitems()
[(1, 1), (2, None)]
```
__setdefaultlist(key, defaultlist=[None])__ is like\
__setdefault(key, default=None)__ except a list of values for __key__ is adopted. If\
__defaultlist__ isn't provided, __key__'s value becomes None.
```python
>>> omd = omdict([(1,1)])
>>> omd.setdefaultlist(1)
[1]
>>> omd.setdefaultlist(2, [2, 22])
[2, 22]
>>> omd.allitems()
[(1, 1), (2, 2), (2, 22)]
>>> omd.setdefaultlist(3)
[None]
>>> print omd[3]
None
```
__add(key, value=None)__ adds __value__ to the list of values for __key__. Returns\
the omdict object for method chaining.
```python
>>> omd = omdict()
>>> omd.add(1, 1)
>>> omd.allitems()
[(1, 1)]
>>> omd.add(1, 11).add(2, 2)
>>> omd.allitems()
[(1, 1), (1, 11), (2, 2)]
```
__addlist(key, valuelist=[])__ adds the values in __valuelist__ to the list of values\
for __key__. Returns the omdict object for method chaining.
```python
>>> omd = omdict([(1,1)])
>>> omd.addlist(1, [11, 111])
>>> omd.allitems()
[(1, 1), (1, 11), (1, 111)]
>>> omd.addlist(2, [2]).addlist(3, [3, 33])
>>> omd.allitems()
[(1, 1), (1, 11), (1, 111), (2, 2), (3, 3), (3, 33)]
```
### Groups and Group Iteration
__items([key])__ behaves identically to [dict.items()](http://docs.python.org/library/stdtypes.html#dict.items) except an optional __key__\
parameter has been added. If __key__ is provided, only items with key __key__\
are returned. __iteritems([key])__ returns an iterator over `items(key)`. KeyError\
is raised if __key__ is provided but not in the dictionary.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.items()
[(1, 1), (2, 2), (3, 3)]
>>> omd.items(1)
[(1, 1), (1, 11), (1, 111)]
```
__keys()__ behaves identically to [dict.keys()](http://docs.python.org/library/stdtypes.html#dict.keys). __iterkeys()__ returns an iterator\
over keys().
__values([key])__ behaves identically to [dict.values()](http://docs.python.org/library/stdtypes.html#dict.values) except an optional __key__\
parameter has been added. If __key__ is provided, only the values for __key__ are\
returned. __itervalues([key])__ returns an iterator over `values(key)`. KeyError\
is raised if __key__ is provided but not in the dictionary.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.values()
[1, 2, 3]
>>> omd.values(1)
[1, 11, 111]
```
__lists()__ returns a list comprised of the lists of values associated with each\
dictionary key. __iterlists()__ returns an iterator over __lists()__.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.lists()
[[1, 11, 111], [2], [3]]
```
__listitems()__ returns a list of key:valuelist items. __iterlistitems()__ returns an\
iterator over __listitems()__.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3), (2,22)])
>>> omd.listitems()
[(1, [1, 11, 111]), (2, [2, 22]), (3, [3])]
```
__allitems([key])__ returns a list of every item in the dictionary, including\
multiple items with the same key. If __key__ is provided and in the dictionary,\
only items with key __key__ are returned . KeyError is raised if __key__ is\
provided and not in the dictionary. __iterallitems([key])__ returns an iterator\
over __allitems(key)__.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.allitems()
[(1, 1), (1, 11), (1, 111), (2, 2), (3, 3)]
```
__allkeys()__ returns a list of the keys of every item in the dictionary.\
__iterallkeys()__ returns an iterator over __allkeys()__.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.allkeys()
[1, 1, 1, 2, 3]
```
__allvalues()__ returns a list of the values of every item in the dictionary.\
__iterallvalues()__ returns an iterator over __allvalues()__.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.allvalues()
[1, 11, 111, 2, 3]
```
### Pops
__pop(key[, default])__ behaves identically to [dict.pop(key[,
default])](http://docs.python.org/library/stdtypes.html#dict.pop). If __key__\
has multiple values, the first value is returned but all items with key __key__\
are popped. KeyError is raised if __default__ isn't provided and __key__ isn't in\
the dictionary.
```python
>>> omd = omdict([(1,1), (2,2), (1,11)])
>>> omd.pop(1)
1
>>> omd.allitems()
[(2, 2)]
```
__poplist(key[, default])__ is like `pop(key[, default])` except it returns the list of\
values for __key__. KeyError is raised if __default__ isn't provided and __key__ isn't in\
the dictionary.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.poplist(1)
[1, 11, 111]
>>> omd.allitems()
[(2, 2), (3, 3)]
>>> omd.poplist(2)
[2]
>>> omd.allitems()
[(3, 3)]
>>> omd.poplist('nonexistent key', 'sup')
'sup'
```
__popvalue(key[, value, default], last=True)__ pops a value for __key__.
If __value__ is not provided, the first or last value for __key__ is popped and\
returned.
If __value__ is provided, the first or last (__key__,__value__) item is popped and __value__\
is returned.
If __key__ no longer has any values after a __popvalue()__ call, __key__ is removed\
from the dictionary. __default__ is returned if provided and __key__ isn't in the\
dictionary. KeyError is raised if __default__ isn't provided and __key__ isn't in the\
dictionary. ValueError is raised if __value__ is provided but isn't a value for\
__key__.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3), (2,22)])
>>> omd.popvalue(1)
111
>>> omd.allitems()
[(1, 1), (1, 11), (2, 2), (3, 3), (2, 22)]
>>> omd.popvalue(1, last=False)
1
>>> omd.allitems()
[(1, 11), (2, 2), (3, 3), (2, 22)]
>>> omd.popvalue(2, 2)
2
>>> omd.allitems()
[(1, 11), (3, 3), (2, 22)]
>>> omd.popvalue(1, 11)
11
>>> omd.allitems()
[(3, 3), (2, 22)]
>>> omd.popvalue('not a key', default='sup')
'sup'
```
__popitem(fromall=False, last=True)__ pops and returns a key:value item.
If __fromall__ is False, `items()[0]` is popped if __last__ is False or `items()[-1]` is\
popped if __last__ is True. All remaining items with the same key are\
removed.
If __fromall__ is True, `allitems()[0]` is popped if __last__ is False or `allitems()[-1]` is\
popped if __last__ is True. No other remaining items are removed, even if\
they have the same key.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.popitem()
(3, 3)
>>> omd.popitem(fromall=False, last=False)
(1, 1)
>>> omd.popitem(fromall=False, last=False)
(2, 2)
>>> omd.allitems()
[]
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.popitem(fromall=True, last=False)
(1, 1)
>>> omd.popitem(fromall=True, last=False)
(1, 11)
>>> omd.popitem(fromall=True, last=True)
(3, 3)
>>> omd.popitem(fromall=True, last=False)
(1, 111)
```
__poplistitem([key], last=True)__ pops and returns a key:valuelist item\
comprised of a key and that key's list of values. If __last__ is False, a\
key:valuelist item comprised of `keys()[0]` and its list of values is popped\
and returned. If __last__ is True, a key:valuelist item comprised of `keys()[-1]`\
and its list of values is popped and returned. KeyError is raised if the\
dictionary is empty or if __key__ is provided and not in the dictionary.
```python
>>> omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
>>> omd.poplistitem(last=True)
(3, [3])
>>> omd.poplistitem(last=False)
(1, [1, 11, 111])
```
### Miscellaneous
__copy()__ returns a shallow copy of the dictionary.
```python
>>> omd = omdict([(1,1), (1,11), (2,2), (3,3)])
>>> copy = omd.copy()
>>> omd == copy
True
>>> isinstance(copy, omdict)
True
```
__clear()__ clears all items.
```python
>>> omd = omdict([(1,1), (1,11), (2,2), (3,3)])
>>> omd.clear()
>>> omd.allitems()
[]
```
__len(omd)__ returns the number of keys in the dictionary, identical to\
[len(dict)](http://docs.python.org/library/stdtypes.html#dict).
```python
>>> omd = omdict([(1, 1), (2, 2), (1, 11)])
>>> len(omd)
2
```
__size()__ returns the total number of items in the dictionary.
```python
>>> omd = omdict([(1, 1), (1, 11), (2, 2), (1, 111)])
>>> omd.size()
4
```
__reverse()__ reverses the order of all items in the dictionary and returns the\
omdict object for method chaining.
```python
>>> omd = omdict([(1, 1), (2, 2), (3, 3)])
>>> omd.allitems()
[(1, 1), (2, 2), (3, 3)]
>>> omd.reverse()
>>> omd.allitems()
[(3, 3), (2, 2), (1, 1)]
```
__fromkeys(keys[, value])__ behaves identically to [dict.fromkeys(key[,
value])](http://docs.python.org/library/stdtypes.html#dict.fromkeys).
__has_key(key)__ behaves identically to [dict.has_key(key)](http://docs.python.org/library/stdtypes.html#dict.has_key), but use\
`key in omd` instead of `omd.has_key(key)` where possible.
python-orderedmultidict-1.0/LICENSE.md 0000664 0000000 0000000 00000002366 13307624441 0017653 0 ustar 00root root 0000000 0000000 Build Amazing Things.
***
### Unlicense
This is free and unencumbered software released into the public\
domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute\
this software, either in source code form or as a compiled binary, for any\
purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of\
this software dedicate any and all copyright interest in the software to the\
public domain. We make this dedication for the benefit of the public at\
large and to the detriment of our heirs and successors. We intend this\
dedication to be an overt act of relinquishment in perpetuity of all\
present and future rights to this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF\
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\
SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT\
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\
SOFTWARE.
For more information, please refer to
python-orderedmultidict-1.0/MANIFEST.in 0000664 0000000 0000000 00000000043 13307624441 0017773 0 ustar 00root root 0000000 0000000 include LICENSE.md README.md API.md python-orderedmultidict-1.0/README.md 0000664 0000000 0000000 00000003500 13307624441 0017515 0 ustar 00root root 0000000 0000000 # orderedmultidict
[](https://pypi.python.org/pypi/orderedmultidict)
[](https://travis-ci.org/gruns/orderedmultidict)
### omdict is an ordered multivalue dictionary that retains method parity with Python's [dict](http://docs.python.org/library/stdtypes.html#dict).
A multivalue dictionary is a dictionary that can store multiple values per\
key. An ordered multivalue dictionary is a multivalue dictionary that\
retains the order of insertions and deletions.
orderedmultidict is well tested, [Unlicensed](http://unlicense.org/) in the public domain, and\
supports Python 2, Python 3, PyPy2, and PyPy3.
Code time: omdict can store multiple values per key.
```python
>>> from orderedmultidict import omdict
>>> omd = omdict()
>>> omd[1] = 1
>>> omd[1]
1
>>> omd.add(1, 11)
>>> omd.getlist(1)
[1, 11]
>>> omd.addlist(1, [111, 1111])
>>> omd.getlist(1)
[1, 11, 111, 1111]
>>> omd.allitems()
[(1, 1), (1, 11), (1, 111), (1, 1111)]
```
omdict retains insertion and deletion order.
```python
>>> omd = omdict()
>>> omd[2] = 2
>>> omd[1] = 1
>>> omd.items()
[(2, 2), (1, 1)]
>>> omd[2] = 'sup'
>>> omd.items()
[(2, 'sup'), (1, 1)]
```
Method parity with dict is retained. omdict can be a drop-in replacement.
```python
>>> d, omd = dict(), omdict()
>>> d.update([(1,1), (1,11), (2,2), (2,22)])
>>> omd.update([(1,1), (1,11), (2,2), (2,22)])
>>> d[1], omd[1]
(11, 11)
>>> d[3] = 3
>>> omd[3] = 3
>>> d.get(3), omd.get(3)
(3, 3)
>>> d.items() == omd.items()
True
```
### API
See all of omdict's methods, with examples, in omdict's API document,\
[API.md](https://github.com/gruns/orderedmultidict/blob/master/API.md).
### Installation
Installing orderedmultidict with pip is easy.
```
$ pip install orderedmultidict
```
python-orderedmultidict-1.0/orderedmultidict/ 0000775 0000000 0000000 00000000000 13307624441 0021603 5 ustar 00root root 0000000 0000000 python-orderedmultidict-1.0/orderedmultidict/__init__.py 0000664 0000000 0000000 00000000702 13307624441 0023713 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
#
# omdict - Ordered Multivalue Dictionary.
#
# Ansgar Grunseid
# grunseid.com
# grunseid@gmail.com
#
# License: Build Amazing Things (Unlicense)
from __future__ import absolute_import
from .orderedmultidict import * # noqa
__title__ = 'orderedmultidict'
__version__ = '1.0'
__author__ = 'Ansgar Grunseid'
__contact__ = 'grunseid@gmail.com'
__license__ = 'Unlicense'
__url__ = 'https://github.com/gruns/orderedmultidict'
python-orderedmultidict-1.0/orderedmultidict/itemlist.py 0000664 0000000 0000000 00000010601 13307624441 0024005 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
#
# omdict - Ordered Multivalue Dictionary.
#
# Ansgar Grunseid
# grunseid.com
# grunseid@gmail.com
#
# License: Build Amazing Things (Unlicense)
from __future__ import absolute_import
from six.moves import zip_longest
_absent = object() # Marker that means no parameter was provided.
class itemnode(object):
"""
Dictionary key:value items wrapped in a node to be members of itemlist, the
doubly linked list defined below.
"""
def __init__(self, prev=None, next=None, key=_absent, value=_absent):
self.prev = prev
self.next = next
self.key = key
self.value = value
class itemlist(object):
"""
Doubly linked list of itemnodes.
This class is used as the key:value item storage of orderedmultidict.
Methods below were only added as needed for use with orderedmultidict, so
some otherwise common list methods may be missing.
"""
def __init__(self, items=[]):
self.root = itemnode()
self.root.next = self.root.prev = self.root
self.size = 0
for key, value in items:
self.append(key, value)
def append(self, key, value):
tail = self.root.prev if self.root.prev is not self.root else self.root
node = itemnode(tail, self.root, key=key, value=value)
tail.next = node
self.root.prev = node
self.size += 1
return node
def removenode(self, node):
node.prev.next = node.next
node.next.prev = node.prev
self.size -= 1
return self
def clear(self):
for node, key, value in self:
self.removenode(node)
return self
def items(self):
return list(self.iteritems())
def keys(self):
return list(self.iterkeys())
def values(self):
return list(self.itervalues())
def iteritems(self):
for node, key, value in self:
yield key, value
def iterkeys(self):
for node, key, value in self:
yield key
def itervalues(self):
for node, key, value in self:
yield value
def reverse(self):
for node, key, value in self:
node.prev, node.next = node.next, node.prev
self.root.prev, self.root.next = self.root.next, self.root.prev
return self
def __len__(self):
return self.size
def __iter__(self):
current = self.root.next
while current and current is not self.root:
# Record current.next here in case current.next changes after the
# yield and before we return for the next iteration. For example,
# methods like reverse() will change current.next() before yield
# gets executed again.
nextnode = current.next
yield current, current.key, current.value
current = nextnode
def __contains__(self, item):
"""
Params:
item: Can either be a (key,value) tuple or an itemnode reference.
"""
node = key = value = _absent
if hasattr(item, '__len__') and callable(item.__len__):
if len(item) == 2:
key, value = item
elif len(item) == 3:
node, key, value = item
else:
node = item
if node is not _absent or _absent not in [key, value]:
for selfnode, selfkey, selfvalue in self:
if ((node is _absent and key == selfkey and value == selfvalue)
or (node is not _absent and node == selfnode)):
return True
return False
def __getitem__(self, index):
# Only support direct access to the first or last element, as this is
# all orderedmultidict needs for now.
if index == 0 and self.root.next is not self.root:
return self.root.next
elif index == -1 and self.root.prev is not self.root:
return self.root.prev
raise IndexError(index)
def __delitem__(self, index):
self.removenode(self[index])
def __eq__(self, other):
for (n1, key1, value1), (n2, key2, value2) in zip_longest(self, other):
if key1 != key2 or value1 != value2:
return False
return True
def __ne__(self, other):
return not self.__eq__(other)
def __nonzero__(self):
return self.size > 0
def __str__(self):
return '[%s]' % self.items()
python-orderedmultidict-1.0/orderedmultidict/orderedmultidict.py 0000664 0000000 0000000 00000070374 13307624441 0025533 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
#
# omdict - Ordered Multivalue Dictionary.
#
# Ansgar Grunseid
# grunseid.com
# grunseid@gmail.com
#
# License: Build Amazing Things (Unlicense)
from __future__ import absolute_import
from itertools import chain
from collections import MutableMapping
import six
from six.moves import map, zip_longest
from .itemlist import itemlist
try:
from collections import OrderedDict as odict # Python 2.7 and later.
except ImportError:
from ordereddict import OrderedDict as odict # Python 2.6 and earlier.
import sys
items_attr = 'items' if sys.version_info[0] >= 3 else 'iteritems'
_absent = object() # Marker that means no parameter was provided.
def callable_attr(obj, attr):
return hasattr(obj, attr) and callable(getattr(obj, attr))
#
# TODO(grun): Create a subclass of list that values(), getlist(), allitems(),
# etc return that the user can manipulate directly to control the omdict()
# object.
#
# For example, users should be able to do things like
#
# omd = omdict([(1,1), (1,11)])
# omd.values(1).append('sup')
# omd.allitems() == [(1,1), (1,11), (1,'sup')]
# omd.values(1).remove(11)
# omd.allitems() == [(1,1), (1,'sup')]
# omd.values(1).extend(['two', 'more'])
# omd.allitems() == [(1,1), (1,'sup'), (1,'two'), (1,'more')]
#
# or
#
# omd = omdict([(1,1), (1,11)])
# omd.allitems().extend([(2,2), (2,22)])
# omd.allitems() == [(1,1), (1,11), (2,2), (2,22)])
#
# or
#
# omd = omdict()
# omd.values(1) = [1, 11]
# omd.allitems() == [(1,1), (1,11)]
# omd.values(1) = list(map(lambda i: i * -10, omd.values(1)))
# omd.allitems() == [(1,-10), (1,-110)]
# omd.allitems() = filter(lambda (k,v): v > -100, omd.allitems())
# omd.allitems() == [(1,-10)]
#
# etc.
#
# To accomplish this, subclass list in such a manner that each list element is
# really a two tuple, where the first tuple value is the actual value and the
# second tuple value is a reference to the itemlist node for that value. Users
# only interact with the first tuple values, the actual values, but behind the
# scenes when an element is modified, deleted, inserted, etc, the according
# itemlist nodes are modified, deleted, inserted, etc accordingly. In this
# manner, users can manipulate omdict objects directly through direct list
# manipulation.
#
# Once accomplished, some methods become redundant and should be removed in
# favor of the more intuitive direct value list manipulation. Such redundant
# methods include getlist() (removed in favor of values()?), addlist(), and
# setlist().
#
# With the removal of many of the 'list' methods, think about renaming all
# remaining 'list' methods to 'values' methods, like poplist() -> popvalues(),
# poplistitem() -> popvaluesitem(), etc. This would be an easy switch for most
# methods, but wouldn't fit others so well. For example, iterlists() would
# become itervalues(), a name extremely similar to iterallvalues() but quite
# different in function.
#
class omdict(MutableMapping):
"""
Ordered Multivalue Dictionary.
A multivalue dictionary is a dictionary that can store multiple values per
key. An ordered multivalue dictionary is a multivalue dictionary that
retains the order of insertions and deletions.
Internally, items are stored in a doubly linked list, self._items. A
dictionary, self._map, is also maintained and stores an ordered list of
linked list node references, one for each value associated with that key.
Standard dict methods interact with the first value associated with a given
key. This means that omdict retains method parity with dict, and a dict
object can be replaced with an omdict object and all interaction will
behave identically. All dict methods that retain parity with omdict are:
get(), setdefault(), pop(), popitem(),
clear(), copy(), update(), fromkeys(), len()
__getitem__(), __setitem__(), __delitem__(), __contains__(),
items(), keys(), values(), iteritems(), iterkeys(), itervalues(),
Optional parameters have been added to some dict methods, but because the
added parameters are optional, existing use remains unaffected. An optional
parameter has been added to these methods:
items(), values(), iteritems(), itervalues()
New methods have also been added to omdict. Methods with 'list' in their
name interact with lists of values, and methods with 'all' in their name
interact with all items in the dictionary, including multiple items with
the same key.
The new omdict methods are:
load(), size(), reverse(),
getlist(), add(), addlist(), set(), setlist(), setdefaultlist(),
poplist(), popvalue(), popvalues(), popitem(), poplistitem(),
allitems(), allkeys(), allvalues(), lists(), listitems(),
iterallitems(), iterallkeys(), iterallvalues(), iterlists(),
iterlistitems()
Explanations and examples of the new methods above can be found in the
function comments below and online at
https://github.com/gruns/orderedmultidict
Additional omdict information and documentation can also be found at the
above url.
"""
def __init__(self, *args, **kwargs):
# Doubly linked list of itemnodes. Each itemnode stores a key:value
# item.
self._items = itemlist()
# Ordered dictionary of keys and itemnode references. Each itemnode
# reference points to one of that keys values.
self._map = odict()
self.load(*args, **kwargs)
def load(self, *args, **kwargs):
"""
Clear all existing key:value items and import all key:value items from
. If multiple values exist for the same key in , they
are all be imported.
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.load([(4,4), (4,44), (5,5)])
omd.allitems() == [(4,4), (4,44), (5,5)]
Returns: .
"""
self.clear()
self.updateall(*args, **kwargs)
return self
def copy(self):
return self.__class__(self.allitems())
def clear(self):
self._map.clear()
self._items.clear()
def size(self):
"""
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.size() == 5
Returns: Total number of items, including multiple items with the same
key.
"""
return len(self._items)
@classmethod
def fromkeys(cls, iterable, value=None):
return cls([(key, value) for key in iterable])
def has_key(self, key):
return key in self
def update(self, *args, **kwargs):
self._update_updateall(True, *args, **kwargs)
def updateall(self, *args, **kwargs):
"""
Update this dictionary with the items from , replacing
existing key:value items with shared keys before adding new key:value
items.
Example:
omd = omdict([(1,1), (2,2)])
omd.updateall([(2,'two'), (1,'one'), (2,222), (1,111)])
omd.allitems() == [(1, 'one'), (2, 'two'), (2, 222), (1, 111)]
Returns: .
"""
self._update_updateall(False, *args, **kwargs)
return self
def _update_updateall(self, replace_at_most_one, *args, **kwargs):
# Bin the items in and into or
# . Items in are new values to replace old
# values for a given key, and items in are new items to be
# added.
replacements, leftovers = dict(), []
for mapping in chain(args, [kwargs]):
self._bin_update_items(
self._items_iterator(mapping), replace_at_most_one,
replacements, leftovers)
# First, replace existing values for each key.
for key, values in six.iteritems(replacements):
self.setlist(key, values)
# Then, add the leftover items to the end of the list of all items.
for key, value in leftovers:
self.add(key, value)
def _bin_update_items(self, items, replace_at_most_one,
replacements, leftovers):
"""
are modified directly, ala pass by
reference.
"""
for key, value in items:
# If there are existing items with key that have yet to be
# marked for replacement, mark that item's value to be replaced by
# by appending it to .
if key in self and key not in replacements:
replacements[key] = [value]
elif (key in self and not replace_at_most_one and
len(replacements[key]) < len(self.values(key))):
replacements[key].append(value)
else:
if replace_at_most_one:
replacements[key] = [value]
else:
leftovers.append((key, value))
def _items_iterator(self, container):
cont = container
iterator = iter(cont)
if callable_attr(cont, 'iterallitems'):
iterator = cont.iterallitems()
elif callable_attr(cont, 'allitems'):
iterator = iter(cont.allitems())
elif callable_attr(cont, 'iteritems'):
iterator = cont.iteritems()
elif callable_attr(cont, 'items'):
iterator = iter(cont.items())
return iterator
def get(self, key, default=None):
if key in self:
return self._map[key][0].value
return default
def getlist(self, key, default=[]):
"""
Returns: The list of values for if is in the dictionary,
else . If is not provided, an empty list is
returned.
"""
if key in self:
return [node.value for node in self._map[key]]
return default
def setdefault(self, key, default=None):
if key in self:
return self[key]
self.add(key, default)
return default
def setdefaultlist(self, key, defaultlist=[None]):
"""
Similar to setdefault() except is a list of values to set
for . If already exists, its existing list of values is
returned.
If isn't a key and is an empty list, [], no values
are added for and will not be added as a key.
Returns: List of 's values if exists in the dictionary,
otherwise .
"""
if key in self:
return self.getlist(key)
self.addlist(key, defaultlist)
return defaultlist
def add(self, key, value=None):
"""
Add to the list of values for . If is not in the
dictionary, then is added as the sole value for .
Example:
omd = omdict()
omd.add(1, 1) # omd.allitems() == [(1,1)]
omd.add(1, 11) # omd.allitems() == [(1,1), (1,11)]
omd.add(2, 2) # omd.allitems() == [(1,1), (1,11), (2,2)]
Returns: .
"""
self._map.setdefault(key, [])
node = self._items.append(key, value)
self._map[key].append(node)
return self
def addlist(self, key, valuelist=[]):
"""
Add the values in to the list of values for . If
is not in the dictionary, the values in become the values
for .
Example:
omd = omdict([(1,1)])
omd.addlist(1, [11, 111])
omd.allitems() == [(1, 1), (1, 11), (1, 111)]
omd.addlist(2, [2])
omd.allitems() == [(1, 1), (1, 11), (1, 111), (2, 2)]
Returns: .
"""
for value in valuelist:
self.add(key, value)
return self
def set(self, key, value=None):
"""
Sets 's value to . Identical in function to __setitem__().
Returns: .
"""
self[key] = value
return self
def setlist(self, key, values):
"""
Sets 's list of values to . Existing items with key
are first replaced with new values from . Any remaining old
items that haven't been replaced with new values are deleted, and any
new values from that don't have corresponding items with
to replace are appended to the end of the list of all items.
If values is an empty list, [], is deleted, equivalent in action
to del self[].
Example:
omd = omdict([(1,1), (2,2)])
omd.setlist(1, [11, 111])
omd.allitems() == [(1,11), (2,2), (1,111)]
omd = omdict([(1,1), (1,11), (2,2), (1,111)])
omd.setlist(1, [None])
omd.allitems() == [(1,None), (2,2)]
omd = omdict([(1,1), (1,11), (2,2), (1,111)])
omd.setlist(1, [])
omd.allitems() == [(2,2)]
Returns: .
"""
if not values and key in self:
self.pop(key)
else:
it = zip_longest(
list(self._map.get(key, [])), values, fillvalue=_absent)
for node, value in it:
if node is not _absent and value is not _absent:
node.value = value
elif node is _absent:
self.add(key, value)
elif value is _absent:
self._map[key].remove(node)
self._items.removenode(node)
return self
def removevalues(self, key, values):
"""
Removes all from the values of . If has no
remaining values after removevalues(), the key is popped.
Example:
omd = omdict([(1, 1), (1, 11), (1, 1), (1, 111)])
omd.removevalues(1, [1, 111])
omd.allitems() == [(1, 11)]
Returns: .
"""
self.setlist(key, [v for v in self.getlist(key) if v not in values])
return self
def pop(self, key, default=_absent):
if key in self:
return self.poplist(key)[0]
elif key not in self._map and default is not _absent:
return default
raise KeyError(key)
def poplist(self, key, default=_absent):
"""
If is in the dictionary, pop it and return its list of values. If
is not in the dictionary, return . KeyError is raised if
is not provided and is not in the dictionary.
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.poplist(1) == [1, 11, 111]
omd.allitems() == [(2,2), (3,3)]
omd.poplist(2) == [2]
omd.allitems() == [(3,3)]
Raises: KeyError if isn't in the dictionary and isn't
provided.
Returns: List of 's values.
"""
if key in self:
values = self.getlist(key)
del self._map[key]
for node, nodekey, nodevalue in self._items:
if nodekey == key:
self._items.removenode(node)
return values
elif key not in self._map and default is not _absent:
return default
raise KeyError(key)
def popvalue(self, key, value=_absent, default=_absent, last=True):
"""
If is provided, pops the first or last (key,value) item in the
dictionary if is in the dictionary.
If is not provided, pops the first or last value for if
is in the dictionary.
If no longer has any values after a popvalue() call, is
removed from the dictionary. If isn't in the dictionary and
was provided, return default. KeyError is raised if
is not provided and is not in the dictionary. ValueError is
raised if is provided but isn't a value for .
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3), (2,22)])
omd.popvalue(1) == 111
omd.allitems() == [(1,11), (1,111), (2,2), (3,3), (2,22)]
omd.popvalue(1, last=False) == 1
omd.allitems() == [(1,11), (2,2), (3,3), (2,22)]
omd.popvalue(2, 2) == 2
omd.allitems() == [(1,11), (3,3), (2,22)]
omd.popvalue(1, 11) == 11
omd.allitems() == [(3,3), (2,22)]
omd.popvalue('not a key', default='sup') == 'sup'
Params:
last: Boolean whether to return 's first value ( is False)
or last value ( is True).
Raises:
KeyError if isn't in the dictionary and isn't
provided.
ValueError if isn't a value for .
Returns: The first or last of 's values.
"""
def pop_node_with_index(key, index):
node = self._map[key].pop(index)
if not self._map[key]:
del self._map[key]
self._items.removenode(node)
return node
if key in self:
if value is not _absent:
if last:
pos = self.values(key)[::-1].index(value)
else:
pos = self.values(key).index(value)
if pos == -1:
raise ValueError(value)
else:
index = (len(self.values(key)) - 1 - pos) if last else pos
return pop_node_with_index(key, index).value
else:
return pop_node_with_index(key, -1 if last else 0).value
elif key not in self._map and default is not _absent:
return default
raise KeyError(key)
def popitem(self, fromall=False, last=True):
"""
Pop and return a key:value item.
If is False, items()[0] is popped if is False or
items()[-1] is popped if is True. All remaining items with the
same key are removed.
If is True, allitems()[0] is popped if is False or
allitems()[-1] is popped if is True. Any remaining items with
the same key remain.
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.popitem() == (3,3)
omd.popitem(fromall=False, last=False) == (1,1)
omd.popitem(fromall=False, last=False) == (2,2)
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.popitem(fromall=True, last=False) == (1,1)
omd.popitem(fromall=True, last=False) == (1,11)
omd.popitem(fromall=True, last=True) == (3,3)
omd.popitem(fromall=True, last=False) == (1,111)
Params:
fromall: Whether to pop an item from items() ( is True) or
allitems() ( is False).
last: Boolean whether to pop the first item or last item of items()
or allitems().
Raises: KeyError if the dictionary is empty.
Returns: The first or last item from item() or allitem().
"""
if not self._items:
raise KeyError('popitem(): %s is empty' % self.__class__.__name__)
if fromall:
node = self._items[-1 if last else 0]
key = node.key
return key, self.popvalue(key, last=last)
else:
key = list(self._map.keys())[-1 if last else 0]
return key, self.pop(key)
def poplistitem(self, last=True):
"""
Pop and return a key:valuelist item comprised of a key and that key's
list of values. If is False, a key:valuelist item comprised of
keys()[0] and its list of values is popped and returned. If is
True, a key:valuelist item comprised of keys()[-1] and its list of
values is popped and returned.
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.poplistitem(last=True) == (3,[3])
omd.poplistitem(last=False) == (1,[1,11,111])
Params:
last: Boolean whether to pop the first or last key and its associated
list of values.
Raises: KeyError if the dictionary is empty.
Returns: A two-tuple comprised of the first or last key and its
associated list of values.
"""
if not self._items:
s = 'poplistitem(): %s is empty' % self.__class__.__name__
raise KeyError(s)
key = self.keys()[-1 if last else 0]
return key, self.poplist(key)
def items(self, key=_absent):
"""
Raises: KeyError if is provided and not in the dictionary.
Returns: List created from iteritems(). Only items with key
are returned if is provided and is a dictionary key.
"""
return list(self.iteritems(key))
def keys(self):
return list(self.iterkeys())
def values(self, key=_absent):
"""
Raises: KeyError if is provided and not in the dictionary.
Returns: List created from itervalues().If is provided and
is a dictionary key, only values of items with key are
returned.
"""
if key is not _absent and key in self._map:
return self.getlist(key)
return list(self.itervalues())
def lists(self):
"""
Returns: List created from iterlists().
"""
return list(self.iterlists())
def listitems(self):
"""
Returns: List created from iterlistitems().
"""
return list(self.iterlistitems())
def iteritems(self, key=_absent):
"""
Parity with dict.iteritems() except the optional parameter has
been added. If is provided, only items with the provided key are
iterated over. KeyError is raised if is provided and not in the
dictionary.
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.iteritems(1) -> (1,1) -> (1,11) -> (1,111)
omd.iteritems() -> (1,1) -> (2,2) -> (3,3)
Raises: KeyError if is provided and not in the dictionary.
Returns: An iterator over the items() of the dictionary, or only items
with the key if is provided.
"""
if key is not _absent:
if key in self:
items = [(node.key, node.value) for node in self._map[key]]
return iter(items)
raise KeyError(key)
items = six.iteritems(self._map)
return iter((key, nodes[0].value) for (key, nodes) in items)
def iterkeys(self):
return six.iterkeys(self._map)
def itervalues(self, key=_absent):
"""
Parity with dict.itervalues() except the optional parameter has
been added. If is provided, only values from items with the
provided key are iterated over. KeyError is raised if is provided
and not in the dictionary.
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.itervalues(1) -> 1 -> 11 -> 111
omd.itervalues() -> 1 -> 11 -> 111 -> 2 -> 3
Raises: KeyError if is provided and isn't in the dictionary.
Returns: An iterator over the values() of the dictionary, or only the
values of key if is provided.
"""
if key is not _absent:
if key in self:
return iter([node.value for node in self._map[key]])
raise KeyError(key)
return iter([nodes[0].value for nodes in six.itervalues(self._map)])
def allitems(self, key=_absent):
'''
Raises: KeyError if is provided and not in the dictionary.
Returns: List created from iterallitems().
'''
return list(self.iterallitems(key))
def allkeys(self):
'''
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.allkeys() == [1,1,1,2,3]
Returns: List created from iterallkeys().
'''
return list(self.iterallkeys())
def allvalues(self, key=_absent):
'''
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.allvalues() == [1,11,111,2,3]
omd.allvalues(1) == [1,11,111]
Raises: KeyError if is provided and not in the dictionary.
Returns: List created from iterallvalues().
'''
return list(self.iterallvalues(key))
def iterallitems(self, key=_absent):
'''
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.iterallitems() == (1,1) -> (1,11) -> (1,111) -> (2,2) -> (3,3)
omd.iterallitems(1) == (1,1) -> (1,11) -> (1,111)
Raises: KeyError if is provided and not in the dictionary.
Returns: An iterator over every item in the diciontary. If is
provided, only items with the key are iterated over.
'''
if key is not _absent:
# Raises KeyError if is not in self._map.
return self.iteritems(key)
return self._items.iteritems()
def iterallkeys(self):
'''
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.iterallkeys() == 1 -> 1 -> 1 -> 2 -> 3
Returns: An iterator over the keys of every item in the dictionary.
'''
return self._items.iterkeys()
def iterallvalues(self, key=_absent):
'''
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.iterallvalues() == 1 -> 11 -> 111 -> 2 -> 3
Returns: An iterator over the values of every item in the dictionary.
'''
if key is not _absent:
if key in self:
return iter(self.getlist(key))
raise KeyError(key)
return self._items.itervalues()
def iterlists(self):
'''
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.iterlists() -> [1,11,111] -> [2] -> [3]
Returns: An iterator over the list comprised of the lists of values for
each key.
'''
return map(lambda key: self.getlist(key), self)
def iterlistitems(self):
"""
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.iterlistitems() -> (1,[1,11,111]) -> (2,[2]) -> (3,[3])
Returns: An iterator over the list of key:valuelist items.
"""
return map(lambda key: (key, self.getlist(key)), self)
def reverse(self):
"""
Reverse the order of all items in the dictionary.
Example:
omd = omdict([(1,1), (1,11), (1,111), (2,2), (3,3)])
omd.reverse()
omd.allitems() == [(3,3), (2,2), (1,111), (1,11), (1,1)]
Returns: .
"""
for key in six.iterkeys(self._map):
self._map[key].reverse()
self._items.reverse()
return self
def __eq__(self, other):
if callable_attr(other, 'iterallitems'):
myiter, otheriter = self.iterallitems(), other.iterallitems()
for i1, i2 in zip_longest(myiter, otheriter, fillvalue=_absent):
if i1 != i2 or i1 is _absent or i2 is _absent:
return False
elif not hasattr(other, '__len__') or not hasattr(other, items_attr):
return False
# Ignore order so we can compare ordered omdicts with unordered dicts.
else:
if len(self) != len(other):
return False
for key, value in six.iteritems(other):
if self.get(key, _absent) != value:
return False
return True
def __ne__(self, other):
return not self.__eq__(other)
def __len__(self):
return len(self._map)
def __iter__(self):
for key in self.iterkeys():
yield key
def __contains__(self, key):
return key in self._map
def __getitem__(self, key):
if key in self:
return self.get(key)
raise KeyError(key)
def __setitem__(self, key, value):
self.setlist(key, [value])
def __delitem__(self, key):
return self.pop(key)
def __nonzero__(self):
return bool(self._map)
def __str__(self):
return '{%s}' % ', '.join(
map(lambda p: '%r: %r' % (p[0], p[1]), self.iterallitems()))
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, self.allitems())
python-orderedmultidict-1.0/setup.py 0000664 0000000 0000000 00000006424 13307624441 0017760 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# omdict - Ordered Multivalue Dictionary.
#
# Ansgar Grunseid
# grunseid.com
# grunseid@gmail.com
#
# License: Build Amazing Things (Unlicense)
import os
import re
import sys
from os.path import dirname, join as pjoin
from setuptools import setup, find_packages, Command
from setuptools.command.test import test as TestCommand
with open(pjoin(dirname(__file__), 'orderedmultidict', '__init__.py')) as fd:
VERSION = re.compile(
r".*__version__ = '(.*?)'", re.S).match(fd.read()).group(1)
class Publish(Command):
"""Publish to PyPI with twine."""
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
os.system('python setup.py sdist')
rc = os.system(
'twine upload dist/orderedmultidict-%s.tar.gz' % VERSION)
sys.exit(rc)
class RunTests(TestCommand):
"""
Run the unit tests.
By default, `python setup.py test` fails if tests/ isn't a Python
module (that is, if the tests/ directory doesn't contain an
__init__.py file). But the tests/ directory shouldn't contain an
__init__.py file and tests/ shouldn't be a Python module. See
http://doc.pytest.org/en/latest/goodpractices.html
Running the unit tests manually here enables `python setup.py test`
without tests/ being a Python module.
"""
def run_tests(self):
from unittest import TestLoader, TextTestRunner
tests_dir = pjoin(dirname(__file__), 'tests')
suite = TestLoader().discover(tests_dir)
result = TextTestRunner().run(suite)
sys.exit(0 if result.wasSuccessful() else -1)
long_description = ('''
A multivalue dictionary is a dictionary that can store multiple values for the
same key. An ordered multivalue dictionary is a multivalue dictionary that
retains the order of insertions and deletions.
omdict retains method parity with dict.
Information and documentation at https://github.com/gruns/orderedmultidict.''')
required = ['six>=1.8.0']
if sys.version_info < (2, 7):
required.append('ordereddict')
tests_require = ['pycodestyle']
if sys.version_info[:2] < (2, 7):
tests_require += ['unittest2']
setup(
name='orderedmultidict',
version=VERSION,
author='Ansgar Grunseid',
author_email='grunseid@gmail.com',
url='https://github.com/gruns/orderedmultidict',
license='Unlicense',
description='Ordered Multivalue Dictionary - omdict.',
long_description=long_description,
packages=find_packages(),
include_package_data=True,
platforms=['any'],
classifiers=[
'Topic :: Software Development :: Libraries',
'Natural Language :: English',
'License :: Freely Distributable',
'Intended Audience :: Developers',
'Development Status :: 5 - Production/Stable',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: Implementation :: PyPy',
],
install_requires=required,
cmdclass={
'test': RunTests,
'publish': Publish,
},
tests_require=tests_require,
)
python-orderedmultidict-1.0/tests/ 0000775 0000000 0000000 00000000000 13307624441 0017402 5 ustar 00root root 0000000 0000000 python-orderedmultidict-1.0/tests/test_itemlist.py 0000664 0000000 0000000 00000007345 13307624441 0022656 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
#
# omdict - Ordered Multivalue Dictionary.
#
# Ansgar Grunseid
# grunseid.com
# grunseid@gmail.com
#
# License: Build Amazing Things (Unlicense)
from __future__ import absolute_import
import unittest
from six.moves import zip
from orderedmultidict.itemlist import itemlist
_unique = object()
class TestItemList(unittest.TestCase):
def setUp(self):
self.inits = [
[], [(0, 0)], [(0, 0), (0, 0), (None, None)], [
(0, 0), (1, 1), (2, 2)],
[(True, False)], [(False, True)], [
(object(), object()), (object(), object())],
[('p', 'pumps'), ('d', 'dumps')],
]
self.appends = [
(0, 0), (1, 1), (None, None), (True, False), (object(), object())]
def test_init(self):
for init in self.inits:
il = itemlist(init)
assert il.items() == init
def test_append(self):
for init in self.inits:
il = itemlist(init)
for key, value in self.appends:
oldsize = len(il)
newnode = il.append(key, value)
assert len(il) == oldsize + 1
assert il[-1] == newnode
def test_removenode(self):
for init in self.inits:
il = itemlist(init)
for node, key, value in il:
oldsize = len(il)
assert node in il
assert il.removenode(node) == il
assert len(il) == oldsize - 1
assert node not in il
def test_clear(self):
for init in self.inits:
il = itemlist(init)
if len(init) > 0:
assert bool(il)
assert il.clear() == il
assert not il
def test_items_keys_values_iteritems_iterkeys_itervalues(self):
for init in self.inits:
il = itemlist(init)
iterator = zip(zip(il.items(), il.keys(), il.values()),
zip(il.iteritems(), il.iterkeys(), il.itervalues()))
for (item1, key1, value1), (item2, key2, value2) in iterator:
assert item1 == item2 and key1 == key2 and value1 == value2
def test_reverse(self):
for init in self.inits:
il = itemlist(init)
items = il.items()
items.reverse()
assert il.reverse() == il
assert items == il.items()
def test_len(self):
for init in self.inits:
il = itemlist(init)
assert len(il) == len(init)
for key, value in self.appends:
oldsize = len(il)
il.append(key, value)
assert len(il) == oldsize + 1
def test_contains(self):
for init in self.inits:
il = itemlist(init)
for node, key, value in il:
assert node in il
assert (key, value) in il
assert None not in il
assert _unique not in il
assert (19283091823, 102893091820) not in il
def test_iter(self):
for init in self.inits:
il = itemlist(init)
for node, key, value in il:
assert node in il
assert (key, value) in il
def test_delitem(self):
for init in self.inits:
for index in [0, -1]:
il = itemlist(init)
while il:
node = il[index]
assert node in il
del il[index]
assert node not in il
def test_nonzero(self):
for init in self.inits:
il = itemlist(init)
if init:
assert il
il.clear()
assert not il
else:
assert not il
python-orderedmultidict-1.0/tests/test_orderedmultidict.py 0000664 0000000 0000000 00000103342 13307624441 0024361 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
#
# omdict - Ordered Multivalue Dictionary.
#
# Ansgar Grunseid
# grunseid.com
# grunseid@gmail.com
#
# License: Build Amazing Things (Unlicense)
from __future__ import absolute_import
import unittest
from itertools import product, repeat
import six
from six.moves import map, zip, zip_longest
from orderedmultidict.orderedmultidict import omdict
try:
from collections import OrderedDict as odict # Python 2.7+.
except ImportError:
from ordereddict import OrderedDict as odict # Python 2.4-2.6.
_unique = object()
# Utility list subclass to expose items() and iteritems() methods on basic
# lists. This provides a common iteration interface for lists and dictionaries
# for looping through their items without having to test for and maintain two
# separate bodies, one for lists and one for dictionaries.
#
# So instead of requiring two bodies, one for lists and one for dicts
#
# lists = [[(1,1),(2,2)]]
# dicts = [{1:1,2:2}]
# for lst in lists:
# lst == ...
# for dic in dicts:
# dic.items() == ...
#
# list and dictionary looping bodies can be merged with itemlist
#
# itemlist = [itemlist([(1,1),(2,2)]), {1:1,2:2}]
# for ilist in itemlist:
# ilist.items() == ...
#
class itemlist(list):
def items(self):
return self
def iteritems(self):
return iter(self)
class TestOmdict(unittest.TestCase):
def setUp(self):
self.inits = [
{}, {1: 1}, {1: 1, 2: 2, 3: 3}, {None: None}, {
None: None, 1: 1, 2: 2}, {False: False},
]
self.inits += list(map(itemlist, [
[], [(1, 1)], [(1, 1), (2, 2)], [(1, 1), (2, 2), (1, 1)],
[(1, 1), (1, 1), (1, 1)], [(None, None), (None, None)],
[(False, False)],
[(None, 1), (1, None), (None, None), (None, 1), (1, None)],
]))
# Updates to test update() and updateall().
self.updates = [
{}, {7: 7}, {7: 7, 8: 8, 9: 9}, {None: None}, {1: 1, 2: 2}]
self.updates += list(map(itemlist, [
[], [(7, 7)], [(7, 7), (8, 8), (9, 9)], [(None, 'none')],
[(9, 9), (1, 2)], [(7, 7), (7, 7), (8, 8), (7, 77)],
[(1, 11), (1, 111), (1, 1111), (2, 22),
(2, 222), ('a', 'a'), ('a', 'aa')],
]))
self.keyword_updates = [
{}, {'1': 1}, {'1': 1, '2': 2}, {
'sup': 'pumps', 'scewps': None}, {'aa': 'aa'},
]
# Items not initially in any of the multidict inputs self.inits.
self.nonitems = [
(44, 44), (None, 44), (55, None), ('a', 'b'), (11, 11), (22, 22)]
# Keys not initially in any of the multidict inputs self.inits or in
# self.nonitems.
self.nonkeys = [_unique, 'asdfasdosduf', 'oaisfiapsn', 'ioausopdaui']
self.valuelist = [1, 2, 3, None, 'a', 'b', object()]
def test_init(self):
for init in self.inits:
omd = omdict(init)
assert omd.allitems() == list(init.items())
omd1 = omdict(init)
omd2 = omdict(omd1)
assert omd1.allitems() == list(omd2.allitems())
# Support both *args and **kwargs dictionary initialization.
items = [('sape', 4139), ('guido', 4127), ('jack', 4098)]
assert omdict(items).allitems() == items
omd_item_set = set(omdict(sape=4139, guido=4127, jack=4098).items())
assert omd_item_set == set(items) # Keyword order isn't preserved.
def test_load(self):
omd = omdict()
for init in self.inits:
assert omd.load(init) == omd
assert omd.allitems() == list(init.items())
def test_copy(self):
for init in self.inits:
omd = omdict(init)
copy = omd.copy()
assert omd is not copy and omd == copy
def test_clear(self):
for init in self.inits:
omd = omdict(init)
omd.clear()
assert omd.items() == []
def test_fromkeys(self):
for init in self.inits:
keys = [key for key, value in init.items()]
allitems = omdict.fromkeys(keys, _unique).allitems()
assert allitems == list(zip(keys, repeat(_unique)))
def test_has_key(self):
for init in self.inits:
omd = omdict(init)
for key, value in init.items():
assert key in omd
def test_update(self):
# Some manual tests.
omd = omdict()
omd.update([(1, 1), (1, 11), (2, 2), (3, 3), (1, 111), (2, 22)])
assert omd.allitems() == [(1, 111), (2, 22), (3, 3)]
omd = omdict([(1, 1), (1, 11), (2, 2), (3, 3), (1, 111), (2, 22)])
omd.update({1: None, 2: None, 3: None})
assert omd.allitems() == [(1, None), (2, None), (3, None)]
for init in self.inits:
zipped = zip(self.updates, self.keyword_updates)
for update, keyword_update in zipped:
omd1, omd2, omd3 = omdict(init), omdict(init), omdict(init)
oldomd = omd1.copy()
# Reduce the update to just the final items that will be
# present post update(), where repeated keys will be reduced to
# their last occurring value. For example, [(7,7),(7,8)] would
# be reduced to [(7,8)].
reduced = [
i for i in update.items() if i in odict(update).items()]
# Update with a dictionary.
omd1.update(update)
# Update with keyword expansion.
omd2.update(**keyword_update)
# Update with both a dictionary and keyword expansion.
omd3.update(update, **keyword_update)
# Verification.
if update or keyword_update:
for key, value in reduced:
assert key in omd1 and key in omd3
for key, value in keyword_update.items():
assert key in omd2 and key in omd3
else:
assert omd1 == omd2 == omd3 == oldomd
def test_updateall(self):
# Some manual tests.
omd = omdict([(1, 1), (1, 11), (2, 2), (3, 3), (1, 111), (2, 22)])
omd.updateall({1: None, 2: None, 3: None})
assert omd.allitems() == [(1, None), (2, None), (3, None)]
omd = omdict([(1, 1), (1, 11), (2, 2), (3, 3), (1, 111), (2, 22)])
omd.updateall([(1, None), (2, None), (3, None), (1, None), (2, None)])
assert omd.allitems() == [
(1, None), (1, None), (2, None), (3, None), (2, None)]
omd = omdict([(1, 1), (1, 11), (2, 2), (3, 3), (1, 111), (2, 22)])
omd.updateall([(1, None), (1, None), (1, None), (2, None)])
assert omd.allitems() == [
(1, None), (1, None), (2, None), (3, 3), (1, None)]
for init in self.inits:
zipped = zip(self.updates, self.keyword_updates)
for update, keyword_update in zipped:
omd1, omd2, omd3 = omdict(init), omdict(init), omdict(init)
oldomd = omd1.copy()
# Update with a dictionary.
omd1.updateall(update)
# Update with keyword expansion.
omd2.updateall(**keyword_update)
# Update with both a dictionary and keyword expansion.
omd3.updateall(update, **keyword_update)
# Verification.
if update or keyword_update:
for key, value in six.iteritems(update):
assert key in omd1 and key in omd3
assert value in omd1.getlist(
key) and value in omd3.getlist(key)
for key, value in keyword_update.items():
assert key in omd2 and key in omd3
assert omd2.getlist(
key) == omd3.getlist(key) == [value]
else:
assert omd1 == omd2 == oldomd
def test_get(self):
for init in self.inits:
omd = omdict(init)
for key in omd.iterkeys():
assert omd.get(key) == omd[key]
for nonkey in self.nonkeys:
assert omd.get(nonkey) is None
assert omd.get(nonkey, _unique) == _unique
def test_getlist(self):
for init in self.inits:
omd = omdict(init)
for key in omd:
assert omd.getlist(
key) == [v for k, v in omd.allitems() if k == key]
for nonkey in self.nonkeys:
assert omd.getlist(nonkey) == []
assert omd.getlist(nonkey, _unique) == _unique
def test_setdefault(self):
for init in self.inits:
omd = omdict(init)
for key in omd.iterkeys():
assert omd.setdefault(key, _unique) == omd[key]
for nonkey in self.nonkeys:
assert omd.setdefault(nonkey) is None
assert omd[nonkey] is None
omd.load(init)
for nonkey in self.nonkeys:
assert omd.setdefault(nonkey, 123456) == 123456
assert omd[nonkey] == 123456
def test_setdefaultlist(self):
for init in self.inits:
omd = omdict(init)
for key in omd.iterkeys():
assert omd.setdefaultlist(key, _unique) == omd.getlist(key)
for nonkey in self.nonkeys:
assert omd.setdefaultlist(nonkey) == [None]
assert omd.getlist(nonkey) == [None]
omd.load(init)
for nonkey in self.nonkeys:
assert omd.setdefaultlist(nonkey, [1, 2, 3]) == [1, 2, 3]
assert omd.getlist(nonkey) == [1, 2, 3]
# setdefaultlist() with an empty list of values does nothing.
for init in self.inits:
omd = omdict(init)
for key in omd.iterkeys():
values = omd.getlist(key)
assert key in omd
assert omd.setdefaultlist(key, []) == values
assert key in omd and omd.getlist(key) == values
for nonkey in self.nonkeys:
assert nonkey not in omd
assert omd.setdefaultlist(nonkey, []) == []
assert nonkey not in omd
def test_add(self):
for init in self.inits:
omd = omdict(init)
for key, value in self.nonitems:
assert (key, value) not in omd.allitems()
assert omd.add(key, value) == omd
assert omd.getlist(key)[-1] == value
assert omd.allitems()[-1] == (key, value)
# Repeat the add() calls with the same items and make sure the old
# items aren't replaced.
oldomd = omd.copy()
for key, value in self.nonitems:
assert (key, value) in omd.allitems()
assert omd.add(key, value) == omd
assert len(omd.getlist(key)) == len(oldomd.getlist(key)) + 1
assert omd.getlist(key)[-1] == value
assert omd.allitems()[-1] == (key, value)
# Assert that containers are valid values, too, not just immutables
# like integers.
assert omd.add(_unique, self.updates) == omd
assert omd.getlist(_unique)[-1] == self.updates
assert omd.allitems()[-1] == (_unique, self.updates)
# Add() doesn't require a value, and when one isn't provided it
# defaults to None.
omd = omdict(init)
assert omd.add(_unique) == omd
assert _unique in omd and omd[_unique] is None
def test_addlist(self):
for init in self.inits:
omd = omdict(init)
for nonkey in self.nonkeys:
assert (nonkey, self.valuelist) not in omd.allitems()
assert omd.addlist(nonkey, self.valuelist) == omd
assert omd.getlist(nonkey) == self.valuelist
assert (omd.allitems()[-1 * len(self.valuelist):] ==
list(zip(repeat(nonkey), self.valuelist)))
# Repeat the addlist() calls with the same items and make sure the
# old items aren't replaced.
oldomd = omd.copy()
for nonkey in self.nonkeys:
for value in self.valuelist:
assert (nonkey, value) in omd.allitems()
assert omd.addlist(nonkey, self.valuelist) == omd
assert len(omd.getlist(nonkey)) == (
len(oldomd.getlist(nonkey)) + len(self.valuelist))
assert omd.getlist(nonkey) == oldomd.getlist(
nonkey) + self.valuelist
assert (omd.allitems()[-1 * len(self.valuelist):] ==
list(zip(repeat(nonkey), self.valuelist)))
# If an empty list is provided to addlist(), nothing is added.
omd = omdict(init)
for nonkey in self.nonkeys:
assert omd.addlist(nonkey) == omd and nonkey not in omd
assert omd.addlist(nonkey, []) == omd and nonkey not in omd
def test_setlist(self):
for init in self.inits:
omd = omdict(init)
for key in (omd.keys() + self.nonkeys):
if key in omd:
assert omd.getlist(key) != self.valuelist
assert omd.setlist(key, self.valuelist)
assert key in omd and omd.getlist(key) == self.valuelist
# Setting a key to an empty list is identical to deleting the key.
for init in self.inits:
omd = omdict(init)
for nonkey in self.nonkeys:
assert nonkey not in omd
omd.setlist(nonkey, [])
assert nonkey not in omd
for key in omd.keys():
assert key in omd
omd.setlist(key, [])
assert key not in omd
assert not omd
def test_removevalues(self):
for init in self.inits:
omd = omdict(init)
removevals = omd.removevalues # Shorten to linewrap for PEP 8.
for nonkey in self.nonkeys:
obj = object()
values = [1, 1.1, '1.1', (), [], {}, obj, 5.5, '1.1']
assert removevals(nonkey, []).getlist(nonkey) == []
assert removevals(nonkey, values).getlist(nonkey) == []
omd.addlist(nonkey, values).removevalues(nonkey, [])
assert omd.getlist(nonkey) == values
assert removevals(nonkey, values).getlist(nonkey) == []
omd.addlist(nonkey, values)
assert (removevals(nonkey, [1]).getlist(nonkey) ==
[1.1, '1.1', (), [], {}, obj, 5.5, '1.1'])
assert (removevals(nonkey, ['1.1', obj]).getlist(nonkey) ==
[1.1, (), [], {}, 5.5])
assert (removevals(nonkey, [[], 5.5, ()]).getlist(nonkey) ==
[1.1, {}])
assert removevals(nonkey, [{}]).getlist(nonkey) == [1.1]
assert removevals(nonkey, [1.1]).getlist(nonkey) == []
assert removevals(
nonkey, [9, 9.9, 'nope']).getlist(nonkey) == []
def test_pop(self):
self._test_pop_poplist(lambda omd, key: omd.get(key) == omd.pop(key))
def test_poplist(self):
self._test_pop_poplist(
lambda omd, key: omd.getlist(key) == omd.poplist(key))
def _test_pop_poplist(self, assert_lambda):
for init in self.inits:
omd = omdict(init)
items = omd.items()
for key in list(omd.keys()):
assert assert_lambda(omd, key)
newitems = [item for item in items if item[0] != key]
assert omd.items() == newitems
items = newitems
omd.load(init)
for nonkey in self.nonkeys:
self.assertRaises(KeyError, omd.pop, nonkey)
assert omd.pop(nonkey, _unique) == _unique
self.assertRaises(KeyError, omd.poplist, nonkey)
assert omd.poplist(nonkey, _unique) == _unique
def test_popvalue(self):
# popvalue() with no value provided.
for init in self.inits:
for last in [True, False]:
omd = omdict(init)
allitems = omd.allitems()
while omd.keys():
for key in omd.keys():
if last:
value = omd.getlist(key)[-1]
_rremove(allitems, (key, value))
else:
value = omd[key]
allitems.remove((key, value))
assert value == omd.popvalue(key, last=last)
assert omd.allitems() == allitems
omd.load(init)
for nonkey in self.nonkeys:
self.assertRaises(KeyError, omd.popvalue, nonkey)
assert omd.popvalue(nonkey, default=_unique) == _unique
# popvalue() with value provided.
# last = True (default).
omd = omdict([(1, 1), (2, 2), (3, 3), (2, 2), (3, 3), (2, 2)])
assert omd.popvalue(2, 2) == 2
assert omd.allitems() == [(1, 1), (2, 2), (3, 3), (2, 2), (3, 3)]
assert omd.popvalue(2, 2) == 2
assert omd.allitems() == [(1, 1), (2, 2), (3, 3), (3, 3)]
assert omd.popvalue(2, 2) == 2
assert omd.allitems() == [(1, 1), (3, 3), (3, 3)]
# last = False.
omd = omdict([(3, 3), (2, 2), (3, 3), (2, 2), (3, 3), (2, 2)])
assert omd.popvalue(2, 2, last=True) == 2
assert omd.allitems() == [(3, 3), (2, 2), (3, 3), (2, 2), (3, 3)]
assert omd.popvalue(2, 2, last=True) == 2
assert omd.allitems() == [(3, 3), (2, 2), (3, 3), (3, 3)]
assert omd.popvalue(2, 2, last=True) == 2
assert omd.allitems() == [(3, 3), (3, 3), (3, 3)]
# Invalid key.
self.assertRaises(KeyError, omd.popvalue, _unique, _unique)
self.assertRaises(KeyError, omd.popvalue, _unique, 2)
self.assertRaises(KeyError, omd.popvalue, _unique, 22)
self.assertRaises(KeyError, omd.popvalue, _unique, _unique, last=False)
self.assertRaises(KeyError, omd.popvalue, _unique, 2)
self.assertRaises(KeyError, omd.popvalue, _unique, 22)
assert omd.popvalue(_unique, _unique, 'sup') == 'sup'
assert omd.popvalue(_unique, 2, 'sup') == 'sup'
assert omd.popvalue(_unique, 22, 'sup') == 'sup'
# Valid key, invalid value.
self.assertRaises(ValueError, omd.popvalue, 3, _unique)
self.assertRaises(ValueError, omd.popvalue, 3, _unique, False)
def test_popitem(self):
for init in self.inits:
# All permutations of booleans and .
for fromall, last in product([True, False], repeat=2):
omd = omdict(init)
allitems = omd.allitems()
while omd.allitems():
if fromall:
key, value = omd.allitems()[-1 if last else 0]
else:
key = omd.keys()[-1 if last else 0]
value = omd[key]
popkey, popvalue = omd.popitem(fromall=fromall, last=last)
assert popkey == key and popvalue == value
if fromall:
if last:
_rremove(allitems, (key, value))
else:
allitems.remove((key, value))
else:
allitems = [(k, v) for k, v in allitems if k != key]
assert omd.allitems() == allitems
omd = omdict()
self.assertRaises(KeyError, omd.popitem)
def test_poplistitem(self):
for init in self.inits:
for last in [True, False]:
omd, omdcopy = omdict(init), omdict(init)
while omd.keys():
key, valuelist = omd.poplistitem(last=last)
assert key == omdcopy.keys()[-1 if last else 0]
assert valuelist == omdcopy.getlist(key)
omdcopy.pop(omdcopy.keys()[-1 if last else 0])
# poplistitem() on an empty omdict.
self.assertRaises(KeyError, omd.poplistitem)
# Tests every non-'all' items, keys, values, lists method: items(), keys(),
# values(), lists(), listitems() and their iterators iteritems(),
# iterkeys(), itervalues(), iterlists(), and iterlistitems().
def test_nonall_item_key_value_lists(self):
for init in self.inits:
dic = odict(init.items())
omd = omdict(init.items())
# Testing items(), keys(), values(), lists(), and listitems().
assert omd.items() == list(dic.items())
assert omd.keys() == list(dic.keys())
assert omd.values() == list(dic.values())
iterator = zip(omd.keys(), omd.lists(), omd.listitems())
for key, valuelist, listitem in iterator:
assert omd.values(key) == omd.getlist(key) == valuelist
assert omd.items(
key) == [i for i in init.items() if i[0] == key]
assert listitem == (key, valuelist)
# Testing iteritems(), iterkeys(), itervalues(), and iterlists().
for key1, key2 in zip(omd.iterkeys(), six.iterkeys(dic)):
assert key1 == key2
for val1, val2 in zip(omd.itervalues(), six.itervalues(dic)):
assert val1 == val2
for item1, item2 in zip(omd.iteritems(), six.iteritems(dic)):
assert item1 == item2
for key, values in zip(six.iterkeys(omd), omd.iterlists()):
assert omd.getlist(key) == values
iterator = zip(
omd.iterkeys(), omd.iterlists(), omd.iterlistitems())
for key, valuelist, listitem in iterator:
assert listitem == (key, valuelist)
# Test iteritems() and itervalues() with a key.
for key in omd.iterkeys():
assert list(omd.iteritems(key)) == list(zip(
repeat(key), omd.getlist(key)))
assert list(omd.iterallitems(key)) == list(zip(
repeat(key), omd.getlist(key)))
for nonkey in self.nonkeys:
self.assertRaises(KeyError, omd.iteritems, nonkey)
self.assertRaises(KeyError, omd.itervalues, nonkey)
# Tests every 'all' items, keys, values method: allitems(), allkeys(),
# allvalues() and their iterators iterallitems(), iterallkeys(),
# iterallvalues().
def test_all_items_keys_values_iterall_items_keys_values(self):
for init in self.inits:
omd = omdict(init)
# map(list, zip(*lst)) - doesn't work if lst is empty, lst == [].
keys = [key for key, value in init.items()]
values = [value for key, value in init.items()]
# Test allitems(), allkeys(), allvalues().
assert omd.allitems() == list(init.items())
assert omd.allkeys() == keys
assert omd.allvalues() == values
# Test iterallitems(), iterallkeys(), iterallvalues().
for key1, key2 in zip(omd.iterallkeys(), keys):
assert key1 == key2
for val1, val2 in zip(omd.iterallvalues(), values):
assert val1 == val2
for item1, item2 in zip(omd.iterallitems(), init.items()):
assert item1 == item2
# Test allitems(), allvalues(), iterallitems() and iterallvalues()
# with a key.
for key in omd.iterkeys():
assert (omd.allvalues(key) == list(omd.iterallvalues(key)) ==
omd.getlist(key))
assert (omd.allitems(key) == list(omd.iterallitems(key)) ==
list(zip(repeat(key), omd.getlist(key))))
for nonkey in self.nonkeys:
self.assertRaises(KeyError, omd.allvalues, nonkey)
self.assertRaises(KeyError, omd.allitems, nonkey)
self.assertRaises(KeyError, omd.iterallvalues, nonkey)
self.assertRaises(KeyError, omd.iterallitems, nonkey)
def test_reverse(self):
for init in self.inits:
reversed = list(init.items())[::-1]
assert omdict(init).reverse().allitems() == reversed
def test_eq(self):
for init in self.inits:
d, omd = dict(init), omdict(init)
assert d == omd
assert omd == omd
assert omd == omd.copy()
def test_ne(self):
diff = omdict([(_unique, _unique)])
for init in self.inits:
assert omdict(init) != diff
# Compare to basic types.
for basic in [1, 1.1, '1.1', (), [], object()]:
assert omdict(init) != basic
def test_len(self):
for init in self.inits:
assert len(omdict(init)) == len(dict(init))
def test_size(self):
for init in self.inits:
assert omdict(init).size() == len(init)
def test_iter(self):
for init in self.inits:
omd = omdict(init)
for key1, key2 in zip_longest(iter(omd), omd.iterkeys()):
assert key1 == key2
def test_contains(self):
for init in self.inits:
omd = omdict(init)
for key, value in init.items():
assert key in omd
def test_getitem(self):
for init in self.inits:
dic = dict(init)
omd = omdict(init)
for key in omd.iterkeys():
assert omd[key] == dic[key]
omd = omdict()
self.assertRaises(KeyError, omd.__getitem__, _unique)
def test_set_setitem(self):
for init in self.inits:
omd = omdict()
omd2 = omdict()
for key, value in init.items():
omd[key] = value
assert omd2.set(key, value) == omd2
assert omd == omd2 and omd[key] == value
# Store containers as values, not just immutables like integers.
omd[_unique] = self.valuelist
assert omd2.set(_unique, self.valuelist) == omd2
assert omd == omd2 and omd[_unique] == self.valuelist
def test_delitem(self):
for init in self.inits:
omd = omdict(init)
for key in list(omd.keys()):
assert key in omd
del omd[key]
assert key not in omd
def test_nonzero(self):
for init in self.inits:
if init:
assert omdict(init)
else:
assert not omdict(init)
def test_str(self):
for init in self.inits:
omd = omdict(init)
s = '{%s}' % ', '.join(
map(lambda p: '%s: %s' % (p[0], p[1]), omd.allitems()))
assert s == str(omd)
def test_odict_omdict_parity(self):
for init in self.inits:
d = odict(init)
omd = omdict(init)
self._compare_odict_and_omddict(d, omd)
self._compare_odict_and_omddict(d.copy(), omd.copy()) # copy().
d.clear(), omd.clear() # clear().
self._compare_odict_and_omddict(d, omd)
assert dict().update(init) == omdict().update(init) # update().
dict_fromkeys = list(d.fromkeys(init).items())
omdict_fromkeys = list(omd.fromkeys(init).items())
assert dict_fromkeys == omdict_fromkeys # fromkeys()
def _compare_odict_and_omddict(self, d, omd):
assert len(d) == len(omd) # __len__().
# __contains__(), has_key(), get(), and setdefault().
for dkey, omdkey in zip(d, omd):
assert dkey == omdkey and dkey in d and omdkey in omd
assert dkey in d and omdkey in omd
assert d.get(dkey) == omd.get(omdkey)
d.setdefault(dkey, _unique)
omd.setdefault(omdkey, _unique)
assert d.get(dkey) == omd.get(omdkey) and d.get(dkey) != _unique
for nonkey in self.nonkeys:
assert d.get(nonkey) == omd.get(nonkey) is None
d.setdefault(nonkey, _unique)
omd.setdefault(nonkey, _unique)
assert d.get(nonkey) == omd.get(nonkey) == _unique
# items(), keys, values(), iteritems(), iterkeys, and itervalues().
iterators = [
zip(d.items(), omd.items(), d.keys(), omd.keys(),
d.values(), omd.values()),
zip(six.iteritems(d), six.iteritems(omd), six.iterkeys(d),
six.iterkeys(omd), six.itervalues(d), six.itervalues(omd))]
for iterator in iterators:
for ditem, omditem, dkey, omdkey, dvalue, omdvalue in iterator:
assert dkey == omdkey
assert ditem == omditem
assert dvalue == omdvalue
# pop().
dcopy, omdcopy = d.copy(), omd.copy()
while dcopy and omdcopy:
dpop = dcopy.pop(list(dcopy.keys())[0])
omdpop = omdcopy.pop(list(omdcopy.keys())[0])
assert dpop == omdpop
# popitem().
dcopy, omdcopy = d.copy(), omd.copy()
while dcopy and omdcopy:
assert dcopy.popitem() == omdcopy.popitem()
# __getitem__().
for dkey, omdkey in zip(six.iterkeys(d), six.iterkeys(omd)):
assert d[dkey] == omd[omdkey]
# __setitem__().
for dkey, omdkey in zip(d, omd):
d[dkey] = _unique
omd[omdkey] = _unique
assert dkey == omdkey and d[dkey] == omd[omdkey]
# __delitem__().
while d and omd:
dkey, omdkey = list(d.keys())[0], list(omd.keys())[0]
del d[dkey]
del omd[omdkey]
assert dkey == omdkey and dkey not in d and omdkey not in omd
def test_fundamentals(self):
# Gets, sets, and pops.
omd = omdict()
omd[1] = 1
omd[2] = 2
assert omd.allitems() == [(1, 1), (2, 2)]
omd[1] = 11
assert omd.allitems() == [(1, 11), (2, 2)]
omd.add(1, 1.1)
assert omd.allitems() == [(1, 11), (2, 2), (1, 1.1)]
assert omd.popvalue(1) == 1.1
assert omd.allitems() == [(1, 11), (2, 2)]
omd.popvalue(2)
assert omd.allitems() == [(1, 11)]
omd[2] = [2, 2]
assert omd.allitems() == [(1, 11), (2, [2, 2])]
omd[1] = None
assert omd.allitems() == [(1, None), (2, [2, 2])]
omd.add(2, None)
assert omd.allitems() == [(1, None), (2, [2, 2]), (2, None)]
del omd[2]
assert omd.allitems() == [(1, None)]
omd[3] = 3
assert omd.allitems() == [(1, None), (3, 3)]
omd.setlist(1, [1, 11, 111])
assert omd.allitems() == [(1, 1), (3, 3), (1, 11), (1, 111)]
omd.addlist(1, [1111])
omd = omdict([(1, 1), (3, 3), (1, 11), (1, 111), (1, 1111)])
assert omd.allitems() == [(1, 1), (3, 3), (1, 11), (1, 111), (1, 1111)]
omd[1] = None
assert omd.allitems() == [(1, None), (3, 3)]
def test_pops(self):
init = [(1, 1), (2, 2), (1, 1), (1, 2), (1, 3)]
# pop().
omd = omdict(init)
assert omd.pop(1) == 1
assert omd.allitems() == [(2, 2)]
assert omd.pop(_unique, 'sup') == 'sup'
# poplist().
omd = omdict(init)
assert omd.poplist(1) == [1, 1, 2, 3]
assert omd.allitems() == [(2, 2)]
self.assertRaises(KeyError, omd.poplist, _unique)
assert omd.poplist(_unique, 'sup') == 'sup'
# popvalue().
omd = omdict(init)
assert omd.popvalue(1) == 3
assert omd.allitems() == [(1, 1), (2, 2), (1, 1), (1, 2)]
self.assertRaises(KeyError, omd.popvalue, _unique)
assert omd.popvalue(_unique, default='sup') == 'sup'
assert omd.popvalue(1, last=False) == 1
assert omd.allitems() == [(2, 2), (1, 1), (1, 2)]
# popitem().
omd = omdict(init)
assert omd.popitem() == (2, 2)
assert omd.allitems() == [(1, 1), (1, 1), (1, 2), (1, 3)]
assert omd.popitem() == (1, 1)
assert omd.allitems() == []
omd = omdict(init)
assert omd.popitem(fromall=True) == (1, 3)
assert omd.allitems() == [(1, 1), (2, 2), (1, 1), (1, 2)]
assert omd.popitem(fromall=True, last=False) == (1, 1)
assert omd.allitems() == [(2, 2), (1, 1), (1, 2)]
def test_splats(self):
items = [('1', 1), ('2', 2), ('3', 3)]
omd = omdict(items)
def splat(*args, **kwargs):
return args, set(kwargs.items())
assert splat(*omd, **omd) == (tuple(i[0] for i in items), set(items))
class TestUtilities(unittest.TestCase):
def test_rfind(self):
tests = [([], 1, -1), ([1], 1, 0), ([1, 2], 2, 1),
([1, 2, 1, 2], 1, 2), ([1, 2, 3], 4, -1), ([1, 2, 3], 1, 0)]
for lst, item, pos in tests:
assert _rfind(lst, item) == pos
def test_rremove(self):
tests = [([1, 1], 1, [1]), ([1], 1, []), ([1, 2], 2, [1]),
([1, 2, 3], 1, [2, 3]), ([1, 2, 1, 2], 1, [1, 2, 2]),
([1, 2, 1], 1, [1, 2])]
for lst, item, result in tests:
_rremove(lst, item)
assert lst == result
nonitems = [None, 'asdf', object(), 1000000]
for nonitem in nonitems:
self.assertRaises(ValueError, _rremove, lst, nonitem)
def _rfind(lst, item):
"""
Returns the index of the last occurance of - in . Returns -1 if
- is not in .
ex: _rfind([1,2,1,2], 1) == 2
"""
try:
return (len(lst) - 1) - lst[::-1].index(item)
except ValueError:
return -1
def _rremove(lst, item):
"""
Removes the last occurance of
- in , or raises a ValueError if
- is not in
.
ex: _rremove([1,2,1,2], 1) == [1,2,2]
"""
pos = _rfind(lst, item)
if pos >= 0:
lst.pop(pos)
return lst
raise ValueError('_rremove(list, x): x not in list')
python-orderedmultidict-1.0/tox.ini 0000664 0000000 0000000 00000000356 13307624441 0017557 0 ustar 00root root 0000000 0000000 [tox]
envlist = codestyle, py26, py27, py34, py35, py36, pypy, pypy3
[testenv]
deps = nose
commands = nosetests --exe []
[testenv:py26]
deps =
{[testenv]deps}
unittest2
[testenv:codestyle]
deps = pycodestyle
commands = pycodestyle