diff --git a/tornado/options.py b/tornado/options.py index 7ebae719f..fdfaea424 100644 --- a/tornado/options.py +++ b/tornado/options.py @@ -640,22 +640,19 @@ def _parse_datetime(self, value: str) -> datetime.datetime: ) def _parse_timedelta(self, value: str) -> datetime.timedelta: - try: - sum = datetime.timedelta() - start = 0 - while start < len(value): - m = self._TIMEDELTA_PATTERN.match(value, start) - if not m: - raise Exception() - num = float(m.group(1)) - units = m.group(2) or "seconds" - units = self._TIMEDELTA_ABBREV_DICT.get(units, units) - - sum += datetime.timedelta(**{units: num}) - start = m.end() - return sum - except Exception: - raise + sum = datetime.timedelta() + start = 0 + while start < len(value): + m = self._TIMEDELTA_PATTERN.match(value, start) + if not m: + raise Error("Invalid time delta: %r" % value) + num = float(m.group(1)) + units = m.group(2) or "seconds" + units = self._TIMEDELTA_ABBREV_DICT.get(units, units) + + sum += datetime.timedelta(**{units: num}) + start = m.end() + return sum def _parse_bool(self, value: str) -> bool: return value.lower() not in ("false", "0", "f") diff --git a/tornado/test/options_test.py b/tornado/test/options_test.py index 6c76da364..b193c0adf 100644 --- a/tornado/test/options_test.py +++ b/tornado/test/options_test.py @@ -254,6 +254,15 @@ def test_multiple_int(self): options.parse_command_line(["main.py", "--foo=1,3,5:7"]) self.assertEqual(options.foo, [1, 3, 5, 6, 7]) + def test_parse_timedelta_invalid_raises_options_error(self): + # Malformed timedelta input should raise options.Error with a + # human-readable message, not a bare Exception with no context. + options = OptionParser() + options.define("foo", type=datetime.timedelta) + with self.assertRaises(Error) as cm: + options.parse_command_line(["main.py", "--foo=xyz"]) + self.assertIn("xyz", str(cm.exception)) + def test_error_redefine(self): options = OptionParser() options.define("foo")