bpeterso2000
12/20/2016 - 4:14 PM

jsonkeys.py

"""
JSON Keys.

A simple command-line utility that allows the user to quickly:
1. Set the root level of JSON data by using a JSON pointer.
2. Select items to pull from each object in a JSON array.
3. Drop items from objects in a JSON array.

It is not uncommon for an API to return a JSON array of objects containing
much more detail than is needed. This tools is designed to allow the user to
quickly filter, view and extract relevant information.

If values alone are sufficient and you don't care about preserving
key/value pairs then consider using JMESPath instead. http://jmespath.org
"""
import json
import sys
from collections import Mapping
from operator import contains

import click
import jsonpointer
from toolz import curry, dissoc, keyfilter


def exit_on_error(error_mesg):
    """Print error message and exit."""
    print(str(error_mesg), file=sys.stderr)
    sys.exit(1)


def parse_keys(keys):
    """Parse comma separated items."""
    return [i.strip() for i in keys.split(',')]


@click.command()
@click.argument('jsonfile', type=click.File('r'))
@click.option('-r', '--rootkey', help='JSON pointer')
@click.option('-g', '--getkeys', help='comma separated property names')
@click.option('-d', '--dropkeys', help='comma separated property names')
def main(jsonfile, rootkey, getkeys, dropkeys):
    """Exectue on the command-line arguments & options."""
    try:
        obj = json.load(jsonfile)
    except EnvironmentError as e:
        print(str(e), file=sys.stderr)
        sys.exit(1)

    if rootkey:
        try:
            obj = jsonpointer.resolve_pointer(obj, rootkey)
        except jsonpointer.JsonPointerException as e:
            exit_on_error(e)

    if getkeys:
        keys = curry(contains)(parse_keys(getkeys))
        try:
            obj = (keyfilter(keys, obj) if isinstance(obj, Mapping)
                   else [keyfilter(keys, d) for d in obj])
        except TypeError as e:
            exit_on_error(e)

    if dropkeys:
        keys = parse_keys(dropkeys)
        try:
            obj = (dissoc(obj, *keys) if isinstance(obj, Mapping)
                   else [dissoc(d, *keys) for d in obj])
        except TypeError as e:
            exit_on_error(e)

    print(json.dumps(obj, indent=2))


if __name__ == '__main__':
    main()