nonlocal day_of_month_in_format
day_of_month_in_format = True
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:
import warnings
warnings.warn("""\
# \\, in which case it was a stray % but with a space after it
except KeyError as err:
bad_directive = err.args[0]
- if bad_directive == "\\":
- bad_directive = "%"
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'" %
(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
found = format_regex.match(data_string)
if not found:
# Make sure ValueError is raised when match fails or format is bad
self.assertRaises(ValueError, _strptime._strptime_time, data_string="%d",
format="%A")
- for bad_format in ("%", "% ", "%e"):
- try:
+ for bad_format in ("%", "% ", "%\n"):
+ 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)
- 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 " \
r"the ISO year directive '%G' and a weekday directive " \
# check that this doesn't chain exceptions needlessly (see #17572)
with self.assertRaises(ValueError) as e:
_strptime._strptime_time('', '%D')
- self.assertIs(e.exception.__suppress_context__, True)
- # additional check for IndexError branch (issue #19545)
+ self.assertTrue(e.exception.__suppress_context__)
+ # additional check for stray % branch
with self.assertRaises(ValueError) as e:
- _strptime._strptime_time('19', '%Y %')
- self.assertIsNone(e.exception.__context__)
+ _strptime._strptime_time('%', '%')
+ self.assertTrue(e.exception.__suppress_context__)
def test_unconverteddata(self):
# Check ValueError is raised when there is unconverted data
# check that this doesn't chain exceptions needlessly (see #17572)
with self.assertRaises(ValueError) as e:
time.strptime('', '%D')
- self.assertIs(e.exception.__suppress_context__, True)
- # additional check for IndexError branch (issue #19545)
+ self.assertTrue(e.exception.__suppress_context__)
+ # additional check for stray % branch
with self.assertRaises(ValueError) as e:
- time.strptime('19', '%Y %')
- self.assertIsNone(e.exception.__context__)
+ time.strptime('%', '%')
+ self.assertTrue(e.exception.__suppress_context__)
def test_strptime_leap_year(self):
# GH-70647: warns if parsing a format with a day and no year.