Coverage for C: \ Users \ peaco \ OneDrive \ Documents \ GitHub \ mt_metadata \ mt_metadata \ common \ location.py: 100%

40 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-10 00:11 -0800

1# ===================================================== 

2# Imports 

3# ===================================================== 

4from typing import Annotated 

5 

6from pydantic import AliasChoices, Field, field_validator, ValidationInfo 

7from pyproj import CRS 

8 

9from mt_metadata.base import MetadataBase 

10from mt_metadata.common import Declination, GeographicLocation 

11from mt_metadata.utils.location_helpers import validate_position 

12 

13 

14# ===================================================== 

15 

16 

17class BasicLocationNoDatum(MetadataBase): 

18 """ 

19 A partial location class that only includes the latitude, longitude, and elevation. 

20 This is used to avoid circular imports. 

21 """ 

22 

23 latitude: Annotated[ 

24 float | None, 

25 Field( 

26 default=0.0, 

27 description="Latitude of the location.", 

28 validation_alias=AliasChoices("latitude", "lat"), 

29 json_schema_extra={ 

30 "units": "degrees", 

31 "required": False, 

32 "examples": ["12.324"], 

33 }, 

34 ), 

35 ] 

36 

37 longitude: Annotated[ 

38 float | None, 

39 Field( 

40 default=0.0, 

41 description="Longitude of the location.", 

42 validation_alias=AliasChoices("longitude", "lon", "long"), 

43 json_schema_extra={ 

44 "units": "degrees", 

45 "required": False, 

46 "examples": ["12.324"], 

47 }, 

48 ), 

49 ] 

50 

51 elevation: Annotated[ 

52 float, 

53 Field( 

54 default=0.0, 

55 description="Elevation of the location.", 

56 alias=None, 

57 json_schema_extra={ 

58 "units": "meters", 

59 "required": False, 

60 "examples": ["1234.0"], 

61 }, 

62 ), 

63 ] 

64 

65 @field_validator("latitude", "longitude", mode="before") 

66 @classmethod 

67 def validate_position(cls, value, info: ValidationInfo): 

68 return validate_position(value, info.field_name) 

69 

70 

71class BasicLocation(BasicLocationNoDatum): 

72 datum: Annotated[ 

73 str | int, 

74 Field( 

75 default="WGS 84", 

76 description="Datum of the location values. Usually a well known datum like WGS84.", 

77 alias=None, 

78 json_schema_extra={ 

79 "units": None, 

80 "required": False, 

81 "examples": ["WGS 84"], 

82 }, 

83 ), 

84 ] 

85 

86 x: Annotated[ 

87 float, 

88 Field( 

89 default=0.0, 

90 description="relative distance to the center of the station", 

91 validation_alias=AliasChoices("x", "easting", "east"), 

92 json_schema_extra={ 

93 "units": "meters", 

94 "required": False, 

95 "examples": ["10.0"], 

96 }, 

97 ), 

98 ] 

99 

100 y: Annotated[ 

101 float, 

102 Field( 

103 default=0.0, 

104 description="relative distance to the center of the station", 

105 validation_alias=AliasChoices("y", "north", "northing"), 

106 json_schema_extra={ 

107 "units": "meters", 

108 "required": False, 

109 "examples": ["10.0"], 

110 }, 

111 ), 

112 ] 

113 

114 z: Annotated[ 

115 float, 

116 Field( 

117 default=0.0, 

118 description="relative elevation to the center of the station", 

119 alias=None, 

120 json_schema_extra={ 

121 "units": "meters", 

122 "required": False, 

123 "examples": ["10.0"], 

124 }, 

125 ), 

126 ] 

127 

128 @field_validator("datum", mode="before") 

129 @classmethod 

130 def validate_datum(cls, value: str | int) -> str: 

131 """ 

132 Validate the datum value and convert it to the appropriate enum type. 

133 """ 

134 try: 

135 datum_crs = CRS.from_user_input(value) 

136 return datum_crs.name 

137 except Exception: 

138 raise ValueError( 

139 f"Invalid datum value: {value}. Must be a valid CRS string or identifier." 

140 ) 

141 

142 

143class Location(BasicLocation): 

144 """ 

145 Positional location of a geographic point 

146 """ 

