Package: dictor
Dictor - the dictionary doctorAn elegant dictionary and JSON handlerATTENTION: Dictor version 0.1.13 and up will be dropping support for Python 2Dictor is a Python JSON and Dictionary (Hash, Map) handler.Dictor takes a dictionary or JSON data and returns value for a specific key.If Dictor doesnt find a value for a key, or if JSON or Dictionary data is missing the key, the return value is either None or whatever fallback value you provide.Dictor is polite with Exception errors commonly encountered when parsing large Dictionaries/JSONs.Using Dictor eliminates the repeated use of try/except blocks in your code when dealing with lookups of large JSON structures, as well as providing flexibility for inserting fallback values on missing keys/values.Why not use dict.get("value") ?using the built-in dict.get() does not parse the full body of a dict.This method works if parsing a simple key=value structure, for example:data = {"name": "Joe"}

>>> print(data.get("name"))
Joe
>>> print(data.get("age"))
None
>>> print(data.get("age", "this key doesnt exist"))
this key doesnt existBut this wont work if the dict is a list,>>> data = [{"name": "Joe"}]
>>> print(data.get("age"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'get'or if the dict has a complex and nested structure, for example if I want to get Joe's age, I need to create a for-loop to parse the hierarchial levels of the dict structure until I reach the "age" key:data = {
    "employees": {
        "Joe": {
            "age": 20,
            "id": 123
        }
    }
}

>>> print(data.get("employees.Joe"))
NoneDictor greatly simplifies all this code by abstracting the logic.Installationpip install dictorUsagesample.json{"characters":{"Lonestar":{"id":55923,"role":"renegade","items":["space winnebago","leather jacket"]},"Barfolomew":{"id":55924,"role":"mawg","items":["peanut butter jar","waggy tail"]},"Dark Helmet":{"id":99999,"role":"Good is dumb","items":["Shwartz","helmet"]},"Skroob":{"id":12345,"role":"Spaceballs CEO","items":["luggage"]}}}now lets get info on all Charactersfromdictorimportdictorwithopen('sample.json')asdata:data=json.load(data)print(dictor(data,'characters')){u'Lonestar':{u'items':[u'space winnebago',u'leather jacket'],u'role':u'renegade',u'id':55923},u'Dark Helmet':{u'items':[u'Shwartz',u'helmet'],u'role':u'Good is dumb',u'id':99999},u'Barfolomew':{u'items':[u'peanut butter jar',u'waggy tail'],u'role':u'mawg',u'id':55924},u'Skroob':{u'items':[u'luggage'],u'role':u'Spaceballs CEO',u'id':12345}}get details for Dark Helmetprint(dictor(data,'characters.Dark Helmet.items'))>>[u'Shwartz',u'helmet']you can also pass a flag to ignore letter Upper/Lower casing,print(dictor(data,'characters.dark helmet.items',ignorecase=True))get only the 1st Item of a characterprint(dictor(data,'characters.Dark Helmet.items.0'))>>ShwartzFallback Value & Error Handlingby default, dictor will return a None if a dictionary does not contain your search path,print(dictor(data,'characters.Princess Leia'))>>Noneyou can provide a default fallback value either by passingdefault="fallback value"or just placing a fallback string,print(dictor(data,'characters.Princess Leia',default='Not in Spaceballs'))>>Notinspaceballsor just add a fallback string,print(dictor(data,'characters.Princess Leia','fallback to this'))>>fallbacktothisif you want to error out on a None value, simply provide a CheckNone flag, a ValueError will be raised.print(dictor(data,'characters.Princess Leia',checknone=True))Traceback(mostrecentcalllast):File"test.py",line14,in<module>print(dictor(data,'characters.Princess Leia',checknone=True))File"/github.com/dictor/dictor/__init__.py",line77,indictorraiseValueError('missing value for%s'%path)ValueError:valuenotfoundforsearchpath:"characters.Princess Leia"Passing a variable into search pathif you need to pass a variable into search pathwho="Barfolomew"print(dictor(data,"characters.{}.id".format(who)))>>55924if using Python 3, you can also use F-stringswho="Barfolomew"print(dictor(data,f"characters.{who}.id"))List of Dictsif the entire JSON structure is a list[{"color":"red","value":"#f00"},{"color":"green","value":"#0f0"},{"color":"blue","value":"#00f"}]just provide the list index into search pathprint(dictor(data,'2.color'))>>blueNested List of liststo parse a complex nested list of lists and dicts, just provide the list index in the search path[{"type":"json","message":[[{"english":"apple","spanish":"manzana"},{"english":"banana","spanish":"platano"}],[{"english":"cherry","spanish":"cereza"},{"english":"durian","spanish":"durian","color":["black","brown","orange"]}]]}]dictor will parse each lookup element hierarchicly, starting with top and will work down to the last element, reading in each dot-separated list index.print(dictor(data,'0.message.1.1.color.2'))>>orangeHandling Key lookups with dots or other charactersif you need to look up a key value that has a dot or some other character in the key name, for example{"dirty.harry":{"year":1977,"genre":"romance"}}searching for dictor(data, 'dirty.harry') will return a None since Dictor sees the dot-separated entry as 2 separate keys.To search for a key with a dot in the name, simply use a Path Separator flag, this allows you to control the separator of keys by using a custom character. (by default, pathsep is set to '.')print(dictor(data,'dirty.harry/genre',pathsep='/'))>>{'romance'}you can also use an escape character "\" to escape a dot,print(dictor(data,"dirty\.harry.genre"))>>>{'romance'}Searching specific keysDictor has the ability to search for specific keys and output a list of values. For example, to search for all values that match "name" keydata={"planets":[{"name":"Mars","type":"rock","attributes":{"name":"named after Roman god of war","color":"red","size":"28,230 km"}},{"name":"Neptune","type":"gas","attributes":{"name":"named after Roman god of ocean","color":"blue","size":"338,382 km"}},]}simply pass thesearch="key_name"flagprint(dictor(data,'planets',search='name'))>>['Mars','Neptune']If search key is non existent, dictor will pass a None. In this case you can pass a default fallback value,print(dictor(data,'planets',search='fake_key',default='couldnt find value'))>>couldntfindvalueif the entire dict structure is a list, ie:[{"name":"spaceballs","genre":"romance"},{"name":"gone with the wind","genre":"chick flick"},{"name":"titanic","genre":"comedy"}]you can search for all keys directly, ieprint(dictor(data, search='genre'))

>> ['romance', 'chick flick', 'comedy']if a key value in the JSON is false, dictor will convert it to pythonic Falseif a key value in the JSON is true, dictor will convert it to pythonic Trueif a key value in the JSON is null, dictor will convert it to pythonic None (unless you provide a default value)if a key value in the JSON is blank or "", dictor will convert it to pythonic None (unless you provide a default value)so this JSON will be translated by dictor like this,[{"status":true},{"status":false},{"status":null},{"status":""}]will be returned asprint(dictor(data, search="status"))
>> [True, False, None, '']

print(dictor(data, search="status", default="fallback"))
>> [True, False, 'fallback', '']Pretty Printyou can pretty print (human readable JSON output) your result,print(dictor(data,pretty=True))[{"genre":"comedy","name":"spaceballs"},{"genre":"tragedy","name":"gone with the wind"},{"genre":"comedy","name":"titanic"}]Return specific typeif you want to return lookup value in a specific character type (int or str), use the return type (rtype) flagConvert an integer return value into a stringdata = { "age": 25 }

print(dictor(data, "age", rtype="str"))
>>> "25"Convert a string return value into an integerdata = { "some string value": "1234" }

print(dictor(data, "some string value", rtype="int"))
>>> 1234This will only return the desired output type if return value is string or int. If the return value is a dictionary, list or tuple, the original return value will be returned.Testingtesting is done using Pytest. Tests are located in 'tests' directory.pip3 install pytest

shell> cd tests
shell> pytest -sv test.pyRelease Notes0.1.12removed Nose as testing lib as its unmaintained, added pytestadded fixes byhttps://github.com/dawid-szaniawskito return empty strings instead of Noneadded searching for key in a nested json/dict structure0.1.11fixed bug with searching non existent pathfixed bug with _findval ValueError0.1.10fixed lookup bug on empty string path, iedictor(data, "")now returns Noneformatted syntax with Black formatter0.1.9added escape option for pathsep (can either use pathsep flag or use "\" escape in path)0.1.8broke down main dictor function into several sub-functionsadded 'rtype' flag to return type-specific output (int or str)0.1.7README win10 compatibility fixdocstring fixes0.1.6added ability to search keys, will return a list of key names via Search flagadded Pretty flag to pretty print JSON output0.1.5checknone updated to only error out on None values, 0 values are accepted0.1.4lookup engine updateability to provide new type of path separator0.1.3bugfix0.1.2fixed lookup bug0.1.1removedeval()function for added securityentire lookup engine was rewritten for increased speed and simplicyaddedignorecaseparameteradded ability to escape dot character for keys with dots in themlooking up lists indexes was modified,in previous version, looking up an element looked like this,dictor(data,'characters.Dark Helmet.items[0]')new syntax is to place everything as a dot-separated path, this creates a single lookup standard, ie,dictor(data,'characters.Dark Helmet.items.0')0.0.1initial project releasedpackagingpython setup.py sdist
sudo pip install twine
sudo twine upload dist/*