Source code for toil.wdl.utils
# Copyright (C) 2020-2021 UCSC Computational Genomics Lab
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from toil.wdl.wdl_analysis import AnalyzeWDL
[docs]def get_version(iterable) -> str:
"""
Get the version of the WDL document.
:param iterable: An iterable that contains the lines of a WDL document.
:return: The WDL version used in the workflow.
"""
if isinstance(iterable, str):
iterable = iterable.split('\n')
for line in iterable:
line = line.strip()
# check if the first non-empty, non-comment line is the version statement
if line and not line.startswith('#'):
if line.startswith('version '):
return line[8:].strip()
break
# only draft-2 doesn't contain the version declaration
return 'draft-2'
[docs]def get_analyzer(wdl_file: str) -> AnalyzeWDL:
"""
Creates an instance of an AnalyzeWDL implementation based on the version.
:param wdl_file: The path to the WDL file.
"""
with open(wdl_file) as f:
version = get_version(f)
if version == 'draft-2':
from toil.wdl.versions.draft2 import AnalyzeDraft2WDL
return AnalyzeDraft2WDL(wdl_file)
elif version == '1.0':
from toil.wdl.versions.v1 import AnalyzeV1WDL
return AnalyzeV1WDL(wdl_file)
elif version == 'development':
from toil.wdl.versions.dev import AnalyzeDevelopmentWDL
return AnalyzeDevelopmentWDL(wdl_file)
else:
raise RuntimeError(f"Unsupported WDL version: '{version}'.")
[docs]def dict_from_JSON(JSON_file: str) -> dict:
"""
Takes a WDL-mapped json file and creates a dict containing the bindings.
:param JSON_file: A required JSON file containing WDL variable bindings.
"""
json_dict = {}
# TODO: Add context support for variables within multiple wdl files
with open(JSON_file) as data_file:
data = json.load(data_file)
for d in data:
if isinstance(data[d], str):
json_dict[d] = f'"{data[d]}"'
else:
json_dict[d] = data[d]
return json_dict
[docs]def write_mappings(parser: AnalyzeWDL, filename: str = 'mappings.out') -> None:
"""
Takes an AnalyzeWDL instance and writes the final task dict and workflow
dict to the given file.
:param parser: An AnalyzeWDL instance.
:param filename: The name of a file to write to.
"""
from collections import OrderedDict
class Formatter:
def __init__(self):
self.types = {}
self.htchar = '\t'
self.lfchar = '\n'
self.indent = 0
self.set_formater(object, self.__class__.format_object)
self.set_formater(dict, self.__class__.format_dict)
self.set_formater(list, self.__class__.format_list)
self.set_formater(tuple, self.__class__.format_tuple)
def set_formater(self, obj, callback):
self.types[obj] = callback
def __call__(self, value, **args):
for key in args:
setattr(self, key, args[key])
formater = self.types[type(value) if type(value) in self.types else object]
return formater(self, value, self.indent)
def format_object(self, value, indent):
return repr(value)
def format_dict(self, value, indent):
items = [
self.lfchar + self.htchar * (indent + 1) + repr(key) + ': ' +
(self.types[type(value[key]) if type(value[key]) in self.types else object])(self, value[key],
indent + 1)
for key in value]
return '{%s}' % (','.join(items) + self.lfchar + self.htchar * indent)
def format_list(self, value, indent):
items = [
self.lfchar + self.htchar * (indent + 1) + (
self.types[type(item) if type(item) in self.types else object])(self, item, indent + 1)
for item in value]
return '[%s]' % (','.join(items) + self.lfchar + self.htchar * indent)
def format_tuple(self, value, indent):
items = [
self.lfchar + self.htchar * (indent + 1) + (
self.types[type(item) if type(item) in self.types else object])(self, item, indent + 1)
for item in value]
return '(%s)' % (','.join(items) + self.lfchar + self.htchar * indent)
pretty = Formatter()
def format_ordereddict(self, value, indent):
items = [
self.lfchar + self.htchar * (indent + 1) +
"(" + repr(key) + ', ' + (self.types[
type(value[key]) if type(value[key]) in self.types else object
])(self, value[key], indent + 1) + ")"
for key in value
]
return 'OrderedDict([%s])' % (','.join(items) +
self.lfchar + self.htchar * indent)
pretty.set_formater(OrderedDict, format_ordereddict)
with open(filename, 'w') as f:
f.write(pretty(parser.tasks_dictionary))
f.write('\n\n\n\n\n\n')
f.write(pretty(parser.workflows_dictionary))