From 94f8bce48b4a2aa9b8ab7631dead934cadbef6f5 Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Sat, 3 Aug 2024 18:01:00 +0200 Subject: [PATCH] Add output filename --- docs/source/conf.py | 4 ++-- docs/source/usage.rst | 28 ++++++++----------------- pyproject.toml | 2 +- src/jsonyx/tool.py | 49 +++++++++++++++++++++++++------------------ 4 files changed, 41 insertions(+), 42 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index eed82fc..64193d0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -9,8 +9,8 @@ copyright: str = "2024, Nice Zombies" # noqa: A001 author: str = "Nice Zombies" -release: str = "1.1" -version: str = "1.1.0" +release: str = "1.2" +version: str = "1.2.0" # -- General configuration diff --git a/docs/source/usage.rst b/docs/source/usage.rst index 8fe2812..eecb128 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -69,7 +69,7 @@ Using Decimal instead of float:: >>> json.loads("1.1", use_decimal=True) Decimal('1.1') >>> json.dump(Decimal("1.1")) - '1.1' + 1.1 Using :mod:`jsonyx` from the shell to validate and pretty-print: @@ -219,31 +219,19 @@ Command Line Interface The :mod:`jsonyx` module provides a simple command line interface to validate and pretty-print JSON objects. -If the optional ``filename`` argument is not specified, :data:`sys.stdin` will -be used: - -.. code-block:: shell-session - - $ echo '{"json": "obj"}' | python -m jsonyx --indent 4 - { - "json": "obj" - } - $ echo '{1.2: 3.4}' | python -m jsonyx - File "", line 1, column 2 - {1.2: 3.4} - ^ - jsonyx._decoder.JSONSyntaxError: Expecting string +If the optional ``input_filename`` and ``output_filename`` arguments are not +specified, :data:`sys.stdin` and :data:`sys.stdout` will be used respectively. Command line options ^^^^^^^^^^^^^^^^^^^^ -.. option:: filename +.. option:: input_filename - The JSON file to be validated or pretty-printed: + The path to the input JSON file, or "-" for standard input. .. code-block:: shell-session - $ python -m jsonyx mp_films.json + $ python -m jsonyx mp_films.json --indent 4 [ { "title": "And Now for Something Completely Different", @@ -255,7 +243,9 @@ Command line options } ] - If *filename* is not specified, read from :data:`sys.stdin`. +.. option:: output_filename + + The path to the output JSON file. .. option:: -h, --help diff --git a/pyproject.toml b/pyproject.toml index 4084aee..8c90ddf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "jsonyx" -version = "1.1.0" +version = "1.2.0" authors = [ { name="Nice Zombies", email="nineteendo19d0@gmail.com" }, ] diff --git a/src/jsonyx/tool.py b/src/jsonyx/tool.py index 0be8d81..49323b9 100644 --- a/src/jsonyx/tool.py +++ b/src/jsonyx/tool.py @@ -8,8 +8,8 @@ from sys import stderr, stdin from typing import TYPE_CHECKING -from jsonyx import Decoder, JSONSyntaxError, dump, format_syntax_error -from jsonyx.allow import EVERYTHING, NOTHING, SURROGATES +from jsonyx import Decoder, Encoder, JSONSyntaxError, format_syntax_error +from jsonyx.allow import EVERYTHING, NOTHING if TYPE_CHECKING: from argparse import ArgumentParser @@ -22,9 +22,10 @@ class JSONNamespace: compact: bool ensure_ascii: bool indent: int | str | None - filename: str | None + input_filename: str | None no_commas: bool nonstrict: bool + output_filename: str | None sort_keys: bool trailing_comma: bool use_decimal: bool @@ -96,9 +97,14 @@ def register(parser: ArgumentParser) -> None: help="indent using tabs", ) parser.add_argument( - "filename", + "input_filename", nargs="?", - help="the JSON file to be validated or pretty-printed", + help='the path to the input JSON file, or "-" for standard input', + ) + parser.add_argument( + "output_filename", + nargs="?", + help="the path to the output JSON file", ) @@ -109,23 +115,11 @@ def run(args: JSONNamespace) -> None: :type args: JSONNamespace """ decoder: Decoder = Decoder( - allow=EVERYTHING - SURROGATES if args.nonstrict else NOTHING, + allow=EVERYTHING if args.nonstrict else NOTHING, use_decimal=args.use_decimal, ) - try: - if args.filename: - obj: object = decoder.read(args.filename) - elif stdin.isatty(): - obj = decoder.loads("\n".join(iter(input, "")), filename="") - else: - obj = decoder.load(stdin) - except JSONSyntaxError as exc: - stderr.write("".join(format_syntax_error(exc))) - sys.exit(1) - - dump( - obj, - allow=EVERYTHING - SURROGATES if args.nonstrict else NOTHING, + encoder: Encoder = Encoder( + allow=EVERYTHING if args.nonstrict else NOTHING, ensure_ascii=args.ensure_ascii, indent=args.indent, item_separator=" " if args.no_commas else ( @@ -135,3 +129,18 @@ def run(args: JSONNamespace) -> None: sort_keys=args.sort_keys, trailing_comma=args.trailing_comma, ) + try: + if args.input_filename and args.input_filename != "-": + obj: object = decoder.read(args.input_filename) + elif stdin.isatty(): + obj = decoder.loads("\n".join(iter(input, "")), filename="") + else: + obj = decoder.load(stdin) + except JSONSyntaxError as exc: + stderr.write("".join(format_syntax_error(exc))) + sys.exit(1) + + if args.output_filename: + encoder.write(obj, args.output_filename) + else: + encoder.dump(obj)