Butler

Python Dictionaries and Lists on Steroids

View the Project on GitHub atmb4u/butler

Butler

Python Dictionaries and Lists on Steroids

Butler is the missing library that adds additional and necessary features to Python dict as well as list. It helps you traversing nested lists/dicts better. Butler tries to be closely resemble the cpython dictionary functions, but has got a ton of helper functions

Butler is NOT python dict 2.0. It is a helper library that provides a clean API for traversing nested lists and dicts.

Butler suppresses errors and exceptions. Its good as well as bad depends on what you expect from it. Also on the kind of data you are working with. If its a huge document(eg., JSON ) with nullable fields and a lot of multi-level lists, Butler is designed for you.

Installation

pip install python-butler

or you can download the source from https://github.com/atmb4u/butler/ and run

python setup.py install

Quick Start Guide

>>> data = {'a':1, 'b':2, 'c': {'d': 4, 'e': 5, 'f': [6, 7, 8],
... 'g':[{'h': 8, 'i': 9, 'j': 10}, {'a':11,
... 'b': 12, 'c': 13}]}, 'n': [14, 15, 16, 17, 18]}  
# define dictionary - can be a parsed output of json.loads or json.load

>>> quick = Butler(data)  # create an instance of Butler with the data

>>> quick.path_exists(['c', 'g', 0, 'k'])  # tells you if the element exists
False
# fetches the value on the path, similar to ```<dict>.get()``` but more featured

>>> quick.get(['c', 'g', 0])
{'h': 8, 'i': 9, 'j': 10}

# it can take an argument called default which is taken as the default value if not found.
>>> quick.get(['c', 'g', 5], default=0)
0
>>> quick.find(['b'])
12
>>> quick.findall(['b'])
[12, 2]
>>> quick.key_exists(['n'])
True

>>> quick.data  # chokes out the object which is being manipulated
{'a':1, 'b':2, 'c': {'d': 4, 'e': 5, 'f': [6, 7, 8],
... 'g':[{'h': 8, 'i': 9, 'j': 10}, {'a':11,
... 'b': 12, 'c': 13}]}, 'n': [14, 15, 16, 17, 18]}

Key Functions

get() - returns the value at the given path

set() - returns True on updating the data, False on failure

path_exists() - returns if the specified path exists

findall() - returns a list of values for matching keys

find() - returns the first match for the keys

key_exists() - returns True or False, on the availability of the key anywhere in the document

data - outputs the object which is being manipulated

path

For dictionaries, path holds the keys for the element and for lists its the index for the element in the list.

get()

Get the element by specifying path with keys to that value.

* INPUT: __path__ - a list of keys for the dictionary or list

* OUTPUT: Returns the corresponding value if found, else None. 
    - No Exception raised
>>> data1 = Butler({"key": "value"})
>>> data1.get(["key"])
'value'
>>> data2 = Butler([1, 2, 4, 5, [10, 20, 30, 40, 50]])
>>> data2.get([4, 3])
40
>>> data2.get([4, 9])

>>> data3 = Butler("Hello world")
>>> data3.get([6])

set()

Set the element by specifying path with keys to that value. Used to write to Butler objects. Makes it very easy to update and insert leaf nodes.

* INPUT: __path__ - a list of keys for the dictionary or list
         __value__ - Value to be set/update/append to the element in the matching location

* OUTPUT:
    Returns True - Successful update or create
    Returns False - Failed due to non-existent path
>>> a = {'b': {'c': {'d': 1, 's': 1001}}}
>>> data = Butler(a)
>>> data.set(['b', 'c', 'd'], 1001 )
True
>>> a
{'b': {'c': {'s': 1001, 'd': 1001}}}
>>> data.set(['b','c','s'], [10,100])
True
>>> a
{'b': {'c': {'s': [10, 100], 'd': 1001}}}
>>> data.data
{'b': {'c': {'s': [10, 100], 'd': 1001}}}
>>> data.set(['b','q','s'], [10,100])
False
>>> a
{'b': {'c': {'s': [10, 100], 'd': 1001}}}
>>> data.data
{'b': {'c': {'s': [10, 100], 'd': 1001}}}
>>> b = [[1, 2, 3], 4, 5]
>>> data = Butler(b)
>>> data.set([0], 1001)
True
>>> b
[[1, 2, 3, 1001], 4, 5]
>>> c = [[1, 2, 3], 4, 5]
>>> data = Butler(c)
>>> data.set([0,2], 1001)
True
>>> c
[[1, 2, 1001], 4, 5]

path_exists()

* INPUT: list containing path to an expected key

* OUTPUT: True if found, False if NOT.
>>> data = {'a':1, 'b':2, 'c': {'d': 4, 'e': 5, 'f': [6, 7, 8], 
... 'g':[{'h': 8, 'i': 9, 'j': 10}, {'a':11,
... 'b': 12, 'c': 13}]}, 'n': [14, 15, 16, 17, 18]}

>>> quick = Butler(data)

>>> quick.path_exists(['c','g',0,'k'])
False
>>> quick.path_exists(['c','g',0,'j'])
True

findall()

Find all the values with the same key in a multi-level dictionary

* INPUT: key to be searched in the dictionary

* OUTPUT: ```list``` of all values with matching keys
>>> data = {'a':1, 'b':2, 'c': {'d': 4, 'e': 5, 'f': [6, 7, 8], 
... 'g':[{'h': 8, 'i': 9, 'j': 10}, {'a':11,
... 'b': 12, 'c': 13}]}, 'n': [14, 15, 16, 17, 18]}

>>> quick = Butler(data)

>>> quick.findall('a')

find()

Gets the first value matching the argument key

*INPUT: key to be searched in the dict or list (list position in case of list)

*OUTPUT: first result matching the key in the entire dictionary
>>> data = {'a':1, 'b':2, 'c': {'d': 4, 'e': 5, 'f': [6, 7, 8], 
... 'g':[{'h': 8, 'i': 9, 'j': 10}, {'a':11,
... 'b': 12, 'c': 13}]}, 'n': [14, 15, 16, 17, 18]}

>>> quick = Butler(data)

>>> quick.find('a')
1
>>> quick.find('e')
5
>>> quick.find('w')

key_exists()

Uses find function to see if the requested key is in the dictionary Returns: True or False

>>> data = {'a':1, 'b':2, 'c': {'d': 4, 'e': 5, 'f': [6, 7, 8], 
... 'g':[{'h': 8, 'i': 9, 'j': 10}, {'a':11,
... 'b': 12, 'c': 13}]}, 'n': [14, 15, 16, 17, 18]}

>>> quick = Butler(data)

>>> quick.key_exists('a')
True
>>> quick.key_exists('w')
False