Last active
June 27, 2019 22:09
-
-
Save akatrevorjay/918755c8eb2c66a48566d77fb578630c to your computer and use it in GitHub Desktop.
( json2yaml | yaml2json | j2y | y2j ) that preserves original ordering in all cases (for normal types at least)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
json2yaml -- what it says. | |
Features: | |
- Preserves order of original document, which makes diffing much easier. | |
- Symlink it to `j2y`, `y2j`, 'yaml2json` and it'll do what you expect. | |
https://gist.github.com/akatrevorjay/918755c8eb2c66a48566d77fb578630c | |
""" | |
import os | |
import sys | |
import argparse | |
import json | |
import yaml | |
import collections | |
class OrderedYAML(object): | |
def dump(self, data, stream=None, Dumper=yaml.SafeDumper, object_pairs_hook=collections.OrderedDict, **kwargs): | |
class OrderedDumper(Dumper): | |
pass | |
def _dict_representer(dumper, data): | |
return dumper.represent_mapping(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, data.items()) | |
OrderedDumper.add_representer(object_pairs_hook, _dict_representer) | |
return yaml.dump(data, stream, OrderedDumper, **kwargs) | |
def load(self, stream, Loader=yaml.Loader, object_pairs_hook=collections.OrderedDict, **kwargs): | |
class OrderedLoader(yaml.Loader): | |
pass | |
def construct_mapping(loader, node): | |
loader.flatten_mapping(node) | |
return object_pairs_hook(loader.construct_pairs(node)) | |
OrderedLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, construct_mapping) | |
return yaml.load(stream, OrderedLoader, **kwargs) | |
oyaml = OrderedYAML() | |
class OrderedJSON(object): | |
__kwargs = dict(object_pairs_hook=collections.OrderedDict) | |
def dump(self, data, stream=None, **kwargs): | |
# kw = self.__kwargs.copy() | |
kw = dict( | |
indent=2, | |
) | |
kw.update(kwargs) | |
if not stream: | |
return json.dumps(data, **kw) | |
else: | |
return json.dump(data, stream, **kw) | |
def load(self, fp, **kwargs): | |
kw = self.__kwargs.copy() | |
kw.update(kwargs) | |
return json.load(fp, **kw) | |
ojson = OrderedJSON() | |
def json2yaml(args, stream=sys.stdout): | |
"""Convert json to yaml.""" | |
data = ojson.load(args.infile) | |
ret = oyaml.dump(data, stream=stream) | |
return ret | |
json2yaml.aliases = ['j2y'] | |
def yaml2json(args, stream=sys.stdout): | |
"""Convert yaml to json.""" | |
data = oyaml.load(args.infile) | |
ret = ojson.dump(data, stream=stream) | |
return ret | |
yaml2json.aliases = ['y2j'] | |
_COMMANDS = [json2yaml, yaml2json] | |
def _arg_parser_factory(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument( | |
'infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin, help='Input file to parse (default: standard input)' | |
) | |
return parser | |
def _parse_args(parser=_arg_parser_factory): | |
if callable(parser): | |
parser = parser() | |
args = parser.parse_args() | |
return args | |
def main(_commands=_COMMANDS): | |
cmd = os.path.basename(sys.argv[0]) | |
args = _parse_args() | |
for meth in _commands: | |
names = [meth.__name__] + getattr(meth, 'aliases', []) | |
if cmd in names: | |
return meth(args) | |
raise ValueError("I don't know what I'm supposed to do for '%s'." % cmd) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment