summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthon van der Neut <anthon@mnt.org>2016-05-02 08:50:15 +0200
committerAnthon van der Neut <anthon@mnt.org>2016-05-02 08:50:15 +0200
commit4fa9ad23e69dcea31fe1b3dc15dc3cc1510b797c (patch)
treecef93d3c5c2c9e40f58360df87958e3d8b8175fa
parentad69246c90b178e99a752769ee4ac70dd4dedb26 (diff)
downloadruamel.yaml-4fa9ad23e69dcea31fe1b3dc15dc3cc1510b797c.tar.gz
allow insert in CommentedMap (Py3) and add comment0.11.11
The insert() would only be available for CommentedMap on Py2 (thanks to ruamel.ordereddict). The standard library lacks this functionality. The method was added in the compatibility layer, and on CommentedMap the optional comment parameter allows directly setting an end-of-line comment on the inserted key.
-rw-r--r--CHANGES4
-rw-r--r--__init__.py2
-rw-r--r--_doc/example.rst31
-rw-r--r--_test/test_comments.py49
-rw-r--r--comments.py8
-rw-r--r--compat.py15
6 files changed, 106 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index 1a14444..50c7e6f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,8 @@
+0.11.10 2016-05-02
+
+- added .insert(pos, key, value, comment=None) to CommentedMap
+
0.11.10 2016-04-19
- indent=2, block_seq_indent=2 works as expected
diff --git a/__init__.py b/__init__.py
index 7a0c6f0..9be2082 100644
--- a/__init__.py
+++ b/__init__.py
@@ -9,7 +9,7 @@ from __future__ import absolute_import
_package_data = dict(
full_package_name="ruamel.yaml",
- version_info=(0, 11, 10),
+ version_info=(0, 11, 11),
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/example.rst b/_doc/example.rst
index 8bf9c6a..4e8ac4a 100644
--- a/_doc/example.rst
+++ b/_doc/example.rst
@@ -34,9 +34,10 @@ Resulting in ::
.. example output small.py
+----
YAML handcrafted anchors and references as well as key merging
-is preserved. The merged keys can transparently be accessed
+are preserved. The merged keys can transparently be accessed
using ``[]`` and ``.get()``::
import ruamel.yaml
@@ -71,3 +72,31 @@ using ``[]`` and ``.get()``::
.. example code anchor_merge.py
+----
+
+The ``CommentedMap``, which is the ``dict`` like construct one gets when round-trip loading,
+supports insertion of a key into a particular position, while optionally adding a comment::
+
+ yaml_str = """\
+ first_name: Art
+ occupation: Architect # This is an occupation comment
+ about: Art Vandelay is a fictional character that George invents...
+ """
+
+ data = ruamel.yaml.round_trip_load(yaml_str)
+ data.insert(1, 'last name', 'Vandelay', comment="new key")
+ print(ruamel.yaml.round_trip_dump(data))
+
+gives::
+
+ first_name: Art
+ last name: Vandelay # new key
+ occupation: Architect # This is an occupation comment
+ about: Art Vandelay is a fictional character that George invents...
+
+Please note that the comment is aligned with that of its neighbour (if available).
+
+The above was inspired by a `question <http://stackoverflow.com/a/36970608/1307905>`_
+posted by *demux* on StackOverflow.
+
+
diff --git a/_test/test_comments.py b/_test/test_comments.py
index ffe0b04..b6b12e2 100644
--- a/_test/test_comments.py
+++ b/_test/test_comments.py
@@ -423,3 +423,52 @@ class TestInsertPopList:
- 1
- 2
""")
+
+
+# inspired by demux' question on stackoverflow
+# http://stackoverflow.com/a/36970608/1307905
+class TestInsertInMapping:
+ @property
+ def ins(self):
+ return """\
+ first_name: Art
+ occupation: Architect # This is an occupation comment
+ about: Art Vandelay is a fictional character that George invents...
+ """
+
+ def test_insert_at_pos_1(self):
+ d = round_trip_load(self.ins)
+ d.insert(1, 'last name', 'Vandelay', comment="new key")
+ y = round_trip_dump(d)
+ print(y)
+ assert y == dedent("""\
+ first_name: Art
+ last name: Vandelay # new key
+ occupation: Architect # This is an occupation comment
+ about: Art Vandelay is a fictional character that George invents...
+ """)
+
+ def test_insert_at_pos_0(self):
+ d = round_trip_load(self.ins)
+ d.insert(0, 'last name', 'Vandelay', comment="new key")
+ y = round_trip_dump(d)
+ print(y)
+ assert y == dedent("""\
+ last name: Vandelay # new key
+ first_name: Art
+ occupation: Architect # This is an occupation comment
+ about: Art Vandelay is a fictional character that George invents...
+ """)
+
+ def test_insert_at_pos_3(self):
+ # much more simple if done with appending.
+ d = round_trip_load(self.ins)
+ d.insert(3, 'last name', 'Vandelay', comment="new key")
+ y = round_trip_dump(d)
+ print(y)
+ assert y == dedent("""\
+ first_name: Art
+ occupation: Architect # This is an occupation comment
+ about: Art Vandelay is a fictional character that George invents...
+ last name: Vandelay # new key
+ """)
diff --git a/comments.py b/comments.py
index 8e5ebb8..4a99931 100644
--- a/comments.py
+++ b/comments.py
@@ -389,6 +389,14 @@ class CommentedMap(ordereddict, CommentedBase):
for x in vals:
self[x] = vals[x]
+ def insert(self, pos, key, value, comment=None):
+ """insert key value into given position
+ attach comment if provided
+ """
+ ordereddict.insert(self, pos, key, value)
+ if comment is not None:
+ self.yaml_add_eol_comment(comment, key=key)
+
def mlget(self, key, default=None, list_ok=False):
"""multi-level get that expects dicts within dicts"""
if not isinstance(key, list):
diff --git a/compat.py b/compat.py
index 8120a4e..abd10ac 100644
--- a/compat.py
+++ b/compat.py
@@ -18,7 +18,20 @@ except:
# to get the right name import ... as ordereddict doesn't do that
class ordereddict(OrderedDict):
- pass
+ if not hasattr(OrderedDict, 'insert'):
+ def insert(self, pos, key, value):
+ if pos >= len(self):
+ self[key] = value
+ return
+ od = ordereddict()
+ od.update(self)
+ for k in od:
+ del self[k]
+ for index, old_key in enumerate(od):
+ if pos == index:
+ self[key] = value
+ self[old_key] = od[old_key]
+
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3