Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/tomli/_re.py: 52%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

40 statements  

1# SPDX-License-Identifier: MIT 

2# SPDX-FileCopyrightText: 2021 Taneli Hukkinen 

3# Licensed to PSF under a Contributor Agreement. 

4 

5from __future__ import annotations 

6 

7from datetime import date, datetime, time, timedelta, timezone, tzinfo 

8from functools import lru_cache 

9import re 

10 

11TYPE_CHECKING = False 

12if TYPE_CHECKING: 

13 from typing import Any, Final 

14 

15 from ._types import ParseFloat 

16 

17_TIME_RE_STR: Final = r""" 

18([01][0-9]|2[0-3]) # hours 

19:([0-5][0-9]) # minutes 

20(?: 

21 :([0-5][0-9]) # optional seconds 

22 (?:\.([0-9]{1,6})[0-9]*)? # optional fractions of a second 

23)? 

24""" 

25 

26RE_NUMBER: Final = re.compile( 

27 r""" 

280 

29(?: 

30 x[0-9A-Fa-f](?:_?[0-9A-Fa-f])* # hex 

31 | 

32 b[01](?:_?[01])* # bin 

33 | 

34 o[0-7](?:_?[0-7])* # oct 

35) 

36| 

37[+-]?(?:0|[1-9](?:_?[0-9])*) # dec, integer part 

38(?P<floatpart> 

39 (?:\.[0-9](?:_?[0-9])*)? # optional fractional part 

40 (?:[eE][+-]?[0-9](?:_?[0-9])*)? # optional exponent part 

41) 

42""", 

43 flags=re.VERBOSE, 

44) 

45RE_LOCALTIME: Final = re.compile(_TIME_RE_STR, flags=re.VERBOSE) 

46RE_DATETIME: Final = re.compile( 

47 rf""" 

48([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) # date, e.g. 1988-10-27 

49(?: 

50 [Tt ] 

51 {_TIME_RE_STR} 

52 (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))? # optional time offset 

53)? 

54""", 

55 flags=re.VERBOSE, 

56) 

57 

58 

59def match_to_datetime(match: re.Match[str]) -> datetime | date: 

60 """Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`. 

61 

62 Raises ValueError if the match does not correspond to a valid date 

63 or datetime. 

64 """ 

65 ( 

66 year_str, 

67 month_str, 

68 day_str, 

69 hour_str, 

70 minute_str, 

71 sec_str, 

72 micros_str, 

73 zulu_time, 

74 offset_sign_str, 

75 offset_hour_str, 

76 offset_minute_str, 

77 ) = match.groups() 

78 year, month, day = int(year_str), int(month_str), int(day_str) 

79 if hour_str is None: 

80 return date(year, month, day) 

81 hour, minute = int(hour_str), int(minute_str) 

82 sec = int(sec_str) if sec_str else 0 

83 micros = int(micros_str.ljust(6, "0")) if micros_str else 0 

84 if offset_sign_str: 

85 tz: tzinfo | None = cached_tz( 

86 offset_hour_str, offset_minute_str, offset_sign_str 

87 ) 

88 elif zulu_time: 

89 tz = timezone.utc 

90 else: # local date-time 

91 tz = None 

92 return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz) 

93 

94 

95# No need to limit cache size. This is only ever called on input 

96# that matched RE_DATETIME, so there is an implicit bound of 

97# 24 (hours) * 60 (minutes) * 2 (offset direction) = 2880. 

98@lru_cache(maxsize=None) 

99def cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone: 

100 sign = 1 if sign_str == "+" else -1 

101 return timezone( 

102 timedelta( 

103 hours=sign * int(hour_str), 

104 minutes=sign * int(minute_str), 

105 ) 

106 ) 

107 

108 

109def match_to_localtime(match: re.Match[str]) -> time: 

110 hour_str, minute_str, sec_str, micros_str = match.groups() 

111 sec = int(sec_str) if sec_str else 0 

112 micros = int(micros_str.ljust(6, "0")) if micros_str else 0 

113 return time(int(hour_str), int(minute_str), sec, micros) 

114 

115 

116def match_to_number(match: re.Match[str], parse_float: ParseFloat) -> Any: 

117 if match.group("floatpart"): 

118 return parse_float(match.group()) 

119 return int(match.group(), 0)