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

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

38 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# E.g. 

18# - 00:32:00.999999 

19# - 00:32:00 

20_TIME_RE_STR: Final = ( 

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

22) 

23 

24RE_NUMBER: Final = re.compile( 

25 r""" 

260 

27(?: 

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

29 | 

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

31 | 

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

33) 

34| 

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

36(?P<floatpart> 

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

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

39) 

40""", 

41 flags=re.VERBOSE, 

42) 

43RE_LOCALTIME: Final = re.compile(_TIME_RE_STR) 

44RE_DATETIME: Final = re.compile( 

45 rf""" 

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

47(?: 

48 [Tt ] 

49 {_TIME_RE_STR} 

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

51)? 

52""", 

53 flags=re.VERBOSE, 

54) 

55 

56 

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

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

59 

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

61 or datetime. 

62 """ 

63 ( 

64 year_str, 

65 month_str, 

66 day_str, 

67 hour_str, 

68 minute_str, 

69 sec_str, 

70 micros_str, 

71 zulu_time, 

72 offset_sign_str, 

73 offset_hour_str, 

74 offset_minute_str, 

75 ) = match.groups() 

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

77 if hour_str is None: 

78 return date(year, month, day) 

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

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

81 if offset_sign_str: 

82 tz: tzinfo | None = cached_tz( 

83 offset_hour_str, offset_minute_str, offset_sign_str 

84 ) 

85 elif zulu_time: 

86 tz = timezone.utc 

87 else: # local date-time 

88 tz = None 

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

90 

91 

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

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

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

95@lru_cache(maxsize=None) 

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

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

98 return timezone( 

99 timedelta( 

100 hours=sign * int(hour_str), 

101 minutes=sign * int(minute_str), 

102 ) 

103 ) 

104 

105 

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

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

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

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

110 

111 

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

113 if match.group("floatpart"): 

114 return parse_float(match.group()) 

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