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

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

51 statements  

1"""GEO property values from :rfc:`5545`.""" 

2 

3import math 

4from typing import Any, ClassVar 

5 

6from icalendar.compatibility import Self 

7from icalendar.error import JCalParsingError 

8from icalendar.parser import Parameters 

9 

10 

11class vGeo: 

12 """Geographic Position 

13 

14 Property Name: 

15 GEO 

16 

17 Purpose: 

18 This property specifies information related to the global 

19 position for the activity specified by a calendar component. 

20 

21 Value Type: 

22 FLOAT. The value MUST be two SEMICOLON-separated FLOAT values. 

23 

24 Property Parameters: 

25 IANA and non-standard property parameters can be specified on 

26 this property. 

27 

28 Conformance: 

29 This property can be specified in "VEVENT" or "VTODO" 

30 calendar components. 

31 

32 Description: 

33 This property value specifies latitude and longitude, 

34 in that order (i.e., "LAT LON" ordering). The longitude 

35 represents the location east or west of the prime meridian as a 

36 positive or negative real number, respectively. The longitude and 

37 latitude values MAY be specified up to six decimal places, which 

38 will allow for accuracy to within one meter of geographical 

39 position. Receiving applications MUST accept values of this 

40 precision and MAY truncate values of greater precision. 

41 

42 Example: 

43 

44 .. code-block:: ics 

45 

46 GEO:37.386013;-122.082932 

47 

48 Parse vGeo: 

49 

50 .. code-block:: pycon 

51 

52 >>> from icalendar.prop import vGeo 

53 >>> geo = vGeo.from_ical('37.386013;-122.082932') 

54 >>> geo 

55 (37.386013, -122.082932) 

56 

57 Add a geo location to an event: 

58 

59 .. code-block:: pycon 

60 

61 >>> from icalendar import Event 

62 >>> event = Event() 

63 >>> latitude = 37.386013 

64 >>> longitude = -122.082932 

65 >>> event.add('GEO', (latitude, longitude)) 

66 >>> event['GEO'] 

67 vGeo((37.386013, -122.082932)) 

68 """ 

69 

70 default_value: ClassVar[str] = "FLOAT" 

71 params: Parameters 

72 

73 def __init__( 

74 self, 

75 geo: tuple[float | str | int, float | str | int], 

76 /, 

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

78 ) -> None: 

79 """Create a new vGeo from a tuple of (latitude, longitude). 

80 

81 Raises: 

82 ValueError: if geo is not a tuple of (latitude, longitude) 

83 """ 

84 try: 

85 latitude, longitude = (geo[0], geo[1]) 

86 latitude = float(latitude) 

87 longitude = float(longitude) 

88 except Exception as e: 

89 raise ValueError( 

90 "Input must be (float, float) for latitude and longitude" 

91 ) from e 

92 self.latitude = latitude 

93 self.longitude = longitude 

94 self.params = Parameters(params) 

95 

96 def to_ical(self) -> str: 

97 return f"{self.latitude};{self.longitude}" 

98 

99 @property 

100 def ical_value(self) -> tuple[float, float]: 

101 """Geographic position as a tuple of (latitude, longitude) according to :rfc:`5545#section-3.8.1.6`.""" 

102 return (self.latitude, self.longitude) 

103 

104 @staticmethod 

105 def from_ical(ical: str) -> tuple[float, float]: 

106 try: 

107 latitude, longitude = ical.split(";") 

108 latitude, longitude = float(latitude), float(longitude) 

109 except Exception as e: 

110 raise ValueError(f"Expected 'float;float' , got: {ical}") from e 

111 if not (math.isfinite(latitude) and math.isfinite(longitude)): 

112 raise ValueError(f"Expected finite 'float;float', got: {ical}") 

113 return (latitude, longitude) 

114 

115 def __eq__(self, other: object) -> bool: 

116 return isinstance(other, vGeo) and self.to_ical() == other.to_ical() 

117 

118 def __hash__(self) -> int: 

119 """Hash of the vGeo object.""" 

120 return hash((self.latitude, self.longitude)) 

121 

122 def __repr__(self) -> str: 

123 """repr(self)""" 

124 return f"{self.__class__.__name__}(({self.latitude}, {self.longitude}))" 

125 

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

127 """Convert to jCal object.""" 

128 return [ 

129 name, 

130 self.params.to_jcal(), 

131 self.VALUE.lower(), 

132 [self.latitude, self.longitude], 

133 ] 

134 

135 @classmethod 

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

137 """Examples of vGeo.""" 

138 return [cls((37.386013, -122.082932))] 

139 

140 from icalendar.param import VALUE 

141 

142 @classmethod 

143 def from_jcal(cls, jcal_property: list) -> Self: 

144 """Parse jCal from :rfc:`7265`. 

145 

146 Parameters: 

147 jcal_property: The jCal property to parse. 

148 

149 Raises: 

150 ~error.JCalParsingError: If the provided jCal is invalid. 

151 """ 

152 JCalParsingError.validate_property(jcal_property, cls) 

153 return cls( 

154 jcal_property[3], 

155 Parameters.from_jcal_property(jcal_property), 

156 ) 

157 

158 

159__all__ = ["vGeo"]