Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Testing and configuration is based on [Poetry](https://python-poetry.org) and is
You should also verify that existing [tests](./tests) are still working and you are encouraged to add new ones. You are also encouraged to add tests that at least maintain the current level of code coverage. You can run the tests using the following commands from the root folder:

```bash
poetry install # Only required the first time
poetry run pytest
```

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ When installed from `pip` a command-line utility `compact-json` is installed whi

``` shell
usage: compact-json [-h] [-V]
[--output-filename [OUTPUT_FILENAME ...]]
[--output [OUTPUT_FILENAME ...]]
[--crlf] [--max-inline-length N]
[--max-inline-complexity N]
[--max-compact-list-complexity N]
Expand All @@ -140,10 +140,11 @@ positional arguments:
optional arguments:
-h, --help show this help message and exit
-V, --version
--output-filename [OUTPUT_FILENAME ...], -out [OUTPUT_FILENAME ...]
--output [OUTPUT_FILENAME ...], -out [OUTPUT_FILENAME ...]
The output file name(s). If empty, no new JSON file(s)
will be saved. If provided, the number of output file
names must match that of the input files.
--in-place Save any edits back to the input file
--crlf Use Windows-style CRLF line endings
--max-inline-length N
Limit inline elements to N chars, excluding
Expand Down
50 changes: 36 additions & 14 deletions src/compact_json/_compact_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,21 @@ def command_line_parser() -> argparse.ArgumentParser:
)
parser.add_argument("-V", "--version", action="store_true")

parser.add_argument(
out_group = parser.add_mutually_exclusive_group()
out_group.add_argument(
"--output",
"-o",
action="append",
help="The output file name(s). The number of output file names must match "
"the number of input files.",
)
out_group.add_argument(
"--in-place",
action="store_true",
default=False,
help="Save any edits back to the input file",
)

parser.add_argument(
"--align-expanded-property-names",
action="store_true",
Expand Down Expand Up @@ -161,7 +169,6 @@ def command_line_parser() -> argparse.ArgumentParser:
parser.add_argument(
"json",
nargs="*",
type=argparse.FileType("r"),
help='JSON file(s) to parse (or stdin with "-")',
)
return parser
Expand Down Expand Up @@ -222,21 +229,36 @@ def die(message: str) -> None:
line_ending = "\r\n" if args.crlf else "\n"

in_files = args.json
out_files = args.output

if out_files is None:
for fh in args.json:
obj = json.load(fh)
json_string = formatter.serialize(obj)
print(json_string, end=line_ending)
return
if args.in_place:
out_files = args.json
elif args.output is None:
out_files = [None] * len(in_files)
else:
if len(in_files) != len(args.output):
die("the numbers of input and output file names do not match")
out_files = args.output

for fn_in, fn_out in zip(in_files, out_files):
if fn_in == "-":
in_json_string = sys.stdin.read()
else:
try:
in_json_string = open(fn_in, "r").read()
except FileNotFoundError as ex:
die(ex)

try:
obj = json.loads(in_json_string)
except Exception as ex:
die("While reading {}: {}".format(fn_in, ex))

if len(in_files) != len(out_files):
die("the numbers of input and output file names do not match")
out_json_string = formatter.serialize(obj) + line_ending

for fn_in, fn_out in zip(args.json, args.output):
obj = json.load(fn_in)
json_string = formatter.dump(obj, output_file=fn_out)
if fn_out is None:
sys.stdout.write(out_json_string)
elif not args.in_place or in_json_string != out_json_string:
open(fn_out, "w").write(out_json_string)


if __name__ == "__main__": # pragma: no cover
Expand Down