Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/prop/broken.py: 85%

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

34 statements  

1"""Parsing error value preservation.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, Any, ClassVar 

6 

7from icalendar.error import BrokenCalendarProperty 

8from icalendar.parser_tools import DEFAULT_ENCODING 

9from icalendar.prop.text import vText 

10 

11if TYPE_CHECKING: 

12 from icalendar.compatibility import Self 

13 from icalendar.parser import Parameters 

14 

15 

16class vBroken(vText): 

17 """Property that failed to parse, preserving raw value as text. 

18 

19 Represents property values that failed to parse with their expected 

20 type. The raw iCalendar string is preserved for round-trip serialization: 

21 ical -> xcal -> ical 

22 """ 

23 

24 default_value: ClassVar[str] = "X-BROKEN" 

25 """The default value is x-broken. 

26 

27 With this, we can identify broken properties in xCal round-trip. 

28 """ 

29 __slots__ = ("expected_type", "parse_error", "property_name") 

30 

31 def __new__( 

32 cls, 

33 value: str | bytes, 

34 encoding: str = DEFAULT_ENCODING, 

35 /, 

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

37 expected_type: str | None = None, 

38 property_name: str | None = None, 

39 parse_error: BaseException | None = None, 

40 ) -> Self: 

41 self = super().__new__(cls, value, encoding, params=params) 

42 self.expected_type = expected_type 

43 self.property_name = property_name 

44 self.parse_error = parse_error 

45 return self 

46 

47 def __getattr__(self, name: str): 

48 """Raise BrokenCalendarProperty for attribute access. 

49 

50 Attributes like ``.dt`` that the expected type would have 

51 raise :class:`~icalendar.error.BrokenCalendarProperty` 

52 with the original parse error chained. Private attributes 

53 (starting with ``_``) raise normal ``AttributeError`` to 

54 preserve ``getattr(..., default)`` patterns. 

55 """ 

56 if name.startswith("_"): 

57 raise AttributeError(name) 

58 raise BrokenCalendarProperty( 

59 f"Cannot access {name!r} on broken property " 

60 f"{self.property_name!r} (expected {self.expected_type!r}): " 

61 f"{self.parse_error}" 

62 ) from self.parse_error 

63 

64 def __repr__(self) -> str: 

65 return ( 

66 f"{self.__class__.__name__}({str(self)!r}, " 

67 f"expected_type={self.expected_type!r}, " 

68 f"property_name={self.property_name!r})" 

69 ) 

70 

71 def to_jcal(self, name: str) -> list: 

72 """Serialize the unparsed value as the :rfc:`7265#section-7.1` ``unknown`` type.""" 

73 return [name, self.params.to_jcal(), "unknown", str(self)] 

74 

75 @classmethod 

76 def from_parse_error( 

77 cls, 

78 raw_value: str, 

79 params: Parameters, 

80 property_name: str, 

81 expected_type: str, 

82 error: Exception, 

83 ) -> Self: 

84 """Create vBroken from parse failure.""" 

85 return cls( 

86 raw_value, 

87 params=params, 

88 expected_type=expected_type, 

89 property_name=property_name, 

90 parse_error=error, 

91 ) 

92 

93 @classmethod 

94 def examples(cls) -> list[Self]: 

95 """Examples of vBroken.""" 

96 return [ 

97 cls( 

98 "INVALID-DATE", 

99 expected_type="date-time", 

100 property_name="DTSTART", 

101 parse_error=ValueError("Invalid date format"), 

102 ) 

103 ] 

104 

105 

106__all__ = ["vBroken"]