@@ -67,7 +67,8 @@ class ApplicationPackage(object):
6767
6868 # Optional
6969 source_repository : str = None
70- workflow_path : str = 'Dockstore.cwl' # Dockstore hard-codes the primary descriptor path
70+ # Dockstore hard-codes the primary descriptor path for the hosted workflow
71+ workflow_path : str = 'Dockstore.cwl'
7172 id : str = None # Not yet commited to catalog
7273 is_published : bool = False
7374 description : str = ""
@@ -209,7 +210,8 @@ def _patch(self, request_url, data):
209210
210211 response = requests .patch (f"{ self .api_url } /{ request_url } " , headers = self ._headers , data = json .dumps (data ))
211212
212- if response .status_code != 200 :
213+ # 204 indicates that no action was taken
214+ if response .status_code != 200 and response .status_code != 204 :
213215 raise ApplicationCatalogAccessError (f"PATCH operation to application catalog at { self .api_url } /{ request_url } return unexpected status code: { response .status_code } with message: { response .content } using data: { data } " )
214216
215217 return response
@@ -251,38 +253,45 @@ def _application_from_json(self, json_dict):
251253 # after registry path
252254 name = json_dict ['full_workflow_path' ].split ("/" )[- 1 ]
253255
254- return DockstoreApplicationPackage (id = str (json_dict ['id' ]),
255- name = name ,
256- source_repository = json_dict ['gitUrl' ],
257- workflow_path = json_dict ['workflow_path' ],
258- is_published = json_dict ['is_published' ],
259- description = json_dict ['description' ],
260- dockstore_info = json_dict )
256+ return DockstoreApplicationPackage (
257+ id = str (json_dict ['id' ]),
258+ name = name ,
259+ source_repository = json_dict ['gitUrl' ],
260+ workflow_path = json_dict ['workflow_path' ],
261+ is_published = json_dict ['is_published' ],
262+ description = json_dict ['description' ],
263+ dockstore_info = json_dict
264+ )
261265
262266 @staticmethod
263267 def _file_to_json (file_path : str , dockstore_path : str , file_format : str ):
264268 """
265269 Generate JSON format of the file representation for the Dockstore request.
266270
267271 file_path: Path to the file to create JSON format request representation for.
272+ If None or empty filepath is provided, then "dockstore_path" file will be
273+ removed from the hosted workflow.
268274 dockstore_path: Path to the file in the Dockstore.
269275 file_format: Dockstore file type for the file.
270276 """
271- # Read contents of the local file
272- with open (file_path , 'r' ) as fhandle :
273- data = fhandle .read ()
277+ # Dockstore requires absolute path for the file to be uploaded
278+ dockstore_file_path = f'/{ dockstore_path } ' if dockstore_path [0 ] != '/' else dockstore_path
274279
275- # Dockstore requires absolute path for the file to be uploaded
276- dockstore_file_path = f'/{ dockstore_path } ' if dockstore_path [0 ] != '/' else dockstore_path
280+ # Content of the file: None means to delete the file from the hosted workflow
281+ data = None
282+ if file_path is not None and len (file_path ):
283+ # Read contents of the local file
284+ with open (file_path , 'r' ) as fhandle :
285+ data = fhandle .read ()
277286
278- return {
279- 'path' : dockstore_file_path ,
280- 'absolutePath' : dockstore_file_path ,
281- 'content' : data ,
282- 'type' : file_format
283- }
287+ return {
288+ 'path' : dockstore_file_path ,
289+ 'absolutePath' : dockstore_file_path ,
290+ 'content' : data ,
291+ 'type' : file_format
292+ }
284293
285- def application (self , app_id ):
294+ def application (self , app_id : int ):
286295 """
287296 Get application information from the Dockstore based on the application ID.
288297 """
@@ -296,12 +305,11 @@ def application_list(self, for_user: bool = False, published: bool = None):
296305
297306 Unpublished applications can only be seen when using for_user=True
298307 """
308+ request_url = "/workflows/published"
309+
299310 if for_user or (published is not None and not published ):
300311 request_url = f"/users/{ self ._user_id } /workflows"
301312
302- else :
303- request_url = "/workflows/published"
304-
305313 app_list = []
306314 for app_info in self ._get (request_url ).json ():
307315 app_obj = None
@@ -365,8 +373,52 @@ def register(
365373
366374 response = self ._post (request_url , params )
367375
376+ new_app = self ._application_from_json (response .json ())
377+
368378 # Dockstore ID of newly registered application
369- new_app_id = response .json ()['id' ]
379+ # new_app_id = response.json()['id']
380+ new_app_id = new_app .id
381+
382+ self .upload_files (new_app , cwl_files , json_files , filename_map )
383+
384+ # Optionally publish workflow: Dockstore allows to publish only workflows that have parameter files uploaded
385+ if publish :
386+ if len (cwl_files ) or len (json_files ):
387+ self ._publish (new_app_id , publish )
388+
389+ else :
390+ raise HostedWorkflowError ('Can not publish hosted workflow (id={new_app_id}) as no parameter files have been uploaded' )
391+
392+ # Reload application information from the Dockstore
393+ return self .application (new_app_id )
394+
395+ def upload_files (
396+ self ,
397+ application ,
398+ cwl_files : list = [],
399+ json_files : list = [],
400+ filename_map : dict = {}
401+ ):
402+ """
403+ Upload workflow parameter files for the workflow.
404+
405+ Basename of each parameter file will be used as absolute path of the file within the Dockstore. If other
406+ than basename path is preferred to store the file in the Dockstore, "filename_map" input argument should
407+ be used to provide mapping of local file vs. preferred path of the file in the Dockstore. For example:
408+ {
409+ 'local_path/step_one.cwl': 'l1/step_one.cwl',
410+ 'local_path/params_one.json': 'l1_params/params_one.json'
411+ }
412+
413+ Inputs:
414+ application: DockstoreApplicationPackage to upload the files for.
415+ cwl_files: List of CWL format parameter file paths to upload to the Dockstore. Default is an empty list.
416+ json_files: List of JSON format parameter file paths to upload to the Dockstore. Default is an empty list.
417+ filename_map: Mapping of parameter filenames on local file system vs. filename path as to appear in
418+ the Dockstore once the file is uploaded. Default is an empty map meaning that each file will be uploaded into
419+ the Dockstore using its basename.
420+ """
421+ app_type = application .workflow_type
370422
371423 if len (cwl_files ) or len (json_files ):
372424 # Format contents of the parameter files for the request to upload all CWL and JSON files if any
@@ -394,20 +446,12 @@ def register(
394446 )
395447 )
396448
397- request_url = f"/workflows/hostedEntry/{ new_app_id } "
449+ request_url = f"/workflows/hostedEntry/{ application . id } "
398450
399451 # Upload the files
400452 self ._patch (request_url , params )
401453
402- # Optionally publish workflow: Dockstore allows to publish only workflows that have parameter files uploaded
403- if publish :
404- if len (cwl_files ) or len (json_files ):
405- self ._publish (new_app_id , publish )
406-
407- else :
408- raise HostedWorkflowError ('Can not publish hosted workflow (id={new_app_id}) as no parameter files have been uploaded' )
409-
410- return self .application (new_app_id )
454+ return
411455
412456 def upload_parameter_file (self , application , param_filename : str , dockstore_filename : str = '' ):
413457 """
@@ -436,7 +480,7 @@ def upload_json_file(self, application, param_filename: str, dockstore_filename:
436480 """
437481 Upload local JSON file "param_filename" to the hosted by Dockstore workflow.
438482
439- If "dockstore_filename" is an empty string than "param_filename" is uploaded into
483+ If "dockstore_filename" is an empty string then "param_filename" is uploaded into
440484 the Dockstore using its basename.
441485
442486 To remove the file from the registered application just upload file of an empy content to the Dockstore.
@@ -457,13 +501,13 @@ def upload_json_file(self, application, param_filename: str, dockstore_filename:
457501
458502 def publish (self , application ):
459503 """
460- Publish the worksflow .
504+ Publish the workflow .
461505 """
462506 self ._publish (application .id , publish = True )
463507
464508 def unpublish (self , application ):
465509 """
466- Unpublish the worksflow .
510+ Unpublish the workflow .
467511
468512 Dockstore does not allow to delete a hosted workflow, so we can only remove/add parameter files and
469513 publish/unpublish hosted workflows within Dockstore.
0 commit comments