diff options
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | README.rst | 8 | ||||
-rw-r--r-- | __init__.py | 6 | ||||
-rw-r--r-- | _doc/_static/pypi.svg | 2 | ||||
-rw-r--r-- | _test/test_datetime.py | 13 | ||||
-rw-r--r-- | constructor.py | 22 | ||||
-rw-r--r-- | emitter.py | 2 | ||||
-rw-r--r-- | util.py | 15 |
9 files changed, 45 insertions, 29 deletions
@@ -1,3 +1,7 @@ +[0, 17, 20]: today + - fix error in microseconds while rounding datetime fractions >= 9999995 + (reported by `Luis Ferreira <https://sourceforge.net/u/ljmf00/>`__) + [0, 17, 19]: 2021-12-26 - fix mypy problems (reported by `Arun <https://sourceforge.net/u/arunppsg/profile/>`__) @@ -1,6 +1,6 @@ The MIT License (MIT) - Copyright (c) 2014-2021 Anthon van der Neut, Ruamel bvba + Copyright (c) 2014-2022 Anthon van der Neut, Ruamel bvba Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -4,8 +4,8 @@ ruamel.yaml ``ruamel.yaml`` is a YAML 1.2 loader/dumper package for Python. -:version: 0.17.19 -:updated: 2021-12-26 +:version: 0.17.20 +:updated: today :documentation: http://yaml.readthedocs.io :repository: https://sourceforge.net/projects/ruamel-yaml/ :pypi: https://pypi.org/project/ruamel.yaml/ @@ -72,6 +72,10 @@ ChangeLog .. should insert NEXT: at the beginning of line for next key (with empty line) +0.17.20 (today): + - fix error in microseconds while rounding datetime fractions >= 9999995 + (reported by `Luis Ferreira <https://sourceforge.net/u/ljmf00/>`__) + 0.17.19 (2021-12-26): - fix mypy problems (reported by `Arun <https://sourceforge.net/u/arunppsg/profile/>`__) diff --git a/__init__.py b/__init__.py index 3666b0b..4e95b86 100644 --- a/__init__.py +++ b/__init__.py @@ -5,9 +5,9 @@ if False: # MYPY _package_data = dict( full_package_name='ruamel.yaml', - version_info=(0, 17, 19), - __version__='0.17.19', - version_timestamp='2021-12-26 16:02:42', + version_info=(0, 17, 20), + __version__='0.17.20', + version_timestamp='2022-01-03 09:19:48', 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/_doc/_static/pypi.svg b/_doc/_static/pypi.svg index cd5be20..85bfab9 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.17.19</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.17.19</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.17.20</text><text x="585" y="140" transform="scale(.1)" textLength="430">0.17.20</text></g> </svg> diff --git a/_test/test_datetime.py b/_test/test_datetime.py index 5874c0d..7321816 100644 --- a/_test/test_datetime.py +++ b/_test/test_datetime.py @@ -145,3 +145,16 @@ class TestDateTime: """) data = copy.deepcopy(round_trip_load(x)) assert round_trip_dump(data) == x + + def test_fraction_overflow(self): + # reported (indirectly) by Luís Ferreira + # https://sourceforge.net/p/ruamel-yaml/tickets/414/ + inp = dedent("""\ + - 2022-01-02T12:34:59.9999994 + - 2022-01-02T12:34:59.9999995 + """) + exp = dedent("""\ + - 2022-01-02T12:34:59.999999 + - 2022-01-02T12:35:00 + """) + round_trip(inp, exp) diff --git a/constructor.py b/constructor.py index 6049c0c..6aa6371 100644 --- a/constructor.py +++ b/constructor.py @@ -1759,20 +1759,7 @@ class RoundTripConstructor(SafeConstructor): else: return create_timestamp(**values) # return SafeConstructor.construct_yaml_timestamp(self, node, values) - year = int(values['year']) - month = int(values['month']) - day = int(values['day']) - hour = int(values['hour']) - minute = int(values['minute']) - second = int(values['second']) - fraction = 0 - if values['fraction']: - fraction_s = values['fraction'][:6] - while len(fraction_s) < 6: - fraction_s += '0' - fraction = int(fraction_s) - if len(values['fraction']) > 6 and int(values['fraction'][6]) > 4: - fraction += 1 + dd = create_timestamp(**values) # this has delta applied delta = None if values['tz_sign']: tz_hour = int(values['tz_hour']) @@ -1782,17 +1769,16 @@ class RoundTripConstructor(SafeConstructor): if values['tz_sign'] == '-': delta = -delta # should check for None and solve issue 366 should be tzinfo=delta) + data = TimeStamp( + dd.year, dd.month, dd.day, dd.hour, dd.minute, dd.second, dd.microsecond + ) if delta: - dt = datetime.datetime(year, month, day, hour, minute) - dt -= delta - data = TimeStamp(dt.year, dt.month, dt.day, dt.hour, dt.minute, second, fraction) data._yaml['delta'] = delta tz = values['tz_sign'] + values['tz_hour'] if values['tz_minute']: tz += ':' + values['tz_minute'] data._yaml['tz'] = tz else: - data = TimeStamp(year, month, day, hour, minute, second, fraction) if values['tz']: # no delta data._yaml['tz'] = values['tz'] @@ -76,7 +76,7 @@ class Indents: def seq_flow_align(self, seq_indent, column, pre_comment=False): # type: (int, int, Optional[bool]) -> int # extra spaces because of dash - nprint('seq_flow_align', self.values, pre_comment) + # nprint('seq_flow_align', self.values, pre_comment) if len(self.values) < 2 or not self.values[-1][1]: if len(self.values) == 0 or not pre_comment: return 0 @@ -68,6 +68,8 @@ def create_timestamp( year, month, day, t, hour, minute, second, fraction, tz, tz_sign, tz_hour, tz_minute ): # type: (Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any) -> Any + # create a timestamp from match against timestamp_regexp + MAX_FRAC = 999999 year = int(year) month = int(month) day = int(day) @@ -76,24 +78,31 @@ def create_timestamp( hour = int(hour) minute = int(minute) second = int(second) + frac = 0 if fraction: - frac = 0 frac_s = fraction[:6] while len(frac_s) < 6: frac_s += '0' frac = int(frac_s) if len(fraction) > 6 and int(fraction[6]) > 4: frac += 1 - fraction = frac + if frac > MAX_FRAC: + fraction = 0 + else: + fraction = frac else: fraction = 0 delta = None if tz_sign: tz_hour = int(tz_hour) tz_minute = int(tz_minute) if tz_minute else 0 - delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute) + delta = datetime.timedelta( + hours=tz_hour, minutes=tz_minute, seconds=1 if frac > MAX_FRAC else 0 + ) if tz_sign == '-': delta = -delta + elif frac > MAX_FRAC: + delta = -datetime.timedelta(seconds=1) # should do something else instead (or hook this up to the preceding if statement # in reverse # if delta is None: |