Package: dictregister
DictRegister============|Build Status| |Version| |PyPi Downloads|Documentation-------------`dictregisterdocumentation <https://dictregister.readthedocs.org/en/latest/>`__**dictregister** provides an object that contains an ordered list ofdictionaries with some functions to search and manage them.Dictionaries are useful objects, as they can easily represent complexobjects; being a basic language structure in Python they are very handy:as an instance, they are serialiable, and if you ever worked with JSONyou are accustomed to see them around.When dealing with more than one dictionary, namely a list of them, aproblem arises: searching the list for dictionaries is complex and youusually write a bunch of repeated code to get the information you need.**dictregister** acts as a standard Python list but can contain onlydictionaries (actually objects implementing collections.Mapping);additionally, it provides functions to search and manage dictionaries bykey, to manage single keys and to store more than one value for eachkey.**dictregister** is a pure Python package, but its syntax has beenheavily influenced by Django's query syntax, so Django users will findat home.Indeed, **dictregister** acts like a small key/value database. Pleasenote that there it stores values in memory and there is no optimization,so use it for small collections.Basic usage-----------The ``DictRegister`` object acts as a ``list``, so you can eitherinitialize it empty.. code:: pythonimport dictregisterdr = dictregister.DictRegister()or with an iterable object as an argument.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}])and you can use any method of ``list`` like ``append()``.. code:: pythonimport dictregisterdr = dictregister.DictRegister()dr.append({'x':1, 'y':2})``DictRegister`` accepts only objects that inherit from the``collections.Mapping`` Abstract Base Class. If you try to insert anobject that does not stick with this rule you will receive a``TypeError``.Managing keys-------------You can manage keys in batch mode with ``kadd()``, ``kreplace()``, and``kremove()``.Adding a key to each element is easy with ``kadd()``.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}])dr == [{'x':1, 'y':2}, {'x':3, 'y':4}]dr.kadd('z', 5)dr == [{'x':1, 'y':2, 'z':5}, {'x':3, 'y':4, 'z':5}]Please note that if you add more than a value to the same key you get amultiple-value element, which is treated in a special way. See theMultiple values section below.When you remove keys you can do it unconditionally.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}])dr == [{'x':1, 'y':2}, {'x':3, 'y':4}]dr.kremove('y')dr == [{'x':1}, {'x':3}]which removes all keys with that name. or you can specify a value, inwhich case only the elments that match both the key and the value willbe removed... code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}])dr == [{'x':1, 'y':2}, {'x':3, 'y':4}]dr.kremove('y',4)dr == [{'x':1, 'y':2}, {'x':3}]Last, you can replace the value of a key.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}])dr == [{'x':1, 'y':2}, {'x':3, 'y':4}]dr.kreplace('x',6)dr == [{'x':6, 'y':2}, {'x':6, 'y':4}]Advanced usage--------------You can find a subset of dictionaries using ``dfilter()``.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}])filtdr = dr.dfilter(x=1)filtdr == [{'x':1, 'y':2}]You can pass as many conditions as you want to ``dfilter()``.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}])filtdr = dr.dfilter(x=1)filtdr == [{'x':1, 'y':2}, {'x':1, 'y':6}]filtdr = dr.dfilter(x=1, y=2)filtdr == [{'x':1, 'y':2}]You can easily get only the first element of the filtering with``dget()``. Remember that while ``dfilter()`` silently accepts a searchthat returns no values, returning an empty ``DictRegister``, ``dget()``raises an ``IndexError`` exception.You can remove elements from a ``DictRegister`` object with``dremove()``, which returns a ``DictRegister`` containing the removedelements... code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}])filtdr = dr.dremove(x=1)dr == [{'x':3, 'y':4}]filtdr == [{'x':1, 'y':2}, {'x':1, 'y':6}]Otherwise you obtain a new object with the elements removed``dremove_copy()``.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}])filtdr = dr.dremove_copy(x=1)dr == [{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}]filtdr == [{'x':3, 'y':4}]Last you can pop an element with ``dpop()``, which returns the firstelement matching the given conditions. Remember that ``dpop()`` raises``IndexError`` if no matching element is found... code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}])filtdr = dr.dpop(x=1)dr == [{'x':3, 'y':4}, {'x':1, 'y':6}]Remember that, being a list, ``DictRegister`` also provides you a``pop([i])`` method that pops the element at index ``i`` or the firstelement if ``i`` is not specified.Note that ``dfilter()``, ``dremove()``, and ``dremove_copy()`` return a``DictRegister`` so you can easily chain calls... code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}])filtdr = dr.dfilter(x=1).dremove_copy(y=2)dr == [{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}]filtdr == [{'x':1, 'y':6}]Matching elements-----------------When using the advanced features of ``DictRegister`` like filtering youcan use a special syntax for keys, namely a ``key__operator`` syntax.The implicit operator is ``eq``, which matches all dictionaries with thegiven key with the given value... code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}])filtdr = dr.dfilter(x__eq=3)filtdr == [{'x':3, 'y':4}]filtdr = dr.dfilter(x=3)filtdr == [{'x':3, 'y':4}]The inequality can be matched with ``ne``.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6}])filtdr = dr.dfilter(x__ne=1)filtdr == [{'x':3, 'y':4}]You can match dictionaries that contain or not a given key.. code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}, {'x':1, 'y':6, 'z':8}])filtdr = dr.dfilter(z__iskey=True)filtdr == [{'x':1, 'y':6, 'z':8}]filtdr = dr.dfilter(z__iskey=False)filtdr == [{'x':1, 'y':2}, {'x':3, 'y':4}]Multiple values---------------The ``DictRegister`` object can contain any dictionary with a singlevalue for each key, like.. code:: pythonimport dictregisterdr = dictregister.DictRegister()dr.append({'x':1, 'y':2})If you store more than a value for a key, ``DictRegister`` uses a set tohost the values. You are free to append dictionaries with genericsequences, most notably lists and sets, as values. However remeber that``DictRegister`` does not consider the sequence itself as the value ofthe key, but the contained elements; so if you need to store a sequenceas a value you have to store a ``set`` that contains the sequence... code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':1, 'y':2}, {'x':3, 'y':4}])dr == [{'x':1, 'y':2}, {'x':3, 'y':4}]dr.kadd('x', 2)dr == [{'x':set([1, 2]), 'y':2}, {'x':set([2, 3]), 'y':4}]You can match multiple values with the ``in`` and ``nin`` operators. Thefirst matches all dictionaries that contain the given key with the givenvalue among its values, while ``nin`` performs the opposite match... code:: pythonimport dictregisterdr = dictregister.DictRegister([{'x':set([1, 2]), 'y':2}, {'x':2, 'y':4}])filtdr = dr.dfilter(x__in=2)filtdr == [{'x':set([1, 2]), 'y':2}, {'x':2, 'y':4}]As you can see ``DictRegister`` treats keys with a single value and withmultiple values in the same way.Installation------------.. code:: shpip install dictregisterContributions-------------Any form of contribution is warmly welcomed. Feel free to submit issuesof to make changes and submit a pull request. being the first Pythonpackage I ship with all the bells and whistles like distutils, tests andfriends, I gladly accept suggestions or corrections on this topic.Thanks------Many thanks to `Jeff Knupp <http://www.jeffknupp.com/about-me/>`__ forhis post `Open Sourcing a Python Project the RightWay <http://www.jeffknupp.com/blog/2013/08/16/open-sourcing-a-python-project-the-right-way/>`__.Many thanks to `Audrey M. Roy <http://www.audreymroy.com/>`__ for her`cookiecutter <https://github.com/audreyr/cookiecutter>`__ and`cookiecutter-pypackage <https://github.com/audreyr/cookiecutter-pypackage>`__tools, which heavily simplified the implementation of the whole thing... |Build Status| image:: https://travis-ci.org/lgiordani/dictregister.png?branch=master:target: https://travis-ci.org/lgiordani/dictregister.. |Version| image:: https://badge.fury.io/py/dictregister.png:target: http://badge.fury.io/py/dictregister.. |PyPi Downloads| image:: https://pypip.in/d/dictregister/badge.png:target: https://crate.io/packages/dictregister?version=latestHistory-------0.9.0 (2013-11-08)++++++++++++++++++* First implementation0.9.0.post1 (2013-11-08)++++++++++++++++++* Fixed PyPI classifiers0.9.1 (2013-11-14)++++++++++++++++++* Added a direct import of DictRegister in __init__.py (thanks to https://github.com/Jeff17Robbins)0.9.2 (2013-11-14)++++++++++++++++++* Fixed import in __init__.py for Python 3, now all tox tests pass1.0.0 (2013-12-04)++++++++++++++++++* Raise TypeError instead of ValueError if invalid object is passed (pull request from joshgeller)