summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES8
-rw-r--r--README.rst9
-rw-r--r--__init__.py4
-rw-r--r--_test/test_fail.py4
-rw-r--r--_test/test_int.py43
-rw-r--r--constructor.py40
-rw-r--r--representer.py36
-rw-r--r--scalarint.py75
-rw-r--r--scalarstring.py3
9 files changed, 213 insertions, 9 deletions
diff --git a/CHANGES b/CHANGES
index 6f116a9..063576e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,11 @@
+[0, 14, 6]: 2017-04-14
+ - binary, octal and hex integers are now preserved by default. This
+ was a known deficiency. Working on this was prompted by the issue report (112)
+ from devnoname120, as well as the additional experience with `.replace()`
+ on `scalarstring` classes.
+ - fix issues 114: cannot install on Buildozer (reported by mixmastamyk).
+ Setting env. var ``RUAMEL_NO_PIP_INSTALL_CHECK`` will suppress ``pip``-check.
+
[0, 14, 5]: 2017-04-04
- fix issue 109: None not dumping correctly at top level (reported by Andrea Censi)
- fix issue 110: .replace on Preserved/DoubleQuoted/SingleQuoted ScalarString
diff --git a/README.rst b/README.rst
index ce30899..ee43342 100644
--- a/README.rst
+++ b/README.rst
@@ -18,7 +18,11 @@ ChangeLog
.. should insert NEXT: at the beginning of line for next key
-NEXT:
+0.14.6 (2017-04-14):
+ - binary, octal and hex integers are now preserved by default. This
+ was a known deficiency. Working on this was prompted by the issue report (112)
+ from devnoname120, as well as the additional experience with `.replace()`
+ on `scalarstring` classes.
- fix issues 114: cannot install on Buildozer (reported by mixmastamyk).
Setting env. var ``RUAMEL_NO_PIP_INSTALL_CHECK`` will suppress ``pip``-check.
@@ -112,6 +116,7 @@ NEXT:
`StackOveflow Q&A <http://stackoverflow.com/a/40705671/1307905>`_ by
`msinn <http://stackoverflow.com/users/7185467/msinn>`_)
----
+----
+
For older changes see the file
`CHANGES <https://bitbucket.org/ruamel/yaml/src/default/CHANGES>`_
diff --git a/__init__.py b/__init__.py
index a7976a3..7963ae0 100644
--- a/__init__.py
+++ b/__init__.py
@@ -10,8 +10,8 @@ from typing import Dict, Any # NOQA
_package_data = dict(
full_package_name='ruamel.yaml',
- version_info=(0, 14, 6, 'dev'),
- __version__='0.14.6.dev',
+ version_info=(0, 14, 6),
+ __version__='0.14.6',
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/_test/test_fail.py b/_test/test_fail.py
index 300bfa6..61b8ffb 100644
--- a/_test/test_fail.py
+++ b/_test/test_fail.py
@@ -220,8 +220,8 @@ class TestFlowValues:
{a: bcd:efg}
""")
- @pytest.mark.xfail(strict=True)
+ # @pytest.mark.xfail(strict=True)
def test_flow_value_with_colon_quoted(self):
round_trip("""\
{a: 'bcd:efg'}
- """)
+ """, preserve_quotes=True)
diff --git a/_test/test_int.py b/_test/test_int.py
new file mode 100644
index 0000000..6776b51
--- /dev/null
+++ b/_test/test_int.py
@@ -0,0 +1,43 @@
+# coding: utf-8
+
+from __future__ import print_function, absolute_import, division, unicode_literals
+
+import pytest # NOQA
+
+from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump
+
+
+class TestBinHexOct:
+ # @pytest.mark.xfail(strict=True)
+ def test_round_trip_hex_oct(self):
+ round_trip("""\
+ - 42
+ - 0b101010
+ - 0x2a
+ - 0x2A
+ - 0o52
+ """)
+
+ def test_calculate(self):
+ s = dedent("""\
+ - 42
+ - 0b101010
+ - 0x2a
+ - 0x2A
+ - 0o52
+ """)
+ x = round_trip_load(s)
+ for idx, elem in enumerate(x):
+ # x[idx] = type(elem)(elem - 21)
+ elem -= 21
+ x[idx] = elem
+ for idx, elem in enumerate(x):
+ # x[idx] = type(elem)(2 * elem)
+ elem *= 2
+ x[idx] = elem
+ for idx, elem in enumerate(x):
+ t = elem
+ elem **= 2
+ elem //= t
+ x[idx] = elem
+ assert round_trip_dump(x) == s
diff --git a/constructor.py b/constructor.py
index 6797d95..f7baef1 100644
--- a/constructor.py
+++ b/constructor.py
@@ -24,6 +24,7 @@ from ruamel.yaml.comments import (CommentedMap, CommentedOrderedMap, CommentedSe
from ruamel.yaml.scalarstring import * # NOQA
from ruamel.yaml.scalarstring import (PreservedScalarString, SingleQuotedScalarString,
DoubleQuotedScalarString, ScalarString)
+from ruamel.yaml.scalarint import BinaryInt, OctalInt, HexInt, HexCapsInt
from ruamel.yaml.timestamp import TimeStamp
__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
@@ -907,6 +908,45 @@ class RoundTripConstructor(SafeConstructor):
return DoubleQuotedScalarString(node.value)
return node.value
+ def construct_yaml_int(self, node):
+ # type: (Any) -> Any
+ value_s = to_str(self.construct_scalar(node))
+ value_s = value_s.replace('_', '')
+ sign = +1
+ if value_s[0] == '-':
+ sign = -1
+ if value_s[0] in '+-':
+ value_s = value_s[1:]
+ if value_s == '0':
+ return 0
+ elif value_s.startswith('0b'):
+ return BinaryInt(sign*int(value_s[2:], 2))
+ elif value_s.startswith('0x'):
+ # default to lower-case if no a-fA-F in string
+ hex_fun = HexInt # type: Any
+ for ch in value_s[2:]:
+ if ch in 'ABCDEF': # first non-digit is capital
+ hex_fun = HexCapsInt
+ break
+ if ch in 'abcdef':
+ break
+ return hex_fun(sign*int(value_s[2:], 16))
+ elif value_s.startswith('0o'):
+ return OctalInt(sign*int(value_s[2:], 8))
+ elif self.resolver.processing_version != (1, 2) and value_s[0] == '0':
+ return sign*int(value_s, 8)
+ elif self.resolver.processing_version != (1, 2) and ':' in value_s:
+ digits = [int(part) for part in value_s.split(':')]
+ digits.reverse()
+ base = 1
+ value = 0
+ for digit in digits:
+ value += digit*base
+ base *= 60
+ return sign*value
+ else:
+ return sign*int(value_s)
+
def construct_yaml_str(self, node):
# type: (Any) -> Any
value = self.construct_scalar(node)
diff --git a/representer.py b/representer.py
index 5db1d98..0c19a61 100644
--- a/representer.py
+++ b/representer.py
@@ -8,7 +8,9 @@ from typing import Dict, List, Any, Union # NOQA
from ruamel.yaml.error import * # NOQA
from ruamel.yaml.nodes import * # NOQA
from ruamel.yaml.compat import text_type, binary_type, to_unicode, PY2, PY3, ordereddict
-from ruamel.yaml.scalarstring import * # NOQA
+from ruamel.yaml.scalarstring import (PreservedScalarString, SingleQuotedScalarString,
+ DoubleQuotedScalarString)
+from ruamel.yaml.scalarint import BinaryInt, OctalInt, HexInt, HexCapsInt
from ruamel.yaml.timestamp import TimeStamp
import datetime
@@ -676,6 +678,22 @@ class RoundTripRepresenter(SafeRepresenter):
tag = u'tag:yaml.org,2002:str'
return self.represent_scalar(tag, data, style=style)
+ def represent_binary_int(self, data):
+ # type: (Any) -> Any
+ return self.represent_scalar(u'tag:yaml.org,2002:int', '0b' + format(data, 'b'))
+
+ def represent_octal_int(self, data):
+ # type: (Any) -> Any
+ return self.represent_scalar(u'tag:yaml.org,2002:int', '0o' + format(data, 'o'))
+
+ def represent_hex_int(self, data):
+ # type: (Any) -> Any
+ return self.represent_scalar(u'tag:yaml.org,2002:int', '0x' + format(data, 'x'))
+
+ def represent_hex_caps_int(self, data):
+ # type: (Any) -> Any
+ return self.represent_scalar(u'tag:yaml.org,2002:int', '0x' + format(data, 'X'))
+
def represent_sequence(self, tag, sequence, flow_style=None):
# type: (Any, Any, Any) -> Any
value = [] # type: List[Any]
@@ -952,6 +970,22 @@ RoundTripRepresenter.add_representer(
DoubleQuotedScalarString,
RoundTripRepresenter.represent_double_quoted_scalarstring)
+RoundTripRepresenter.add_representer(
+ BinaryInt,
+ RoundTripRepresenter.represent_binary_int)
+
+RoundTripRepresenter.add_representer(
+ OctalInt,
+ RoundTripRepresenter.represent_octal_int)
+
+RoundTripRepresenter.add_representer(
+ HexInt,
+ RoundTripRepresenter.represent_hex_int)
+
+RoundTripRepresenter.add_representer(
+ HexCapsInt,
+ RoundTripRepresenter.represent_hex_caps_int)
+
RoundTripRepresenter.add_representer(CommentedSeq,
RoundTripRepresenter.represent_list)
diff --git a/scalarint.py b/scalarint.py
new file mode 100644
index 0000000..e2028e3
--- /dev/null
+++ b/scalarint.py
@@ -0,0 +1,75 @@
+# coding: utf-8
+
+from __future__ import print_function, absolute_import, division, unicode_literals
+
+import sys
+
+if sys.version_info >= (3, 5, 2):
+ from typing import Text, Any, Dict, List # NOQA
+
+__all__ = ["ScalarInt", "BinaryInt", "OctalInt", "HexInt", "HexCapsInt"]
+
+
+class ScalarInt(int):
+ __slots__ = ()
+
+ def __new__(cls, *args, **kw):
+ # type: (Any, Any) -> Any
+ return int.__new__(cls, *args, **kw) # type: ignore
+
+ def __iadd__(self, a): # type: ignore
+ # type: (Any) -> Any
+ return type(self)(self + a)
+
+ def __ifloordiv__(self, a): # type: ignore
+ # type: (Any) -> Any
+ return type(self)(self // a)
+
+ def __imul__(self, a): # type: ignore
+ # type: (Any) -> Any
+ return type(self)(self * a)
+
+ def __ipow__(self, a): # type: ignore
+ # type: (Any) -> Any
+ return type(self)(self ** a)
+
+ def __isub__(self, a): # type: ignore
+ # type: (Any) -> Any
+ return type(self)(self - a)
+
+
+class BinaryInt(ScalarInt):
+ __slots__ = ()
+
+ def __new__(cls, value):
+ # type: (Text) -> Any
+ return ScalarInt.__new__(cls, value)
+
+
+class OctalInt(ScalarInt):
+ __slots__ = ()
+
+ def __new__(cls, value):
+ # type: (Text) -> Any
+ return ScalarInt.__new__(cls, value)
+
+
+# mixed casing of A-F is not supported, when loading the first non digit
+# determines the case
+
+class HexInt(ScalarInt):
+ """uses lower case (a-f)"""
+ __slots__ = ()
+
+ def __new__(cls, value):
+ # type: (Text) -> Any
+ return ScalarInt.__new__(cls, value)
+
+
+class HexCapsInt(ScalarInt):
+ """uses upper case (A-F)"""
+ __slots__ = ()
+
+ def __new__(cls, value):
+ # type: (Text) -> Any
+ return ScalarInt.__new__(cls, value)
diff --git a/scalarstring.py b/scalarstring.py
index 3282c1e..05e4593 100644
--- a/scalarstring.py
+++ b/scalarstring.py
@@ -1,7 +1,6 @@
# coding: utf-8
-from __future__ import absolute_import
-from __future__ import print_function
+from __future__ import print_function, absolute_import, division, unicode_literals
import sys