summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--_test/test_comments.py50
-rw-r--r--_test/test_float.py48
-rw-r--r--comments.py1
-rw-r--r--constructor.py30
-rw-r--r--cyaml.py2
-rw-r--r--error.py2
-rw-r--r--main.py4
-rw-r--r--representer.py49
-rw-r--r--scalarfloat.py8
-rw-r--r--tokens.py1
10 files changed, 157 insertions, 38 deletions
diff --git a/_test/test_comments.py b/_test/test_comments.py
index 2557b94..8c892c6 100644
--- a/_test/test_comments.py
+++ b/_test/test_comments.py
@@ -715,6 +715,14 @@ class TestEmptyValueBeforeComments:
- e: f
""")
+ def test_issue_25a1(self):
+ round_trip("""\
+ - a: b
+ c: d
+ d: # foo
+ e: f
+ """)
+
def test_issue_25b(self):
round_trip("""\
var1: #empty
@@ -729,6 +737,15 @@ class TestEmptyValueBeforeComments:
c: 3 # comment c
""")
+ def test_issue_25c1(self):
+ round_trip("""\
+ params:
+ a: 1 # comment a
+ b: # comment b
+ # extra
+ c: 3 # comment c
+ """)
+
def test_issue_25_00(self):
round_trip("""\
params:
@@ -736,6 +753,39 @@ class TestEmptyValueBeforeComments:
b: # comment b
""")
+ @pytest.mark.xfail(strict=True)
+ def test_issue_25_01(self):
+ round_trip("""\
+ a: # comment 1
+ # comment 2
+ - b: # comment 3
+ c: 1 # comment 4
+ """)
+
+ @pytest.mark.xfail(strict=True)
+ def test_issue_25_02(self):
+ round_trip("""\
+ a: # comment 1
+ # comment 2
+ - b: 2 # comment 3
+ """)
+
+ @pytest.mark.xfail(strict=True)
+ def test_issue_25_03(self):
+ round_trip("""\
+ a: # comment 1
+ # comment 2
+ - b: 2 # comment 3
+ """)
+
+ def test_issue_25_04(self):
+ round_trip("""\
+ a: # comment 1
+ # comment 2
+ b: 1 # comment 3
+ """)
+
+
test_block_scalar_commented_line_template = """\
y: p
diff --git a/_test/test_float.py b/_test/test_float.py
index 0adde1d..98a1f78 100644
--- a/_test/test_float.py
+++ b/_test/test_float.py
@@ -16,19 +16,56 @@ class TestFloat:
- 1.0
- 1.00
- 23.100
+ - -1.0
+ - -1.00
+ - -23.100
+ - 42.
+ - -42.
+ - +42.
""")
print(data)
assert 0.999 < data[0] < 1.001
assert 0.999 < data[1] < 1.001
assert 23.099 < data[2] < 23.101
+ assert 0.999 < -data[3] < 1.001
+ assert 0.999 < -data[4] < 1.001
+ assert 23.099 < -data[5] < 23.101
+ assert 41.999 < data[6] < 42.001
+ assert 41.999 < -data[7] < 42.001
+ assert 41.999 < data[8] < 42.001
- @pytest.mark.xfail(strict=True)
- def test_round_trip_non_exp_trailing_dot(self):
+ def test_round_trip_zeros_0(self):
+ data = round_trip("""\
+ - 0.
+ - +0.
+ - -0.
+ - 0.0
+ - +0.0
+ - -0.0
+ - 0.00
+ - +0.00
+ - -0.00
+ """)
+ print(data)
+ for d in data:
+ assert -0.00001 < d < 0.00001
+
+ # @pytest.mark.xfail(strict=True)
+ def test_round_trip_zeros_1(self):
+ # not sure if this should be supported, but it is
+ data = round_trip("""\
+ - 00.0
+ - +00.0
+ - -00.0
+ """)
+ print(data)
+ for d in data:
+ assert -0.00001 < d < 0.00001
+
+ def Xtest_round_trip_non_exp_trailing_dot(self):
data = round_trip("""\
- - 42.
""")
print(data)
- assert 41.999 < data[0] < 42.001
def test_round_trip_exp_00(self):
data = round_trip("""\
@@ -43,7 +80,7 @@ class TestFloat:
for d in data:
assert 41.99e56 < d < 42.01e56
- @pytest.mark.xfail(strict=True)
+ # @pytest.mark.xfail(strict=True)
def test_round_trip_exp_00f(self):
data = round_trip("""\
- 42.E56
@@ -94,6 +131,7 @@ class TestFloat:
- 1.230e+34
- 1.023e+34
- -1.023e+34
+ - 250e6
""")
def test_yaml_1_1_no_dot(self):
diff --git a/comments.py b/comments.py
index f8e68a6..1e2bf82 100644
--- a/comments.py
+++ b/comments.py
@@ -177,6 +177,7 @@ class Tag(object):
self.value = None
def __repr__(self):
+ # type: () -> Any
return '{0.__class__.__name__}({0.value!r})'.format(self)
diff --git a/constructor.py b/constructor.py
index 7e572ad..e91961e 100644
--- a/constructor.py
+++ b/constructor.py
@@ -1042,16 +1042,25 @@ class RoundTripConstructor(SafeConstructor):
return sign * int(value_s)
def construct_yaml_float(self, node):
- # type: (Any) -> float
+ # type: (Any) -> Any
+ def leading_zeros(v):
+ # type: (Any) -> int
+ lead0 = 0
+ idx = 0
+ while idx < len(v) and v[idx] in '0.':
+ if v[idx] == '0':
+ lead0 += 1
+ idx += 1
+ return lead0
underscore = None
- m_sign = False
+ m_sign = False # type: Any
value_so = to_str(self.construct_scalar(node))
value_s = value_so.replace('_', '').lower()
sign = +1
if value_s[0] == '-':
sign = -1
if value_s[0] in '+-':
- m_sign = True
+ m_sign = value_s[0]
value_s = value_s[1:]
if value_s == '.inf':
return sign * self.inf_value
@@ -1077,21 +1086,22 @@ class RoundTripConstructor(SafeConstructor):
# value_s is lower case independent of input
if '.' not in mantissa:
warnings.warn(MantissaNoDotYAML1_1Warning(node, value_so))
+ lead0 = leading_zeros(mantissa)
width = len(mantissa)
prec = mantissa.find('.')
- if prec > width - 2:
- prec = 0
if m_sign:
width -= 1
e_width = len(exponent)
e_sign = exponent[0] in '+-'
# print('sf', width, prec, m_sign, exp, e_width, e_sign)
- return ScalarFloat(sign * float(value_s), width=width, prec=prec, m_sign=m_sign,
- exp=exp, e_width=e_width, e_sign=e_sign)
+ return ScalarFloat(sign * float(value_s), # type: ignore
+ width=width, prec=prec, m_sign=m_sign,
+ m_lead0=lead0, exp=exp, e_width=e_width, e_sign=e_sign)
width = len(value_so)
- prec = value_so.index('.')
- return ScalarFloat(sign * float(value_s), width=width, prec=prec)
- # return sign * float(value_s)
+ prec = value_so.index('.') # you can use index, this would not be float without dot
+ lead0 = leading_zeros(value_so)
+ return ScalarFloat(sign * float(value_s), # type: ignore
+ width=width, prec=prec, m_sign=m_sign, m_lead0=lead0)
def construct_yaml_str(self, node):
# type: (Any) -> Any
diff --git a/cyaml.py b/cyaml.py
index 7f504a5..3e5b90a 100644
--- a/cyaml.py
+++ b/cyaml.py
@@ -92,7 +92,7 @@ class CSafeDumper(CEmitter, SafeRepresenter, Resolver): # type: ignore
explicit_start=explicit_start,
explicit_end=explicit_end,
version=version, tags=tags)
- self._emitter = self._serializer = self._representer = self
+ self._emitter = self._serializer = self._representer = self # type: ignore
SafeRepresenter.__init__(self, default_style=default_style,
default_flow_style=default_flow_style)
Resolver.__init__(self)
diff --git a/error.py b/error.py
index 4658f8e..f712a60 100644
--- a/error.py
+++ b/error.py
@@ -195,10 +195,12 @@ warnings.simplefilter('once', UnsafeLoaderWarning)
class MantissaNoDotYAML1_1Warning(YAMLWarning):
def __init__(self, node, flt_str):
+ # type: (Any, Any) -> None
self.node = node
self.flt = flt_str
def __str__(self):
+ # type: () -> Any
line = self.node.start_mark.line
col = self.node.start_mark.column
return """
diff --git a/main.py b/main.py
index 35bcdcf..949191d 100644
--- a/main.py
+++ b/main.py
@@ -383,10 +383,10 @@ class YAML(object):
delattr(self, "_serializer")
delattr(self, "_emitter")
if transform:
- val = stream.getvalue()
+ val = stream.getvalue() # type: ignore
if self.encoding:
val = val.decode(self.encoding)
- fstream.write(transform(val)) # type: ignore
+ fstream.write(transform(val))
return None
def get_serializer_representer_emitter(self, stream, tlca):
diff --git a/representer.py b/representer.py
index d2cc557..a4cf481 100644
--- a/representer.py
+++ b/representer.py
@@ -277,7 +277,7 @@ class SafeRepresenter(BaseRepresenter):
def represent_bool(self, data):
# type: (Any) -> Any
try:
- value = self.dumper.boolean_representation[bool(data)]
+ value = self.dumper.boolean_representation[bool(data)] # type: ignore
except AttributeError:
if data:
value = u'true'
@@ -309,15 +309,16 @@ class SafeRepresenter(BaseRepresenter):
value = u'-.inf'
else:
value = to_unicode(repr(data)).lower()
- if self.dumper.version == (1, 1) and u'.' not in value and u'e' in value:
- # Note that in some cases `repr(data)` represents a float number
- # without the decimal parts. For instance:
- # >>> repr(1e17)
- # '1e17'
- # Unfortunately, this is not a valid float representation according
- # to the definition of the `!!float` tag in YAML 1.1. We fix this by adding
- # '.0' before the 'e' symbol.
- value = value.replace(u'e', u'.0e', 1)
+ if self.dumper.version == (1, 1): # type: ignore
+ if u'.' not in value and u'e' in value:
+ # Note that in some cases `repr(data)` represents a float number
+ # without the decimal parts. For instance:
+ # >>> repr(1e17)
+ # '1e17'
+ # Unfortunately, this is not a valid float representation according
+ # to the definition of the `!!float` tag in YAML 1.1. We fix this by adding
+ # '.0' before the 'e' symbol.
+ value = value.replace(u'e', u'.0e', 1)
return self.represent_scalar(u'tag:yaml.org,2002:float', value)
def represent_list(self, data):
@@ -763,21 +764,22 @@ class RoundTripRepresenter(SafeRepresenter):
value = u'-.inf'
if value:
return self.represent_scalar(u'tag:yaml.org,2002:float', value)
- if data._exp is None:
+ if data._exp is None and data._prec > 0 and data._prec == data._width - 1:
+ # no exponent, but trailing dot
+ value = '{}{:d}.'.format(data._m_sign if data._m_sign else '', abs(int(data)))
+ elif data._exp is None:
+ # no exponent, "normal" dot
prec = data._prec
if prec < 1:
prec = 1
# print('dw2', data._width, prec)
- value = '{:{}.{}f}'.format(data, data._width, data._width-prec-1)
+ ms = data._m_sign if data._m_sign else ''
+ # -1 for the dot
+ value = '{}{:0{}.{}f}'.format(ms, abs(data), data._width-len(ms), data._width-prec-1)
while len(value) < data._width:
value += '0'
else:
- # print('pr', data._width, prec)
- # if data._prec > 0:
- # prec = data._width - data.prec
- # prec = data._prec
- # if prec < 1:
- # prec = 1
+ # exponent
m, es = '{:{}e}'.format(data, data._width).split('e')
w = data._width if data._prec > 0 else (data._width + 1)
if data < 0:
@@ -791,16 +793,23 @@ class RoundTripRepresenter(SafeRepresenter):
m1 = '+' + m1
esgn = '+' if data._e_sign else ''
if data._prec < 0: # mantissa without dot
- # print('ew2', m2, len(m2), e)
if m2 != '0':
e -= len(m2)
else:
m2 = ''
+ while (len(m1) + len(m2) - (1 if data._m_sign else 0)) < data._width:
+ m2 += '0'
+ e -= 1
value = m1 + m2 + data._exp + '{:{}0{}d}'.format(e, esgn, data._e_width)
- elif data._prec == 0: # mantissa with trailind dot
+ elif data._prec == 0: # mantissa with trailing dot
e -= len(m2)
value = m1 + m2 + '.' + data._exp + '{:{}0{}d}'.format(e, esgn, data._e_width)
else:
+ if data._m_lead0 > 0:
+ m2 = '0' * (data._m_lead0 - 1) + m1 + m2
+ m1 = '0'
+ m2 = m2[:-data._m_lead0] # these should be zeros
+ e += data._m_lead0
while len(m1) < data._prec:
m1 += m2[0]
m2 = m2[1:]
diff --git a/scalarfloat.py b/scalarfloat.py
index 01d7080..4608094 100644
--- a/scalarfloat.py
+++ b/scalarfloat.py
@@ -7,6 +7,7 @@ if False: # MYPY
__all__ = ["ScalarFloat", "ExponentialFloat", "ExponentialCapsFloat"]
+import sys
from .compat import no_limit_int # NOQA
@@ -16,6 +17,7 @@ class ScalarFloat(float):
width = kw.pop('width', None) # type: ignore
prec = kw.pop('prec', None) # type: ignore
m_sign = kw.pop('m_sign', None) # type: ignore
+ m_lead0 = kw.pop('m_lead0', 0) # type: ignore
exp = kw.pop('exp', None) # type: ignore
e_width = kw.pop('e_width', None) # type: ignore
e_sign = kw.pop('e_sign', None) # type: ignore
@@ -24,6 +26,7 @@ class ScalarFloat(float):
v._width = width
v._prec = prec
v._m_sign = m_sign
+ v._m_lead0 = m_lead0
v._exp = exp
v._e_width = e_width
v._e_sign = e_sign
@@ -65,6 +68,11 @@ class ScalarFloat(float):
x._underscore = self._underscore[:] if self._underscore is not None else None # type: ignore # NOQA
return x
+ def dump(self, out=sys.stdout):
+ # type: (Any) -> Any
+ print('ScalarFloat({}| w:{}, p:{}, s:{}, lz:{}|{}, w:{}, s:{})'.format(
+ self, self._width, self._prec, self._m_sign, self._m_lead0, # type: ignore
+ self._exp, self._e_width, self._e_sign), file=out) # type: ignore
class ExponentialFloat(ScalarFloat):
def __new__(cls, value, width=None, underscore=None):
diff --git a/tokens.py b/tokens.py
index aff531c..b60d11b 100644
--- a/tokens.py
+++ b/tokens.py
@@ -243,4 +243,5 @@ class CommentToken(Token):
delattr(self, 'pre_done')
def __repr__(self):
+ # type: () -> Any
return 'CommentToken({!r})'.format(self.value)