Skip to content

Commit 1bc5b5e

Browse files
authored
Merge pull request kubernetes-client#2266 from kflynn/flynn/dev/gep-2257-tweaks
GEP-2257 tweaks
2 parents 90d4fef + 8e3d9c4 commit 1bc5b5e

File tree

1 file changed

+72
-5
lines changed

1 file changed

+72
-5
lines changed

kubernetes/utils/duration.py

+72-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
# really be a big deal.
2222
reDuration = re.compile(r'^([0-9]{1,5}(h|m|s|ms)){1,4}$')
2323

24+
# maxDuration_ms is the maximum duration that GEP-2257 can support, in
25+
# milliseconds.
26+
maxDuration_ms = (((99999 * 3600) + (59 * 60) + 59) * 1_000) + 999
27+
28+
2429
def parse_duration(duration) -> datetime.timedelta:
2530
"""
2631
Parse GEP-2257 Duration format to a datetime.timedelta object.
@@ -32,17 +37,47 @@ def parse_duration(duration) -> datetime.timedelta:
3237
See https://gateway-api.sigs.k8s.io/geps/gep-2257/ for more details.
3338
3439
Input: duration: string
35-
3640
Returns: datetime.timedelta
3741
3842
Raises: ValueError on invalid or unknown input
43+
44+
Examples:
45+
>>> parse_duration("1h")
46+
datetime.timedelta(seconds=3600)
47+
>>> parse_duration("1m")
48+
datetime.timedelta(seconds=60)
49+
>>> parse_duration("1s")
50+
datetime.timedelta(seconds=1)
51+
>>> parse_duration("1ms")
52+
datetime.timedelta(microseconds=1000)
53+
>>> parse_duration("1h1m1s")
54+
datetime.timedelta(seconds=3661)
55+
>>> parse_duration("10s30m1h")
56+
datetime.timedelta(seconds=5410)
57+
58+
Units are always required.
59+
>>> parse_duration("1")
60+
Traceback (most recent call last):
61+
...
62+
ValueError: Invalid duration format: 1
63+
64+
Floating-point and negative durations are not valid.
65+
>>> parse_duration("1.5m")
66+
Traceback (most recent call last):
67+
...
68+
ValueError: Invalid duration format: 1.5m
69+
>>> parse_duration("-1m")
70+
Traceback (most recent call last):
71+
...
72+
ValueError: Invalid duration format: -1m
3973
"""
4074

4175
if not reDuration.match(duration):
4276
raise ValueError("Invalid duration format: {}".format(duration))
4377

4478
return durationpy.from_str(duration)
4579

80+
4681
def format_duration(delta: datetime.timedelta) -> str:
4782
"""
4883
Format a datetime.timedelta object to GEP-2257 Duration format.
@@ -59,12 +94,48 @@ def format_duration(delta: datetime.timedelta) -> str:
5994
6095
Raises: ValueError if the timedelta given cannot be expressed as a
6196
GEP-2257 Duration.
97+
98+
Examples:
99+
>>> format_duration(datetime.timedelta(seconds=3600))
100+
'1h'
101+
>>> format_duration(datetime.timedelta(seconds=60))
102+
'1m'
103+
>>> format_duration(datetime.timedelta(seconds=1))
104+
'1s'
105+
>>> format_duration(datetime.timedelta(microseconds=1000))
106+
'1ms'
107+
>>> format_duration(datetime.timedelta(seconds=5410))
108+
'1h30m10s'
109+
110+
The zero duration is always "0s".
111+
>>> format_duration(datetime.timedelta(0))
112+
'0s'
113+
114+
Sub-millisecond precision is not allowed.
115+
>>> format_duration(datetime.timedelta(microseconds=100))
116+
Traceback (most recent call last):
117+
...
118+
ValueError: Cannot express sub-millisecond precision in GEP-2257: 0:00:00.000100
119+
120+
Negative durations are not allowed.
121+
>>> format_duration(datetime.timedelta(seconds=-1))
122+
Traceback (most recent call last):
123+
...
124+
ValueError: Cannot express negative durations in GEP-2257: -1 day, 23:59:59
62125
"""
63126

64127
# Short-circuit if we have a zero delta.
65128
if delta == datetime.timedelta(0):
66129
return "0s"
67130

131+
# Check range early.
132+
if delta < datetime.timedelta(0):
133+
raise ValueError("Cannot express negative durations in GEP-2257: {}".format(delta))
134+
135+
if delta > datetime.timedelta(milliseconds=maxDuration_ms):
136+
raise ValueError(
137+
"Cannot express durations longer than 99999h59m59s999ms in GEP-2257: {}".format(delta))
138+
68139
# durationpy.to_str() is happy to use floating-point seconds, which
69140
# GEP-2257 is _not_ happy with. So start by peeling off any microseconds
70141
# from our delta.
@@ -90,8 +161,4 @@ def format_duration(delta: datetime.timedelta) -> str:
90161

91162
delta_str += f"{delta_ms}ms"
92163

93-
if not reDuration.match(delta_str):
94-
raise ValueError("Invalid duration format: {}".format(durationpy.to_str(delta)))
95-
96164
return delta_str
97-

0 commit comments

Comments
 (0)