Skip to content

Commit

Permalink
Add preserve_block_seqs_indents
Browse files Browse the repository at this point in the history
  • Loading branch information
guibog committed Feb 29, 2024
1 parent 05d641b commit b8c5005
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 4 deletions.
97 changes: 97 additions & 0 deletions _test/test_block_seq_local_indent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

import pytest
import io
import ruyaml # NOQA
from .roundtrip import round_trip, dedent

from ruyaml import YAML
from ruyaml.util import load_yaml_guess_indent
from ruyaml.scalarbool import ScalarBoolean
from ruyaml.comments import CommentedSeq
from ruyaml.representer import RoundTripRepresenter, ScalarNode
from ruyaml.constructor import RoundTripConstructor
from typing import Text, Any, Dict, List # NOQA


def round_trip_stabler(
inp,
outp=None,
):
if outp is None:
outp = inp
doutp = dedent(outp)
yaml = ruyaml.YAML()
yaml.preserve_quotes = True
yaml.preserve_block_seqs_indents = True
data = yaml.load(doutp)
buf = io.StringIO()
yaml.dump(data, stream=buf)
res = buf.getvalue()
assert res == doutp


class TestStability:

def test_blockseq1(self):
round_trip(
"""
a:
- a1
- a2
"""
)

@pytest.mark.xfail(strict=True)
def test_blockseq2(self):
round_trip(
"""
a:
- a1
- a2
"""
)

@pytest.mark.xfail(strict=True)
def test_blockseq3(self):
round_trip(
"""
a:
- a1
- a2
b:
- b1
- b2
"""
)

class TestStabilityStabler:

def test_blockseq1(self):
round_trip_stabler(
"""
a:
- a1
- a2
"""
)

def test_blockseq2(self):
round_trip_stabler(
"""
a:
- a1
- a2
"""
)

def test_blockseq3(self):
round_trip_stabler(
"""
a:
- a1
- a2
b:
- b1
- b2
"""
)
11 changes: 9 additions & 2 deletions lib/ruyaml/emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ def __init__(
top_level_colon_align=None,
prefix_colon=None,
brace_single_entry_mapping_in_flow_sequence=None,
preserve_block_seqs_indents=None,
dumper=None,
):
# type: (StreamType, Any, Optional[int], Optional[int], Optional[bool], Any, Optional[int], Optional[bool], Any, Optional[bool], Any) -> None # NOQA
Expand Down Expand Up @@ -185,6 +186,8 @@ def __init__(
# set to False to get "\Uxxxxxxxx" for non-basic unicode like emojis
self.unicode_supplementary = sys.maxunicode > 0xFFFF
self.sequence_dash_offset = block_seq_indent if block_seq_indent else 0
self.preserve_block_seqs_indents = preserve_block_seqs_indents
self.current_local_block_seq_indent = None
self.top_level_colon_align = top_level_colon_align
self.best_sequence_indent = 2
self.requested_indent = indent # specific for literal zero indent
Expand Down Expand Up @@ -446,6 +449,7 @@ def expect_node(self, root=False, sequence=False, mapping=False, simple_key=Fals
self.expect_scalar()
elif isinstance(self.event, SequenceStartEvent):
# nprint('@', self.indention, self.no_newline, self.column)
self.current_local_block_seq_indent = self.event.block_seq_indent
i2, n2 = self.indention, self.no_newline # NOQA
if self.event.comment:
if self.event.flow_style is False and self.event.comment:
Expand Down Expand Up @@ -669,9 +673,12 @@ def expect_block_sequence_item(self, first=False):
self.write_pre_comment(self.event)
nonl = self.no_newline if self.column == 0 else False
self.write_indent()
ind = self.sequence_dash_offset # if len(self.indents) > 1 else 0
cur_dash_offset = self.sequence_dash_offset
if self.current_local_block_seq_indent and self.preserve_block_seqs_indents:
cur_dash_offset = self.current_local_block_seq_indent
ind = cur_dash_offset # if len(self.indents) > 1 else 0
self.write_indicator(' ' * ind + '-', True, indention=True)
if nonl or self.sequence_dash_offset + 2 > self.best_sequence_indent:
if nonl or cur_dash_offset + 2 > self.best_sequence_indent:
self.no_newline = True
self.states.append(self.expect_block_sequence_item)
self.expect_node(sequence=True)
Expand Down
18 changes: 17 additions & 1 deletion lib/ruyaml/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,23 @@ def __init__(


class SequenceStartEvent(CollectionStartEvent):
__slots__ = ()
__slots__ = ('block_seq_indent', )

def __init__(
self,
anchor,
tag,
implicit,
start_mark=None,
end_mark=None,
flow_style=None,
comment=None,
nr_items=None,
block_seq_indent=None,
):
# type: (Any, Any, Any, Any, Any, Any, Any, Optional[int]) -> None
CollectionStartEvent.__init__(self, anchor, tag, implicit, start_mark, end_mark, flow_style, comment, nr_items)
self.block_seq_indent = block_seq_indent


class SequenceEndEvent(CollectionEndEvent):
Expand Down
2 changes: 2 additions & 0 deletions lib/ruyaml/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def __init__(
self.version = None
self.preserve_quotes = None
self.preserve_bools = None
self.preserve_block_seqs_indents = None
self.allow_duplicate_keys = False # duplicate keys in map, set
self.encoding = 'utf-8'
self.explicit_start = None
Expand Down Expand Up @@ -273,6 +274,7 @@ def emitter(self):
line_break=self.line_break,
prefix_colon=self.prefix_colon,
brace_single_entry_mapping_in_flow_sequence=self.brace_single_entry_mapping_in_flow_sequence, # NOQA
preserve_block_seqs_indents=self.preserve_block_seqs_indents,
dumper=self,
)
setattr(self, attr, _emitter)
Expand Down
18 changes: 17 additions & 1 deletion lib/ruyaml/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,25 @@ def __init__(


class SequenceNode(CollectionNode):
__slots__ = ()
__slots__ = ('block_seq_indent', )
id = 'sequence'

def __init__(
self,
tag,
value,
start_mark=None,
end_mark=None,
flow_style=None,
comment=None,
anchor=None,
):
# type: (Any, Any, Any, Any, Any, Any, Any) -> None
CollectionNode.__init__(
self, tag, value, start_mark, end_mark, flow_style, comment, anchor
)
self.block_seq_indent = None


class MappingNode(CollectionNode):
__slots__ = ('merge',)
Expand Down
11 changes: 11 additions & 0 deletions lib/ruyaml/representer.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,8 +815,19 @@ def represent_sequence(self, tag, sequence, flow_style=None):
node.flow_style = self.default_flow_style
else:
node.flow_style = best_style
self.set_block_seq_indent(node, sequence)
return node

def set_block_seq_indent(self, node, sequence):
local_block_seq_indent = 10000
if not isinstance(sequence, CommentedSeq):
return
if not sequence.lc.data:
return
for lc_item in sequence.lc.data.values():
local_block_seq_indent = min(local_block_seq_indent, lc_item[1] - 2) # Why '2'?
node.block_seq_indent = local_block_seq_indent

def merge_comments(self, node, comments):
# type: (Any, Any) -> Any
if comments is None:
Expand Down
1 change: 1 addition & 0 deletions lib/ruyaml/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ def serialize_node(self, node, parent, index):
implicit,
flow_style=node.flow_style,
comment=node.comment,
block_seq_indent=node.block_seq_indent,
)
)
index = 0
Expand Down

0 comments on commit b8c5005

Please sign in to comment.