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

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

36 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 

10from typing import Any, Final 

11 

12from ._types import ParseFloat 

13 

14# E.g. 

15# - 00:32:00.999999 

16# - 00:32:00 

17_TIME_RE_STR: Final = ( 

18 r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?" 

19) 

20 

21RE_NUMBER: Final = re.compile( 

22 r""" 

230 

24(?: 

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

26 | 

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

28 | 

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

30) 

31| 

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

33(?P<floatpart> 

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

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

36) 

37""", 

38 flags=re.VERBOSE, 

39) 

40RE_LOCALTIME: Final = re.compile(_TIME_RE_STR) 

41RE_DATETIME: Final = re.compile( 

42 rf""" 

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

44(?: 

45 [Tt ] 

46 {_TIME_RE_STR} 

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

48)? 

49""", 

50 flags=re.VERBOSE, 

51) 

52 

53 

54def match_to_datetime(match: re.Match) -> datetime | date: 

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

56 

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

58 or datetime. 

59 """ 

60 ( 

61 year_str, 

62 month_str, 

63 day_str, 

64 hour_str, 

65 minute_str, 

66 sec_str, 

67 micros_str, 

68 zulu_time, 

69 offset_sign_str, 

70 offset_hour_str, 

71 offset_minute_str, 

72 ) = match.groups() 

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

74 if hour_str is None: 

75 return date(year, month, day) 

76 hour, minute, sec = int(hour_str), int(minute_str), int(sec_str) 

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

78 if offset_sign_str: 

79 tz: tzinfo | None = cached_tz( 

80 offset_hour_str, offset_minute_str, offset_sign_str 

81 ) 

82 elif zulu_time: 

83 tz = timezone.utc 

84 else: # local date-time 

85 tz = None 

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

87 

88 

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

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

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

92@lru_cache(maxsize=None) 

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

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

95 return timezone( 

96 timedelta( 

97 hours=sign * int(hour_str), 

98 minutes=sign * int(minute_str), 

99 ) 

100 ) 

101 

102 

103def match_to_localtime(match: re.Match) -> time: 

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

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

106 return time(int(hour_str), int(minute_str), int(sec_str), micros) 

107 

108 

109def match_to_number(match: re.Match, parse_float: ParseFloat) -> Any: 

110 if match.group("floatpart"): 

111 return parse_float(match.group()) 

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