Skip to content

Instantly share code, notes, and snippets.

@bockel
Created October 22, 2013 18:45
Show Gist options
  • Select an option

  • Save bockel/7105913 to your computer and use it in GitHub Desktop.

Select an option

Save bockel/7105913 to your computer and use it in GitHub Desktop.
Validates YAML and converts it to JSON. Can also reverse the process and covert JSON back to YAML.
#!/usr/bin/env python
"""
Validates YAML and converts it to JSON.
Can also reverse the process and covert JSON back to YAML.
Intended to be used as a command line utility.
Requirements:
* Python >= 2.5 or >= 3.0
* PyYAML_
Example::
> python yaml2json.py file.yaml
> cat file.yaml | python yaml2json.py -
The ``-r`` or ``--reverse`` flag can be used to encode JSON as YAML::
> python yaml2json.py --reverse file.json
It is also possible to roundtrip a YAML to JSON and back::
> python yaml2json.py file.yaml | python yaml2json.py -r -
.. _PyYAML: http://pyyaml.org/
"""
from __future__ import absolute_import
from __future__ import print_function
import json
import sys
from yaml import safe_load_all, safe_dump
# fix the input function if in python2
if sys.version_info[0] < 3:
input = raw_input
error = lambda err: print(err, file=sys.stderr)
def processor(decoder, encoder, fh, quiet=True):
"""
Decode and validate the filehandle, *fh*, using the decoder, *decoder*.
Write the output to stdout using the encoder.
Parameters:
* **decoder**: a function that takes a filehandle and returns a list
of decoded data representing the file contents.
* **encoder**: a function that python data structure such as a
dictionary, list, or string, and returns a string representing the
encoded version of that data
* **fh**: the filehandle of the file to decode
* **quiet**: whether or not to print the encoded data
Returns:
A tuple of *(count, success)* with the number of documents
attempted to decode and the number of those successfully
decoded
"""
success = 0
count = 0
try:
docs = decoder(fh)
# print(docs)
success += 1
count += len(docs)
if not quiet or encoder is None:
while True:
try:
d = docs.pop(0)
except IndexError:
break
else:
print(encoder(d, indent=4))
if len(docs) > 0: # or fcount < flen:
input("Press Enter to continue...")
except Exception as exc:
if not quiet:
error("Error: {0}".format(exc))
return (count, success)
if __name__ == "__main__":
from argparse import ArgumentParser
from functools import partial
parser = ArgumentParser(
description="Validate and convert YAML docs to JSON"
)
parser.add_argument('-q', '--quiet', action='store_true', default=False,
help='Quiet. Only print validation status and errors')
parser.add_argument('-r', '--reverse', action='store_true', default=False,
help='Reverse the process: convert JSON to YAML')
parser.add_argument('files', metavar='file', nargs='*', default='-',
help='a YAML or JSON file (stdin: -)')
args = parser.parse_args()
count = 0
success = 0
flen = len(args.files)
fcount = 0
decode_yaml = lambda yamldoc: [doc for doc in safe_load_all(yamldoc)]
decode_json = lambda jsondoc: [json.load(jsondoc)]
process = partial(processor,
decode_json if args.reverse else decode_yaml,
json.dumps if not args.reverse else safe_dump,
quiet=args.quiet)
for f in set(args.files):
if f == '-':
c, s = process(sys.stdin)
else:
with open(f) as fh:
c, s = process(fh)
count += c
success += s
if not args.quiet:
error("Validated {0} of {1} files (found {2} streams)".
format(success, flen, count))
# set the shell exit status:
# 0 = success;
# >0 = number of errors found
sys.exit(flen - success)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment