Skip to content

Commit 6968da9

Browse files
author
Lachlan Grose
committed
refactor: 🎨 adding type hints and some validation checks
1 parent 24e79fe commit 6968da9

File tree

1 file changed

+122
-36
lines changed

1 file changed

+122
-36
lines changed

LoopProjectFile/projectfile.py

Lines changed: 122 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from multiprocessing.sharedctypes import Value
12
from .LoopProjectFile import Get, Set, CreateBasic, OpenProjectFile, CheckFileValid,CheckFileIsLoopProjectFile
23
from .LoopProjectFileUtils import ElementToDataframe, ElementFromDataframe
34
import LoopProjectFile
@@ -77,18 +78,45 @@ def new(cls, filename):
7778
projectfile = ProjectFile(filename)
7879
return projectfile
7980

80-
def is_valid(self):
81+
@property
82+
def valid(self) -> bool:
83+
"""Check if the project file is valid
84+
85+
Returns
86+
-------
87+
bool
88+
true if project file is valid, false if not
89+
"""
90+
return self.is_valid()
91+
92+
def is_valid(self) -> bool:
8193
return CheckFileValid(self.project_filename)
8294

8395
def _add_names_to_df(self, log, df):
96+
"""_summary_
97+
98+
Parameters
99+
----------
100+
log : _type_
101+
_description_
102+
df : _type_
103+
_description_
104+
"""
84105
df['name'] = 'none'
85106
for stratigraphic_id in log.index:
86107
df.loc[df['layerId'] == stratigraphic_id,'name'] = \
87108
log.loc[stratigraphic_id,'name']
88109

89110

90111
@property
91-
def extents(self):
112+
def extents(self)->np.ndarray:
113+
"""Get the extents of the model
114+
115+
Returns
116+
-------
117+
np.ndarray
118+
_description_
119+
"""
92120
resp = Get(self.project_filename,'extents')
93121
if resp['errorFlag'] == True:
94122
return None
@@ -101,128 +129,180 @@ def extents(self,extents):
101129

102130

103131
@property
104-
def version(self):
132+
def version(self) -> str:
133+
"""Get version of the project file
134+
135+
Returns
136+
-------
137+
str
138+
version string major.minor.patch
139+
"""
105140
resp = Get(self.project_filename,'version')
106141
if resp['errorFlag'] == True:
107142
return None
108143
return "{}.{}.{}".format(*resp['value'])
109144

110145
@property
111-
def origin(self):
146+
def origin(self) -> np.ndarray:
147+
"""Get the origin of the model"""
112148
origin = np.zeros(3)
113149
origin[0] = self.extents['utm'][2]
114150
origin[1] = self.extents['utm'][4]
115151
origin[2] = self.extents['depth'][0]
116152
return origin
117153
@property
118-
def maximum(self):
154+
def maximum(self) -> np.ndarray:
155+
"""Get top right hand coordinate of the bouinding box
156+
157+
Returns
158+
-------
159+
np.ndarray
160+
_description_
161+
"""
119162
maximum = np.zeros(3)
120163
maximum[0] = self.extents['utm'][3]
121164
maximum[1] = self.extents['utm'][5]
122165
maximum[2] = self.extents['depth'][1]
123166
return maximum
124-
# should we be able to set the version or should this be fixed?
125-
# @version.setter
126-
# def version(self, version):
127-
# if isinstance(version, str):
128-
# version = version.split('.')
129-
# if len(version) != 3:
130-
# raise ValueError('Version must be in the format major.minor.patch')
131-
# version = list(map(int, version))
132-
# resp = Set(self.project_filename,'version',version=version)
133-
# if resp['errorFlag'] == True:
134-
# raise ValueError('Version must be in the format major.minor.patch')
167+
135168

136169
@property
137-
def faultObservations(self):
170+
def faultObservations(self) ->pd.DataFrame:
138171
return self.__getitem__('faultObservations')
139172

140173
@faultObservations.setter
141-
def faultObservations(self, value):
174+
def faultObservations(self, value:pd.DataFrame):
175+
if isinstance(value, pd.DataFrame):
176+
self.__setitem__('faultObservations', value)
177+
self._validate_data_frame_columns(value, [ 'eventId', 'easting', 'northing', 'altitude' ,'type' ,'dipDir' ,'dip', 'dipPolarity', 'val', 'displacement','posOnly'])
142178
self.__setitem__('faultObservations', value)
143179

144180

145181
@property
146-
def faultLocations(self):
182+
def faultLocations(self)->pd.DataFrame:
183+
"""Get only the observations of the fault location
184+
185+
Returns
186+
-------
187+
pd.DataFrame
188+
_description_
189+
"""
147190
df = self.__getitem__('faultObservations')
148191
# self._add_names_to_df(self.faultLog,df)
149192
return df.loc[df['posOnly']==1,:]
150193

194+
def _validate_data_frame_columns(self, df:pd.DataFrame, columns:list):
195+
for c in columns.keys():
196+
if c in df.columns:
197+
columns[c] = True
198+
columns_in_df = True
199+
for c in columns.keys():
200+
if columns[c] == False:
201+
columns_in_df = False
202+
print(f'Column: {c} not dataframe')
203+
# logger.error(f'Column: {c} not dataframe')
204+
if columns_in_df == False:
205+
raise ValueError('Columns not in dataframe')
151206
@faultLocations.setter
152-
def faultLocations(self, value):
207+
def faultLocations(self, value:pd.DataFrame):
208+
"""Update the faultObservations with new fault locations
209+
210+
Parameters
211+
----------
212+
value : pd.DataFrame
213+
_description_
214+
"""
215+
if isinstance(value, pd.DataFrame) == False:
216+
raise TypeError('faultLocations must be set with a pandas dataframe')
217+
columns = {'eventId':False, 'easting':False, 'northing':False, 'altitude':False, 'val':False}
218+
self._validate_data_frame_columns(value, columns)
153219
df = self.__getitem__('faultObservations')
154-
value = pd.concat([value,df.loc[df['posOnly']==1,:]])
220+
value['posOnly'] == 1
221+
value = pd.concat([value,df.loc[df['posOnly']==0,:]])
155222
value.reset_index(inplace=True)
156223
self.__setitem__('faultObservations', value)
157224

