Skip to content

Commit

Permalink
Add --max-indent-leaves and its alias -L
Browse files Browse the repository at this point in the history
  • Loading branch information
nineteendo committed Nov 27, 2024
1 parent b31f897 commit fc8bd8b
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 57 deletions.
1 change: 1 addition & 0 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jsonyx 2.0.0 (unreleased)
:func:`jsonyx.write`
- Added ``python -m jsonyx diff`` and ``python -m jsonyx patch``
- Added ``--indent-leaves`` and its alias ``-l`` to ``python -m jsonyx format``
- Added ``--max-indent-level`` and its alias ``-L`` to ``python -m jsonyx format``
- Added ``--unquoted-keys`` and its alias ``-q`` to ``python -m jsonyx format``
- Added ``--version`` and its alias ``-v`` to ``python -m jsonyx``
- Added :data:`jsonyx.allow.UNQUOTED_KEYS`
Expand Down
4 changes: 4 additions & 0 deletions docs/source/cli/jsonyx-diff.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ Options

Indent leaf objects and arrays.

.. option:: -L, --max-indent-level

The level up to which to indent.

.. option:: -q, --unquoted-keys

Don't quote keys which are identifiers.
Expand Down
4 changes: 4 additions & 0 deletions docs/source/cli/jsonyx-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ Options

Indent leaf objects and arrays.

.. option:: -L, --max-indent-level

The level up to which to indent.

.. option:: -q, --unquoted-keys

Don't quote keys which are identifiers.
Expand Down
4 changes: 4 additions & 0 deletions docs/source/cli/jsonyx-patch.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ Options

Indent leaf objects and arrays.

.. option:: -L, --max-indent-level

The level up to which to indent.

.. option:: -q, --unquoted-keys

Don't quote keys which are identifiers.
Expand Down
7 changes: 4 additions & 3 deletions docs/source/get-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,16 @@ Pretty printing
.. versionchanged:: 2.0 Added ``indent_leaves`` and ``max_indent_level``.

>>> import jsonyx as json
>>> json.dump({"foo": [1, 2, 3], "bar": {"a": 1, "b": 2, "c": 3}}, indent=4)
>>> obj = {"foo": [1, 2, 3], "bar": {"a": 1, "b": 2, "c": 3}}
>>> json.dump(obj, indent=4, indent_leaves=False)
{
"foo": [1, 2, 3],
"bar": {"a": 1, "b": 2, "c": 3}
}

.. tip:: Use ``ensure_ascii=True`` to escape non-ASCII characters,
``indent_leaves=True`` to indent everything, ``max_indent_level=1`` to
indent up to level 1, and ``sort_keys=True`` to sort the keys of objects.
``max_indent_level=1`` to indent up to level 1, and ``sort_keys=True``
to sort the keys of objects.

