Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider support for yaml (using ruamel.yaml) #136

Open
cmungall opened this issue Sep 18, 2021 · 2 comments
Open

Consider support for yaml (using ruamel.yaml) #136

cmungall opened this issue Sep 18, 2021 · 2 comments

Comments

@cmungall
Copy link

My use case:

  1. I want to use the awesome jsonpatch on yaml files
  2. I wish to preserve yaml comments

This is actually very easy to do with minimal code using ruamel (which preserves comments, unlike pyyaml):

import sys
from ruamel.yaml import YAML

inp = """\
# example
name:
  # details
  family: Smith   # very common
  given: Alice    # one of the siblings
"""

yaml = YAML()
obj = yaml.load(inp)
patch = JsonPatch([
    {'op': 'add', 'path': '/foo', 'value': {'bar': 'baz'}},
    {'op': 'remove', 'path': '/name/family'}
])
obj = patch.apply(obj)
yaml.dump(obj, sys.stdout)

yields:

# example
name:
  # details
  given: Alice    # one of the siblings
foo:
  bar: baz

which is nice

I would like to put a convenient (if trivial) interface on top of this. I could

  1. Make a new pypi module python-yaml-patch that has this trivial wrapping code, plus CLI bindings
  2. Make a PR on this repo

I suspect (1) would be preferred but thought I would check first. Feel free to close this issue, and I will go ahead with (1), and post a link here when done.

Aside:

I note there is a lib https://github.com/krishicks/yaml-patch from @krishicks but this seems abandoned, and also duplicative. If I go ahead with (1) I wouldn't duplicate any code, just wrap as in the example above

There is also https://github.com/campos-ddc/yaml-patch from @campos-ddc which looks great, but this isn't intended to support the json-patch standard

@stefankoegl
Copy link
Owner

Hi! Thanks for your input!

As far as I know (I don't use YAML regularly, though) YAML is another serialization for similar structures (nested dict/list like) than JSON. As YAML objects can be used through indexing, and as your example shows, it already works with jsonpatch. Therefore I am not quite sure which additional functionality you'd need. Can you give some example?

@bobvanderlinden
Copy link

bobvanderlinden commented Aug 5, 2024

I do have to say that jsonpatch is quite compatible in most cases. It's great for patching yaml with minimal syntactic changes 👍

That said, I think I ran into an issue when combining ruamel.yaml with make_patch. This is an example that reproduces the problem:

from ruamel.yaml import YAML
import jsonpatch

yaml = YAML()
src = yaml.load("""
- a
- b
- c
""")

dst = yaml.load("""
- b
- c
""")
p = jsonpatch.make_patch(src, dst)
print(p.to_string())

This results in:

[{"op": "remove", "path": "/0"}, {"op": "move", "from": "/1", "path": "/0"}, {"op": "move", "from": "/2", "path": "/1"}]

This will thus fail jsonpatch.apply_patch(src, p).

I think this is because dst is of type ruamel.yaml.comments.CommentedSeq. Having the dst be a normal list it works fine (even though src is still of type ruamel.yaml.comments.CommentedSeq). I'm guessing ruamel.yaml.comments.CommentedSeq is interpreted as a dict-like by jsonpatch?

My current workaround is to convert all values to normal dict/lists:

def deep_copy(value: JSON) -> JSON:
    match value:
        case dict(value_dict):
            return {key: deep_copy(value) for key, value in value_dict.items()}
        case list(value_list):
            return [deep_copy(value) for value in value_list]
        case str() | int() | float() | bool() | None:
            return value
        case _:
            raise ValueError(f"Invalid JSON type: {type(value)}")


src = deep_copy(src)
dst = deep_copy(dst)

Note that copy.deepcopy won't work, as it still will be a ruamel.yaml`-specific type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants