@@ -332,19 +332,30 @@ def _find_isoformat_datetime_separator(dtstr):
332332 return 8
333333
334334
335+ def _read_isoformat_component (s , n ):
336+ # The caller has verified the string is ASCII, so isdigit() matches only
337+ # the ASCII digits accepted by the C parser.
338+ if len (s ) != n or not s .isdigit ():
339+ raise ValueError ("Invalid isoformat string" )
340+ return int (s )
341+
342+
335343def _parse_isoformat_date (dtstr ):
336344 # It is assumed that this is an ASCII-only string of lengths 7, 8 or 10,
337345 # see the comment on Modules/_datetimemodule.c:_find_isoformat_datetime_separator
338346 if len (dtstr ) not in (7 , 8 , 10 ):
339347 raise ValueError ("Invalid isoformat string" )
340- year = int (dtstr [0 :4 ])
348+ if not dtstr .isascii ():
349+ raise ValueError ("Invalid isoformat string" )
350+
351+ year = _read_isoformat_component (dtstr [0 :4 ], 4 )
341352 has_sep = dtstr [4 ] == '-'
342353
343354 pos = 4 + has_sep
344355 if dtstr [pos :pos + 1 ] == "W" :
345356 # YYYY-?Www-?D?
346357 pos += 1
347- weekno = int (dtstr [pos :pos + 2 ])
358+ weekno = _read_isoformat_component (dtstr [pos :pos + 2 ], 2 )
348359 pos += 2
349360
350361 dayno = 1
@@ -354,17 +365,17 @@ def _parse_isoformat_date(dtstr):
354365
355366 pos += has_sep
356367
357- dayno = int (dtstr [pos :pos + 1 ])
368+ dayno = _read_isoformat_component (dtstr [pos :pos + 1 ], 1 )
358369
359370 return list (_isoweek_to_gregorian (year , weekno , dayno ))
360371 else :
361- month = int (dtstr [pos :pos + 2 ])
372+ month = _read_isoformat_component (dtstr [pos :pos + 2 ], 2 )
362373 pos += 2
363374 if (dtstr [pos :pos + 1 ] == "-" ) != has_sep :
364375 raise ValueError ("Inconsistent use of dash separator" )
365376
366377 pos += has_sep
367- day = int (dtstr [pos :pos + 2 ])
378+ day = _read_isoformat_component (dtstr [pos :pos + 2 ], 2 )
368379
369380 return [year , month , day ]
370381
@@ -379,10 +390,7 @@ def _parse_hh_mm_ss_ff(tstr):
379390 time_comps = [0 , 0 , 0 , 0 ]
380391 pos = 0
381392 for comp in range (0 , 3 ):
382- if (len_str - pos ) < 2 :
383- raise ValueError ("Incomplete time component" )
384-
385- time_comps [comp ] = int (tstr [pos :pos + 2 ])
393+ time_comps [comp ] = _read_isoformat_component (tstr [pos :pos + 2 ], 2 )
386394
387395 pos += 2
388396 next_char = tstr [pos :pos + 1 ]
@@ -403,7 +411,7 @@ def _parse_hh_mm_ss_ff(tstr):
403411 raise ValueError ("Invalid microsecond component" )
404412 else :
405413 pos += 1
406- if not all ( map ( _is_ascii_digit , tstr [pos :]) ):
414+ if not tstr [pos :]. isdigit ( ):
407415 raise ValueError ("Non-digit values in fraction" )
408416
409417 len_remainder = len_str - pos
@@ -424,6 +432,8 @@ def _parse_isoformat_time(tstr):
424432 len_str = len (tstr )
425433 if len_str < 2 :
426434 raise ValueError ("Isoformat time too short" )
435+ if not tstr .isascii ():
436+ raise ValueError ("Invalid isoformat string" )
427437
428438 # This is equivalent to re.search('[+-Z]', tstr), but faster
429439 tz_pos = (tstr .find ('-' ) + 1 or tstr .find ('+' ) + 1 or tstr .find ('Z' ) + 1 )
0 commit comments