seansummers
12/18/2017 - 7:09 PM

YAML, JSON, etc...

YAML, JSON, etc...

#! /usr/bin/env python
from __future__ import print_function

import argparse
import contextlib
import functools
import json
import os
import sys

import yaml
try:
    from yaml import CSafeDumper as yaml_dumper
except ImportError:
    from yaml import SafeDumper as yaml_dumper
yaml_dump = functools.partial(
    yaml.dump,
    Dumper=yaml_dumper,
    default_flow_style=False,
    explicit_start=True,
    explicit_end=True,
)

try:
    basestring
except NameError:
    basestring = (str, bytes)


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'json_filename',
        type=argparse.FileType('r'),
        default='-',
        nargs='*',
        help='json file to parse',
    )
    parser.add_argument(
        '--save',
        '-s',
        type=bool,
        nargs='?',
        const=True,
        default=False,
        help='save output to .yaml files',
    )
    return parser.parse_args()


@contextlib.contextmanager
def open_input(input_file=None, mode='rt'):
    """ yield a self-closing file_object
        if input_file supports .read(), just pass it through
        fallback to sys.stdin
    """
    if not hasattr(input_file, 'read'):
        try:
            input_file = open(input_file, mode)
        except IOError:
            input_file = sys.stdin

    if getattr(input_file, 'fileno', lambda: -1)() in {0, 1, 2}:
        yield input_file
    else:
        try:
            with contextlib.closing(input_file) as file_object:
                yield file_object
        except AttributeError:
            # apparently, this wasn't actually a file
            pass


@contextlib.contextmanager
def open_output_from_input(input_file=None, ext='yaml', mode='wt'):
    """ yield a self-closing writable file object
        file name matches input_file with extension defaulting to 'yaml'
        if input_file is stdin or missing, yield stdout
    """
    input_file_name = getattr(input_file, 'name', None)
    if input_file_name in {None, '-', '<stdin>'}:
        yield sys.stdout
    else:
        new_file = os.path.splitext(input_file_name)[0]
        output_file = os.path.extsep.join((new_file, ext))
        with open(output_file, mode) as output_fp:
            yield output_fp


def parse_json_file(json_file, save):
    with open_input(json_file) as json_fp:
        obj = json.load(json_fp)
    yaml = yaml_dump(obj)
    print(yaml)
    if save:
        with open_output_from_input(json_file) as output_fp:
            print(yaml, file=output_fp)


if __name__ == '__main__':
    args = parse_args()
    for json_file in args.json_filename:
        parse_json_file(json_file, args.save)