Source code for tooldog.annotate.cwl
#!/usr/bin/env python3
"""
Generation of CWL tool from https://bio.tools based on the ToolDog model using
cwlgen library.
"""
# Import ------------------------------
# General libraries
import os
import logging
# External libraries
import cwlgen
from cwlgen.import_cwl import CWLToolParser
# Class and Objects
# Constant(s) ------------------------------
LOGGER = logging.getLogger(__name__)
# Class(es) ------------------------------
[docs]class CwlToolGen(object):
"""
Class to support generation of CWL from :class:`tooldog.biotool_model.Biotool` object.
"""
[docs] def __init__(self, biotool, existing_tool=None):
"""
Initialize a [CommandLineTool] object from cwlgen.
:param biotool: Biotool object of an entry from https://bio.tools.
:type biotool: :class:`tooldog.biotool_model.Biotool`
"""
if existing_tool:
LOGGER.info("Loading existing CWL tool from " + existing_tool)
ctp = CWLToolParser()
self.tool = ctp.import_cwl(existing_tool)
if 'None' in self.tool.doc:
self.tool.doc = biotool.generate_cwl_doc()
else:
LOGGER.info("Creating new CwlToolGen object...")
# Initialize counters for inputs and outputs
self.input_ct = 0
self.output_ct = 0
# Initialize tool
# Get the first sentence of the description only
description = biotool.description.split('.')[0] + '.'
documentation = biotool.generate_cwl_doc()
self.tool = cwlgen.CommandLineTool(tool_id=biotool.tool_id,
label=description,
base_command="COMMAND",
doc=documentation,
cwl_version='v1.0')
self._set_meta_from_biotool(biotool)
[docs] def add_input_file(self, input_obj):
"""
Add an input to the CWL tool.
:param input_obj: Input object.
:type input_obj: :class:`tooldog.biotool_model.Input`
"""
LOGGER.info("Adding input to CwlToolGen object...")
# Build parameter
self.input_ct += 1
# Give unique name to the input
name = 'INPUT' + str(self.input_ct)
# Get all different formats for this input
list_formats = []
for format_obj in input_obj.formats:
list_formats.append(format_obj.uri)
formats = ', '.join(list_formats)
# Create the parameter
param_binding = cwlgen.CommandLineBinding(prefix='--' + name)
param = cwlgen.CommandInputParameter(name, param_type='File',
label=input_obj.data_type.term,
param_format=formats,
input_binding=param_binding)
# Appends parameter to inputs
self.tool.inputs.append(param)
[docs] def add_output_file(self, output):
"""
Add an output to the CWL tool.
:param output: Output object.
:type output: :class:`tooldog.biotool_model.Output`
"""
LOGGER.info("Adding output to CwlToolGen object...")
# Build parameter
self.output_ct += 1
# Give unique name to the output
name = 'OUTPUT' + str(self.output_ct)
# Get all different format for this output
list_formats = []
for format_obj in output.formats:
list_formats.append(format_obj.uri)
formats = ', '.join(list_formats)
# Create the parameter
param_binding = cwlgen.CommandOutputBinding(glob=name + '.ext')
param = cwlgen.CommandOutputParameter(name, param_type='File',
label=output.data_type.term,
param_format=formats,
output_binding=param_binding)
self.tool.outputs.append(param)
def _set_meta_from_biotool(self, biotool):
"""
Add first set of metadata found on bio.tools to the description.
:param biotool: Biotool object of an entry from https://bio.tools.
:type biotool: :class:`tooldog.biotool_model.Biotool`
"""
self.tool.metadata = cwlgen.Metadata()
self.tool.metadata.name = biotool.name
self.tool.metadata.about = biotool.description
self.tool.metadata.url = biotool.homepage
if biotool.informations.language:
self.tool.metadata.programmingLanguage = biotool.informations.language
[docs] def add_publication(self, publication):
"""
Add publication to the tool (CWL: s:publication).
:param publication: Publication object.
:type publication: :class:`tooldog.biotool_model.Publication`
"""
LOGGER.debug("Adding publication to CwlToolGen object...")
if not hasattr(self.tool.metadata, 'publication'):
self.tool.metadata.publication = []
# Add citation depending the type (doi, pmid...)
if publication.doi is not None:
self.tool.metadata.publication.append({'id': 'http://dx.doi.org/' + publication.doi})
# <citation> only supports doi and bibtex as a type
elif publication.pmid is not None:
LOGGER.warn('pmid is not supported by publication, publication skipped')
elif publication.pmcid is not None:
LOGGER.warn('pmcid is not supported by publication, publication skipped')
[docs] def add_edam_topic(self, topic):
"""
Add the EDAM topic to the tool (CWL: s:topic).
:param topic: Topic object.
:type topic: :class:`tooldog.biotool_model.Topic`
"""
LOGGER.debug("Adding EDAM topic to CwlToolGen object...")
if not hasattr(self.tool.metadata, 'keywords'):
self.tool.metadata.keywords = []
self.tool.namespaces.edam = "https://edamontology.org/"
self.tool.metadata.keywords.append('edam:' + topic.get_edam_id())
[docs] def add_edam_operation(self, operation):
"""
Add the EDAM operation to the tool (CWL: s:operation).
:param operation: Operation object.
:type operation: :class:`tooldog.biotool_model.Operation`
"""
LOGGER.debug("Adding EDAM operation to CwlToolGen object...")
if not hasattr(self.tool.metadata, 'keywords'):
self.tool.metadata.keywords = []
self.tool.namespaces.edam = "https://edamontology.org/"
self.tool.metadata.keywords.append('edam:' + operation.get_edam_id())
[docs] def write_cwl(self, out_file=None, index=None):
"""
Write CWL to STDOUT or out_file(s).
:param out_file: path to output file.
:type out_file: STRING
:param index: Index in case more than one function is described.
:type index: INT
"""
# Give CWL on STDout
if out_file is None:
if index is not None:
print('########## CWL number ' + str(index) + ' ##########')
LOGGER.info("Writing CWL file to STDOUT...")
self.tool.export()
else:
# Format name for output file(s)
if index is not None:
out_file = os.path.splitext(out_file)[0] + str(index) + '.cwl'
else:
out_file = os.path.splitext(out_file)[0] + '.cwl'
LOGGER.info("Writing CWL file to " + out_file)
self.tool.export(out_file)