From a4806d4d15f81571b930926b777206c2441d0572 Mon Sep 17 00:00:00 2001 From: guibog Date: Thu, 29 Feb 2024 15:17:18 +0800 Subject: [PATCH 1/4] Hide flake --- _test/lib/test_appliance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_test/lib/test_appliance.py b/_test/lib/test_appliance.py index bdcafc7..bb291ef 100644 --- a/_test/lib/test_appliance.py +++ b/_test/lib/test_appliance.py @@ -141,7 +141,7 @@ def display(results, verbose): sys.stdout.write('=' * 75 + '\n') sys.stdout.write('%s(%s): %s\n' % (name, ', '.join(filenames), kind)) if kind == 'ERROR': - traceback.print_exception(file=sys.stdout, *info) + traceback.print_exception(file=sys.stdout, *info) # NOQA else: sys.stdout.write('Traceback (most recent call last):\n') traceback.print_tb(info[2], file=sys.stdout) From 05d641bb63087086b2b729381c3ec220c6f3146e Mon Sep 17 00:00:00 2001 From: guibog Date: Wed, 28 Feb 2024 18:36:05 +0800 Subject: [PATCH 2/4] Add preserve_bools --- _test/test_bools.py | 77 +++++++++++++++++++++++++++++++++++++++ lib/ruyaml/constructor.py | 7 ++-- lib/ruyaml/main.py | 5 ++- lib/ruyaml/representer.py | 17 +++++---- lib/ruyaml/scalarbool.py | 5 +++ 5 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 _test/test_bools.py diff --git a/_test/test_bools.py b/_test/test_bools.py new file mode 100644 index 0000000..d6620b3 --- /dev/null +++ b/_test/test_bools.py @@ -0,0 +1,77 @@ + +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_bools = True + data = yaml.load(doutp) + buf = io.StringIO() + yaml.dump(data, stream=buf) + res = buf.getvalue() + assert res == doutp + + +class TestStability: + + def test_lowercase_boolean(self): + round_trip( + """ + - true + """ + ) + + @pytest.mark.xfail(strict=True) + def test_uppercase_boolean(self): + round_trip( + """ + - True + """ + ) + + # @pytest.mark.xfail(strict=True) # Why not failing?? + def test_yes_boolean(self): + round_trip( + """ + - yes + """ + ) + + def test_lowercase_boolean2(self): + round_trip_stabler( + """ + - true + """ + ) + + def test_uppercase_boolean2(self): + round_trip_stabler( + """ + - True + """ + ) + + def test_yes_boolean2(self): + round_trip_stabler( + """ + - yes + """ + ) diff --git a/lib/ruyaml/constructor.py b/lib/ruyaml/constructor.py index 2c89807..104a090 100644 --- a/lib/ruyaml/constructor.py +++ b/lib/ruyaml/constructor.py @@ -75,7 +75,7 @@ class BaseConstructor: yaml_constructors = {} # type: Dict[Any, Any] yaml_multi_constructors = {} # type: Dict[Any, Any] - def __init__(self, preserve_quotes=None, loader=None): + def __init__(self, preserve_quotes=None, loader=None, preserve_bools=None): # type: (Optional[bool], Any) -> None self.loader = loader if ( @@ -91,6 +91,7 @@ def __init__(self, preserve_quotes=None, loader=None): self.state_generators = [] # type: List[Any] self.deep_construct = False self._preserve_quotes = preserve_quotes + self._preserve_bools = preserve_bools self.allow_duplicate_keys = False @property @@ -1862,8 +1863,8 @@ def construct_yaml_timestamp(self, node, values=None): def construct_yaml_bool(self, node): # type: (Any) -> Any b = SafeConstructor.construct_yaml_bool(self, node) - if node.anchor: - return ScalarBoolean(b, anchor=node.anchor) + if node.anchor or self._preserve_bools: + return ScalarBoolean(b, anchor=node.anchor, orig_repr=node.value) return b diff --git a/lib/ruyaml/main.py b/lib/ruyaml/main.py index 4e54d2b..fd0a4fb 100644 --- a/lib/ruyaml/main.py +++ b/lib/ruyaml/main.py @@ -168,6 +168,7 @@ def __init__( self.prefix_colon = None self.version = None self.preserve_quotes = None + self.preserve_bools = None self.allow_duplicate_keys = False # duplicate keys in map, set self.encoding = 'utf-8' self.explicit_start = None @@ -242,7 +243,9 @@ def constructor(self): # type: () -> Any attr = '_' + sys._getframe().f_code.co_name if not hasattr(self, attr): - cnst = self.Constructor(preserve_quotes=self.preserve_quotes, loader=self) + cnst = self.Constructor(preserve_quotes=self.preserve_quotes, + preserve_bools=self.preserve_bools, + loader=self) cnst.allow_duplicate_keys = self.allow_duplicate_keys setattr(self, attr, cnst) return getattr(self, attr) diff --git a/lib/ruyaml/representer.py b/lib/ruyaml/representer.py index 5ce9855..d332e19 100644 --- a/lib/ruyaml/representer.py +++ b/lib/ruyaml/representer.py @@ -254,13 +254,16 @@ def represent_binary(self, data): def represent_bool(self, data, anchor=None): # type: (Any, Optional[Any]) -> Any - try: - value = self.dumper.boolean_representation[bool(data)] # type: ignore - except AttributeError: - if data: - value = 'true' - else: - value = 'false' + if getattr(data, 'yaml_orig_repr', None) is not None: + value = data.yaml_orig_repr + else: + try: + value = self.dumper.boolean_representation[bool(data)] # type: ignore + except AttributeError: + if data: + value = 'true' + else: + value = 'false' return self.represent_scalar('tag:yaml.org,2002:bool', value, anchor=anchor) def represent_int(self, data): diff --git a/lib/ruyaml/scalarbool.py b/lib/ruyaml/scalarbool.py index 8cae835..6da413b 100644 --- a/lib/ruyaml/scalarbool.py +++ b/lib/ruyaml/scalarbool.py @@ -18,10 +18,15 @@ class ScalarBoolean(int): + yaml_orig_repr = None + def __new__(cls, *args, **kw): # type: (Any, Any, Any) -> Any anchor = kw.pop('anchor', None) + orig_repr = kw.pop('orig_repr', None) b = int.__new__(cls, *args, **kw) + if orig_repr is not None: + b.yaml_orig_repr = orig_repr if anchor is not None: b.yaml_set_anchor(anchor, always_dump=True) return b From 91aeca40161222eac39a53958d7b5064fc6757dc Mon Sep 17 00:00:00 2001 From: guibog Date: Thu, 29 Feb 2024 15:15:25 +0800 Subject: [PATCH 3/4] Add preserve_block_seqs_indents --- _test/test_block_seq_local_indent.py | 97 ++++++++++++++++++++++++++++ lib/ruyaml/emitter.py | 13 +++- lib/ruyaml/events.py | 18 +++++- lib/ruyaml/main.py | 2 + lib/ruyaml/nodes.py | 18 +++++- lib/ruyaml/representer.py | 11 ++++ lib/ruyaml/serializer.py | 1 + 7 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 _test/test_block_seq_local_indent.py diff --git a/_test/test_block_seq_local_indent.py b/_test/test_block_seq_local_indent.py new file mode 100644 index 0000000..2185c87 --- /dev/null +++ b/_test/test_block_seq_local_indent.py @@ -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 + """ + ) diff --git a/lib/ruyaml/emitter.py b/lib/ruyaml/emitter.py index d5fe1a1..dfaa427 100644 --- a/lib/ruyaml/emitter.py +++ b/lib/ruyaml/emitter.py @@ -117,9 +117,10 @@ 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 + # type: (StreamType, Any, Optional[int], Optional[int], Optional[bool], Any, Optional[int], Optional[bool], Any, Optional[bool], Optional[bool], Any) -> None # NOQA self.dumper = dumper if self.dumper is not None and getattr(self.dumper, '_emitter', None) is None: self.dumper._emitter = self @@ -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 @@ -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: @@ -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) diff --git a/lib/ruyaml/events.py b/lib/ruyaml/events.py index 558d2db..e5836fe 100644 --- a/lib/ruyaml/events.py +++ b/lib/ruyaml/events.py @@ -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, + block_seq_indent=None, + nr_items=None, + ): + # type: (Any, 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): diff --git a/lib/ruyaml/main.py b/lib/ruyaml/main.py index fd0a4fb..19288c9 100644 --- a/lib/ruyaml/main.py +++ b/lib/ruyaml/main.py @@ -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 @@ -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) diff --git a/lib/ruyaml/nodes.py b/lib/ruyaml/nodes.py index e9c0188..311f329 100644 --- a/lib/ruyaml/nodes.py +++ b/lib/ruyaml/nodes.py @@ -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',) diff --git a/lib/ruyaml/representer.py b/lib/ruyaml/representer.py index d332e19..29812f5 100644 --- a/lib/ruyaml/representer.py +++ b/lib/ruyaml/representer.py @@ -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: diff --git a/lib/ruyaml/serializer.py b/lib/ruyaml/serializer.py index 9f9425f..83742d0 100644 --- a/lib/ruyaml/serializer.py +++ b/lib/ruyaml/serializer.py @@ -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 From c9a2091208870e012109d75baf391e225efd5a0c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 08:01:50 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- _test/test_block_seq_local_indent.py | 18 +++++++++--------- _test/test_bools.py | 16 ++++++++-------- lib/ruyaml/events.py | 14 ++++++++++++-- lib/ruyaml/main.py | 8 +++++--- lib/ruyaml/nodes.py | 2 +- lib/ruyaml/representer.py | 4 +++- 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/_test/test_block_seq_local_indent.py b/_test/test_block_seq_local_indent.py index 2185c87..0c55655 100644 --- a/_test/test_block_seq_local_indent.py +++ b/_test/test_block_seq_local_indent.py @@ -1,16 +1,17 @@ +import io +from typing import Any, Dict, List, Text # NOQA import pytest -import io -import ruyaml # NOQA -from .roundtrip import round_trip, dedent +import ruyaml # NOQA 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 +from ruyaml.representer import RoundTripRepresenter, ScalarNode +from ruyaml.scalarbool import ScalarBoolean +from ruyaml.util import load_yaml_guess_indent + +from .roundtrip import dedent, round_trip def round_trip_stabler( @@ -31,7 +32,6 @@ def round_trip_stabler( class TestStability: - def test_blockseq1(self): round_trip( """ @@ -64,8 +64,8 @@ def test_blockseq3(self): """ ) -class TestStabilityStabler: +class TestStabilityStabler: def test_blockseq1(self): round_trip_stabler( """ diff --git a/_test/test_bools.py b/_test/test_bools.py index d6620b3..3ed4085 100644 --- a/_test/test_bools.py +++ b/_test/test_bools.py @@ -1,16 +1,17 @@ +import io +from typing import Any, Dict, List, Text # NOQA import pytest -import io -import ruyaml # NOQA -from .roundtrip import round_trip, dedent +import ruyaml # NOQA 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 +from ruyaml.representer import RoundTripRepresenter, ScalarNode +from ruyaml.scalarbool import ScalarBoolean +from ruyaml.util import load_yaml_guess_indent + +from .roundtrip import dedent, round_trip def round_trip_stabler( @@ -31,7 +32,6 @@ def round_trip_stabler( class TestStability: - def test_lowercase_boolean(self): round_trip( """ diff --git a/lib/ruyaml/events.py b/lib/ruyaml/events.py index e5836fe..44d821a 100644 --- a/lib/ruyaml/events.py +++ b/lib/ruyaml/events.py @@ -186,7 +186,7 @@ def __init__( class SequenceStartEvent(CollectionStartEvent): - __slots__ = ('block_seq_indent', ) + __slots__ = ('block_seq_indent',) def __init__( self, @@ -201,7 +201,17 @@ def __init__( nr_items=None, ): # type: (Any, 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) + CollectionStartEvent.__init__( + self, + anchor, + tag, + implicit, + start_mark, + end_mark, + flow_style, + comment, + nr_items, + ) self.block_seq_indent = block_seq_indent diff --git a/lib/ruyaml/main.py b/lib/ruyaml/main.py index 19288c9..67a4fd1 100644 --- a/lib/ruyaml/main.py +++ b/lib/ruyaml/main.py @@ -244,9 +244,11 @@ def constructor(self): # type: () -> Any attr = '_' + sys._getframe().f_code.co_name if not hasattr(self, attr): - cnst = self.Constructor(preserve_quotes=self.preserve_quotes, - preserve_bools=self.preserve_bools, - loader=self) + cnst = self.Constructor( + preserve_quotes=self.preserve_quotes, + preserve_bools=self.preserve_bools, + loader=self, + ) cnst.allow_duplicate_keys = self.allow_duplicate_keys setattr(self, attr, cnst) return getattr(self, attr) diff --git a/lib/ruyaml/nodes.py b/lib/ruyaml/nodes.py index 311f329..63ef260 100644 --- a/lib/ruyaml/nodes.py +++ b/lib/ruyaml/nodes.py @@ -121,7 +121,7 @@ def __init__( class SequenceNode(CollectionNode): - __slots__ = ('block_seq_indent', ) + __slots__ = ('block_seq_indent',) id = 'sequence' def __init__( diff --git a/lib/ruyaml/representer.py b/lib/ruyaml/representer.py index 29812f5..8180ef7 100644 --- a/lib/ruyaml/representer.py +++ b/lib/ruyaml/representer.py @@ -825,7 +825,9 @@ def set_block_seq_indent(self, node, sequence): 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'? + 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):