summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthon van der Neut <anthon@mnt.org>2018-08-14 16:30:15 +0200
committerAnthon van der Neut <anthon@mnt.org>2018-08-14 16:30:15 +0200
commit0923c2a691f57f9e095f5c4b9a8f06fa78bb46d2 (patch)
treeba2dc411b705bc0290711a591480a66225634352
parent65d95151526615f21aa9fbecb92831e17da697bc (diff)
downloadruamel.yaml-0923c2a691f57f9e095f5c4b9a8f06fa78bb46d2.tar.gz
reimplement CommentedSeq to subclass MutableSequence instead of list
re issue #176
-rw-r--r--_test/test_issues.py19
-rw-r--r--comments.py87
-rw-r--r--compat.py4
-rw-r--r--constructor.py5
4 files changed, 67 insertions, 48 deletions
diff --git a/_test/test_issues.py b/_test/test_issues.py
index 7c779d7..9539dc5 100644
--- a/_test/test_issues.py
+++ b/_test/test_issues.py
@@ -39,8 +39,8 @@ class TestIssues:
from ruamel import yaml
import re
-
-
+
+
class SINumber(yaml.YAMLObject):
PREFIXES = {'k': 1e3, 'M': 1e6, 'G': 1e9}
yaml_loader = yaml.Loader
@@ -48,29 +48,29 @@ class TestIssues:
yaml_tag = u'!si'
yaml_implicit_pattern = re.compile(
r'^(?P<value>[0-9]+(?:\.[0-9]+)?)(?P<prefix>[kMG])$')
-
+
@classmethod
def from_yaml(cls, loader, node):
return cls(node.value)
-
+
@classmethod
def to_yaml(cls, dumper, data):
return dumper.represent_scalar(cls.yaml_tag, str(data))
-
+
def __init__(self, *args):
m = self.yaml_implicit_pattern.match(args[0])
self.value = float(m.groupdict()['value'])
self.prefix = m.groupdict()['prefix']
-
+
def __str__(self):
return str(self.value)+self.prefix
-
+
def __int__(self):
return int(self.value*self.PREFIXES[self.prefix])
-
+
# This fails:
yaml.add_implicit_resolver(SINumber.yaml_tag, SINumber.yaml_implicit_pattern)
-
+
ret = yaml.load("""
[1,2,3, !si 10k, 100G]
""", Loader=yaml.Loader)
@@ -83,7 +83,6 @@ class TestIssues:
yaml_str = "[1, 2, 3, !si 10k, 100G]\n"
x = round_trip(yaml_str, preserve_quotes=True) # NOQA
-
def test_issue_102(self):
yaml_str = dedent("""
var1: #empty
diff --git a/comments.py b/comments.py
index c98baf8..2063775 100644
--- a/comments.py
+++ b/comments.py
@@ -12,7 +12,7 @@ import sys
import copy
-from ruamel.yaml.compat import ordereddict, PY2, string_types
+from ruamel.yaml.compat import ordereddict, PY2, string_types, MutableSequence
from ruamel.yaml.scalarstring import ScalarString
if PY2:
@@ -385,42 +385,73 @@ class CommentedBase(object):
raise NotImplementedError
-class CommentedSeq(list, CommentedBase):
- __slots__ = (Comment.attrib,)
+class CommentedSeq(MutableSequence, CommentedBase):
+ __slots__ = (Comment.attrib, '_lst')
- def _yaml_add_comment(self, comment, key=NoComment):
- # type: (Any, Optional[Any]) -> None
- if key is not NoComment:
- self.yaml_key_comment_extend(key, comment)
- else:
- self.ca.comment = comment
+ def __init__(self, *args, **kw):
+ # type: (Any, Any) -> None
+ self._lst = list(*args, **kw)
- def _yaml_add_eol_comment(self, comment, key):
+ def __getitem__(self, idx):
+ # type: (Any) -> Any
+ return self._lst[idx]
+
+ def __setitem__(self, idx, value):
# type: (Any, Any) -> None
- self._yaml_add_comment(comment, key=key)
+ # try to preserve the scalarstring type if setting an existing key to a new value
+ if idx < len(self):
+ if (
+ isinstance(value, string_types)
+ and not isinstance(value, ScalarString)
+ and isinstance(self[idx], ScalarString)
+ ):
+ value = type(self[idx])(value)
+ self._lst.__setitem__(idx, value)
- def _yaml_get_columnX(self, key):
+ def __delitem__(self, idx=None):
# type: (Any) -> Any
- return self.ca.items[key][0].start_mark.column
+ del self._lst[idx]
+ self.ca.items.pop(idx, None) # might not be there -> default value
+ for list_index in sorted(self.ca.items):
+ if list_index < idx:
+ continue
+ self.ca.items[list_index - 1] = self.ca.items.pop(list_index)
+
+ def __len__(self):
+ # type: () -> int
+ return len(self._lst)
def insert(self, idx, val):
# type: (Any, Any) -> None
"""the comments after the insertion have to move forward"""
- list.insert(self, idx, val)
+ self._lst.insert(idx, val)
for list_index in sorted(self.ca.items, reverse=True):
if list_index < idx:
break
self.ca.items[list_index + 1] = self.ca.items.pop(list_index)
- def pop(self, idx=None):
+ def extend(self, val):
+ # type: (Any) -> None
+ self._lst.extend(val)
+
+ def __eq__(self, other):
+ # type: (Any) -> bool
+ return bool(self._lst == other)
+
+ def _yaml_add_comment(self, comment, key=NoComment):
+ # type: (Any, Optional[Any]) -> None
+ if key is not NoComment:
+ self.yaml_key_comment_extend(key, comment)
+ else:
+ self.ca.comment = comment
+
+ def _yaml_add_eol_comment(self, comment, key):
+ # type: (Any, Any) -> None
+ self._yaml_add_comment(comment, key=key)
+
+ def _yaml_get_columnX(self, key):
# type: (Any) -> Any
- res = list.pop(self, idx)
- self.ca.items.pop(idx, None) # might not be there -> default value
- for list_index in sorted(self.ca.items):
- if list_index < idx:
- continue
- self.ca.items[list_index - 1] = self.ca.items.pop(list_index)
- return res
+ return self.ca.items[key][0].start_mark.column
def _yaml_get_column(self, key):
# type: (Any) -> Any
@@ -461,18 +492,6 @@ class CommentedSeq(list, CommentedBase):
self.copy_attributes(res, deep=True)
return res
- def __setitem__(self, idx, value):
- # type: (Any, Any) -> None
- # try to preserve the scalarstring type if setting an existing key to a new value
- if idx < len(self):
- if (
- isinstance(value, string_types)
- and not isinstance(value, ScalarString)
- and isinstance(self[idx], ScalarString)
- ):
- value = type(self[idx])(value)
- list.__setitem__(self, idx, value)
-
class CommentedKeySeq(tuple, CommentedBase):
"""This primarily exists to be able to roundtrip keys that are sequences"""
diff --git a/compat.py b/compat.py
index c2db2bb..80cb089 100644
--- a/compat.py
+++ b/compat.py
@@ -91,7 +91,7 @@ if PY3:
BytesIO = io.BytesIO
# have unlimited precision
no_limit_int = int
- from collections.abc import Hashable # NOQA
+ from collections.abc import Hashable, MutableSequence # NOQA
else:
string_types = basestring # NOQA
@@ -110,7 +110,7 @@ else:
BytesIO = cStringIO.StringIO
# have unlimited precision
no_limit_int = long # NOQA not available on Python 3
- from collections import Hashable # NOQA
+ from collections import Hashable, MutableSequence # NOQA
if False: # MYPY
# StreamType = Union[BinaryIO, IO[str], IO[unicode], StringIO]
diff --git a/constructor.py b/constructor.py
index 8bf72bb..9de28d0 100644
--- a/constructor.py
+++ b/constructor.py
@@ -16,7 +16,8 @@ from ruamel.yaml.error import (MarkedYAMLError, MarkedYAMLFutureWarning,
from ruamel.yaml.nodes import * # NOQA
from ruamel.yaml.nodes import (SequenceNode, MappingNode, ScalarNode)
from ruamel.yaml.compat import (utf8, builtins_module, to_str, PY2, PY3, # NOQA
- ordereddict, text_type, nprint, version_tnf, Hashable)
+ ordereddict, text_type, nprint, version_tnf, Hashable,
+ MutableSequence)
from ruamel.yaml.comments import * # NOQA
from ruamel.yaml.comments import (CommentedMap, CommentedOrderedMap, CommentedSet,
CommentedKeySeq, CommentedSeq, TaggedScalar)
@@ -1311,7 +1312,7 @@ class RoundTripConstructor(SafeConstructor):
key = self.construct_object(key_node, deep=True)
# lists are not hashable, but tuples are
if not isinstance(key, Hashable):
- if isinstance(key, list):
+ if isinstance(key, MutableSequence):
key_a = CommentedKeySeq(key)
if key_node.flow_style is True:
key_a.fa.set_flow_style()