Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/prop/recur/weekday.py: 89%

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

47 statements  

1"""BYWEEKDAY, BYDAY, and WKST value type of RECUR from :rfc:`5545`.""" 

2 

3import re 

4from typing import Any 

5 

6from icalendar.caselessdict import CaselessDict 

7from icalendar.compatibility import Self 

8from icalendar.error import JCalParsingError 

9from icalendar.parser import Parameters 

10from icalendar.parser_tools import DEFAULT_ENCODING, to_unicode 

11 

12WEEKDAY_RULE = re.compile( 

13 r"(?P<signal>[+-]?)(?P<relative>[\d]{0,2})(?P<weekday>[\w]{2})$" 

14) 

15 

16 

17class vWeekday(str): 

18 """Either a ``weekday`` or a ``weekdaynum``. 

19 

20 .. code-block:: pycon 

21 

22 >>> from icalendar import vWeekday 

23 >>> vWeekday("MO") # Simple weekday 

24 'MO' 

25 >>> vWeekday("2FR").relative # Second friday 

26 2 

27 >>> vWeekday("2FR").weekday 

28 'FR' 

29 >>> vWeekday("-1SU").relative # Last Sunday 

30 -1 

31 

32 Definition from :rfc:`5545#section-3.3.10`: 

33 

34 .. code-block:: text 

35 

36 weekdaynum = [[plus / minus] ordwk] weekday 

37 plus = "+" 

38 minus = "-" 

39 ordwk = 1*2DIGIT ;1 to 53 

40 weekday = "SU" / "MO" / "TU" / "WE" / "TH" / "FR" / "SA" 

41 ;Corresponding to SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, 

42 ;FRIDAY, and SATURDAY days of the week. 

43 

44 """ 

45 

46 params: Parameters 

47 __slots__ = ("params", "relative", "weekday") 

48 

49 week_days = CaselessDict( 

50 { 

51 "SU": 0, 

52 "MO": 1, 

53 "TU": 2, 

54 "WE": 3, 

55 "TH": 4, 

56 "FR": 5, 

57 "SA": 6, 

58 } 

59 ) 

60 

61 def __new__( 

62 cls, 

63 value, 

64 encoding=DEFAULT_ENCODING, 

65 /, 

66 params: dict[str, Any] | None = None, 

67 ): 

68 value = to_unicode(value, encoding=encoding) 

69 self = super().__new__(cls, value) 

70 match = WEEKDAY_RULE.match(self) 

71 if match is None: 

72 raise ValueError(f"Expected weekday abbreviation, got: {self}") 

73 match = match.groupdict() 

74 sign = match["signal"] 

75 weekday = match["weekday"] 

76 relative = match["relative"] 

77 if weekday not in vWeekday.week_days or sign not in "+-": 

78 raise ValueError(f"Expected weekday abbreviation, got: {self}") 

79 self.weekday = weekday or None 

80 self.relative = (relative and int(relative)) or None 

81 if sign == "-" and self.relative: 

82 self.relative *= -1 

83 self.params = Parameters(params) 

84 return self 

85 

86 def to_ical(self): 

87 return self.encode(DEFAULT_ENCODING).upper() 

88 

89 @classmethod 

90 def from_ical(cls, ical): 

91 try: 

92 return cls(ical.upper()) 

93 except Exception as e: 

94 raise ValueError(f"Expected weekday abbreviation, got: {ical}") from e 

95 

96 @classmethod 

97 def parse_jcal_value(cls, value: Any) -> Self: 

98 """Parse a jCal value for vWeekday. 

99 

100 Raises: 

101 ~error.JCalParsingError: If the value is not a valid weekday. 

102 """ 

103 JCalParsingError.validate_value_type(value, str, cls) 

104 try: 

105 return cls(value) 

106 except ValueError as e: 

107 raise JCalParsingError( 

108 "The value must be a valid weekday.", cls, value=value 

109 ) from e 

110 

111 

112__all__ = ["vWeekday"]