Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/isodate/isoduration.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
comparison
equal
deleted
inserted
replaced
4:79f47841a781 | 5:9b1c78e6ba9c |
---|---|
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 |