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

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"""BYMONTH value type of RECUR from :rfc:`5545` and :rfc:`7529`.""" 

2 

3from typing import Any 

4 

5from icalendar.compatibility import Self 

6from icalendar.error import JCalParsingError 

7from icalendar.parser import Parameters 

8 

9 

10class vMonth(int): 

11 """The number of the month for recurrence. 

12 

13 In :rfc:`5545`, this is just an int. 

14 In :rfc:`7529`, this can be followed by `L` to indicate a leap month. 

15 

16 .. code-block:: pycon 

17 

18 >>> from icalendar import vMonth 

19 >>> vMonth(1) # first month January 

20 vMonth('1') 

21 >>> vMonth("5L") # leap month in Hebrew calendar 

22 vMonth('5L') 

23 >>> vMonth(1).leap 

24 False 

25 >>> vMonth("5L").leap 

26 True 

27 

28 Definition from RFC: 

29 

30 .. code-block:: text 

31 

32 type-bymonth = element bymonth { 

33 xsd:positiveInteger | 

34 xsd:string 

35 } 

36 """ 

37 

38 params: Parameters 

39 

40 def __new__(cls, month: str | int, /, params: dict[str, Any] | None = None): 

41 if isinstance(month, vMonth): 

42 return cls(month.to_ical().decode()) 

43 if isinstance(month, str): 

44 if month.isdigit(): 

45 month_index = int(month) 

46 leap = False 

47 else: 

48 if not month or month[-1] != "L" or not month[:-1].isdigit(): 

49 raise ValueError(f"Invalid month: {month!r}") 

50 month_index = int(month[:-1]) 

51 leap = True 

52 else: 

53 leap = False 

54 month_index = int(month) 

55 self = super().__new__(cls, month_index) 

56 self.leap = leap 

57 self.params = Parameters(params) 

58 return self 

59 

60 def to_ical(self) -> bytes: 

61 """The ical representation.""" 

62 return str(self).encode("utf-8") 

63 

64 @classmethod 

65 def from_ical(cls, ical: str): 

66 return cls(ical) 

67 

68 @property 

69 def leap(self) -> bool: 

70 """Whether this is a leap month.""" 

71 return self._leap 

72 

73 @leap.setter 

74 def leap(self, value: bool) -> None: 

75 self._leap = value 

76 

77 def __repr__(self) -> str: 

78 """repr(self)""" 

79 return f"{self.__class__.__name__}({str(self)!r})" 

80 

81 def __str__(self) -> str: 

82 """str(self)""" 

83 return f"{int(self)}{'L' if self.leap else ''}" 

84 

85 @classmethod 

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

87 """Parse a jCal value for vMonth. 

88 

89 Raises: 

90 ~error.JCalParsingError: If the value is not a valid month. 

91 """ 

92 JCalParsingError.validate_value_type(value, (str, int), cls) 

93 try: 

94 return cls(value) 

95 except ValueError as e: 

96 raise JCalParsingError( 

97 "The value must be a string or an integer.", cls, value=value 

98 ) from e 

99 

100 

101__all__ = ["vMonth"]