mirror of https://github.com/jab/bidict.git
241 lines
5.5 KiB
Plaintext
241 lines
5.5 KiB
Plaintext
# Copyright 2009-2020 Joshua Bronson. All Rights Reserved.
|
|
#
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
Test script for bidict.bidict::
|
|
|
|
>>> from bidict import bidict
|
|
>>> keys = (1, 2, 3)
|
|
>>> vals = ('one', 'two', 'three')
|
|
>>> bi = bidict(zip(keys, vals))
|
|
>>> bi == bidict({1: 'one', 2: 'two', 3: 'three'})
|
|
True
|
|
|
|
Works like dict for getting and changing forward mappings::
|
|
|
|
>>> bi[2]
|
|
'two'
|
|
>>> bi[2] = 'twain'
|
|
>>> bi[2]
|
|
'twain'
|
|
>>> bi[4]
|
|
Traceback (most recent call last):
|
|
...
|
|
KeyError: 4
|
|
>>> del bi[2]
|
|
>>> bi.pop(3)
|
|
'three'
|
|
>>> bi
|
|
bidict({1: 'one'})
|
|
|
|
``put`` can also be used to insert a mapping as long as its key and value
|
|
don't already exist::
|
|
|
|
>>> bi.put(0, 'zero')
|
|
>>> bi[0]
|
|
'zero'
|
|
>>> bi.put(1, 'aught')
|
|
Traceback (most recent call last):
|
|
...
|
|
KeyDuplicationError: 1
|
|
>>> del bi[1]
|
|
>>> bi.put(1, 'aught')
|
|
>>> bi[1]
|
|
'aught'
|
|
>>> del bi[0]
|
|
>>> bi
|
|
bidict({1: 'aught'})
|
|
|
|
bidicts maintain references to their inverses via the ``inv`` property,
|
|
which can also be used to access or modify them::
|
|
|
|
>>> bi.inv
|
|
bidict({'aught': 1})
|
|
>>> bi.inv['aught']
|
|
1
|
|
>>> bi.inv['aught'] = 'one'
|
|
>>> bi
|
|
bidict({'one': 'aught'})
|
|
>>> bi.inv.pop('aught')
|
|
'one'
|
|
>>> bi == bi.inv == bidict()
|
|
True
|
|
>>> bi.inv.update(one=1)
|
|
>>> bi
|
|
bidict({1: 'one'})
|
|
>>> bi is bi.inv.inv
|
|
True
|
|
>>> bi.inv is bi.inv.inv.inv
|
|
True
|
|
|
|
bidicts work with ``inverted`` as expected::
|
|
|
|
>>> from bidict import inverted
|
|
>>> biinv = bidict(inverted(bi))
|
|
>>> biinv
|
|
bidict({'one': 1})
|
|
|
|
This created a new object (equivalent but not identical)::
|
|
|
|
>>> biinv == bi.inv
|
|
True
|
|
>>> biinv is bi.inv
|
|
False
|
|
|
|
Inverting the inverse should round-trip::
|
|
|
|
>>> bi == bidict(inverted(inverted(bi)))
|
|
True
|
|
>>> bi = bi.inv
|
|
>>> bi == bidict(inverted(inverted(bi)))
|
|
True
|
|
|
|
The rest of the ``MutableMapping`` interface is supported::
|
|
|
|
>>> bi.get('one')
|
|
1
|
|
>>> bi.get('zero')
|
|
>>> bi.get('zero', 'default')
|
|
'default'
|
|
>>> list(bi.keys())
|
|
['one']
|
|
>>> list(bi.values())
|
|
[1]
|
|
>>> list(bi.items())
|
|
[('one', 1)]
|
|
>>> bi.setdefault('one', 2)
|
|
1
|
|
>>> bi.setdefault('two', 2)
|
|
2
|
|
>>> bi.pop('one')
|
|
1
|
|
>>> bi
|
|
bidict({'two': 2})
|
|
>>> bi.inv
|
|
bidict({2: 'two'})
|
|
>>> bi.pop('wrong', 'number', 'of', 'args')
|
|
Traceback (most recent call last):
|
|
...
|
|
TypeError: pop expected at most 2 arguments (got 4)
|
|
>>> bi.popitem()
|
|
('two', 2)
|
|
>>> bi.popitem()
|
|
Traceback (most recent call last):
|
|
...
|
|
KeyError: 'popitem(): bidict is empty'
|
|
>>> bi.inv.setdefault(3, 'three')
|
|
'three'
|
|
>>> bi
|
|
bidict({'three': 3})
|
|
>>> len(bi) # calls __len__
|
|
1
|
|
>>> [key for key in bi] # calls __iter__, returns keys like dict
|
|
['three']
|
|
>>> 'three' in bi # calls __contains__
|
|
True
|
|
>>> list(bi.keys())
|
|
['three']
|
|
>>> list(bi.values())
|
|
[3]
|
|
>>> bi.update([('four', 4)])
|
|
>>> bi.update({'five': 5}, six=6, seven=7)
|
|
>>> sorted(bi.items(), key=lambda x: x[1])
|
|
[('three', 3), ('four', 4), ('five', 5), ('six', 6), ('seven', 7)]
|
|
>>> bi.clear()
|
|
>>> bi
|
|
bidict()
|
|
|
|
Empty update is a no-op::
|
|
|
|
>>> bi.update()
|
|
>>> bi
|
|
bidict()
|
|
|
|
Not part of the public API, but test this anyway for the coverage::
|
|
|
|
>>> bi._update(False, None)
|
|
>>> bi
|
|
bidict()
|
|
|
|
Initializing with different keys mapping to the same value fails::
|
|
|
|
>>> bidict([(1, 1), (2, 1)])
|
|
Traceback (most recent call last):
|
|
...
|
|
ValueDuplicationError: 1
|
|
|
|
Adding a new key associated with an existing value fails::
|
|
|
|
>>> b = bidict({1: 1})
|
|
>>> b[2] = 1
|
|
Traceback (most recent call last):
|
|
...
|
|
ValueDuplicationError: 1
|
|
>>> b.update({2: 1})
|
|
Traceback (most recent call last):
|
|
...
|
|
ValueDuplicationError: 1
|
|
|
|
``forceput`` and ``forceupdate`` can be used instead::
|
|
|
|
>>> b.forceput(2, 1)
|
|
>>> b
|
|
bidict({2: 1})
|
|
>>> b.forceupdate({1: 1})
|
|
>>> b
|
|
bidict({1: 1})
|
|
|
|
Trying to insert an existing mapping does not raise, and is a no-op::
|
|
|
|
>>> b = bidict({1: 'one'})
|
|
>>> b[1] = 'one'
|
|
>>> b[1]
|
|
'one'
|
|
>>> b.inv['one'] = 1
|
|
>>> b.inv['one']
|
|
1
|
|
|
|
The following case does not half-succeed,
|
|
i.e. the bidict is not in an inconsistent state after::
|
|
|
|
>>> b = bidict(one=1, two=2)
|
|
>>> b['one'] = 2
|
|
Traceback (most recent call last):
|
|
...
|
|
KeyAndValueDuplicationError: ('one', 2)
|
|
>>> len(b) == len(b.inv)
|
|
True
|
|
|
|
``put`` and ``putall`` allow you to have
|
|
per-call control over duplication behavior
|
|
(see doctests in ``../docs/unique-values.rst.inc``).
|
|
|
|
Even with RAISE duplication behavior,
|
|
inserting existing items is a no-op (i.e. it doesn't raise)::
|
|
|
|
>>> from bidict import RAISE, OnDup
|
|
>>> b.putall(
|
|
... [('three', 3), ('one', 1)],
|
|
... OnDup(key=RAISE, val=RAISE)
|
|
... ) # does not raise an error because these items were already contained
|
|
>>> b0 = b.copy()
|
|
>>> b.putall([]) # no-op
|
|
>>> b == b0
|
|
True
|
|
|
|
Make sure copy.copy and copy.deepcopy create shallow and deep copies, respectively::
|
|
|
|
>>> from copy import copy, deepcopy
|
|
>>> from bidict import frozenbidict
|
|
>>> b = frozenbidict({1: frozenbidict()})
|
|
>>> c = copy(b)
|
|
>>> d = deepcopy(b)
|
|
>>> b == c == d
|
|
True
|
|
>>> b[1] is c[1]
|
|
True
|
|
>>> b[1] is d[1]
|
|
False
|