1# =====================================================
2# Imports
3# =====================================================
4from enum import Enum
5from typing import Annotated
6from xml.etree import cElementTree as et
7
8from pydantic import Field, field_validator, HttpUrl
9
10from mt_metadata.base import MetadataBase
11from mt_metadata.common.enumerations import ArrayDTypeEnum, EstimateIntentionEnum
12from mt_metadata.common.units import get_unit_object
13from mt_metadata.transfer_functions.io.emtfxml.metadata import helpers
14
15
16# =====================================================
17
18
19class OutputEnum(str, Enum):
20 E = "E"
21 H = "H"
22
23
24class InputEnum(str, Enum):
25 E = "E"
26 H = "H"
27
28
29class DataType(MetadataBase):
30 name: Annotated[
31 str,
32 Field(
33 default="",
34 description="Name of the statistical estimate",
35 alias=None,
36 json_schema_extra={
37 "units": None,
38 "required": True,
39 "examples": ["var"],
40 },
41 ),
42 ]
43
44 type: Annotated[
45 ArrayDTypeEnum,
46 Field(
47 default="real",
48 description="Type of number contained in the estimate",
49 alias=None,
50 json_schema_extra={
51 "units": None,
52 "required": True,
53 "examples": ["real"],
54 },
55 ),
56 ]
57
58 description: Annotated[
59 str,
60 Field(
61 default="",
62 description="Description of the statistical estimate",
63 alias=None,
64 json_schema_extra={
65 "units": None,
66 "required": True,
67 "examples": ["this is an estimate"],
68 },
69 ),
70 ]
71
72 external_url: Annotated[
73 HttpUrl,
74 Field(
75 default="",
76 description="Full path to external link that has additional information",
77 alias=None,
78 json_schema_extra={
79 "units": None,
80 "required": True,
81 "examples": ["http://www.iris.edu/dms/products/emtf/variance.html"],
82 },
83 ),
84 ]
85
86 intention: Annotated[
87 EstimateIntentionEnum,
88 Field(
89 default="",
90 description="The intension of the statistical estimate",
91 alias=None,
92 json_schema_extra={
93 "units": None,
94 "required": True,
95 "examples": ["error estimate"],
96 },
97 ),
98 ]
99
100 tag: Annotated[
101 str,
102 Field(
103 default="",
104 description="A useful tag for the estimate",
105 alias=None,
106 json_schema_extra={
107 "units": None,
108 "required": True,
109 "examples": ["tipper"],
110 },
111 ),
112 ]
113
114 output: Annotated[
115 OutputEnum,
116 Field(
117 default="",
118 description="Type of output channels in data type",
119 alias=None,
120 json_schema_extra={
121 "units": None,
122 "required": True,
123 "examples": ["E"],
124 },
125 ),
126 ]
127
128 input: Annotated[
129 InputEnum,
130 Field(
131 default="",
132 description="Type of input channels in data type",
133 alias=None,
134 json_schema_extra={
135 "units": None,
136 "required": True,
137 "examples": ["E"],
138 },
139 ),
140 ]
141
142 units: Annotated[
143 str,
144 Field(
145 default="milliVolt per kilometer per nanoTesla",
146 description="Units for the data type",
147 alias=None,
148 json_schema_extra={
149 "units": None,
150 "required": True,
151 "examples": ["[mV/km]/[nT]"],
152 },
153 ),
154 ]
155
156 @field_validator("units", mode="before")
157 @classmethod
158 def validate_units(cls, value: str) -> str:
159 if value in [None, ""]:
160 return ""
161 try:
162 unit_object = get_unit_object(value)
163 return unit_object.symbol
164 except ValueError as error:
165 raise KeyError(error)
166 except KeyError as error:
167 raise KeyError(error)
168
169 def read_dict(self, input_dict: dict) -> None:
170 """
171
172 :param input_dict: input dictionary to read and populate the model fields.
173 :type input_dict: dict
174 :return: None
175 """
176 helpers._read_element(self, input_dict, "estimate")
177
178 def to_xml(self, string: bool = False, required: bool = True) -> str | et.Element:
179 """
180
181 :param string: return value as a string, defaults to False
182 :type string: bool, optional
183 :param required: include required values only, defaults to True
184 :type required: bool, optional
185 :return: XML representation of the model
186 :rtype: str | et.Element
187
188 """
189
190 element = helpers.to_xml(
191 self,
192 string=string,
193 required=required,
194 order=["description", "external_url", "intention", "tag"],
195 )
196 xml_unit = get_unit_object(self.units).symbol
197 if not string:
198 element.attrib = {
199 "name": self.name,
200 "type": self.type,
201 "output": self.output,
202 "input": self.input,
203 "units": xml_unit,
204 }
205
206 return element