11import os
22import json
3+ import schema_salad .ref_resolver
4+ from subprocess32 import check_call , DEVNULL , CalledProcessError
5+ import yaml
36import glob
47import requests
58import urllib
69import logging
7- import schema_salad .ref_resolver
810
911from wes_service .util import visit
12+ from urllib import urlopen
1013
1114
12- def wf_type (workflow_file ):
13- if workflow_file .lower ().endswith ('wdl' ):
14- return 'WDL'
15- elif workflow_file .lower ().endswith ('cwl' ):
16- return 'CWL'
17- elif workflow_file .lower ().endswith ('py' ):
18- return 'PY'
19- else :
20- raise ValueError ('Unrecognized/unsupported workflow file extension: %s' % workflow_file .lower ().split ('.' )[- 1 ])
15+ def two_seven_compatible (filePath ):
16+ """Determines if a python file is 2.7 compatible by seeing if it compiles in a subprocess"""
17+ try :
18+ check_call (['python2' , '-m' , 'py_compile' , filePath ], stderr = DEVNULL )
19+ except CalledProcessError :
20+ raise RuntimeError ('Python files must be 2.7 compatible' )
21+ return True
2122
2223
23- def wf_version ( workflow_file ):
24- # TODO: Check inside of the file, handling local/http/etc.
25- if wf_type ( workflow_file ) == 'PY' :
24+ def get_version ( extension , workflow_file ):
25+ '''Determines the version of a .py, .wdl, or .cwl file.'''
26+ if extension == 'py' and two_seven_compatible ( workflow_file ) :
2627 return '2.7'
27- # elif wf_type(workflow_file) == 'CWL':
28- # # only works locally
29- # return yaml.load(open(workflow_file))['cwlVersion']
28+ elif extension == 'cwl' :
29+ return yaml .load (open (workflow_file ))['cwlVersion' ]
30+ else : # Must be a wdl file.
31+ # Borrowed from https://github.com/Sage-Bionetworks/synapse-orchestrator/blob/develop/synorchestrator/util.py#L142
32+ try :
33+ return [l .lstrip ('version' ) for l in workflow_file .splitlines () if 'version' in l .split (' ' )][0 ]
34+ except IndexError :
35+ return 'draft-2'
36+
37+
38+ def wf_info (workflow_path ):
39+ """
40+ Returns the version of the file and the file extension.
41+
42+ Assumes that the file path is to the file directly ie, ends with a valid file extension.Supports checking local
43+ files as well as files at http:// and https:// locations. Files at these remote locations are recreated locally to
44+ enable our approach to version checking, then removed after version is extracted.
45+ """
46+
47+ supported_formats = ['py' , 'wdl' , 'cwl' ]
48+ file_type = workflow_path .lower ().split ('.' )[- 1 ] # Grab the file extension
49+ workflow_path = workflow_path if ':' in workflow_path else 'file://' + workflow_path
50+
51+ if file_type in supported_formats :
52+ if workflow_path .startswith ('file://' ):
53+ version = get_version (file_type , workflow_path [7 :])
54+ elif workflow_path .startswith ('https://' ) or workflow_path .startswith ('http://' ):
55+ # If file not local go fetch it.
56+ html = urlopen (workflow_path ).read ()
57+ local_loc = os .path .join (os .getcwd (), 'fetchedFromRemote.' + file_type )
58+ with open (local_loc , 'w' ) as f :
59+ f .write (html )
60+ version = wf_info ('file://' + local_loc )[0 ] # Don't take the file_type here, found it above.
61+ os .remove (local_loc ) # TODO: Find a way to avoid recreating file before version determination.
62+ else :
63+ raise NotImplementedError ('Unsupported workflow file location: {}. Must be local or HTTP(S).' .format (workflow_path ))
3064 else :
31- # TODO: actually check the wdl file
32- return "v1.0"
65+ raise TypeError ( 'Unsupported workflow type: .{}. Must be {}.' . format ( file_type , '.py, .cwl, or .wdl' ))
66+ return version , file_type . upper ()
3367
3468
3569def build_wes_request (workflow_file , json_path , attachments = None ):
@@ -42,10 +76,11 @@ def build_wes_request(workflow_file, json_path, attachments=None):
4276 """
4377 workflow_file = "file://" + workflow_file if ":" not in workflow_file else workflow_file
4478 json_path = json_path [7 :] if json_path .startswith ("file://" ) else json_path
79+ wf_version , wf_type = wf_info (workflow_file )
4580
4681 parts = [("workflow_params" , json .dumps (json .load (open (json_path )))),
47- ("workflow_type" , wf_type ( workflow_file ) ),
48- ("workflow_type_version" , wf_version ( workflow_file ) )]
82+ ("workflow_type" , wf_type ),
83+ ("workflow_type_version" , wf_version )]
4984
5085 if workflow_file .startswith ("file://" ):
5186 parts .append (("workflow_attachment" , (os .path .basename (workflow_file [7 :]), open (workflow_file [7 :], "rb" ))))
0 commit comments