mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-131434: Improve error reporting for incorrect format in strptime() (GH-131568)
In particularly, fix regression in detecting stray % at the end of the format string.
This commit is contained in:
parent
7ebbd27144
commit
3feac7a093
4 changed files with 23 additions and 23 deletions
|
@ -365,7 +365,7 @@ class TimeRE(dict):
|
||||||
nonlocal day_of_month_in_format
|
nonlocal day_of_month_in_format
|
||||||
day_of_month_in_format = True
|
day_of_month_in_format = True
|
||||||
return self[format_char]
|
return self[format_char]
|
||||||
format = re_sub(r'%(O?.)', repl, format)
|
format = re_sub(r'%([OE]?\\?.?)', repl, format)
|
||||||
if day_of_month_in_format and not year_in_format:
|
if day_of_month_in_format and not year_in_format:
|
||||||
import warnings
|
import warnings
|
||||||
warnings.warn("""\
|
warnings.warn("""\
|
||||||
|
@ -439,14 +439,13 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
|
||||||
# \\, in which case it was a stray % but with a space after it
|
# \\, in which case it was a stray % but with a space after it
|
||||||
except KeyError as err:
|
except KeyError as err:
|
||||||
bad_directive = err.args[0]
|
bad_directive = err.args[0]
|
||||||
if bad_directive == "\\":
|
|
||||||
bad_directive = "%"
|
|
||||||
del err
|
del err
|
||||||
|
bad_directive = bad_directive.replace('\\s', '')
|
||||||
|
if not bad_directive:
|
||||||
|
raise ValueError("stray %% in format '%s'" % format) from None
|
||||||
|
bad_directive = bad_directive.replace('\\', '', 1)
|
||||||
raise ValueError("'%s' is a bad directive in format '%s'" %
|
raise ValueError("'%s' is a bad directive in format '%s'" %
|
||||||
(bad_directive, format)) from None
|
(bad_directive, format)) from None
|
||||||
# IndexError only occurs when the format string is "%"
|
|
||||||
except IndexError:
|
|
||||||
raise ValueError("stray %% in format '%s'" % format) from None
|
|
||||||
_regex_cache[format] = format_regex
|
_regex_cache[format] = format_regex
|
||||||
found = format_regex.match(data_string)
|
found = format_regex.match(data_string)
|
||||||
if not found:
|
if not found:
|
||||||
|
|
|
@ -220,16 +220,16 @@ class StrptimeTests(unittest.TestCase):
|
||||||
# Make sure ValueError is raised when match fails or format is bad
|
# Make sure ValueError is raised when match fails or format is bad
|
||||||
self.assertRaises(ValueError, _strptime._strptime_time, data_string="%d",
|
self.assertRaises(ValueError, _strptime._strptime_time, data_string="%d",
|
||||||
format="%A")
|
format="%A")
|
||||||
for bad_format in ("%", "% ", "%e"):
|
for bad_format in ("%", "% ", "%\n"):
|
||||||
try:
|
with self.assertRaisesRegex(ValueError, "stray % in format "):
|
||||||
|
_strptime._strptime_time("2005", bad_format)
|
||||||
|
for bad_format in ("%e", "%Oe", "%O", "%O ", "%Ee", "%E", "%E ",
|
||||||
|
"%.", "%+", "%_", "%~", "%\\",
|
||||||
|
"%O.", "%O+", "%O_", "%O~", "%O\\"):
|
||||||
|
directive = bad_format[1:].rstrip()
|
||||||
|
with self.assertRaisesRegex(ValueError,
|
||||||
|
f"'{re.escape(directive)}' is a bad directive in format "):
|
||||||
_strptime._strptime_time("2005", bad_format)
|
_strptime._strptime_time("2005", bad_format)
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
except Exception as err:
|
|
||||||
self.fail("'%s' raised %s, not ValueError" %
|
|
||||||
(bad_format, err.__class__.__name__))
|
|
||||||
else:
|
|
||||||
self.fail("'%s' did not raise ValueError" % bad_format)
|
|
||||||
|
|
||||||
msg_week_no_year_or_weekday = r"ISO week directive '%V' must be used with " \
|
msg_week_no_year_or_weekday = r"ISO week directive '%V' must be used with " \
|
||||||
r"the ISO year directive '%G' and a weekday directive " \
|
r"the ISO year directive '%G' and a weekday directive " \
|
||||||
|
@ -285,11 +285,11 @@ class StrptimeTests(unittest.TestCase):
|
||||||
# check that this doesn't chain exceptions needlessly (see #17572)
|
# check that this doesn't chain exceptions needlessly (see #17572)
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
_strptime._strptime_time('', '%D')
|
_strptime._strptime_time('', '%D')
|
||||||
self.assertIs(e.exception.__suppress_context__, True)
|
self.assertTrue(e.exception.__suppress_context__)
|
||||||
# additional check for IndexError branch (issue #19545)
|
# additional check for stray % branch
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
_strptime._strptime_time('19', '%Y %')
|
_strptime._strptime_time('%', '%')
|
||||||
self.assertIsNone(e.exception.__context__)
|
self.assertTrue(e.exception.__suppress_context__)
|
||||||
|
|
||||||
def test_unconverteddata(self):
|
def test_unconverteddata(self):
|
||||||
# Check ValueError is raised when there is unconverted data
|
# Check ValueError is raised when there is unconverted data
|
||||||
|
|
|
@ -345,11 +345,11 @@ class TimeTestCase(unittest.TestCase):
|
||||||
# check that this doesn't chain exceptions needlessly (see #17572)
|
# check that this doesn't chain exceptions needlessly (see #17572)
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
time.strptime('', '%D')
|
time.strptime('', '%D')
|
||||||
self.assertIs(e.exception.__suppress_context__, True)
|
self.assertTrue(e.exception.__suppress_context__)
|
||||||
# additional check for IndexError branch (issue #19545)
|
# additional check for stray % branch
|
||||||
with self.assertRaises(ValueError) as e:
|
with self.assertRaises(ValueError) as e:
|
||||||
time.strptime('19', '%Y %')
|
time.strptime('%', '%')
|
||||||
self.assertIsNone(e.exception.__context__)
|
self.assertTrue(e.exception.__suppress_context__)
|
||||||
|
|
||||||
def test_strptime_leap_year(self):
|
def test_strptime_leap_year(self):
|
||||||
# GH-70647: warns if parsing a format with a day and no year.
|
# GH-70647: warns if parsing a format with a day and no year.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improve error reporting for incorrect format in :func:`time.strptime`.
|
Loading…
Add table
Add a link
Reference in a new issue