diff options
-rw-r--r-- | CHANGES | 8 | ||||
-rw-r--r-- | README.rst | 11 | ||||
-rw-r--r-- | __init__.py | 4 | ||||
-rw-r--r-- | _doc/_static/pypi.svg | 2 | ||||
-rw-r--r-- | _test/test_spec_examples.py | 1 | ||||
-rw-r--r-- | _test/test_tag.py | 16 | ||||
-rw-r--r-- | constructor.py | 14 | ||||
-rw-r--r-- | emitter.py | 54 | ||||
-rw-r--r-- | events.py | 6 | ||||
-rw-r--r-- | main.py | 3 | ||||
-rw-r--r-- | serializer.py | 1 |
11 files changed, 88 insertions, 32 deletions
@@ -1,3 +1,11 @@ +[0, 15, 64]: 2018-08-30 + - support round-trip of tagged sequences: ``!Arg [a, {b: 1}]`` + - single entry mappings in flow sequences now written by default without quotes + set ``yaml.brace_single_entry_mapping_in_flow_sequence=True`` to force + getting ``[a, {b: 1}, {c: {d: 2}}]`` instead of the default ``[a, b: 1, c: {d: 2}]`` + - fix issue when roundtripping floats starting with a dot such as ``.5`` + (reported by `Harrison Gregg <https://bitbucket.org/HarrisonGregg/>`__) + [0, 15, 63]: 2018-08-29 - small fix only necessary for Windows users that don't use wheels. @@ -4,8 +4,8 @@ ruamel.yaml ``ruamel.yaml`` is a YAML 1.2 loader/dumper package for Python. -:version: 0.15.63 -:updated: 2018-08-29 +:version: 0.15.64 +:updated: 2018-08-30 :documentation: http://yaml.readthedocs.io :repository: https://bitbucket.org/ruamel/ :pypi: https://pypi.org/project/ruamel.yaml/ @@ -54,8 +54,13 @@ ChangeLog .. should insert NEXT: at the beginning of line for next key (with empty line) -NEXT: +0.15.64 (2018-08-30): - support round-trip of tagged sequences: ``!Arg [a, {b: 1}]`` + - single entry mappings in flow sequences now written by default without quotes + set ``yaml.brace_single_entry_mapping_in_flow_sequence=True`` to force + getting ``[a, {b: 1}, {c: {d: 2}}]`` instead of the default ``[a, b: 1, c: {d: 2}]`` + - fix issue when roundtripping floats starting with a dot such as ``.5`` + (reported by `Harrison Gregg <https://bitbucket.org/HarrisonGregg/>`__) 0.15.63 (2018-08-29): - small fix only necessary for Windows users that don't use wheels. diff --git a/__init__.py b/__init__.py index 71d15b2..1638ae5 100644 --- a/__init__.py +++ b/__init__.py @@ -7,8 +7,8 @@ if False: # MYPY _package_data = dict( full_package_name='ruamel.yaml', - version_info=(0, 15, 63), - __version__='0.15.63', + version_info=(0, 15, 64), + __version__='0.15.64', author='Anthon van der Neut', author_email='a.van.der.neut@ruamel.eu', description='ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order', # NOQA diff --git a/_doc/_static/pypi.svg b/_doc/_static/pypi.svg index 8e6d98c..04d56a6 100644 --- a/_doc/_static/pypi.svg +++ b/_doc/_static/pypi.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="86" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="86" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h33v20H0z"/><path fill="#007ec6" d="M33 0h53v20H33z"/><path fill="url(#b)" d="M0 0h86v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="175" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="230">pypi</text><text x="175" y="140" transform="scale(.1)" textLength="230">pypi</text><text x="585" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">0.15.63</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.15.63</text></g> </svg> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="86" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="86" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h33v20H0z"/><path fill="#007ec6" d="M33 0h53v20H33z"/><path fill="url(#b)" d="M0 0h86v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="175" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="230">pypi</text><text x="175" y="140" transform="scale(.1)" textLength="230">pypi</text><text x="585" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">0.15.64</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.15.64</text></g> </svg> diff --git a/_test/test_spec_examples.py b/_test/test_spec_examples.py index ba38585..c95b5aa 100644 --- a/_test/test_spec_examples.py +++ b/_test/test_spec_examples.py @@ -1,3 +1,4 @@ + from roundtrip import YAML import pytest # NOQA diff --git a/_test/test_tag.py b/_test/test_tag.py index 47d4722..31a192e 100644 --- a/_test/test_tag.py +++ b/_test/test_tag.py @@ -2,7 +2,7 @@ import pytest # NOQA -from roundtrip import round_trip, round_trip_load +from roundtrip import round_trip, round_trip_load, YAML def register_xxx(**kw): @@ -121,13 +121,23 @@ class TestImplicitTaggedNodes: round_trip("""\ - !Scalar abcdefg """) - + def test_mapping(self): round_trip("""\ - !Mapping {a: 1, b: 2} """) def test_sequence(self): - x = round_trip("""\ + yaml = YAML() + yaml.brace_single_entry_mapping_in_flow_sequence = True + yaml.mapping_value_align = True + yaml.round_trip(""" - !Sequence [a, {b: 1}, {c: {d: 3}}] """) + + def test_sequence2(self): + yaml = YAML() + yaml.mapping_value_align = True + yaml.round_trip(""" + - !Sequence [a, b: 1, c: {d: 3}] + """) diff --git a/constructor.py b/constructor.py index 26a4dd1..169155c 100644 --- a/constructor.py +++ b/constructor.py @@ -1562,15 +1562,15 @@ class RoundTripConstructor(SafeConstructor): yield data2 return elif isinstance(node, SequenceNode): - data = CommentedSeq() - data._yaml_set_line_col(node.start_mark.line, node.start_mark.column) + data3 = CommentedSeq() + data3._yaml_set_line_col(node.start_mark.line, node.start_mark.column) if node.flow_style is True: - data.fa.set_flow_style() + data3.fa.set_flow_style() elif node.flow_style is False: - data.fa.set_block_style() - data.yaml_set_tag(node.tag) - yield data - data.extend(self.construct_sequence(node)) + data3.fa.set_block_style() + data3.yaml_set_tag(node.tag) + yield data3 + data3.extend(self.construct_sequence(node)) return except: # NOQA pass @@ -111,9 +111,10 @@ class Emitter(object): block_seq_indent=None, top_level_colon_align=None, prefix_colon=None, + brace_single_entry_mapping_in_flow_sequence=None, dumper=None, ): - # type: (StreamType, Any, Optional[int], Optional[int], Optional[bool], Any, Optional[int], Optional[bool], Any, Any) -> None # NOQA + # type: (StreamType, Any, Optional[int], Optional[int], Optional[bool], Any, Optional[int], Optional[bool], Any, 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 @@ -136,8 +137,9 @@ class Emitter(object): self.indents = Indents() self.indent = None # type: Optional[int] - # Flow level. - self.flow_level = 0 + # flow_context is an expanding/shrinking list consisting of '{' and '[' + # for each unclosed flow context. If empty list that means block context + self.flow_context = [] # type: List[Text] # Contexts. self.root_context = False @@ -162,6 +164,10 @@ class Emitter(object): # colon handling self.colon = u':' self.prefixed_colon = self.colon if prefix_colon is None else prefix_colon + self.colon + # single entry mappings in flow sequence + self.brace_single_entry_mapping_in_flow_sequence = ( + brace_single_entry_mapping_in_flow_sequence + ) # NOQA # Formatting details. self.canonical = canonical @@ -222,6 +228,11 @@ class Emitter(object): except AttributeError: return self # cyaml + @property + def flow_level(self): + # type: () -> int + return len(self.flow_context) + def dispose(self): # type: () -> None # Reset the state attributes (to clear self-references) @@ -421,7 +432,7 @@ class Emitter(object): or self.event.flow_style or self.check_empty_mapping() ): - self.expect_flow_mapping() + self.expect_flow_mapping(single=self.event.nr_items == 1) else: self.expect_block_mapping() else: @@ -448,14 +459,15 @@ class Emitter(object): ind = self.indents.seq_flow_align(self.best_sequence_indent, self.column) self.write_indicator(u' ' * ind + u'[', True, whitespace=True) self.increase_indent(flow=True, sequence=True) - self.flow_level += 1 + self.flow_context.append('[') self.state = self.expect_first_flow_sequence_item def expect_first_flow_sequence_item(self): # type: () -> None if isinstance(self.event, SequenceEndEvent): self.indent = self.indents.pop() - self.flow_level -= 1 + popped = self.flow_context.pop() + assert popped == '[' self.write_indicator(u']', False) if self.event.comment and self.event.comment[0]: # eol comment on empty flow sequence @@ -473,7 +485,8 @@ class Emitter(object): # type: () -> None if isinstance(self.event, SequenceEndEvent): self.indent = self.indents.pop() - self.flow_level -= 1 + popped = self.flow_context.pop() + assert popped == '[' if self.canonical: self.write_indicator(u',', False) self.write_indent() @@ -493,11 +506,21 @@ class Emitter(object): # Flow mapping handlers. - def expect_flow_mapping(self): - # type: () -> None + def expect_flow_mapping(self, single=False): + # type: (Optional[bool]) -> None ind = self.indents.seq_flow_align(self.best_sequence_indent, self.column) - self.write_indicator(u' ' * ind + u'{', True, whitespace=True) - self.flow_level += 1 + map_init = u'{' + if ( + single + and self.flow_level + and self.flow_context[-1] == '[' + and not self.canonical + and not self.brace_single_entry_mapping_in_flow_sequence + ): + # single map item with flow context no curly braces necessary + map_init = u'' + self.write_indicator(u' ' * ind + map_init, True, whitespace=True) + self.flow_context.append(map_init) self.increase_indent(flow=True, sequence=False) self.state = self.expect_first_flow_mapping_key @@ -505,7 +528,8 @@ class Emitter(object): # type: () -> None if isinstance(self.event, MappingEndEvent): self.indent = self.indents.pop() - self.flow_level -= 1 + popped = self.flow_context.pop() + assert popped == '{' # empty flow mapping self.write_indicator(u'}', False) if self.event.comment and self.event.comment[0]: # eol comment on empty mapping @@ -528,11 +552,13 @@ class Emitter(object): # if self.event.comment and self.event.comment[1]: # self.write_pre_comment(self.event) self.indent = self.indents.pop() - self.flow_level -= 1 + popped = self.flow_context.pop() + assert popped in [u'{', u''] if self.canonical: self.write_indicator(u',', False) self.write_indent() - self.write_indicator(u'}', False) + if popped != u'': + self.write_indicator(u'}', False) if self.event.comment and self.event.comment[0]: # eol comment on flow mapping, never reached on empty mappings self.write_post_comment(self.event) @@ -46,7 +46,7 @@ class NodeEvent(Event): class CollectionStartEvent(NodeEvent): - __slots__ = 'tag', 'implicit', 'flow_style' + __slots__ = 'tag', 'implicit', 'flow_style', 'nr_items' def __init__( self, @@ -57,12 +57,14 @@ class CollectionStartEvent(NodeEvent): end_mark=None, flow_style=None, comment=None, + nr_items=None, ): - # type: (Any, Any, Any, Any, Any, Any, Any) -> None + # type: (Any, Any, Any, Any, Any, Any, Any, Optional[int]) -> None NodeEvent.__init__(self, anchor, start_mark, end_mark, comment) self.tag = tag self.implicit = implicit self.flow_style = flow_style + self.nr_items = nr_items class CollectionEndEvent(Event): @@ -158,6 +158,8 @@ class YAML(object): self.tags = None self.default_style = None self.top_level_block_style_scalar_no_indent_error_1_1 = False + # [a, b: 1, c: {d: 2}] vs. [a, {b: 1}, {c: {d: 2}}] + self.brace_single_entry_mapping_in_flow_sequence = False @property def reader(self): @@ -239,6 +241,7 @@ class YAML(object): allow_unicode=self.allow_unicode, 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 dumper=self, ) setattr(self, attr, _emitter) diff --git a/serializer.py b/serializer.py index fa4ae62..16763ac 100644 --- a/serializer.py +++ b/serializer.py @@ -225,6 +225,7 @@ class Serializer(object): implicit, flow_style=node.flow_style, comment=node.comment, + nr_items=len(node.value), ) ) for key, value in node.value: |