Coverage for C: \ Users \ peaco \ OneDrive \ Documents \ GitHub \ mt_metadata \ mt_metadata \ transfer_functions \ io \ emtfxml \ metadata \ dipole.py: 100%

43 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 

5from xml.etree import cElementTree as et 

6 

7from loguru import logger 

8from pydantic import Field, field_validator 

9 

10from mt_metadata.base import MetadataBase 

11from mt_metadata.transfer_functions.io.emtfxml.metadata import helpers 

12 

13from . import Electrode 

14 

15 

16# ===================================================== 

17class Dipole(MetadataBase): 

18 manufacturer: Annotated[ 

19 str | None, 

20 Field( 

21 default=None, 

22 description="Name of the manufacturer of the instrument", 

23 json_schema_extra={ 

24 "units": None, 

25 "required": False, 

26 "examples": ["MT Gurus"], 

27 }, 

28 ), 

29 ] 

30 

31 length: Annotated[ 

32 float | None, 

33 Field( 

34 default=None, 

35 description="Dipole length", 

36 json_schema_extra={ 

37 "units": "meters", 

38 "required": False, 

39 "examples": ["100.0"], 

40 }, 

41 ), 

42 ] 

43 

44 azimuth: Annotated[ 

45 float | None, 

46 Field( 

47 default=None, 

48 description="Azimuth of the dipole relative to coordinate system", 

49 json_schema_extra={ 

50 "units": "degrees", 

51 "required": False, 

52 "examples": ["90"], 

53 }, 

54 ), 

55 ] 

56 

57 name: Annotated[ 

58 str | None, 

59 Field( 

60 default=None, 

61 description="Name of the dipole", 

62 json_schema_extra={ 

63 "units": None, 

64 "required": False, 

65 "examples": ["dipole1"], 

66 }, 

67 ), 

68 ] 

69 

70 type: Annotated[ 

71 str | None, 

72 Field( 

73 default=None, 

74 description="type of dipole", 

75 json_schema_extra={ 

76 "units": None, 

77 "required": False, 

78 "examples": ["wire"], 

79 }, 

80 ), 

81 ] 

82 

83 electrode: Annotated[ 

84 list[Electrode], 

85 Field( 

86 default_factory=list, 

87 description="List of electrodes that make up the dipole", 

88 alias=None, 

89 json_schema_extra={ 

90 "units": None, 

91 "required": False, 

92 "examples": [{"name": "ex", "type": "wire"}], 

93 }, 

94 ), 

95 ] 

96 

97 @field_validator("electrode", mode="before") 

98 def validate_electrode(cls, value: list[Electrode] | list[dict]) -> list[Electrode]: 

99 """ 

100 Validate that the value is a list of Electrode objects. 

101 """ 

102 if not isinstance(value, list): 

103 value = [value] 

104 value_list = [] 

105 for item in value: 

106 if isinstance(item, dict): 

107 e_obj = Electrode() # type: ignore 

108 e_obj.from_dict(item) 

109 value_list.append(e_obj) 

110 elif isinstance(item, Electrode): 

111 value_list.append(item) 

112 else: 

113 raise TypeError( 

114 "Electrode must be an instance of Electrode class or a dict" 

115 ) 

116 return value_list 

117 

118 def to_xml(self, string: bool = False, required: bool = True) -> str | et.Element: 

119 """ 

120 

121 :param string: DESCRIPTION, defaults to False 

122 :type string: TYPE, optional 

123 :param required: DESCRIPTION, defaults to True 

124 :type required: TYPE, optional 

125 :return: DESCRIPTION 

126 :rtype: TYPE 

127 

128 """ 

129 

130 root = et.Element( 

131 self.__class__.__name__, {"name": self.name, "type": self.type} 

132 ) 

133 try: 

134 et.SubElement(root, "manufacturer").text = self.manufacturer 

135 except AttributeError: 

136 logger.debug("Dipole has no manufacturer information") 

137 if self.length is not None: 

138 et.SubElement(root, "length", {"units": "meters"}).text = ( 

139 f"{self.length:.3f}" 

140 ) 

141 if self.azimuth is not None: 

142 et.SubElement(root, "azimuth", {"units": "degrees"}).text = ( 

143 f"{self.azimuth:.3f}" 

144 ) 

145 for item in self.electrode: 

146 root.append(item.to_xml()) 

147 

148 if string: 

149 return helpers.element_to_string(root) 

150 return root