Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/isoduration/parser/parsing.py: 13%

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

68 statements  

1from collections import OrderedDict 

2from decimal import Decimal, InvalidOperation 

3 

4import arrow # type: ignore 

5 

6from isoduration.parser.exceptions import ( 

7 IncorrectDesignator, 

8 NoTime, 

9 OutOfDesignators, 

10 UnknownToken, 

11 UnparseableValue, 

12) 

13from isoduration.parser.util import ( 

14 is_letter, 

15 is_number, 

16 is_time, 

17 is_week, 

18 parse_designator, 

19) 

20from isoduration.types import DateDuration, Duration, TimeDuration 

21 

22 

23def parse_datetime_duration(duration_str: str, sign: int) -> Duration: 

24 try: 

25 duration: arrow.Arrow = arrow.get(duration_str) 

26 except (arrow.ParserError, ValueError): 

27 raise UnparseableValue(f"Value could not be parsed as datetime: {duration_str}") 

28 

29 return Duration( 

30 DateDuration( 

31 years=sign * duration.year, 

32 months=sign * duration.month, 

33 days=sign * duration.day, 

34 ), 

35 TimeDuration( 

36 hours=sign * duration.hour, 

37 minutes=sign * duration.minute, 

38 seconds=sign * duration.second, 

39 ), 

40 ) 

41 

42 

43def parse_date_duration(date_str: str, sign: int) -> Duration: 

44 date_designators = OrderedDict( 

45 (("Y", "years"), ("M", "months"), ("D", "days"), ("W", "weeks")) 

46 ) 

47 

48 duration = DateDuration() 

49 tmp_value = "" 

50 

51 for idx, ch in enumerate(date_str): 

52 if is_time(ch): 

53 if tmp_value != "" and tmp_value == date_str[:idx]: 

54 # PYYYY-MM-DDThh:mm:ss 

55 # PYYYYMMDDThhmmss 

56 return parse_datetime_duration(date_str, sign) 

57 

58 time_idx = idx + 1 

59 time_str = date_str[time_idx:] 

60 

61 if time_str == "": 

62 raise NoTime("Wanted time, no time provided") 

63 

64 return Duration(duration, parse_time_duration(time_str, sign)) 

65 

66 if is_letter(ch): 

67 try: 

68 key = parse_designator(date_designators, ch) 

69 value = sign * Decimal(tmp_value) 

70 except OutOfDesignators as exc: 

71 raise IncorrectDesignator( 

72 f"Wrong date designator, or designator in the wrong order: {ch}" 

73 ) from exc 

74 except InvalidOperation as exc: 

75 raise UnparseableValue( 

76 f"Value could not be parsed as decimal: {tmp_value}" 

77 ) from exc 

78 

79 if is_week(ch) and duration != DateDuration(): 

80 raise IncorrectDesignator( 

81 "Week is incompatible with any other date designator" 

82 ) 

83 

84 setattr(duration, key, value) 

85 tmp_value = "" 

86 

87 continue 

88 

89 if is_number(ch): 

90 if ch == ",": 

91 tmp_value += "." 

92 else: 

93 tmp_value += ch 

94 

95 continue 

96 

97 raise UnknownToken(f"Token not recognizable: {ch}") 

98 

99 return Duration(duration, TimeDuration()) 

100 

101 

102def parse_time_duration(time_str: str, sign: int) -> TimeDuration: 

103 time_designators = OrderedDict((("H", "hours"), ("M", "minutes"), ("S", "seconds"))) 

104 

105 duration = TimeDuration() 

106 tmp_value = "" 

107 

108 for ch in time_str: 

109 if is_letter(ch): 

110 try: 

111 key = parse_designator(time_designators, ch) 

112 value = sign * Decimal(tmp_value) 

113 except OutOfDesignators as exc: 

114 raise IncorrectDesignator( 

115 f"Wrong time designator, or designator in the wrong order: {ch}" 

116 ) from exc 

117 except InvalidOperation as exc: 

118 raise UnparseableValue( 

119 f"Value could not be parsed as decimal: {tmp_value}" 

120 ) from exc 

121 

122 setattr(duration, key, value) 

123 tmp_value = "" 

124 

125 continue 

126 

127 if is_number(ch): 

128 if ch == ",": 

129 tmp_value += "." 

130 else: 

131 tmp_value += ch 

132 

133 continue 

134 

135 raise UnknownToken(f"Token not recognizable: {ch}") 

136 

137 return duration