Coverage for C: \ Users \ peaco \ OneDrive \ Documents \ GitHub \ mt_metadata \ mt_metadata \ timeseries \ filtered.py: 100%

23 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 Field, field_validator, ValidationInfo 

7 

8from mt_metadata.base import MetadataBase 

9from mt_metadata.common.comment import Comment 

10 

11 

12# ===================================================== 

13 

14# this will be a better way of keeping track of filter names and 

15# if they have been applied or not. This can also include the stage 

16# number of the filter and could be extended to other attributes. 

17# TODO: figure out setting a applied and name. 

18 

19 

20class AppliedFilter(MetadataBase): 

21 name: Annotated[ 

22 str, 

23 Field( 

24 default=None, 

25 description="Name of the filter.", 

26 json_schema_extra={ 

27 "units": None, 

28 "required": True, 

29 "examples": ["low pass"], 

30 }, 

31 ), 

32 ] 

33 

34 applied: Annotated[ 

35 bool, 

36 Field( 

37 default=True, 

38 description="Whether the filter has been applied.", 

39 json_schema_extra={ 

40 "units": None, 

41 "required": True, 

42 "examples": ["True"], 

43 }, 

44 ), 

45 ] 

46 

47 stage: Annotated[ 

48 int | None, 

49 Field( 

50 default=None, 

51 description="Stage of the filter in the processing chain.", 

52 json_schema_extra={ 

53 "units": None, 

54 "required": False, 

55 "examples": [1], 

56 }, 

57 ), 

58 ] 

59 

60 comments: Annotated[ 

61 Comment, 

62 Field( 

63 default_factory=lambda: Comment(), # type: ignore 

64 description="Any comments on filters.", 

65 alias=None, 

66 json_schema_extra={ 

67 "units": None, 

68 "required": False, 

69 "examples": ["low pass is not calibrated"], 

70 }, 

71 ), 

72 ] 

73 

74 @field_validator("comments", mode="before") 

75 @classmethod 

76 def validate_comments(cls, value, info: ValidationInfo) -> Comment: 

77 """ 

78 Validate that the value is a valid comment. 

79 """ 

80 if isinstance(value, str): 

81 return Comment(value=value) 

82 return value 

83 

84 @field_validator("name", mode="before") 

85 @classmethod 

86 def validate_name(cls, value, info: ValidationInfo) -> str: 

87 """ 

88 Validate that the name is not empty or whitespace only. Also, replace 

89 '/' with ' per ' and convert to lower case for consistency. 

90 """ 

91 if isinstance(value, str): 

92 if not value or value.isspace(): 

93 raise ValueError("Filter name cannot be empty or whitespace only") 

94 value = value.replace("/", " per ").lower() 

95 return value 

96 

97 

98# class Filter(MetadataBase): 

99# _objects_included: dict = PrivateAttr( 

100# default_factory=lambda: {"applied_filter": AppliedFilter} 

101# ) 

102 

103# filter_list: Annotated[ 

104# list[AppliedFilter], 

105# Field( 

106# default_factory=list, 

107# description="List of AppliedFilter() objects.", 

108# examples=["[AppliedFilter(name='filter_name', applied=True, stage=1)]"], 

109# alias=None, 

110# json_schema_extra={ 

111# "units": None, 

112# "required": False, 

113# }, 

114# ), 

115# ] 

116 

117# applied: Annotated[ 

118# list[bool], 

119# Field( 

120# default_factory=list, 

121# description="List of booleans indicating if the filter has been applied.", 

122# examples=[True, False], 

123# alias=None, 

124# deprecated=deprecated( 

125# "'applied' will be deprecated in the future use an AppliedFilter object." 

126# ), 

127# json_schema_extra={ 

128# "units": None, 

129# "required": False, 

130# }, 

131# ), 

132# ] 

133 

134# name: Annotated[ 

135# list[str], 

136# Field( 

137# default_factory=list, 

138# description="List of filter names.", 

139# examples=["low pass", "high pass"], 

140# alias=None, 

141# deprecated=deprecated( 

142# "'name' will be deprecated in the future use an AppliedFilter object." 

143# ), 

144# json_schema_extra={ 

145# "units": None, 

146# "required": False, 

147# }, 

148# ), 