147 

148 latitude_uncertainty: Annotated[ 

149 float, 

150 Field( 

151 default=0.0, 

152 description="uncertainty in latitude estimation in degrees", 

153 alias=None, 

154 json_schema_extra={ 

155 "units": "degrees", 

156 "required": False, 

157 "examples": ["0.01"], 

158 }, 

159 ), 

160 ] 

161 

162 longitude_uncertainty: Annotated[ 

163 float, 

164 Field( 

165 default=0.0, 

166 description="uncertainty in longitude estimation in degrees", 

167 alias=None, 

168 json_schema_extra={ 

169 "units": "degrees", 

170 "required": False, 

171 "examples": ["0.01"], 

172 }, 

173 ), 

174 ] 

175 

176 elevation_uncertainty: Annotated[ 

177 float, 

178 Field( 

179 default=0.0, 

180 description="uncertainty in elevation estimation", 

181 alias=None, 

182 json_schema_extra={ 

183 "units": "meters", 

184 "required": False, 

185 "examples": ["0.01"], 

186 }, 

187 ), 

188 ] 

189 

190 x2: Annotated[ 

191 float, 

192 Field( 

193 default=0.0, 

194 description="relative distance to the center of the station", 

195 validation_alias=AliasChoices("x2", "east", "easting"), 

196 json_schema_extra={ 

197 "units": "meters", 

198 "required": False, 

199 "examples": ["10.0"], 

200 }, 

201 ), 

202 ] 

203 

204 y2: Annotated[ 

205 float, 

206 Field( 

207 default=0.0, 

208 description="relative distance to the center of the station", 

209 validation_alias=AliasChoices("y2", "north", "northing"), 

210 json_schema_extra={ 

211 "units": "meters", 

212 "required": False, 

213 "examples": ["10.0"], 

214 }, 

215 ), 

216 ] 

217 

218 z2: Annotated[ 

219 float, 

220 Field( 

221 default=0.0, 

222 description="relative elevation to the center of the station", 

223 alias=None, 

224 json_schema_extra={ 

225 "units": "meters", 

226 "required": False, 

227 "examples": ["10.0"], 

228 }, 

229 ), 

230 ] 

231 

232 x_uncertainty: Annotated[ 

233 float, 

234 Field( 

235 default=0.0, 

236 description="uncertainty in longitude estimation in x-direction", 

237 alias=None, 

238 json_schema_extra={ 

239 "units": "meters", 

240 "required": False, 

241 "examples": ["0.01"], 

242 }, 

243 ), 

244 ] 

245 

246 y_uncertainty: Annotated[ 

247 float, 

248 Field( 

249 default=0.0, 

250 description="uncertainty in longitude estimation in y-direction", 

251 alias=None, 

252 json_schema_extra={ 

253 "units": "meters", 

254 "required": False, 

255 "examples": ["0.01"], 

256 }, 

257 ), 

258 ] 

259 

260 z_uncertainty: Annotated[ 

261 float, 

262 Field( 

263 default=0.0, 

264 description="uncertainty in longitude estimation in z-direction", 

265 alias=None, 

266 json_schema_extra={ 

267 "units": "meters", 

268 "required": False, 

269 "examples": ["0.01"], 

270 }, 

271 ), 

272 ] 

273 

274 

275class StationLocation(Location): 

276 """ 

277 A class that represents the location of a station. It includes latitude, longitude, elevation, 

278 and other related attributes. 

279 """ 

280 

281 declination: Annotated[ 

282 Declination, 

283 Field( 

284 default_factory=Declination, # type: ignore 

285 description="Declination of the location.", 

286 alias=None, 

287 json_schema_extra={ 

288 "units": "degrees", 

289 "required": False, 

290 "examples": ["Declination(10.0)"], 

291 }, 

292 ), 

293 ] 

294 

295 geographic_location: Annotated[ 

296 GeographicLocation, 

297 Field( 

298 default_factory=GeographicLocation, # type: ignore 

299 description="Geographic location of the station.", 

300 alias=None, 

301 json_schema_extra={ 

302 "units": None, 

303 "required": False, 

304 "examples": ["GeographicLocation(latitude=12.34, longitude=56.78)"], 

305 }, 

306 ), 

307 ]