midict package API

midict.AttrDict

class midict.AttrDict(*args, **kw)[source]

Bases: dict

A dictionary that can get/set/delete a key using the attribute syntax if it is a valid Python identifier. (d.key <==> d['key'])

Note that it treats an attribute as a dictionary key only when it can not find a normal attribute with that name. Thus, it is the programmer’s responsibility to choose the correct syntax while writing the code.

Be aware that besides all the inherited attributes, AttrDict has an additional internal attribute “_AttrDict__attr2item”.

Examples:

d = AttrDict(__init__='value for key "__init__"')
d.__init__ -> <bound method AttrDict.__init__>
d["__init__"] -> 'value for key "__init__"'
__init__(*args, **kw)[source]

Init the dict using the same arguments for dict.

set any attributes here (or in subclass) - before __init__() so that these remain as normal attributes

__getattr__(item)[source]

Maps values to attributes. Only called if there isn’t an attribute with this name

__setattr__(item, value)[source]

Maps attributes to values. Only if initialized and there isn’t an attribute with this name

__delattr__(item)[source]

Maps attributes to values. Only if there isn’t an attribute with this name

class midict.AttrOrdDict(*args, **kw)[source]

Bases: midict.AttrDict, collections.OrderedDict

AttrDict + OrderedDict

midict.IndexDict

class midict.IndexDict(*args, **kw)[source]

Bases: dict

A dictionary that supports flexible indexing (get/set/delete) of multiple keys via an int, tuple, list or slice object.

The type of a valid key in IndexDict should not be int, tuple, or NoneType.

To index one or more items, use a proper item argument with the bracket syntax: d[item]. The possible types and contents of item as well as the corresponding values are summarized as follows:

type content of the item argument corresponding values
int the index of a key in d.keys() the value of the key
tuple/list multiple keys or indices of keys list of values
slice “key_start : key_stop : step” list of values
other types a normal key the value of the key

The tuple/list syntax can mix keys with indices of keys.

The slice syntax means a range of keys (like the normal list slicing), and the key_start and key_stop parameter can be a key, the index of a key, or None (which can be omitted).

When setting items, the slice and int syntax (including int in the tuple/list syntax) can only be used to change values of existing keys, rather than set values for new keys.

Examples:

d = IndexDict(a=1,b=2,c=3)

d -> {'a': 1, 'c': 3, 'b': 2}
d.keys() -> ['a', 'c', 'b']

d['a'] -> 1
d[0] -> 1
d['a','b'] <==> d[('a','b')] <==> d[['a','b']] -> [1, 2]
d[:] -> [1,3,2]
d['a':'b'] <==> d[0:2] <==> d['a':2] <==> d['a':-1] -> [1, 3]
d[0::2] -> [1, 2]

d[0] = 10 # d -> {'a': 10, 'c': 3, 'b': 2}
d['a':-1] = [10, 30] # d -> {'a': 10, 'c': 30, 'b': 2}

d[5] = 10 -> KeyError: 'Index out of range of keys: 5'
__init__(*args, **kw)[source]

check key is valid

__getitem__(item)[source]

Get one or more items using flexible indexing.

__setitem__(item, value)[source]

Set one or more items using flexible indexing.

The slice and int syntax (including int in the tuple/list syntax) can only be used to change values of existing keys, rather than set values for new keys.

__delitem__(item)[source]

Delete one or more items using flexible indexing.

__contains__(item)[source]

Check if the dictionary contains one or more items using flexible indexing.

class midict.IdxOrdDict(*args, **kw)[source]

Bases: midict.IndexDict, midict.AttrDict, collections.OrderedDict

IndexDict + AttrDict + OrderedDict

midict.MIMapping

class midict.MIMapping(*args, **kw)[source]

Bases: midict.AttrOrdDict

Base class for all provided multi-index dictionary (MIDict) types.

Mutable and immutable MIDict types extend this class, which implements all the shared logic. Users will typically only interact with subclasses of this class.

__init__(*args, **kw)[source]

Init dictionary with items and index names:

(items, names, **kw)
(dict, names, **kw)
(MIDict, names, **kw)

names and kw are optional.

names must all be str or unicode type. When names not present, index names default to: ‘index_0’, ‘index_1’, etc. When keyword arguments present, only two indices allowed (like a normal dict)

Examples:

index_names = ['uid', 'name', 'ip']
rows_of_data = [[1, 'jack', '192.1'],
                [2, 'tony', '192.2']]

user = MIDict(rows_of_data, index_names)

user = MIDict(rows_of_data)
<==> user = MIDict(rows_of_data, ['index_0', 'index_1', 'index_2'])

Construct from normal dict:

normal_dict = {'jack':1, 'tony':2}
user = MIDict(normal_dict.items(), ['name', 'uid'])
# user -> MIDict([['tony', 2], ['jack', 1]], ['name', 'uid'])
__getitem__(args)[source]

get values via multi-indexing

__setitem__(args, value)[source]