149# ] 

150 

151# comments: Annotated[ 

152# Comment, 

153# Field( 

154# default_factory=Comment, 

155# description="Any comments on filters.", 

156# examples=["low pass is not calibrated"], 

157# alias=None, 

158# json_schema_extra={ 

159# "units": None, 

160# "required": False, 

161# }, 

162# ), 

163# ] 

164 

165# @field_validator("comments", mode="before") 

166# @classmethod 

167# def validate_comments(cls, value, info: ValidationInfo) -> Comment: 

168# """ 

169# Validate that the value is a valid comment. 

170# """ 

171# if isinstance(value, str): 

172# return Comment(value=value) 

173# return value 

174 

175# @model_validator(mode="after") 

176# def validate_applied_and_names(self) -> Self: 

177# """ 

178# Validate the applied_list to ensure it contains only AppliedFilter objects. 

179# """ 

180# if self.name != [] or self.applied != []: 

181# logger.warning( 

182# "'applied' and 'name' will be deprecated in the future append an " 

183# "AppliedFilter(name='name', applied=True) to 'filter_list'." 

184# ) 

185 

186# if len(self.name) != len(self.applied): 

187# diff = len(self.name) - len(self.applied) 

188# if diff > 0: 

189# self.applied.extend([True] * diff) 

190# else: 

191# self.name.extend(["unknown"] * abs(diff)) 

192 

193# if len(self.name) != len(self.filter_list): 

194# for name, applied, index in zip( 

195# self.name, self.applied, range(len(self.name)) 

196# ): 

197# self.filter_list.append( 

198# AppliedFilter(name=name, applied=applied, stage=index + 1) 

199# ) 

200 

201# return self 

202 

203# def to_dict( 

204# self, single: bool = False, nested: bool = False, required: bool = True 

205# ) -> dict: 

206# """ 

207# Convert the object to a dictionary. To be compliant with older versions 

208# of the metadata, use name and applied as lists 

209 

210# Parameters 

211# ---------- 

212# single : bool, optional 

213# Whether to return a single dictionary or a list of dictionaries, 

214# by default False. 

215 

216# Returns 

217# ------- 

218# dict 

219# Dictionary representation of the object. 

220# """ 

221# d = OrderedDict() 

222# d["name"] = self.name 

223# d["applied"] = self.applied 

224# d["comments"] = self.comments.to_dict(single=single, nested=nested) 

225# return d 

226 

227# def add_filter( 

228# self, 

229# applied_filter: AppliedFilter = None, 

230# name: str = None, 

231# applied: bool = True, 

232# stage: int | None = None, 

233# ) -> None: 

234# """ 

235# Add a filter to the filter list. 

236 

237# Parameters 

238# ---------- 

239# name : str 

240# Name of the filter. 

241# applied : bool, optional 

242# Whether the filter has been applied, by default True. 

243# stage : int | None, optional 

244# Stage of the filter in the processing chain, by default None. 

245# """ 

246# if applied_filter is not None: 

247# if not isinstance(applied_filter, AppliedFilter): 

248# raise TypeError("applied_filter must be an instance of AppliedFilter") 

249# if applied_filter.stage is None: 

250# applied_filter.stage = len(self.filter_list) + 1 

251# self.filter_list.append(applied_filter) 

252# else: 

253# if name is None: 

254# raise ValueError("name must be provided if applied_filter is None") 

255# if not isinstance(name, str): 

256# raise TypeError("name must be a string") 

257# if stage is None: 

258# stage = len(self.filter_list) + 1 

259# self.filter_list.append( 

260# AppliedFilter(name=name, applied=applied, stage=stage) 

261# ) 

262 

263# def remove_filter(self, name: str, reset_stages: bool = True) -> None: 

264# """ 

265# Remove a filter from the filter list. 

266 

267# Parameters 

268# ---------- 

269# name : str 

270# Name of the filter to remove. 

271# reset_stages : bool, optional 

272# Whether to reset the stages of the remaining filters, by default True. 

273# """ 

274 

275# new_list = [] 

276# for f in self.filter_list: 

277# if f.name == name: 

278# continue 

279# if reset_stages: 

280# f.stage = len(new_list) + 1 

281# new_list.append(f) 

282# self.filter_list = new_list