Skip to content

maxx27/pyyaml-sort

Repository files navigation

PyYAML

PyYAML doesn't support comments:

import sys
import yaml

yaml_str = """\
# comment 1
line 1: one # comment 2
# comment 3
"""

obj = yaml.load(yaml_str, Loader=yaml.FullLoader)
yaml.dump(obj, sys.stdout)

Output is:

line 1: one

ruamel.yaml

ruamel.yaml supports comments:

import sys
import ruamel.yaml

yaml_str = """\
# comment 1
line 1: one # comment 2
# comment 3
"""

yaml = ruamel.yaml.YAML()
obj = yaml.load(yaml_str)
yaml.dump(obj, sys.stdout)

Output is:

# comment 1
line 1: one # comment 2
# comment 3

Sorting YAML with comments

Comments are not documented well (unfortunately). So many information was acquired from StackOverflow user Anthon:

(if you don't have ruamel.yaml installed you can find sources for comments here)

But I found this question without answer and I need this too. So this gist is my answer.

Main point about comments that in ruamel.yaml they refer to the current line or line above:

- one # comment to the current line
# comment to the line above
- two

But many people consider them in different way:

- one # comment to the current line
# comment to the line below
- two

Sorting this way requires more efforts.

Sorting dict and list

Use function map_sort_before to sort maps:

import sys

import ruamel.yaml
from comments_sort import map_sort_before

yaml = ruamel.yaml.YAML()

yaml_str = """\
# comment 3.1
line 3: three  # comment 3.2
line 2:
  # comment
  line 2.2: two-two
line 1: one
 # last comment
"""

obj = yaml.load(yaml_str)
sorted_keys = sorted(
    list(obj.keys()),
    key=lambda x: x,
)
obj_sorted = map_sort_before(obj, sorted_keys)
yaml.dump(obj_sorted, sys.stdout)

Output is:

line 1: one
line 2:
  # comment
  line 2.2: two-two
# comment 3.1
line 3: three  # comment 3.2
 # last comment

Use function seq_sort_before and sorted_index to sort sequences:

import sys

import ruamel.yaml
from comments_sort import seq_sort_before, sorted_index

yaml = ruamel.yaml.YAML()
yaml_str = """\
  # comment 2.1
- line 2 # comment 2.2
# comment 1
- line 1
- line 4   # comment 4
- line 3
# last comment
"""

obj = yaml.load(yaml_str)
obj_sorted = seq_sort_before(obj, sorted_index(obj))
yaml.dump(obj_sorted, sys.stdout)

Output is:

# comment 1
- line 1
  # comment 2.1
- line 2 # comment 2.2
- line 3
- line 4   # comment 4
# last comment

sorted_index is a helper function that returns new indices to construct new sequence. See the description of the function for more details.

Some critics for the implementation

You must provide sort information in advance (as argument for the functions) because you construct new YAML object while sorting. I tried an implementation with sorting parameters (to call sorted inside the functions) but I don't like how it looks.

Pairs of functions are very similar:

  • _get_map_comments and _get_seq_comments
  • map_sort_before and seq_sort_before

It could be implemented using DRY.

About

A few methods to sort you YAML

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages