bidict/tests/test_bidict.txt

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