set values via multi-indexing

__delitem__(args)[source]

delete a key (and the whole item) via multi-indexing

__eq__(other)[source]

Test for equality with other.

if other is a regular mapping/dict, compare only order-insensitive keys/values. if other is also a OrderedDict, also compare the order of keys. if other is also a MIDict, also compare the index names.

__lt__(other)[source]

Check if self < other

If other is not a Mapping type, return NotImplemented.

If other is a Mapping type, compare in the following order:
  • convert self to an OrderedDict or a dict (depends on the type of other) and compare it with other
  • index names (only if other is a MIMapping)
__le__(other)[source]

self <= other

__gt__(other)[source]

self > other

__ge__(other)[source]

self >= other

__repr__(_repr_running={})[source]

repr as “MIDict(items, names)”

__reduce__()[source]

Return state information for pickling

copy()[source]

a shallow copy

clear(clear_indices=False)[source]

Remove all items. index names are removed if clear_indices==True.

classmethod fromkeys(keys, value=None, names=None)[source]

Create a new dictionary with keys from keys and values set to value.

fromkeys() is a class method that returns a new dictionary. value defaults to None.

Length of keys must not exceed one because no duplicate values are allowed.

Optional names can be provided for index names (of length 2).

get(key, default=None)[source]

Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

Support “multi-indexing” keys

__contains__(key)[source]

Test for the presence of key in the dictionary.

Support “multi-indexing” keys

__iter__(index=None)[source]

Iterate through keys in the index (defaults to the first index)

__reversed__(index=None)[source]

Iterate in reversed order through keys in the index (defaults to the first index)

iterkeys(index=None)[source]

Iterate through keys in the index (defaults to the first index)

keys(index=None)[source]

a set-like object providing a view on the keys in index (defaults to the first index)

itervalues(index=None)[source]

Iterate through values in the index (defaults to all indices except the first index).

When index is None, yielded values depend on the length of indices (N):

  • if N <= 1: return
  • if N == 2: yield values in the 2nd index
  • if N > 2: yield values in all indices except the first index (each value is a list of N-1 elements)
values(index=None)[source]

a set-like object providing a view on the values in index (defaults to all indices except the first index)

iteritems(indices=None)[source]

Iterate through items in the indices (defaults to all indices)

items(index=None)[source]

a set-like object providing a view on the items in index (defaults to all indices)

update(*args, **kw)[source]

Update the dictionary

viewdict(index_key=None, index_value=None)[source]

a dict-like object providing a view on the keys in index_key (defaults to the first index) and values in index_value (defaults to the last index)

todict(dict_type=<class 'dict'>, index_key=0, index_value=-1)[source]

convert to a specific type of dict using index_key as keys and index_value as values (discarding index names)

midict.MIDict

class midict.MIDict(*args, **kw)[source]

Bases: midict.MIMapping

MIDict is an ordered “dictionary” with multiple indices where any index can serve as “keys” or “values”, capable of assessing multiple values via its powerful indexing syntax, and suitable as a bidirectional/inverse dict (a drop-in replacement for dict/OrderedDict in Python 2 & 3).

Features:

  • Multiple indices
  • Multi-value indexing syntax
  • Convenient indexing shortcuts
  • Bidirectional/inverse dict
  • Compatible with normal dict in Python 2 & 3
  • Accessing keys via attributes
  • Extended methods for multi-indices
  • Additional APIs to handle indices
  • Duplicate keys/values handling
__setitem__(args, value)[source]

set values via multi-indexing

If d.indices is empty (i.e., no index names and no items are set), index names can be created when setting a new item with specified names (index1 and index2 can not be int or slice):

d = MIDict()
d['uid':1, 'name'] = 'jack'
# d -> MIDict([[1, 'jack']], ['uid', 'name'])

d = MIDict()
d[1] = 'jack' # using default index names
<==> d[:'jack'] = 1
# d -> MIDict([(1, 'jack')], ['index_1', 'index_2'])

If d.indices is not empty, when setting a new item, all indices of the item must be specified via index1 and index2 (implicitly or explicitly):

d = MIDict([['jack', 1, '192.1']], ['name', 'uid', 'ip'])
d['tony'] = [2, '192.2']
<==> d['name':'tony',['uid', 'ip']] = [2, '192.2']
# the following will not work:
d['alice', ['uid']] = [3] # raise ValueError

More examles:

d = MIDict(jack=1, tony=2)

d['jack'] = 10 # replace value of key 'jack'
d['tom'] = 3 # add new key/value
d['jack'] = 2 # raise ValueExistsError
d['alice'] = 2 # raise ValueExistsError
d[:2] = 'jack' # raise ValueExistsError
d['jack', :] = ['tony', 22] # raise ValueExistsError
d['jack', :] = ['jack2', 11] # replace item of key 'jack'
__delitem__(args)[source]

delete a key (and the whole item) via multi-indexing

clear(clear_indices=False)[source]