.. seealso:: The built-in :mod:`pprint` module for pretty-printing arbitrary
Python data structures.
Expand Down
6 changes: 3 additions & 3 deletions src/jsonyx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def write(
end: str = "\n",
ensure_ascii: bool = False,
indent: int | str | None = None,
indent_leaves: bool = False,
indent_leaves: bool = True,
mapping_types: type | tuple[type, ...] = (),
max_indent_level: int | None = None,
quoted_keys: bool = True,
Expand Down Expand Up @@ -308,7 +308,7 @@ def dump(
end: str = "\n",
ensure_ascii: bool = False,
indent: int | str | None = None,
indent_leaves: bool = False,
indent_leaves: bool = True,
mapping_types: type | tuple[type, ...] = (),
max_indent_level: int | None = None,
quoted_keys: bool = True,
Expand Down Expand Up @@ -388,7 +388,7 @@ def dumps(
end: str = "\n",
ensure_ascii: bool = False,
indent: int | str | None = None,
indent_leaves: bool = False,
indent_leaves: bool = True,
mapping_types: type | tuple[type, ...] = (),
max_indent_level: int | None = None,
quoted_keys: bool = True,
Expand Down
9 changes: 8 additions & 1 deletion src/jsonyx/__main__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env python
# Copyright (C) 2024 Nice Zombies
"""A command line utility to manipulate JSON files."""
# TODO(Nice Zombies): add --max-indent-level
from __future__ import annotations

__all__: list[str] = ["main"]
Expand All @@ -28,6 +27,7 @@ class _Namespace:
indent: int | str | None
indent_leaves: bool
input_filename: str | None
max_indent_level: int | None
quoted_keys: bool
nonstrict: bool
output_filename: str | None
Expand Down Expand Up @@ -92,6 +92,12 @@ def _configure(parser: ArgumentParser) -> None:
action="store_true",
help="indent leaf objects and arrays",
)
parent_parser.add_argument(
"-L",
"--max-indent-level",
type=int,
help="the level up to which to indent",
)
parent_parser.add_argument(
"-s",
"--sort-keys",
Expand Down Expand Up @@ -198,6 +204,7 @@ def _run(args: _Namespace) -> None:
ensure_ascii=args.ensure_ascii,
indent=args.indent,
indent_leaves=args.indent_leaves,
max_indent_level=args.max_indent_level,
quoted_keys=args.quoted_keys,
separators=(",", ":") if args.compact else (", ", ": "),
sort_keys=args.sort_keys,
Expand Down
2 changes: 1 addition & 1 deletion src/jsonyx/_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ def __init__(
end: str = "\n",
ensure_ascii: bool = False,
indent: int | str | None = None,
indent_leaves: bool = False,
indent_leaves: bool = True,
mapping_types: type | tuple[type, ...] = (),
max_indent_level: int | None = None,
quoted_keys: bool = True,
Expand Down
89 changes: 40 additions & 49 deletions src/jsonyx/test/test_dumps.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,17 +206,6 @@ def test_list(json: ModuleType, obj: list[object], expected: str) -> None:
assert json.dumps(obj, end="") == expected


@pytest.mark.parametrize(("obj", "expected"), [
([1, 2, 3], "[1, 2, 3]"),
([[1, 2, 3]], "[\n [1, 2, 3]\n]"),
])
def test_list_indent(
json: ModuleType, obj: list[object], expected: str,
) -> None:
"""Test list indent."""
assert json.dumps(obj, end="", indent=1) == expected


@pytest.mark.parametrize(("indent", "expected"), [
# Integer
(0, ""),
Expand All @@ -225,19 +214,29 @@ def test_list_indent(
# String
("\t", "\t"),
])
def test_list_indent_leaves(
def test_list_indent(
json: ModuleType, indent: int | str, expected: str,
) -> None:
"""Test list indent with indent_leaves."""
s: str = json.dumps([1, 2, 3], end="", indent=indent, indent_leaves=True)
"""Test list indent."""
s: str = json.dumps([1, 2, 3], end="", indent=indent)
assert s == f"[\n{expected}1,\n{expected}2,\n{expected}3\n]"


@pytest.mark.parametrize(("obj", "expected"), [
([1, 2, 3], "[1, 2, 3]"),
([[1, 2, 3]], "[\n [1, 2, 3]\n]"),
])
def test_list_indent_leaves(
json: ModuleType, obj: list[object], expected: str,
) -> None:
"""Test list indent without indent_leaves."""
assert json.dumps(obj, end="", indent=1, indent_leaves=False) == expected


def test_list_max_indent_level(json: ModuleType) -> None:
"""Test list indent with max_indent_level and indent_leaves."""
assert json.dumps(
[[1, 2, 3]], end="", indent=1, indent_leaves=True, max_indent_level=1,
) == "[\n [1, 2, 3]\n]"
"""Test list indent with max_indent_level."""
s: str = json.dumps([[1, 2, 3]], end="", indent=1, max_indent_level=1)
assert s == "[\n [1, 2, 3]\n]"


def test_list_recursion(json: ModuleType) -> None:
Expand Down Expand Up @@ -388,17 +387,6 @@ def test_sort_keys(json: ModuleType) -> None:
assert s == '{"a": 1, "b": 2, "c": 3}'


@pytest.mark.parametrize(("obj", "expected"), [
({"a": 1, "b": 2, "c": 3}, '{"a": 1, "b": 2, "c": 3}'),
({"": {"a": 1, "b": 2, "c": 3}}, '{\n "": {"a": 1, "b": 2, "c": 3}\n}'),
])
def test_dict_indent(
json: ModuleType, obj: dict[str, object], expected: str,
) -> None:
"""Test dict indent."""
assert json.dumps(obj, end="", indent=1) == expected


@pytest.mark.parametrize(("indent", "expected"), [
# Integer
(0, ""),
Expand All @@ -407,23 +395,33 @@ def test_dict_indent(
# String
("\t", "\t"),
])
def test_dict_indent_leaves(
def test_dict_indent(
json: ModuleType, indent: int | str, expected: str,
) -> None:
"""Test dict indent with indent_leaves."""
"""Test dict indent."""
obj: dict[str, object] = {"a": 1, "b": 2, "c": 3}
s: str = json.dumps(obj, end="", indent=indent, indent_leaves=True)
s: str = json.dumps(obj, end="", indent=indent)
assert s == (
f'{{\n{expected}"a": 1,\n{expected}"b": 2,\n{expected}"c": 3\n}}'
)


@pytest.mark.parametrize(("obj", "expected"), [
({"a": 1, "b": 2, "c": 3}, '{"a": 1, "b": 2, "c": 3}'),
({"": {"a": 1, "b": 2, "c": 3}}, '{\n "": {"a": 1, "b": 2, "c": 3}\n}'),
])
def test_dict_indent_leaves(
json: ModuleType, obj: dict[str, object], expected: str,
) -> None:
"""Test dict indent without indent_leaves."""
assert json.dumps(obj, end="", indent=1, indent_leaves=False) == expected


def test_dict_max_indent_level(json: ModuleType) -> None:
"""Test dict indent with max_indent_level and indent_leaves."""
"""Test dict indent with max_indent_level."""
obj: dict[str, object] = {"": {"a": 1, "b": 2, "c": 3}}
assert json.dumps(
obj, end="", indent=1, indent_leaves=True, max_indent_level=1,
) == '{\n "": {"a": 1, "b": 2, "c": 3}\n}'
s: str = json.dumps(obj, end="", indent=1, max_indent_level=1)
assert s == '{\n "": {"a": 1, "b": 2, "c": 3}\n}'


def test_dict_recursion(json: ModuleType) -> None:
Expand Down Expand Up @@ -478,20 +476,15 @@ def test_no_commas(
({"a": 1, "b": 2, "c": 3}, '{\n "a": 1\n "b": 2\n "c": 3\n}'),
])
@pytest.mark.parametrize("trailing_comma", [True, False])
def test_no_commas_indent_leaves(
def test_no_commas_indent(
json: ModuleType,
obj: dict[str, object] | list[object],
expected: str,
trailing_comma: bool, # noqa: FBT001
) -> None:
"""Test no commas with indent and indent_leaves."""
"""Test no commas with indent."""
assert json.dumps(
obj,
commas=False,
end="",
indent=1,
indent_leaves=True,
trailing_comma=trailing_comma,
obj, commas=False, end="", indent=1, trailing_comma=trailing_comma,
) == expected


Expand Down Expand Up @@ -531,10 +524,8 @@ def test_trailing_comma(
([1, 2, 3], "[\n 1,\n 2,\n 3,\n]"),
({"a": 1, "b": 2, "c": 3}, '{\n "a": 1,\n "b": 2,\n "c": 3,\n}'),
])
def test_trailing_comma_indent_leaves(
def test_trailing_comma_indent(
json: ModuleType, obj: dict[str, object] | list[object], expected: str,
) -> None:
"""Test trailing_comma with indent and indent_leaves."""
assert json.dumps(
obj, end="", indent=1, indent_leaves=True, trailing_comma=True,
) == expected
"""Test trailing_comma with indent."""
assert json.dumps(obj, end="", indent=1, trailing_comma=True) == expected

0 comments on commit fc8bd8b

Please sign in to comment.