Skip to content
Merged
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
35 changes: 35 additions & 0 deletions cels/cli/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@
type=click.Path(dir_okay=False, writable=True, path_type=Path),
help="File to write the result to. If not provided, STDOUT is used.",
)
@click.option(
"-I",
"--in-place",
is_flag=True,
help="Overwrite the input file with the patched result.",
)
@click.option(
"--indent",
default=default.indent,
type=click.INT,
help="Indent to use in the output file.",
)
@click.option(
"--sort-keys",
is_flag=True,
help="Sort dictionary keys alphabetically in the output file (only for JSON and YAML).",
)
@click.option(
"--separator",
default=default.separator,
Expand Down Expand Up @@ -95,6 +112,9 @@ def cels_patch(
input_format,
patch_format,
output_format,
in_place,
indent,
sort_keys,
separator,
left_marker,
index_marker,
Expand Down Expand Up @@ -133,6 +153,19 @@ def cels_patch(
output_format = input_format
output_format = output_format.lower()

# set output file
if in_place:
if output_file != Path("-"):
raise click.UsageError(
"Options --in-place and --output-file are mutually exclusive."
)
elif input_format != output_format:
raise click.UsageError(
"Options --output-format can't be different from the input format when --in-place is used."
)
else:
output_file = input_file

# compose output
input_text = input_file.read_text(encoding="utf-8")
patch_text = patch_file.read_text(encoding="utf-8")
Expand All @@ -143,6 +176,8 @@ def cels_patch(
patch_format=patch_format,
patch_text=patch_text,
output_format=output_format,
indent=indent,
sort_keys=sort_keys,
separator=separator,
left_marker=left_marker,
index_marker=index_marker,
Expand Down
2 changes: 2 additions & 0 deletions cels/default.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
indent = 2
sort_keys = False
separator = " "
left_marker = "{"
index_marker = "@"
Expand Down
3 changes: 3 additions & 0 deletions cels/lib/json_dumps/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .dumpers import json_dumps

__all__ = ["json_dumps"]
6 changes: 6 additions & 0 deletions cels/lib/json_dumps/dumpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import json


def json_dumps(*args, **kwargs):
"""Customize the standard Python JSON dumper."""
return json.dumps(*args, **kwargs) + "\n"
33 changes: 22 additions & 11 deletions cels/services/patch_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from cels.exceptions import CelsInputError
from cels.lib.yaml_parsing import SafePreserveTagLoader
from cels.lib.yaml_parsing import SafePreserveTagDumper
from cels.lib.json_dumps import json_dumps

from .patch_dictionary import patch_dictionary

Expand All @@ -34,20 +35,10 @@

dump_functions: Dict[str, Callable] = {
"yaml": yaml.dump,
"json": json.dumps,
"json": json_dumps,
"toml": tomli_w.dumps,
}

dump_parameters: Dict[str, Dict[str, Any]] = {
"yaml": {
"Dumper": SafePreserveTagDumper,
"sort_keys": False,
"allow_unicode": True,
},
"json": {"indent": 2, "ensure_ascii": False},
"toml": {},
}


serialize_exceptions = (yaml.YAMLError, ValueError, TypeError)
deserialize_exceptions = (yaml.YAMLError, toml.TOMLDecodeError, json.JSONDecodeError)
Expand All @@ -59,16 +50,36 @@ def patch_document(
patch_format: str,
patch_text: str,
output_format: str,
indent: int = default.indent,
sort_keys: bool = default.sort_keys,
separator: str = default.separator,
left_marker: str = default.left_marker,
index_marker: str = default.index_marker,
right_marker: str = default.right_marker,
) -> str:
"""Patch a text-based structured document."""

# all parameters
dump_parameters: Dict[str, Dict[str, Any]] = {
"yaml": {
"Dumper": SafePreserveTagDumper,
"indent": indent,
"sort_keys": sort_keys,
"allow_unicode": True,
},
"json": {"indent": indent, "sort_keys": sort_keys, "ensure_ascii": False},
"toml": {
"indent": indent,
},
}

# get input dictionary
try:
parameters = load_parameters[input_format]
if "indent" in parameters:
parameters["indent"] = indent
if "sort_keys" in parameters:
parameters["sort_keys"] = sort_keys
input_dict = load_functions[input_format](input_text, **parameters) or {}
except KeyError:
raise CelsInputError(
Expand Down
19 changes: 6 additions & 13 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,19 @@ export PYTHONPATH := project_dir
just --list

@test-all:
pytest --capture=no -o log_cli=false tests/
uv run pytest --capture=no -o log_cli=false tests/

@test *params:
pytest -x --capture=no -o log_cli=true {{ params }}
uv run pytest -x --capture=no -o log_cli=true {{ params }}

@format:
black {{ project_dir }}
uv run black {{ project_dir }}

@type-check:
mypy {{ project_dir }}/cels/
uv run mypy {{ project_dir }}/cels/

@cli:
ipython
uv run ipython

@setup:
pip install -e ".[dev]"

run *params:
#!/usr/bin/env python3
from cels.cli import cels
params = "{{ params }}".split()
cels(params)

uv run pip install -e ".[dev]"
6 changes: 0 additions & 6 deletions requirements-dev.txt

This file was deleted.

2 changes: 1 addition & 1 deletion tests/_fixtures/full-example-json/result.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@
},
"rendered": "some-text-100!",
"only_in_patch": 2
}
}
78 changes: 39 additions & 39 deletions tests/_fixtures/full-example-toml/result.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,65 @@ in_both = 3
in_both_but_changed = 5
"new name" = 100
multiple = [
"b",
"c",
"b",
"c",
]
list1 = [
"foo",
"foo",
[
"one",
[
"one",
[
"up",
"mid",
100,
],
"three",
"up",
"mid",
100,
],
"baz",
"three",
],
"baz",
]
"list2.1" = [
"a",
"b",
"c",
"a",
"b",
"c",
]
"list3.1" = [
"a",
"c",
"b",
"a",
"c",
"b",
]
"list4.1" = [
"foo",
"foo",
[
"one",
[
"one",
[
"up",
"mid",
"down",
100,
],
"up",
"mid",
"down",
100,
],
],
]
"list2.2" = [
"a",
"b",
"c",
"a",
"b",
"c",
]
"list3.2" = [
"a",
"c",
"b",
"a",
"c",
"b",
]
"list4.2" = [
"foo",
"foo",
[
"one",
[
"one",
[
"up",
"mid",
"down",
100,
],
"up",
"mid",
"down",
100,
],
],
]
rendered = "some-text-100!"
only_in_patch = 2
Expand Down
Loading