158225

159226
@property
160-
def faultOrientations(self):
227+
def faultOrientations(self)->pd.DataFrame:
161228
df = self.__getitem__('faultObservations')
162229
return df.loc[df['posOnly']==0,:]
163230

164231
@faultOrientations.setter
165-
def faultOrientations(self, value):
232+
def faultOrientations(self, value:pd.DataFrame):
233+
if isinstance(value, pd.DataFrame) == False:
234+
raise TypeError('faultOrientations must be set with a pandas dataframe')
235+
columns = {'eventId':False, 'easting':False, 'northing':False, 'altitude':False, 'dipDir':False, 'dip':False, 'dipPolarity':False}
236+
self._validate_data_frame_columns(value, columns)
237+
166238
df = self.__getitem__('faultObservations')
167-
value = pd.concat([value,df.loc[df['posOnly']==0,:]])
239+
value['posOnly'] == 0
240+
value = pd.concat([value,df.loc[df['posOnly']==1,:]])
168241
value.reset_index(inplace=True)
169242
self.__setitem__('faultObservations', value)
170243

171244

172245
@property
173-
def faultLog(self):
246+
def faultLog(self)->pd.DataFrame:
174247
return self.__getitem__('faultLog').set_index('name')
175248

176249
@faultLog.setter
177-
def faultLog(self, value):
250+
def faultLog(self, value:pd.DataFrame):
178251
self.__setitem__('faultLog',value)
179252

180253

181254
@property
182-
def foliationObservations(self):
255+
def foliationObservations(self)->pd.DataFrame:
183256
return self.__getitem__('foliationObservations')
184257

185258
@foliationObservations.setter
186-
def foliationObservations(self, value):
259+
def foliationObservations(self, value:pd.DataFrame):
187260
self.__setitem__('foliationObservations',value)
188261

189262

190263
@property
191-
def foldObservations(self):
264+
def foldObservations(self)->pd.DataFrame:
192265
return self.__getitem__('foldObservations')
193266

194267
@foldObservations.setter
195-
def foldObservations(self, value):
268+
def foldObservations(self, value:pd.DataFrame):
196269
self.__setitem__('foldObservations', value)
197270

198271

199272
@property
200-
def stratigraphicLog(self):
273+
def stratigraphicLog(self)->pd.DataFrame:
201274
return self.__getitem__('stratigraphicLog')
202275

203276
@stratigraphicLog.setter
204-
def stratigraphicLog(self, value):
277+
def stratigraphicLog(self, value:pd.DataFrame):
278+
## TODO add a validator
205279
self.__setitem__('stratigraphicLog', value)
206280

207281

208282
@property
209-
def stratigraphyLocations(self):
283+
def stratigraphyLocations(self)->pd.DataFrame:
210284
df = self.__getitem__('contacts')
211285
self._add_names_to_df(self.stratigraphicLog,df)
212286
return df
213287

214288
@stratigraphyLocations.setter
215-
def stratigraphyLocations(self, value):
289+
def stratigraphyLocations(self, value:pd.DataFrame):
290+
if isinstance(value, pd.DataFrame) == False:
291+
raise TypeError('stratigraphyLocations must be set with a pandas dataframe')
292+
self._validate_data_frame_columns(value, ['layerId','easting','northing','altitude', 'type', 'name'])
216293
self.__setitem__('contacts',value)
217294

218295
@property
219-
def stratigraphyOrientations(self):
296+
def stratigraphyOrientations(self)->pd.DataFrame:
220297
df = self.__getitem__('stratigraphicObservations')
221298
self._add_names_to_df(self.stratigraphicLog,df)
222299
return df
223300

224301
@stratigraphyOrientations.setter
225-
def stratigraphyOrientations(self, value):
302+
def stratigraphyOrientations(self, value:pd.DataFrame):
303+
if isinstance(value, pd.DataFrame) == False:
304+
raise TypeError('stratigraphyOrientations must be set with a pandas dataframe')
305+
self._validate_data_frame_columns(value, ['layerId','easting','northing','altitude','type', 'name','dipDir','dip','dipPolarity','layer'])
226306
self.__setitem__('stratigraphicObservations',value)
227307

228308

@@ -237,6 +317,12 @@ def __getitem__(self, element):
237317
else:
238318
return LoopProjectFile.ElementToDataframe(self.project_filename,
239319
element,compoundTypeMap[element])
320+
# if the project file is empty for a given element, return an empty dataframe with the correct headers
321+
if resp['errorFlag'] == True:
322+
if resp['errorString'] == 'No Observations present in DataCollection for access request':
323+
## this isn't really ideal and maybe need to be removed but at least it gives an idea of the column
324+
## names needed.
325+
return pd.DataFrame(columns=list(compoundTypeMap[element].names))
240326
# return ProjectFileElement(self.project_filename, element).value
241327

242328
def __setitem__(self, element, value):

0 commit comments

Comments
 (0)