Skip to content

Commit 4e29c31

Browse files
committed
bpo-36959: Fix checks for invalid ISO date formats in _strptime
1 parent 1c1a5d4 commit 4e29c31

File tree

3 files changed

+61
-32
lines changed

3 files changed

+61
-32
lines changed

Lib/_strptime.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,6 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
358358
tz = -1
359359
gmtoff = None
360360
gmtoff_fraction = 0
361-
# Default to -1 to signify that values not known; not critical to have,
362-
# though
363361
iso_week = week_of_year = None
364362
week_of_year_start = None
365363
# weekday and julian defaulted to None so as to signal need to calculate
@@ -483,26 +481,28 @@ def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
483481
else:
484482
tz = value
485483
break
486-
# Deal with the cases where ambiguities arize
484+
485+
# Deal with the cases where ambiguities arise
487486
# don't assume default values for ISO week/year
488-
if year is None and iso_year is not None:
489-
if iso_week is None or weekday is None:
490-
raise ValueError("ISO year directive '%G' must be used with "
491-
"the ISO week directive '%V' and a weekday "
492-
"directive ('%A', '%a', '%w', or '%u').")
493-
if julian is not None:
494-
raise ValueError("Day of the year directive '%j' is not "
495-
"compatible with ISO year directive '%G'. "
496-
"Use '%Y' instead.")
497-
elif week_of_year is None and iso_week is not None:
498-
if weekday is None:
487+
if iso_year is None and iso_week is not None:
488+
if year is None or weekday is None:
499489
raise ValueError("ISO week directive '%V' must be used with "
500490
"the ISO year directive '%G' and a weekday "
501491
"directive ('%A', '%a', '%w', or '%u').")
502492
else:
503493
raise ValueError("ISO week directive '%V' is incompatible with "
504494
"the year directive '%Y'. Use the ISO year '%G' "
505495
"instead.")
496+
elif iso_year is not None:
497+
if julian is not None:
498+
raise ValueError("Day of the year directive '%j' is not "
499+
"compatible with ISO year directive '%G'. "
500+
"Use '%Y' instead.")
501+
elif iso_week is None or weekday is None:
502+
raise ValueError("ISO year directive '%G' must be used with "
503+
"the ISO week directive '%V' and a weekday "
504+
"directive ('%A', '%a', '%w', or '%u').")
505+
506506

507507
leap_year_fix = False
508508
if year is None:

Lib/test/test_strptime.py

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -219,25 +219,49 @@ def test_ValueError(self):
219219
else:
220220
self.fail("'%s' did not raise ValueError" % bad_format)
221221

222-
# Ambiguous or incomplete cases using ISO year/week/weekday directives
223-
# 1. ISO week (%V) is specified, but the year is specified with %Y
224-
# instead of %G
225-
with self.assertRaises(ValueError):
226-
_strptime._strptime("1999 50", "%Y %V")
227-
# 2. ISO year (%G) and ISO week (%V) are specified, but weekday is not
228-
with self.assertRaises(ValueError):
229-
_strptime._strptime("1999 51", "%G %V")
230-
# 3. ISO year (%G) and weekday are specified, but ISO week (%V) is not
231-
for w in ('A', 'a', 'w', 'u'):
232-
with self.assertRaises(ValueError):
233-
_strptime._strptime("1999 51","%G %{}".format(w))
234-
# 4. ISO year is specified alone (e.g. time.strptime('2015', '%G'))
235-
with self.assertRaises(ValueError):
236-
_strptime._strptime("2015", "%G")
237-
# 5. Julian/ordinal day (%j) is specified with %G, but not %Y
238-
with self.assertRaises(ValueError):
239-
_strptime._strptime("1999 256", "%G %j")
222+
msg_week_no_year_or_weekday = r"ISO week directive '%V' must be used with " \
223+
r"the ISO year directive '%G' and a weekday directive " \
224+
r"\('%A', '%a', '%w', or '%u'\)."
225+
msg_week_not_compatible = r"ISO week directive '%V' is incompatible with " \
226+
r"the year directive '%Y'. Use the ISO year '%G' instead."
227+
msg_julian_not_compatible = r"Day of the year directive '%j' is not " \
228+
r"compatible with ISO year directive '%G'. Use '%Y' instead."
229+
msg_year_no_week_or_weekday = r"ISO year directive '%G' must be used with " \
230+
r"the ISO week directive '%V' and a weekday directive " \
231+
r"\('%A', '%a', '%w', or '%u'\)."
232+
233+
locale_time = _strptime.LocaleTime()
240234

235+
# Ambiguous or incomplete cases using ISO year/week/weekday directives
236+
subtests = [
237+
# 1. ISO week (%V) is specified, but the year is specified with %Y
238+
# instead of %G
239+
("1999 50", "%Y %V", msg_week_no_year_or_weekday),
240+
("1999 50 5", "%Y %V %u", msg_week_not_compatible),
241+
# 2. ISO year (%G) and ISO week (%V) are specified, but weekday is not
242+
("1999 51", "%G %V", msg_year_no_week_or_weekday),
243+
# 3. ISO year (%G) and weekday are specified, but ISO week (%V) is not
244+
("1999 {}".format(locale_time.f_weekday[5]), "%G %A",
245+
msg_year_no_week_or_weekday),
246+
("1999 {}".format(locale_time.a_weekday[5]), "%G %a",
247+
msg_year_no_week_or_weekday),
248+
("1999 5", "%G %w", msg_year_no_week_or_weekday),
249+
("1999 5", "%G %u", msg_year_no_week_or_weekday),
250+
# 4. ISO year is specified alone (e.g. time.strptime('2015', '%G'))
251+
("2015", "%G", msg_year_no_week_or_weekday),
252+
# 5. Julian/ordinal day (%j) is specified with %G, but not %Y
253+
("1999 256", "%G %j", msg_julian_not_compatible),
254+
("1999 50 5 256", "%G %V %u %j", msg_julian_not_compatible),
255+
# ISO week specified alone
256+
("50", "%V", msg_week_no_year_or_weekday),
257+
# ISO year is unspecified, falling back to year
258+
("50 5", "%V %u", msg_week_no_year_or_weekday),
259+
]
260+
261+
for (data_string, format, message) in subtests:
262+
with self.subTest(data_string=data_string, format=format):
263+
with self.assertRaisesRegex(ValueError, message):
264+
_strptime._strptime(data_string, format)
241265

242266
def test_strptime_exception_context(self):
243267
# check that this doesn't chain exceptions needlessly (see #17572)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix checks for invalid combinations of ISO format strings in strptime.
2+
3+
(This will change ValueError messages for certain invalid combinations.)
4+
5+
Patch by Gordon P. Hemsley.

0 commit comments

Comments
 (0)