Remove all items. index names are removed if clear_indices==True.

update(*args, **kw)[source]

Update the dictionary with items and names:

(items, names, **kw)
(dict, names, **kw)
(MIDict, names, **kw)

Optional positional argument names is only allowed when self.indices is empty (no indices are set yet).

rename_index(*args)[source]

change the index name(s).

  • call with one argument:
    1. list of new index names (to replace all old names)
  • call with two arguments:
    1. old index name(s) (or index/indices)
    2. new index name(s)
reorder_indices(indices_order)[source]

reorder all the indices

add_index(values, name=None)[source]

add an index of name with the list of values

remove_index(index)[source]

remove one or more indices

midict.FrozenMIDict

class midict.FrozenMIDict(*args, **kw)[source]

Bases: midict.MIMapping, collections.abc.Hashable

An immutable, hashable multi-index dictionary (similar to MIDict).

__hash__()[source]

Return the hash of this bidict.

Exceptions

exception midict.MIMappingError[source]

Bases: Exception

Base class for MIDict exceptions

exception midict.ValueExistsError[source]

Bases: KeyError, midict.MIMappingError

Value already exists in an index and can not be used as a key.

Usage:

ValueExistsException(value, index_order, index_name)
__str__()[source]

Get a string representation of this exception for use with str.

Dict views

class midict.MIKeysView(mapping, index=None)[source]

Bases: collections.abc.KeysView

a set-like object providing a view on the keys in index (defaults to the first index)

class midict.MIValuesView(mapping, index=None)[source]

Bases: collections.abc.ValuesView

a set-like object providing a view on the values in index (defaults to all indices except the first index)

class midict.MIItemsView(mapping, index=None)[source]

Bases: collections.abc.ItemsView

a set-like object providing a view on the items in index (defaults to all indices)

class midict.MIDictView(mapping, index_key=None, index_value=None)[source]

Bases: collections.abc.KeysView

a dict-like object providing a view on the keys in index_key (defaults to the first index) and values in index_value (defaults to the last index)

Auxiliary functions

midict._MI_init(self, *args, **kw)[source]

Separate __init__ function of MIMapping

midict._MI_setitem(self, args, value)[source]

Separate __setitem__ function of MIMapping

midict.force_list(a)[source]

convert an iterable a into a list if it is not a list.

midict.cvt_iter(a)[source]

Convert an iterator/generator to a tuple so that it can be iterated again.

E.g., convert zip in PY3.

midict.convert_dict(d, cls=<class 'midict.AttrDict'>)[source]

recursively convert a normal Mapping d and it’s values to a specified type (defaults to AttrDict)

midict.convert_key_to_index(keys, key)[source]

convert key of various types to int or list of int

return index, single

midict.convert_index_to_keys(d, item)[source]

Convert item in various types (int, tuple/list, slice, or a normal key) to a single key or a list of keys.

midict.IndexDict_check_key_type(key)[source]

raise TypeError if key is int, tuple or NoneType

midict.MI_check_index_name(name)[source]

Check if index name is a valid str or unicode

midict.get_unique_name(name='', collection=())[source]

Generate a unique name (str type) by appending a sequence number to the original name so that it is not contained in the collection. collection has a __contains__ method (tuple, list, dict, etc.)

midict.get_value_len(value)[source]

Get length of value. If value (eg, iterator) has no len(), convert it to list first.

return both length and converted value.

midict.MI_parse_args(self, args, ingore_index2=False, allow_new=False)[source]

Parse the arguments for indexing in MIDict.

Full syntax: d[index1:key, index2].

index2 can be flexible indexing (int, list, slice etc.) as in IndexDict.

Short syntax:

  • d[key] <==> d[key,] <==> d[first_index:key, all_indice_except_first]
  • d[:key] <==> d[:key,] <==> d[None:key] <==> d[last_index:key, all_indice_except_last]
  • d[key, index2] <==> d[first_index:key, index2] # this is valid # only when index2 is a list or slice object
  • d[index1:key, index2_1, index2_2, ...] <==> d[index1:key, (index2_1, index2_2, ...)]
midict.mget_list(item, index)[source]

get mulitple items via index of int, slice or list

midict.mset_list(item, index, value)[source]

set mulitple items via index of int, slice or list

midict.MI_get_item(self, key, index=0)[source]

return list of item

midict.od_replace_key(od, key, new_key, *args, **kw)[source]

Replace key(s) in OrderedDict od by new key(s) in-place (i.e., preserving the order(s) of the key(s))

Optional new value(s) for new key(s) can be provided as a positional argument (otherwise the old value(s) will be used):

od_replace_key(od, key, new_key, new_value)

To replace multiple keys, pass argument key as a list instance, or explicitly pass a keyword argument multi=True:

od_replace_key(od, keys, new_keys, [new_values,] multi=True)
midict.od_reorder_keys(od, keys_in_new_order)[source]

Reorder the keys in an OrderedDict od in-place.