# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['pelecanus']

package_data = \
{'': ['*']}

setup_kwargs = {
    'name': 'pelecanus',
    'version': '0.5.3',
    'description': 'Python3 application for navigating and editing nested JSON',
    'long_description': '# pelecanus ![](https://travis-ci.org/pellagic-puffbomb/pelecanus.svg?branch=master) [![Coverage Status](https://coveralls.io/repos/pellagic-puffbomb/pelecanus/badge.png?branch=develop)](https://coveralls.io/r/pellagic-puffbomb/pelecanus?branch=master)\n\nA small Python3 application for navigating and editing nested dictionaries, which typically come from JSON BLOBs, named \'pelecanus\' after Pelecanus occidentalis, the [brown Pelican of California and the Eastern Pacific](http://www.nps.gov/chis/naturescience/brown-pelican.htm), which is a wonderful bird, but also named such because I got tired of writing "NestedJson".\n\nThis application has been built-for Python3+. It has no external dependencies.\n\n## Project Goals\n\nOften, it\'s necessary to explore a JSON object without knowing precisely where things are (in the case of Hypermedia, for example). By creating a recursive data structure, we can facilitate such tasks as retrieving key-value pairs, iterating through the data structure, and searching for elements in the data structure.\n\n## How to Use\n\nTo install for Python3.3+, simply do:\n\n```\n$ pip install pelecanus\n```\n\n`pelecanus` offers `PelicanJson` objects, which are nested dictionaries created from valid JSON objects. `PelicanJson` objects provide a few methods to make it easier to navigate and edit nested JSON objects.\n\nTo create a PelicanJson object, you can pass the constructor a Python dictionary created from a JSON dump (or a simple Python dictionary that could be a valid JSON object):\n\n```python\n>>> content = {\'links\': {\'alternate\': [{\'href\': \'somelink\'}]}}\n>>> from pelecanus import PelicanJson\n>>> pelican = PelicanJson(content)\n```\n\n#### Enumerate\n\nOnce you have a `PelicanJson` object, probably one of the most useful things to do is to find all the nested paths and the values located at those paths. The `enumerate` method has been provided for this purpose:\n\n```python\n>>> for item in pelican.enumerate():\n...   print(item)\n([\'links\', \'alternate\', 0, \'href\'], \'somelink\')\n...\n```\n\nIn JSON, only strings may be used as keys [(see JSON spec)](http://json.org/), so the integers that appear in the nested path represent list indices. In this case, `[\'links\', alternate\', 0, \'href\']` actually represents:\n\n1. A dictionary with a key `links`, which points to...\n2. Another dictionary which contains a key \'alternate\', which contains...\n3. A list, the first item of which...\n4. Is a dictionary containing the key `href`.\n\n`enumerate`, like most methods in a `PelicanJson` object, returns a generator. If you want just the paths and not their associated values, use the `paths` method:\n\n```python\n>>> for item in pelican.paths():\n...   print(item)\n[\'links\', \'alternate\', 0, \'href\']\n```\n\n#### Getting and Setting Values\n\nYou can retrieve the value from a nested path using `get_nested_value`:\n\n```python\n>>> pelican.get_nested_value([\'links\', \'alternate\', 0, \'href\'])\n\'somelink\'\n```\n\nIf you would like to have a default returned instead of an exception, you use `safe_get_nested_value:\n\n``` python\n>>> pelican.safe_get_nested_value([\'broken\', \'route\', 0])\nNone\n>>> pelican.safe_get_nested_value([\'broken\', \'route\', 0], default=1)\n1\n```\n\nIf you want to change a nested value, you can use the `set_nested_value` method:\n\n```python\n>>> pelican.set_nested_value([\'links\', \'alternate\', 0, \'href\'], \'newvalue\')\n>>> pelican.get_nested_value([\'links\', \'alternate\', 0, \'href\'])\n\'newvalue\'\n```\n\nIf you attempt to set a nested value for a path that does not exist, an exception will be raised:\n\n```python\n>>> pelican.set_nested_value([\'links\', \'BADKEY\'], \'newvalue\')\nTraceback (most recent call last):\n...\nKeyError: \'BADKEY\'\n```\n\nHowever, you can create a new path and set it equal to a new value if you pass in `force=True` when you call `set_nested_value`:\n\n```python\n>>> pelican.set_nested_value([\'links\', \'BADKEY\'], \'newvalue\', force=True)\n>>> pelican.get_nested_value([\'links\', \'BADKEY\'])\n\'newvalue\'\n```\n\nBecause integers will *always* be interpreted as list-indices, this works for creating ad-hoc lists or adding elements to lists, but be advised: when setting a new path with `force=True`, a `PelicanJson` object will back-fill any missing list indices with `None` (simliar to [assigning to a non-existent array index in Ruby](http://www.ruby-doc.org/core-2.1.2/Array.html#method-i-5B-5D-3D)):\n\n```python\n>>> new_path = [\'links\', \'NewKey\', 4, \'NewNestedKey\']\n>>> pelican.set_nested_value(new_path, \'LIST Example\', force=True)\n>>> pelican.get_nested_value(new_path)\n\'LIST EXAMPLE\'\n>>> pelican.get_nested_value([\'links\', \'NewKey\'])\n[None, None, None, None, {\'NestedKey\': \'LIST EXAMPLE\'}]\n```\n\nIn this example, the `PelicanJson` object found the integer and realized this must be a list index. However, the list was missing, so it created the list and then created all of the items at indices *before* the missing index, at which point it inserted the missing item, a new object with the key-value pair of `NewNestedKey` and `LIST EXAMPLE`. If unexpected, this behavior could be kind of annoying, but the goal is to *force* the path into existence and expected path is now present.\n\n\n#### Keys, Values, Items, etc.\n\nA `PelicanJson` object is a modified version of a Python dictionary, so you can use all of the normal dictionary methods, but it will mostly return nested results (which means you will often get duplicate `keys`). The length of the object too will be based on all the nested keys present:\n\n```python\n>>> list(pelican.keys())\n[\'links\', \'attributes\', \'href\']\n>>> len(pelican)\n3\n```\n\nYou can get *normal* dict behavior with `keys` if you tell it you want the `flat` keys:\n\n```python\n>>> list(pelican.keys(flat=True))\n[\'links\']\n```\n\n`values` is only going to return values that exist at endpoints, which are the inside-most points of all nested objects, leaves in the tree, in other words:\n\n```python\n>>> list(pelican.values())\n[\'somelink\']\n```\n\nWhile `items` attempts to do double-duty, returning each key in the tree and its corresponding value:\n\n```python\n>>> list(pelican.items())\n[(\'links\', <PelicanJson: {\'attributes\': [<PelicanJson: {\'href\': \'somelink\'}>]}>), (\'attributes\', [<PelicanJson: {\'href\': \'somelink\'}>]), (\'href\', \'somelink\')]\n```\n\nYou can also use `in` to see if a key is somewhere inside the dictionary (even if it\'s a nested key):\n\n```python\n>>> \'attributes\' in pelican\nTrue\n```\n\n\n#### Turning it back into a plain dictionary or JSON\n\nOther useful methods include `convert` and `serialize` for turning the object back into a plain Python dictionary and for returning a JSON dump, respectively:\n\n```python\n>>> pelican.convert() == content\nTrue\n>>> pelican.serialize()\n\'{"links": {"attributes": [{"href": "somelink"}]}}\'\n>>> import json\n>>> json.loads(pelican.serialize()) == content\nTrue\n```\n\n\n#### Searching Keys and Values\n\nYou can also use the methods `search_key` and `search_value` in order to find all the paths that lead to keys or values you are searching for (data comes from the [Open Library API](https://openlibrary.org/developers/api)).\n\n```python\n>>> book = {\'ISBN:9780804720687\': {\'preview\': \'noview\', \'bib_key\': \'ISBN:9780804720687\', \'preview_url\': \'https://openlibrary.org/books/OL7928788M/Between_Pacific_Tides\', \'info_url\': \'https://openlibrary.org/books/OL7928788M/Between_Pacific_Tides\', \'thumbnail_url\': \'https://covers.openlibrary.org/b/id/577352-S.jpg\'}}\n>>> pelican = PelicanJson(book)\n>>> for path in pelican.search_key(\'preview\'):\n...   print(path)\n[\'ISBN:9780804720687\', \'preview\']\n>>> for path in pelican.search_value(\'https://covers.openlibrary.org/b/id/577352-S.jpg\'):\n...  print(path)\n[\'ISBN:9780804720687\', \'thumbnail_url\']\n```\n\nIn addition, `pluck` is for retrieving the whole object that contains a particular key-value pair:\n\n```python\n>>> list(pelican.pluck(\'preview\', \'noview\'))\n[<PelicanJson: {\'preview\': \'noview\', \'thumbnail_url\': \'https://covers.openlibrary.org/b/id/577352-S.jpg\', \'bib_key\': \'ISBN:9780804720687\', \'preview_url\': \'https://openlibrary.org/books/OL7928788M/Between_Pacific_Tides\', \'info_url\': \'https://openlibrary.org/books/OL7928788M/Between_Pacific_Tides\'}>]\n```\n\n#### Find and Replace\n\nFinally, there is also a `find_and_replace` method which searches for a particular value and replaces it with a passed-in replacement value:\n\n```python\n>>> for path in pelican.search_value(\'https://covers.openlibrary.org/b/id/577352-S.jpg\'):\n...  print(path)\n[\'ISBN:9780804720687\', \'thumbnail_url\']\n>>> pelican.find_and_replace(\'https://covers.openlibrary.org/b/id/577352-S.jpg\', \'SOME NEW URL\')\n>>> pelican.get_nested_value([\'ISBN:9780804720687\', \'thumbnail_url\'])\n\'SOME NEW URL\'\n```\n\nThis can, of course, be dangerous, so use with caution.\n',
    'author': 'Erik Aker',
    'author_email': 'eraker@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/erewok/pelecanus',
    'packages': packages,
    'package_data': package_data,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
