diff options
author | Anthon van der Neut <anthon@mnt.org> | 2018-08-09 08:34:41 +0200 |
---|---|---|
committer | Anthon van der Neut <anthon@mnt.org> | 2018-08-09 08:34:41 +0200 |
commit | ab28d38e95b2ae8871c1f68ff3a690cf360ce60a (patch) | |
tree | 0a6ac735c227b12b33b8a4a8dc2599d8c559a78b | |
parent | c2d45fe4a14cb67f52b04bf8c82c39aac74eece6 (diff) | |
download | ruamel.yaml-ab28d38e95b2ae8871c1f68ff3a690cf360ce60a.tar.gz |
fix issue #196 loosing items on cast to dict0.15.52
*When this change indeed resolves your problem, please **Close** this issue*.
*(You can do so usingthe WorkFlow pull-down (close to the top right of this page)*
-rw-r--r-- | CHANGES | 9 | ||||
-rw-r--r-- | README.rst | 13 | ||||
-rw-r--r-- | __init__.py | 10 | ||||
-rw-r--r-- | _doc/_static/pypi.svg | 2 | ||||
-rw-r--r-- | _doc/conf.py | 2 | ||||
-rw-r--r-- | _test/test_anchor.py | 15 | ||||
-rw-r--r-- | _test/test_contextmanager.py | 5 | ||||
-rw-r--r-- | comments.py | 89 | ||||
-rw-r--r-- | compat.py | 2 | ||||
-rw-r--r-- | scalarstring.py | 2 |
10 files changed, 96 insertions, 53 deletions
@@ -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/>`__) @@ -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): @@ -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 = '|' |