summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES9
-rw-r--r--README.rst13
-rw-r--r--__init__.py10
-rw-r--r--_doc/_static/pypi.svg2
-rw-r--r--_doc/conf.py2
-rw-r--r--_test/test_anchor.py15
-rw-r--r--_test/test_contextmanager.py5
-rw-r--r--comments.py89
-rw-r--r--compat.py2
-rw-r--r--scalarstring.py2
10 files changed, 96 insertions, 53 deletions
diff --git a/CHANGES b/CHANGES
index 4f7abf4..7d08c2a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,12 @@
+[0, 15, 52]: 2018-08-09
+ - added `.copy()` mapping representation for round-tripping
+ (``CommentedMap``) to fix incomplete copies of merged mappings
+ (reported by `Will Richards
+ <https://bitbucket.org/will_richards/>`__)
+ - Also unmade that class a subclass of ordereddict to solve incorrect behaviour
+ for ``{**merged-mapping}`` and ``dict(**merged-mapping)`` (reported by
+ `Filip Matzner <https://bitbucket.org/FloopCZ/>`__)
+
[0, 15, 51]: 2018-08-08
- Fix method name dumps (were not dotted) and loads (reported by `Douglas Raillard
<https://bitbucket.org/DouglasRaillard/>`__)
diff --git a/README.rst b/README.rst
index eefccde..81b5ec4 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.15.51
-:updated: 2018-08-08
+:version: 0.15.52
+:updated: 2018-08-09
:documentation: http://yaml.readthedocs.io
:repository: https://bitbucket.org/ruamel/
:pypi: https://pypi.org/project/ruamel.yaml/
@@ -54,6 +54,15 @@ ChangeLog
.. should insert NEXT: at the beginning of line for next key (with empty line)
+0.15.52 (2018-08-09):
+ - added `.copy()` mapping representation for round-tripping
+ (``CommentedMap``) to fix incomplete copies of merged mappings
+ (reported by `Will Richards
+ <https://bitbucket.org/will_richards/>`__)
+ - Also unmade that class a subclass of ordereddict to solve incorrect behaviour
+ for ``{**merged-mapping}`` and ``dict(**merged-mapping)`` (reported by
+ `Filip Matzner <https://bitbucket.org/FloopCZ/>`__)
+
0.15.51 (2018-08-08):
- Fix method name dumps (were not dotted) and loads (reported by `Douglas Raillard
<https://bitbucket.org/DouglasRaillard/>`__)
diff --git a/__init__.py b/__init__.py
index 07126c3..ffd84c2 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, 51),
- __version__='0.15.51',
+ version_info=(0, 15, 52),
+ __version__='0.15.52',
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
@@ -65,9 +65,9 @@ _package_data = dict(
many_linux='libyaml-devel',
supported=[(2, 7), (3, 4)], # minimum
tox=dict(
- env=u'*pn', # also test narrow 2.7.15
- deps=u'ruamel.std.pathlib',
- fl8excl=u'_test/lib',
+ env='*pn', # also test narrow 2.7.15
+ deps='ruamel.std.pathlib',
+ fl8excl='_test/lib',
),
rtfd='yaml',
) # type: Dict[Any, Any]
diff --git a/_doc/_static/pypi.svg b/_doc/_static/pypi.svg
index def9f4b..253e2c2 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.51</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.15.51</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.52</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.15.52</text></g> </svg>
diff --git a/_doc/conf.py b/_doc/conf.py
index 632b117..f0fbcad 100644
--- a/_doc/conf.py
+++ b/_doc/conf.py
@@ -46,7 +46,7 @@ master_doc = 'index'
# General information about the project.
project = u'yaml'
-copyright = u'2017, Anthon van der Neut, Ruamel bvba'
+copyright = u'2017-2018, Anthon van der Neut, Ruamel bvba'
author = u'Anthon van der Neut'
# The version info for the project you're documenting, acts as replacement for
diff --git a/_test/test_anchor.py b/_test/test_anchor.py
index 102e48b..294d7f1 100644
--- a/_test/test_anchor.py
+++ b/_test/test_anchor.py
@@ -402,11 +402,12 @@ class TestMergeKeysValues:
def test_issue_196_cast_of_dict(self, capsys):
from ruamel.yaml import YAML
+
yaml = YAML()
mapping = yaml.load("""\
anchored: &anchor
a : 1
-
+
mapping:
<<: *anchor
b: 2
@@ -416,7 +417,7 @@ class TestMergeKeysValues:
print('k', k)
for k in mapping.copy():
print('kc', k)
-
+
print('v', list(mapping.keys()))
print('v', list(mapping.values()))
print('v', list(mapping.items()))
@@ -436,9 +437,17 @@ class TestMergeKeysValues:
assert mapping.__getitem__('a') == 1
assert 'a' in dict(mapping)
assert 'a' in dict(mapping.items())
-
+
+ def test_values_of_merged(self):
+ from ruamel.yaml import YAML
+
+ yaml = YAML()
+ data = yaml.load(dedent(self.yaml_str))
+ assert list(data[2].values()) == [1, 6, 'x2', 'x3', 'y4']
+
def test_issue_213_copy_of_merge(self):
from ruamel.yaml import YAML
+
yaml = YAML()
d = yaml.load("""\
foo: &foo
diff --git a/_test/test_contextmanager.py b/_test/test_contextmanager.py
index 76d24aa..7216473 100644
--- a/_test/test_contextmanager.py
+++ b/_test/test_contextmanager.py
@@ -41,7 +41,10 @@ def get_yaml():
class TestOldStyle:
def test_single_load(self):
- assert get_yaml().load(single_doc) == single_data
+ d = get_yaml().load(single_doc)
+ print(d)
+ print(type(d[0]))
+ assert d == single_data
def test_single_load_no_arg(self):
with pytest.raises(TypeError):
diff --git a/comments.py b/comments.py
index 22040fa..fd28a62 100644
--- a/comments.py
+++ b/comments.py
@@ -532,6 +532,7 @@ class CommentedMapView(Sized):
count = len(self._mapping)
return count
+
class CommentedMapKeysView(CommentedMapView, Set):
__slots__ = ()
@@ -591,8 +592,12 @@ class CommentedMapValuesView(CommentedMapView):
yield self._mapping[key]
-class CommentedMap(ordereddict, CommentedBase):
- __slots__ = (Comment.attrib,)
+class CommentedMap(CommentedBase, MutableMapping):
+ __slots__ = (Comment.attrib, '_od')
+
+ def __init__(self, *args, **kw):
+ # type: (Any, Any) -> None
+ self._od = ordereddict(*args, **kw)
def _yaml_add_comment(self, comment, key=NoComment, value=NoComment):
# type: (Any, Optional[Any], Optional[Any]) -> None
@@ -654,7 +659,7 @@ class CommentedMap(ordereddict, CommentedBase):
def update(self, vals):
# type: (Any) -> None
try:
- ordereddict.update(self, vals)
+ self._od.update(vals)
except TypeError:
# probably a dict that is used
for x in vals:
@@ -665,7 +670,7 @@ class CommentedMap(ordereddict, CommentedBase):
"""insert key value into given position
attach comment if provided
"""
- ordereddict.insert(self, pos, key, value)
+ self._od.insert(pos, key, value)
if comment is not None:
self.yaml_add_eol_comment(comment, key=key)
@@ -698,7 +703,7 @@ class CommentedMap(ordereddict, CommentedBase):
def __getitem__(self, key):
# type: (Any) -> Any
try:
- return ordereddict.__getitem__(self, key)
+ return self._od.__getitem__(key)
except KeyError:
for merged in getattr(self, merge_attrib, []):
if key in merged[1]:
@@ -715,17 +720,17 @@ class CommentedMap(ordereddict, CommentedBase):
and isinstance(self[key], ScalarString)
):
value = type(self[key])(value)
- ordereddict.__setitem__(self, key, value)
+ self._od.__setitem__(key, value)
def _unmerged_contains(self, key):
# type: (Any) -> Any
- if ordereddict.__contains__(self, key):
+ if self._od.__contains__(key):
return True
return None
def __contains__(self, key):
# type: (Any) -> bool
- if ordereddict.__contains__(self, key):
+ if self._od.__contains__(key):
return True
# this will only work once the mapping/dict is built to completion
for merged in getattr(self, merge_attrib, []):
@@ -743,13 +748,13 @@ class CommentedMap(ordereddict, CommentedBase):
def __repr__(self):
# type: () -> Any
if not hasattr(self, merge_attrib):
- return ordereddict.__repr__(self)
+ return self._od.__repr__()
return 'ordereddict(' + repr(list(self._items())) + ')'
def non_merged_items(self):
# type: () -> Any
- for x in ordereddict.__iter__(self):
- yield x, ordereddict.__getitem__(self, x)
+ for x in self._od.__iter__():
+ yield x, self._od.__getitem__(x)
def __delitem__(self, key):
# type: (Any) -> None
@@ -761,19 +766,19 @@ class CommentedMap(ordereddict, CommentedBase):
except KeyError:
pass
try:
- ordereddict.__delitem__(self, key)
+ self._od.__delitem__(key)
except KeyError:
if not found:
raise
def __iter__(self):
# type: () -> Any
- for x in ordereddict.__iter__(self):
+ for x in self._od.__iter__():
yield x
done = [] # type: List[Any] # list of processed merge items, kept for masking
for merged in getattr(self, merge_attrib, []):
for x in merged[1]:
- if ordereddict.__contains__(self, x):
+ if self._od.__contains__(x):
continue
for y in done:
if x in y:
@@ -784,12 +789,12 @@ class CommentedMap(ordereddict, CommentedBase):
def _keys(self):
# type: () -> Any
- for x in ordereddict.__iter__(self):
+ for x in self._od.__iter__():
yield x
done = [] # type: List[Any] # list of processed merge items, kept for masking
for merged in getattr(self, merge_attrib, []):
for x in merged[1].keys():
- if ordereddict.__contains__(self, x):
+ if self._od.__contains__(x):
continue
for y in done:
if x in y:
@@ -799,11 +804,12 @@ class CommentedMap(ordereddict, CommentedBase):
done.append(merged[1])
def __len__(self):
- count = ordereddict.__len__(self)
+ # type: () -> int
+ count = self._od.__len__() # type: int
done = [] # type: List[Any] # list of processed merge items, kept for masking
for merged in getattr(self, merge_attrib, []):
for x in merged[1]:
- if ordereddict.__contains__(self, x):
+ if self._od.__contains__(x):
continue
for y in done:
if x in y:
@@ -813,6 +819,10 @@ class CommentedMap(ordereddict, CommentedBase):
done.append(merged[1])
return count
+ def __eq__(self, other):
+ # type: (Any) -> bool
+ return bool(dict(self) == other)
+
if PY2:
def keys(self):
@@ -833,24 +843,24 @@ class CommentedMap(ordereddict, CommentedBase):
# type: () -> Any
return CommentedMapKeysView(self)
- def _values(self):
- # type: () -> Any
- for x in ordereddict.__iter__(self):
- yield ordereddict.__getitem__(self, x)
- done = [] # type: List[Any] # list of processed merge items, kept for masking
- for merged in getattr(self, merge_attrib, []):
- for x in merged[1]:
- if ordereddict.__contains__(self, x):
- continue
- for y in done:
- if x in y:
- break
- else:
- yield ordereddict.__getitem__(merged[1], x)
- done.append(merged[1])
-
if PY2:
+ def _values(self):
+ # type: () -> Any
+ for x in self._od.__iter__():
+ yield self._od.__getitem__(x)
+ done = [] # type: List[Any] # list of processed merge items, kept for masking
+ for merged in getattr(self, merge_attrib, []):
+ for x in merged[1]:
+ if self._od.__contains__(x):
+ continue
+ for y in done:
+ if x in y:
+ break
+ else:
+ yield merged[1]._od.__getitem__(x)
+ done.append(merged[1])
+
def values(self):
# type: () -> Any
return list(self._values())
@@ -871,18 +881,18 @@ class CommentedMap(ordereddict, CommentedBase):
def _items(self):
# type: () -> Any
- for x in ordereddict.__iter__(self):
- yield x, ordereddict.__getitem__(self, x)
+ for x in self._od.__iter__():
+ yield x, self._od.__getitem__(x)
done = [] # type: List[Any] # list of processed merge items, kept for masking
for merged in getattr(self, merge_attrib, []):
for x, v in merged[1].items():
- if ordereddict.__contains__(self, x):
+ if self._od.__contains__(x):
continue
for y in done:
if x in y:
break
else:
- yield x, v # ordereddict.__getitem__(merged[1], x)
+ yield x, v # self._od.__getitem__(merged[1], x)
done.append(merged[1])
if PY2:
@@ -913,6 +923,7 @@ class CommentedMap(ordereddict, CommentedBase):
return getattr(self, merge_attrib)
def copy(self):
+ # type: () -> Any
x = {} # update doesn't work
for k, v in self._items():
x[k] = v
@@ -936,7 +947,7 @@ class CommentedOrderedMap(CommentedMap):
__slots__ = (Comment.attrib,)
-class CommentedSet(MutableSet, CommentedMap):
+class CommentedSet(MutableSet, CommentedMap): # NOQA
__slots__ = Comment.attrib, 'odict'
def __init__(self, values=None):
diff --git a/compat.py b/compat.py
index 3eb6464..c2db2bb 100644
--- a/compat.py
+++ b/compat.py
@@ -8,8 +8,10 @@ import sys
import os
import types
+# fmt: off
if False: # MYPY
from typing import Any, Dict, Optional, List, Union, BinaryIO, IO, Text, Tuple, Optional # NOQA
+# fmt: on
_DEFAULT_YAML_VERSION = (1, 2)
diff --git a/scalarstring.py b/scalarstring.py
index ef283d2..822ae83 100644
--- a/scalarstring.py
+++ b/scalarstring.py
@@ -28,7 +28,7 @@ class ScalarString(text_type):
class PreservedScalarString(ScalarString):
- __slots__ = ('comment') # the comment after the | on the first line
+ __slots__ = 'comment' # the comment after the | on the first line
style = '|'