summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Nephin <dnephin@docker.com>2016-11-10 17:38:19 -0500
committerDaniel Nephin <dnephin@docker.com>2016-11-16 12:10:32 -0500
commit6cac48c0564f7f6b4e4d91055f50ec8c86505dd9 (patch)
tree26e4af6c14d2b80325b039ad2503c5adb68b7ec6
parent586443ba5d10c0540f61392e25a71daa1b439722 (diff)
Add a vendored and modified pytimeparse
Signed-off-by: Daniel Nephin <dnephin@docker.com>
-rw-r--r--compose/timeparse.py96
-rw-r--r--tests/unit/timeparse_test.py52
2 files changed, 148 insertions, 0 deletions
diff --git a/compose/timeparse.py b/compose/timeparse.py
new file mode 100644
index 00000000..16ef8a6d
--- /dev/null
+++ b/compose/timeparse.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+'''
+timeparse.py
+(c) Will Roberts <wildwilhelm@gmail.com> 1 February, 2014
+
+This is a vendored and modified copy of:
+github.com/wroberts/pytimeparse @ cc0550d
+
+It has been modified to mimic the behaviour of
+https://golang.org/pkg/time/#ParseDuration
+'''
+# MIT LICENSE
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+import re
+
+HOURS = r'(?P<hours>[\d.]+)h'
+MINS = r'(?P<mins>[\d.]+)m'
+SECS = r'(?P<secs>[\d.]+)s'
+MILLI = r'(?P<milli>[\d.]+)ms'
+MICRO = r'(?P<micro>[\d.]+)(?:us|µs)'
+NANO = r'(?P<nano>[\d.]+)ns'
+
+
+def opt(x):
+ return r'(?:{x})?'.format(x=x)
+
+
+TIMEFORMAT = r'{HOURS}{MINS}{SECS}{MILLI}{MICRO}{NANO}'.format(
+ HOURS=opt(HOURS),
+ MINS=opt(MINS),
+ SECS=opt(SECS),
+ MILLI=opt(MILLI),
+ MICRO=opt(MICRO),
+ NANO=opt(NANO),
+)
+
+MULTIPLIERS = dict([
+ ('hours', 60 * 60),
+ ('mins', 60),
+ ('secs', 1),
+ ('milli', 1.0 / 1000),
+ ('micro', 1.0 / 1000.0 / 1000),
+ ('nano', 1.0 / 1000.0 / 1000.0 / 1000.0),
+])
+
+
+def timeparse(sval):
+ """Parse a time expression, returning it as a number of seconds. If
+ possible, the return value will be an `int`; if this is not
+ possible, the return will be a `float`. Returns `None` if a time
+ expression cannot be parsed from the given string.
+
+ Arguments:
+ - `sval`: the string value to parse
+
+ >>> timeparse('1m24s')
+ 84
+ >>> timeparse('1.2 minutes')
+ 72
+ >>> timeparse('1.2 seconds')
+ 1.2
+ """
+ match = re.match(r'\s*' + TIMEFORMAT + r'\s*$', sval, re.I)
+ if not match or not match.group(0).strip():
+ return
+
+ mdict = match.groupdict()
+ return sum(
+ MULTIPLIERS[k] * cast(v) for (k, v) in mdict.items() if v is not None)
+
+
+def cast(value):
+ return int(value, 10) if value.isdigit() else float(value)
diff --git a/tests/unit/timeparse_test.py b/tests/unit/timeparse_test.py
new file mode 100644
index 00000000..e9fe6c24
--- /dev/null
+++ b/tests/unit/timeparse_test.py
@@ -0,0 +1,52 @@
+from __future__ import absolute_import
+from __future__ import unicode_literals
+
+from compose import timeparse
+
+
+def test_milli():
+ assert timeparse.timeparse('5ms') == 0.005
+
+
+def test_milli_float():
+ assert timeparse.timeparse('50.5ms') == 0.0505
+
+
+def test_second_milli():
+ assert timeparse.timeparse('200s5ms') == 200.005
+
+
+def test_second_milli_micro():
+ assert timeparse.timeparse('200s5ms10us') == 200.00501
+
+
+def test_second():
+ assert timeparse.timeparse('200s') == 200
+
+
+def test_second_as_float():
+ assert timeparse.timeparse('20.5s') == 20.5
+
+
+def test_minute():
+ assert timeparse.timeparse('32m') == 1920
+
+
+def test_hour_minute():
+ assert timeparse.timeparse('2h32m') == 9120
+
+
+def test_minute_as_float():
+ assert timeparse.timeparse('1.5m') == 90
+
+
+def test_hour_minute_second():
+ assert timeparse.timeparse('5h34m56s') == 20096
+
+
+def test_invalid_with_space():
+ assert timeparse.timeparse('5h 34m 56s') is None
+
+
+def test_invalid_with_comma():
+ assert timeparse.timeparse('5h,34m,56s') is None