@@ -355,19 +355,30 @@ def _find_isoformat_datetime_separator(dtstr):
355355 return 8
356356
357357
358+ def _read_isoformat_component (s , n ):
359+ # The caller has verified the string is ASCII, so isdigit() matches only
360+ # the ASCII digits accepted by the C parser.
361+ if len (s ) != n or not s .isdigit ():
362+ raise ValueError ("Invalid isoformat string" )
363+ return int (s )
364+
365+
358366def _parse_isoformat_date (dtstr ):
359367 # It is assumed that this is an ASCII-only string of lengths 7, 8 or 10,
360368 # see the comment on Modules/_datetimemodule.c:_find_isoformat_datetime_separator
361369 if len (dtstr ) not in (7 , 8 , 10 ):
362370 raise ValueError ("Invalid isoformat string" )
363- year = int (dtstr [0 :4 ])
371+ if not dtstr .isascii ():
372+ raise ValueError ("Invalid isoformat string" )
373+
374+ year = _read_isoformat_component (dtstr [0 :4 ], 4 )
364375 has_sep = dtstr [4 ] == '-'
365376
366377 pos = 4 + has_sep
367378 if dtstr [pos :pos + 1 ] == "W" :
368379 # YYYY-?Www-?D?
369380 pos += 1
370- weekno = int (dtstr [pos :pos + 2 ])
381+ weekno = _read_isoformat_component (dtstr [pos :pos + 2 ], 2 )
371382 pos += 2
372383
373384 dayno = 1
@@ -377,17 +388,17 @@ def _parse_isoformat_date(dtstr):
377388
378389 pos += has_sep
379390
380- dayno = int (dtstr [pos :pos + 1 ])
391+ dayno = _read_isoformat_component (dtstr [pos :pos + 1 ], 1 )
381392
382393 return list (_isoweek_to_gregorian (year , weekno , dayno ))
383394 else :
384- month = int (dtstr [pos :pos + 2 ])
395+ month = _read_isoformat_component (dtstr [pos :pos + 2 ], 2 )
385396 pos += 2
386397 if (dtstr [pos :pos + 1 ] == "-" ) != has_sep :
387398 raise ValueError ("Inconsistent use of dash separator" )
388399
389400 pos += has_sep
390- day = int (dtstr [pos :pos + 2 ])
401+ day = _read_isoformat_component (dtstr [pos :pos + 2 ], 2 )
391402
392403 return [year , month , day ]
393404
@@ -402,10 +413,7 @@ def _parse_hh_mm_ss_ff(tstr):
402413 time_comps = [0 , 0 , 0 , 0 ]
403414 pos = 0
404415 for comp in range (0 , 3 ):
405- if (len_str - pos ) < 2 :
406- raise ValueError ("Incomplete time component" )
407-
408- time_comps [comp ] = int (tstr [pos :pos + 2 ])
416+ time_comps [comp ] = _read_isoformat_component (tstr [pos :pos + 2 ], 2 )
409417
410418 pos += 2
411419 next_char = tstr [pos :pos + 1 ]
@@ -426,7 +434,7 @@ def _parse_hh_mm_ss_ff(tstr):
426434 raise ValueError ("Invalid microsecond separator" )
427435 else :
428436 pos += 1
429- if not all ( map ( _is_ascii_digit , tstr [pos :]) ):
437+ if not tstr [pos :]. isdigit ( ):
430438 raise ValueError ("Non-digit values in fraction" )
431439
432440 len_remainder = len_str - pos
@@ -447,6 +455,8 @@ def _parse_isoformat_time(tstr):
447455 len_str = len (tstr )
448456 if len_str < 2 :
449457 raise ValueError ("Isoformat time too short" )
458+ if not tstr .isascii ():
459+ raise ValueError ("Invalid isoformat string" )
450460
451461 # This is equivalent to re.search('[+-Z]', tstr), but faster
452462 tz_pos = (tstr .find ('-' ) + 1 or tstr .find ('+' ) + 1 or tstr .find ('Z' ) + 1 )
0 commit comments