Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/isodate/isoduration.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 1 ############################################################################## | |
| 2 # Copyright 2009, Gerhard Weis | |
| 3 # All rights reserved. | |
| 4 # | |
| 5 # Redistribution and use in source and binary forms, with or without | |
| 6 # modification, are permitted provided that the following conditions are met: | |
| 7 # | |
| 8 # * Redistributions of source code must retain the above copyright notice, | |
| 9 # this list of conditions and the following disclaimer. | |
| 10 # * Redistributions in binary form must reproduce the above copyright notice, | |
| 11 # this list of conditions and the following disclaimer in the documentation | |
| 12 # and/or other materials provided with the distribution. | |
| 13 # * Neither the name of the authors nor the names of its contributors | |
| 14 # may be used to endorse or promote products derived from this software | |
| 15 # without specific prior written permission. | |
| 16 # | |
| 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| 18 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 20 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
| 21 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| 22 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| 23 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| 24 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| 25 # CONTRACT, STRICT LIABILITY, OR TORT | |
| 26 ############################################################################## | |
| 27 ''' | |
| 28 This module provides an ISO 8601:2004 duration parser. | |
| 29 | |
| 30 It also provides a wrapper to strftime. This wrapper makes it easier to | |
| 31 format timedelta or Duration instances as ISO conforming strings. | |
| 32 ''' | |
| 33 from datetime import timedelta | |
| 34 from decimal import Decimal | |
| 35 import re | |
| 36 | |
| 37 from six import string_types | |
| 38 | |
| 39 from isodate.duration import Duration | |
| 40 from isodate.isoerror import ISO8601Error | |
| 41 from isodate.isodatetime import parse_datetime | |
| 42 from isodate.isostrf import strftime, D_DEFAULT | |
| 43 | |
| 44 ISO8601_PERIOD_REGEX = re.compile( | |
| 45 r"^(?P<sign>[+-])?" | |
| 46 r"P(?!\b)" | |
| 47 r"(?P<years>[0-9]+([,.][0-9]+)?Y)?" | |
| 48 r"(?P<months>[0-9]+([,.][0-9]+)?M)?" | |
| 49 r"(?P<weeks>[0-9]+([,.][0-9]+)?W)?" | |
| 50 r"(?P<days>[0-9]+([,.][0-9]+)?D)?" | |
| 51 r"((?P<separator>T)(?P<hours>[0-9]+([,.][0-9]+)?H)?" | |
| 52 r"(?P<minutes>[0-9]+([,.][0-9]+)?M)?" | |
| 53 r"(?P<seconds>[0-9]+([,.][0-9]+)?S)?)?$") | |
| 54 # regular expression to parse ISO duartion strings. | |
| 55 | |
| 56 | |
| 57 def parse_duration(datestring): | |
| 58 """ | |
| 59 Parses an ISO 8601 durations into datetime.timedelta or Duration objects. | |
| 60 | |
| 61 If the ISO date string does not contain years or months, a timedelta | |
| 62 instance is returned, else a Duration instance is returned. | |
| 63 | |
| 64 The following duration formats are supported: | |
| 65 -PnnW duration in weeks | |
| 66 -PnnYnnMnnDTnnHnnMnnS complete duration specification | |
| 67 -PYYYYMMDDThhmmss basic alternative complete date format | |
| 68 -PYYYY-MM-DDThh:mm:ss extended alternative complete date format | |
| 69 -PYYYYDDDThhmmss basic alternative ordinal date format | |
| 70 -PYYYY-DDDThh:mm:ss extended alternative ordinal date format | |
| 71 | |
| 72 The '-' is optional. | |
| 73 | |
| 74 Limitations: ISO standard defines some restrictions about where to use | |
| 75 fractional numbers and which component and format combinations are | |
| 76 allowed. This parser implementation ignores all those restrictions and | |
| 77 returns something when it is able to find all necessary components. | |
| 78 In detail: | |
| 79 it does not check, whether only the last component has fractions. | |
| 80 it allows weeks specified with all other combinations | |
| 81 | |
| 82 The alternative format does not support durations with years, months or | |
| 83 days set to 0. | |
| 84 """ | |
| 85 if not isinstance(datestring, string_types): | |
| 86 raise TypeError("Expecting a string %r" % datestring) | |
| 87 match = ISO8601_PERIOD_REGEX.match(datestring) | |
| 88 if not match: | |
| 89 # try alternative format: | |
| 90 if datestring.startswith("P"): | |
| 91 durdt = parse_datetime(datestring[1:]) | |
| 92 if durdt.year != 0 or durdt.month != 0: | |
| 93 # create Duration | |
| 94 ret = Duration(days=durdt.day, seconds=durdt.second, | |
| 95 microseconds=durdt.microsecond, | |
| 96 minutes=durdt.minute, hours=durdt.hour, | |
| 97 months=durdt.month, years=durdt.year) | |
| 98 else: # FIXME: currently not possible in alternative format | |
| 99 # create timedelta | |
| 100 ret = timedelta(days=durdt.day, seconds=durdt.second, | |
| 101 microseconds=durdt.microsecond, | |
| 102 minutes=durdt.minute, hours=durdt.hour) | |
| 103 return ret | |
| 104 raise ISO8601Error("Unable to parse duration string %r" % datestring) | |
| 105 groups = match.groupdict() | |
| 106 for key, val in groups.items(): | |
| 107 if key not in ('separator', 'sign'): | |
| 108 if val is None: | |
| 109 groups[key] = "0n" | |
| 110 # print groups[key] | |
| 111 if key in ('years', 'months'): | |
| 112 groups[key] = Decimal(groups[key][:-1].replace(',', '.')) | |
| 113 else: | |
| 114 # these values are passed into a timedelta object, | |
| 115 # which works with floats. | |
| 116 groups[key] = float(groups[key][:-1].replace(',', '.')) | |
| 117 if groups["years"] == 0 and groups["months"] == 0: | |
| 118 ret = timedelta(days=groups["days"], hours=groups["hours"], | |
| 119 minutes=groups["minutes"], seconds=groups["seconds"], | |
| 120 weeks=groups["weeks"]) | |
| 121 if groups["sign"] == '-': | |
| 122 ret = timedelta(0) - ret | |
| 123 else: | |
| 124 ret = Duration(years=groups["years"], months=groups["months"], | |
| 125 days=groups["days"], hours=groups["hours"], | |
| 126 minutes=groups["minutes"], seconds=groups["seconds"], | |
| 127 weeks=groups["weeks"]) | |
| 128 if groups["sign"] == '-': | |
| 129 ret = Duration(0) - ret | |
| 130 return ret | |
| 131 | |
| 132 | |
| 133 def duration_isoformat(tduration, format=D_DEFAULT): | |
| 134 ''' | |
| 135 Format duration strings. | |
| 136 | |
| 137 This method is just a wrapper around isodate.isostrf.strftime and uses | |
| 138 P%P (D_DEFAULT) as default format. | |
| 139 ''' | |
| 140 # TODO: implement better decision for negative Durations. | |
| 141 # should be done in Duration class in consistent way with timedelta. | |
| 142 if (((isinstance(tduration, Duration) and | |
| 143 (tduration.years < 0 or tduration.months < 0 or | |
| 144 tduration.tdelta < timedelta(0))) or | |
| 145 (isinstance(tduration, timedelta) and | |
| 146 (tduration < timedelta(0))))): | |
| 147 ret = '-' | |
| 148 else: | |
| 149 ret = '' | |
| 150 ret += strftime(tduration, format) | |
| 151 return ret |
