summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthon van der Neut <anthon@mnt.org>2023-05-06 12:29:03 +0200
committerAnthon van der Neut <anthon@mnt.org>2023-05-06 12:29:03 +0200
commita7e27772f48e9e7f1040344739f680081da50a41 (patch)
tree0887b210272f81e1a01e6404e1e1aac25e4558f3
parenta4e09a2ba0d2adb1b2e63b6bf8fa39c055b9c99b (diff)
downloadruamel.yaml-a7e27772f48e9e7f1040344739f680081da50a41.tar.gz
fix issue: 453, 4470.17.24
-rw-r--r--CHANGES15
-rw-r--r--README.rst19
-rw-r--r--__init__.py6
-rw-r--r--_doc/_static/pypi.svg2
-rw-r--r--_test/test_issues.py31
-rw-r--r--comments.py33
-rw-r--r--scanner.py7
-rw-r--r--setup.py3
8 files changed, 97 insertions, 19 deletions
diff --git a/CHANGES b/CHANGES
index a6f0909..68f0036 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,18 @@
+[0, 17, 24]: 2023-05-06
+ - rewrite of ``CommentedMap.insert()``. If you have a merge key in
+ the YAML document for the mapping you insert to, the position value should
+ be the one as you look at the YAML input.
+ This fixes issue 453 where other
+ keys of a merged in mapping would show up after an insert (reported by
+ `Alex Miller <https://sourceforge.net/u/millerdevel/profile/>`__). It
+ also fixes a call to `.insert()` resulting into the merge key to move
+ to be the first key if it wasn't already and it is also now possible
+ to insert a key before a merge key (even if the fist key in the mapping).
+ - fix (in the pure Python implementation including default) for issue 447.
+ (reported by `Jack Cherng <https://sourceforge.net/u/jfcherng/profile/>`__,
+ also brought up by brent on
+ `StackOverflow <https://stackoverflow.com/q/40072485/1307905>`__)
+
[0, 17, 23]: 2023-05-05
- fix 458, error on plain scalars starting with word longer than width.
(reported by `Kyle Larose <https://sourceforge.net/u/klarose/profile/>`__)
diff --git a/README.rst b/README.rst
index e9a2b08..092b63c 100644
--- a/README.rst
+++ b/README.rst
@@ -4,8 +4,8 @@ ruamel.yaml
``ruamel.yaml`` is a YAML 1.2 loader/dumper package for Python.
-:version: 0.17.23
-:updated: 2023-05-05
+:version: 0.17.24
+:updated: 2023-05-06
:documentation: http://yaml.readthedocs.io
:repository: https://sourceforge.net/projects/ruamel-yaml/
:pypi: https://pypi.org/project/ruamel.yaml/
@@ -61,6 +61,21 @@ ChangeLog
.. should insert NEXT: at the beginning of line for next key (with empty line)
+0.17.24 (2023-05-06):
+ - rewrite of ``CommentedMap.insert()``. If you have a merge key in
+ the YAML document for the mapping you insert to, the position value should
+ be the one as you look at the YAML input.
+ This fixes issue 453 where other
+ keys of a merged in mapping would show up after an insert (reported by
+ `Alex Miller <https://sourceforge.net/u/millerdevel/profile/>`__). It
+ also fixes a call to `.insert()` resulting into the merge key to move
+ to be the first key if it wasn't already and it is also now possible
+ to insert a key before a merge key (even if the fist key in the mapping).
+ - fix (in the pure Python implementation including default) for issue 447.
+ (reported by `Jack Cherng <https://sourceforge.net/u/jfcherng/profile/>`__,
+ also brought up by brent on
+ `StackOverflow <https://stackoverflow.com/q/40072485/1307905>`__)
+
0.17.23 (2023-05-05):
- fix 458, error on plain scalars starting with word longer than width.
(reported by `Kyle Larose <https://sourceforge.net/u/klarose/profile/>`__)
diff --git a/__init__.py b/__init__.py
index 5dcf734..d548852 100644
--- a/__init__.py
+++ b/__init__.py
@@ -5,9 +5,9 @@ if False: # MYPY
_package_data = dict(
full_package_name='ruamel.yaml',
- version_info=(0, 17, 23),
- __version__='0.17.23',
- version_timestamp='2023-05-05 20:19:23',
+ version_info=(0, 17, 24),
+ __version__='0.17.24',
+ version_timestamp='2023-05-06 12:28:17',
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 32bd51f..1784380 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.17.23</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.17.23</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.17.24</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.17.24</text></g> </svg>
diff --git a/_test/test_issues.py b/_test/test_issues.py
index ce78cce..eadf94d 100644
--- a/_test/test_issues.py
+++ b/_test/test_issues.py
@@ -954,6 +954,11 @@ class TestIssues:
yaml.dump(data, buf)
assert buf.getvalue() == '%YAML 1.1\n---\nquote: I have seen things\n'
+ def test_issue_447(self) -> None:
+ from ruamel.yaml import YAML
+
+ YAML().load("{\n\t\"FOO\": \"BAR\"\n}")
+
def test_issue_449(self) -> None:
inp = """\
emoji_index: !!python/name:materialx.emoji.twemoji
@@ -974,6 +979,32 @@ class TestIssues:
assert ord(k) == v
assert len(cm) == 4
+ def test_issue_453(self) -> None:
+ from io import StringIO
+ from ruamel.yaml import YAML
+
+ inp = dedent(
+ """
+ to-merge: &anchor
+ merge-key: should not be duplicated
+
+ to-merge2: &anchor2
+ merge-key2: should not be duplicated
+
+ usage:
+ <<: [*anchor, *anchor2]
+ usage-key: usage-value
+ """
+ )
+ yaml = YAML()
+ data = yaml.load(inp)
+ data['usage'].insert(0, 'insert-key', 'insert-value')
+ out_stream = StringIO()
+ yaml.dump(data, out_stream)
+ result = out_stream.getvalue()
+ print(result)
+ assert inp.replace('usage:\n', 'usage:\n insert-key: insert-value\n') == result
+
def test_issue_454(self) -> None:
inp = """
test1: 🎉
diff --git a/comments.py b/comments.py
index c7a4575..dc128ee 100644
--- a/comments.py
+++ b/comments.py
@@ -793,16 +793,33 @@ class CommentedMap(ordereddict, CommentedBase):
self._ok.update(*kw.keys()) # type: ignore
def insert(self, pos: Any, key: Any, value: Any, comment: Optional[Any] = None) -> None:
- """insert key value into given position
+ """insert key value into given position, as defined by source YAML
attach comment if provided
"""
- keys = list(self.keys()) + [key]
- ordereddict.insert(self, pos, key, value)
- for keytmp in keys:
- self._ok.add(keytmp)
- for referer in self._ref:
- for keytmp in keys:
- referer.update_key_value(keytmp)
+ if key in self._ok:
+ del self[key]
+ keys = [k for k in self.keys() if k in self._ok]
+ ma0 = getattr(self, merge_attrib, [[-1]])[0]
+ merge_pos = ma0[0]
+ if merge_pos >= 0:
+ if merge_pos >= pos:
+ getattr(self, merge_attrib)[0] = (merge_pos + 1, ma0[1])
+ idx_min = pos
+ idx_max = len(self._ok)
+ else:
+ idx_min = pos - 1
+ idx_max = len(self._ok)
+ else:
+ idx_min = pos
+ idx_max = len(self._ok)
+ self[key] = value # at the end
+ # print(f'{idx_min=} {idx_max=}')
+ for idx in range(idx_min, idx_max):
+ self.move_to_end(keys[idx])
+ self._ok.add(key)
+ # for referer in self._ref:
+ # for keytmp in keys:
+ # referer.update_key_value(keytmp)
if comment is not None:
self.yaml_add_eol_comment(comment, key=key)
diff --git a/scanner.py b/scanner.py
index 2bc199f..c09ae9c 100644
--- a/scanner.py
+++ b/scanner.py
@@ -822,8 +822,9 @@ class Scanner:
srf()
found = False
_the_end = _THE_END
+ white_space = ' \t' if self.flow_level > 0 else ' '
while not found:
- while srp() == ' ':
+ while srp() in white_space:
srf()
if srp() == '#':
while srp() not in _the_end:
@@ -1837,14 +1838,14 @@ class RoundTripScanner(Scanner):
# We also need to add the check for `allow_simple_keys == True` to
# `unwind_indent` before issuing BLOCK-END.
# Scanners for block, flow, and plain scalars need to be modified.
-
srp = self.reader.peek
srf = self.reader.forward
if self.reader.index == 0 and srp() == '\uFEFF':
srf()
found = False
+ white_space = ' \t' if self.flow_level > 0 else ' '
while not found:
- while srp() == ' ':
+ while srp() in white_space:
srf()
ch = srp()
if ch == '#':
diff --git a/setup.py b/setup.py
index a0ea309..98f7e93 100644
--- a/setup.py
+++ b/setup.py
@@ -888,7 +888,7 @@ def main():
# if nsp.wheel(kw, setup):
# return
- with TmpFiles(pkg_data, keep=False):
+ with TmpFiles(pkg_data, keep=True):
for x in ['-c', 'egg_info', '--egg-base', 'pip-egg-info']:
if x not in sys.argv:
break
@@ -912,7 +912,6 @@ def main():
break
try_dir = os.path.dirname(try_dir)
setup(**kw)
- print('done')
main()