5
5
from pathlib import Path
6
6
from uuid import UUID
7
7
from warnings import warn
8
- import shutil
8
+ import zipfile
9
9
from git import Repo
10
10
import io
11
11
@@ -36,16 +36,25 @@ def getZippedModel(model, gPath, project=None):
36
36
projectName = project .name
37
37
else :
38
38
projectName = mr .get_project (project ).name
39
- # Attempt to put model in project folder
40
- try :
41
- with open (Path (gPath ) / (projectName + '/' + modelName + '.zip' ), 'wb' ) as zFile :
42
- zFile .write (modelZip )
43
- # If the folder doesn't exist, create it and then put model into the project folder
44
- except FileNotFoundError :
45
- newDir = Path (projectName + '/' )
39
+ # Check to see if project folder exists
40
+ if (Path (gPath ) / projectName ).exists ():
41
+ #Check to see if model folder exists
42
+ if (Path (gPath ) / projectName / modelName ).exists ():
43
+ with open (Path (gPath ) / projectName / modelName / (modelName + '.zip' ), 'wb' ) as zFile :
44
+ zFile .write (modelZip )
45
+ else :
46
+ newDir = Path (gPath ) / projectName / modelName
47
+ newDir .mkdir (parents = True , exist_ok = True )
48
+ with open (Path (gPath ) / projectName / modelName / (modelName + '.zip' ), 'wb' ) as zFile :
49
+ zFile .write (modelZip )
50
+ else :
51
+ newDir = Path (gPath ) / projectName
52
+ newDir .mkdir (parents = True , exist_ok = True )
53
+ newDir = Path (gPath ) / projectName / modelName
46
54
newDir .mkdir (parents = True , exist_ok = True )
47
55
with open (Path (gPath ) / (projectName + '/' + modelName + '.zip' ), 'wb' ) as zFile :
48
56
zFile .write (modelZip )
57
+
49
58
return modelName , projectName
50
59
51
60
def project_exists (response , project ):
@@ -84,7 +93,51 @@ def project_exists(response, project):
84
93
return response
85
94
else :
86
95
return response
96
+
97
+ def model_exists (project , name , force ):
98
+ """Checks if model already exists and either raises an error or deletes the redundant model.
87
99
100
+ Parameters
101
+ ----------
102
+ project : string or dict
103
+ The name or id of the model project, or a dictionary representation of the project.
104
+ name : str or dict
105
+ The name of the model.
106
+ force : bool, optional
107
+ Sets whether to overwrite models with the same name upon upload.
108
+
109
+ Raises
110
+ ------
111
+ ValueError
112
+ Model repository API cannot overwrite an already existing model with the upload model call.
113
+ Alerts user of the force argument to allow multi-call API overwriting.
114
+ """
115
+ project = mr .get_project (project )
116
+ projectId = project ["id" ]
117
+ projectModels = mr .get ("/projects/{}/models" .format (projectId ))
118
+
119
+ for model in projectModels :
120
+ # Throws a TypeError if only one model is in the project
121
+ try :
122
+ if model ["name" ] == name :
123
+ if force :
124
+ mr .delete_model (model .id )
125
+ else :
126
+ raise ValueError (
127
+ "A model with the same model name exists in project {}. Include the force=True argument to overwrite models with the same name." .format (
128
+ project .name
129
+ )
130
+ )
131
+ except TypeError :
132
+ if projectModels ["name" ] == name :
133
+ if force :
134
+ mr .delete_model (projectModels .id )
135
+ else :
136
+ raise ValueError (
137
+ "A model with the same model name exists in project {}. Include the force=True argument to overwrite models with the same name." .format (
138
+ project .name
139
+ )
140
+ )
88
141
class GitIntegrate :
89
142
@classmethod
90
143
def pullViyaModel (
@@ -121,7 +174,7 @@ def pullViyaModel(
121
174
else :
122
175
UUID (model )
123
176
projectName = mr .get_model (model ).projectName
124
- modelName = getZippedModel (model , projectName , gPath )
177
+ modelName , projectName = getZippedModel (model , gPath , projectName )
125
178
# If a name is provided instead, use the provided project name or UUID to find the correct model
126
179
except ValueError :
127
180
projectResponse = mr .get_project (project )
@@ -137,15 +190,16 @@ def pullViyaModel(
137
190
try :
138
191
if model ["name" ] == model :
139
192
modelId = model .id
140
- modelName = getZippedModel (modelId , projectName , gPath )
193
+ modelName , projectName = getZippedModel (modelId , gPath , projectName )
141
194
except TypeError :
142
195
if projectModels ["name" ] == model :
143
196
modelId = projectModels .id
144
- modelName = getZippedModel (modelId , projectName , gPath )
197
+ modelName , projectName = getZippedModel (modelId , gPath , projectName )
145
198
146
199
# Unpack the pulled down zip model and overwrite any duplicate files
147
200
mPath = Path (gPath ) / '{projectName}/{modelName}' .format (projectName = projectName , modelName = modelName )
148
- shutil .unpack_archive (filename = (modelName + '.zip' ), extract_dir = mPath )
201
+ with zipfile .ZipFile (str (mPath / (modelName + '.zip' )), mode = 'r' ) as zFile :
202
+ zFile .extractall (str (mPath ))
149
203
150
204
# Delete the zip model objects in the directory to minimize confusion when uploading back to SAS Model Manager
151
205
for zipFile in mPath .glob ('*.zip' ):
@@ -159,21 +213,29 @@ def pushGitModel(cls, gPath, modelName=None, projectName=None):
159
213
Parameters
160
214
----------
161
215
gPath : string or Path
162
- Base directory of the git repository.
216
+ Base directory of the git repository or path which includes project and model directories .
163
217
modelName : string, optional
164
218
Name of model to be imported, by default None
165
219
projectName : string, optional
166
220
Name of project the model is imported from, by default None
167
221
'''
168
222
if modelName is None and projectName is None :
169
223
modelDir = gPath
224
+ modelName = modelDir .name
225
+ projectName = modelDir .parent .name
170
226
else :
171
227
modelDir = Path (gPath ) / (projectName + '/' + modelName )
172
228
for zipFile in modelDir .glob ('*.zip' ):
173
229
zipFile .unlink ()
174
- shutil .make_archive (modelName , 'zip' , modelDir )
175
- with open (modelDir / (modelName + '.zip' ), 'rb' ) as zFile :
230
+ fileNames = []
231
+ fileNames .extend (sorted (Path (modelDir ).glob ('*' )))
232
+ with zipfile .ZipFile (str (modelDir / (modelDir .name + '.zip' )), mode = 'w' ) as zFile :
233
+ for file in fileNames :
234
+ zFile .write (str (file ), arcname = file .name )
235
+ with open (modelDir / (modelDir .name + '.zip' ), 'rb' ) as zFile :
176
236
zipIOFile = io .BytesIO (zFile .read ())
237
+ # Check if model with same name already exists in project. Delete if it exists.
238
+ model_exists (projectName , modelName , True )
177
239
mr .import_model_from_zip (modelName , projectName , zipIOFile )
178
240
179
241
@classmethod
@@ -191,7 +253,7 @@ def gitRepoPush(cls, gPath, commitMessage, branch='origin'):
191
253
Branch name for the remote repository, by default 'origin'
192
254
'''
193
255
repo = Repo (gPath )
194
- repo .git .add (update = True )
256
+ repo .git .add (all = True )
195
257
repo .index .commit (commitMessage )
196
258
pushBranch = repo .remote (name = branch )
197
259
pushBranch .push ()
@@ -236,7 +298,7 @@ def pullGitProject(cls, gPath, project=None):
236
298
models = [x for x in pPath .glob ('*' ) if x .is_dir ()]
237
299
if len (models ) == 0 :
238
300
print ('No models were found in project {}.' .format (projectName ))
239
- print ('{numModels} were found in project {projectName}.' .format (numModels = len (models ), projectName = projectName ))
301
+ print ('{numModels} models were found in project {projectName}.' .format (numModels = len (models ), projectName = projectName ))
240
302
else :
241
303
raise FileNotFoundError ('No directory with the name {} was found in the specified git path.' .format (project ))
242
304
@@ -275,10 +337,11 @@ def pullMMProject(cls, gPath, project):
275
337
if modelResponse == []:
276
338
raise FileNotFoundError ('No models were found in the specified project. A new project folder ' +
277
339
'has been created if it did not already exist within the git repository.' )
278
- modelNames , modelId = []* 2
279
- for i , model in enumerate (modelResponse ):
280
- modelNames [i ] = model .name
281
- modelId [i ] = model .id
340
+ modelNames = []
341
+ modelId = []
342
+ for model in modelResponse :
343
+ modelNames .append (model .name )
344
+ modelId .append (model .id )
282
345
283
346
# For each model, search for an appropriate model directory in the project directory and pull down the model
284
347
for name , id in zip (modelNames , modelId ):
0 commit comments