{ "info": { "author": "Michael Franklin", "author_email": "michael.franklin@petermac.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", "Topic :: Scientific/Engineering" ], "description": "# python-wdlgen\n\n[![Build Status](https://travis-ci.org/illusional/python-wdlgen.svg?branch=master)](https://travis-ci.org/illusional/python-wdlgen)\n[![PyPI version](https://badge.fury.io/py/illusional.wdlgen.svg)](https://badge.fury.io/py/illusional.wdlgen)\n \n[Workflow Description Language](http://www.openwdl.org) is way to describe tasks and workflows in a \"_human readable and writable way_\". It was initially developed and offered by [Broad Institute](https://software.broadinstitute.org/) to be paired with their workflow engine [Cromwell](https://cromwell.readthedocs.io/en/stable/), however it has since been made open source with other engines such as [Toil](http://toil.readthedocs.io/en/3.14.0/running/wdl.html) and [DNAnexus\\*](https://github.com/dnanexus/dxWDL).\n\n\n### WARNING\n\nThis module now only generates developmental WDL, this includes Directories and wrapping all inputs in an input block. \nTo use this generated WDL, you must use a version of **Cromwell higher than 37**. \n\nThis module automatically includes `version development` in the Workflow and Task outputs. \nThe guides below may not reflect the current version of this repository, but will be updated soon.\n\nThis syntax is based on the [Developmental Workflow Description Language specification](https://github.com/openwdl/wdl/blob/master/versions/development/SPEC.md).\n\n___\n\n## Motiviation\n\nI needed an easy way to generate some _BASIC_ WDL through some in memory objects, and I was using ([a fork](https://github.com/illusional/python-cwlgen) of) [common-workflow-language/python-cwlgen](https://github.com/common-workflow-language/python-cwlgen), I figured I could open this up to see what use it has.\n\n## Installation\n\n```\npip install illusional.wdlgen\n```\n\n## General support\n\nThis software is provided as-is, without warranty of any kind ... and so on.\n\nIt's a pretty dumb wrapper that uses string interpolation to generate the structure. It wouldn't handle automatically escaping illegal characters.\n\nGenerally it supports:\n\n- Types - All types are represented as a `WdlType`, which can either be a [`PrimitiveType`](https://github.com/openwdl/wdl/blob/master/versions/1.0/SPEC.md#types), or an `ArrayType` (see [goal](#goals)). Also supports the postfix quantifiers.\n\n- Workflow creation (`wdlgen.Workflow`)\n\t- manual imports (`wdlgen.Workflow.WorkflowImport`)\n\t- inputs (`wdlgen.Input`)\n\t- outputs (`wdlgen.Output`)\n\t- calls:\n\t\t- general call (`wdlgen.WorkflowCall`)\n\t\t- scatter (`wdlgen.WorkflowScatter(WorkflowCall[])`)\n\n- Task creation (`wdlgen.Task`) - This is based similar to how [CWL constructs its commands](https://www.commonwl.org/v1.0/CommandLineTool.html#CommandLineTool).\n\t- inputs: `wdlgen.Input`\n\t- outputs: `wdlgen.Output`\n\t- runtime: `wdlgen.Task.Runtime`\n\t- command: `wdlgen.Task.Command`\n\t\t- arguments: `wdlgen.Task.Command.Argument`\n\t\t- inputs: `wdlgen.Task.Command.Input`\n\n## How to use\n\nThis will give you a _brief_ overview on how to _use_ python-wdlgen. Goals are to improve the write a proper documentation spec, but if you have a moderate understanding of workflows in either CWL or WDL, this code will hopefully be fairly intuitive.\n\nEvery class inherits from a `WDLBase` which means it must have a `get_string()` method which returns the string representation of the class, calling this on any children it may have.\n\n### Types\n\nAll types are represented as a WDLType, which has a parse method. It's a little overkill in some cases, but makes managing attributes a bit easier.\n\n```python\nparsed_string = wdlgen.WdlType.parse(\"String\")\t# WdlType>\nparsed_op_str = wdlgen.WdlType.parse(\"String?\") # WdlType>\nparsed_array = wdlgen.WDLType.parse(\"File[]\")\t# WdlType>\nparsed_ar_oq = wdlgen.WdlType(parse(\"Int?[]+\"))\t# WdlType (+)>\n```\n\nYou can also construct these manually:\n```python\nparsed_string = WdlType(PrimitiveType(\"String\"))\nparsed_op_str = WdlType(PrimtiveType(\"String\", optional=True))\nparsed_array = WdlType(ArrayType(WdlType(PrimitiveType(\"File\"))))\nparsed_ar_q = WdlType(ArrayType(WdlType(PrimitiveType(\"Int\"), optional=True), requires_multiple=True))\n```\n\n### Input / Output\nInput: `wdlgen.Input(data_type: WdlType, name: str, expression: str = None)`\n\nOutput: `wdlgen.Output(data_type: WdlType, name: str, expression: str = None)`\n\nboth of which output something like:\n\t`{WdlType} {name} [= {expression}]`\n\n### Task\n\nA task is a collection of Inputs, Outputs and a Command that are identified by a _name_. Inputs and Outputs are as above. Note that you can use functions such as `stdout()` or other for the expression.\n\n> If you don't want to play by these rules, don't include any inputs or outputs and just provide your whole string to the initializer for command.\n\n```python\nt = wdlgen.Task(\"task_name\")\nt.inputs.append(wdlgen.Input(wdlgen.WdlType.parse(\"String\"), \"taskGreeting\"))\n# command in next section\nt.outputs.append(wdlgen.Output(wdlgen.WdlType.parse(\"File\"), \"standardOut\", \"stdout()\"))\n```\n\n#### Command\n\nThe command is broken up similar to how CWL breaks its command generation up, by itself it has a _base command_. Each component has a corresponding input (else use the `wdlgen.Task.Command.Argument` class), optionality, position, prefix (and whether the value should be separated from prefix; think `-o {val}` vs `outputDir={val}`) and potentially a default.\n\nConstruct a command like the following:\n```python\ncommand = wdlgen.Task.Command(\"echo\")\ncommand.inputs.append(wdlgen.Task.Command.CommandInput(\"taskGreeting\", optional=False, position=None, prefix=\"-a\", separate_value_from_prefix=True, default=None))\ncommand.inputs.append(wdlgen.Task.Command.CommandInput(\"otherInput\", optional=True, position=2, prefix=\"optional-param=\", separate_value_from_prefix=False, default=None))\n\n# t is the task\nt.command = command\nprint(command.get_string())\n```\n\nThis will result in the following WDL command:\n```bash\necho \\\n -a ${taskGreeting} \\\n ${\"optional-param=\" + otherInput}\n```\n\n#### Task output:\n\nThe combination of the task and command outputs:\n```wdl\nversion development\n\ntask task_name {\n input {\n String taskGreeting\n }\n command {\n echo \\\n -a ${taskGreeting} \\\n ${\"optional-param=\" + otherInput}\n }\n\n output {\n File standardOut = stdout()\n }\n}\n```\n\n### Workflow\n\nYou should have moderate idea of the structure of WDL as there's no cleverness or abstraction done anywhere. Beware: there's also no checking attributes (to see if your `inputMap` actually corresponds to inputs).\n\nThe structure of a workflow is m\n\n```python\nw = wdlgen.Workflow(\"workflow_name\")\n\nw.imports.append(wdlgen.Workflow.WorkflowImport(\"tool_file\", \"\"))\nw.inputs.append(wdlgen.WdlType.parse(\"String\"), wdlgen.Input(\"inputGreeting\"))\n\n\ninputs_map = {\"taskGreeting\": \"inputGreeting\"}\nw.calls.append(wdlgen.WorkflowCall(\"Q.namspaced_task_identifier\", \"task_alias\", inputs_map))\nw.outputs.append(wdlgen.Output(wdlgen.WdlType.parse(\"File\"), \"standardOut\", \"task_alias.standardOut\")\n```\n\nWhich outputs:\n```wdl\nversion development\n\nimport \"tools/tool_file.wdl\"\n\nworkflow workflow_name {\n input { \n String inputGreeting\n }\n call Q.namspaced_task_identifier as task_alias {\n input:\n taskGreeting=inputGreeting\n }\n output {\n File standardOut = task_alias.standardOut\n }\n}\n```\n\n\n## Known limitations\n\nI'm not a fan of the string interpolation generation of WDL that this module does. I think trying to build an [Abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) and then there should be something that convert that into the DSL that WDL uses.\n\nYou could also cause syntax errors in generated WDL by providing illegal characters. \n\n## Goals\n\n- Improve code-level documentation.\n- Increase the testing coverage + quality of unit tests.\n- Better represent the WDL spec.\n- ~~Find an easier distribution / release method - such as PIP.~~\n- ~~Automate testing and delivery through TravisCI / CircleCI or similar.~~\n- Validate each value by [WDL's language specifications](https://github.com/openwdl/wdl/blob/master/versions/1.0/SPEC.md#language-specification).\n- Add support for structs\n\n### Long goals\n- Write a documentation site.\n- Make classes convert into AST and then into DSL.\n\n## Issues and Pull Requests\nFeel free to log issues and make pull requests. I make no guarantee to the existence or timeliness of replies.\n\n\nLinks:\n\n- WDL description: https://github.com/openwdl/wdl/blob/master/versions/1.0/SPEC.md", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/illusional/python-wdlgen", "keywords": "", "license": "GNU", "maintainer": "", "maintainer_email": "", "name": "illusional.wdlgen", "package_url": "https://pypi.org/project/illusional.wdlgen/", "platform": "", "project_url": "https://pypi.org/project/illusional.wdlgen/", "project_urls": { "Homepage": "https://github.com/illusional/python-wdlgen" }, "release_url": "https://pypi.org/project/illusional.wdlgen/0.2.5/", "requires_dist": null, "requires_python": "", "summary": "Contains classes and helpers to generate WDL without worrying about the syntax. This is primarily intended for generating WDL from other in-memory representations of a workflow.", "version": "0.2.5" }, "last_serial": 5801727, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "daf321d6d6879246d71fdfc69adfb1b2", "sha256": "5312a9d06b9caa79d9f56ee41aeb520b69262699caf35c4ac78dd88ced733dbf" }, "downloads": -1, "filename": "illusional.wdlgen-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "daf321d6d6879246d71fdfc69adfb1b2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 11340, "upload_time": "2019-01-31T03:56:39", "url": "https://files.pythonhosted.org/packages/e9/3b/53f57fe74e271c660634df532763b103a51dbb9f156dc9e9e0a343e4cd96/illusional.wdlgen-0.0.1-py3-none-any.whl" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "d7dc07d9ca8b96fe39108fd5face2822", "sha256": "760e94cb8fa5f628bbee5ffa34c0611504e8f855f82caaca8d343fc9289912d2" }, "downloads": -1, "filename": "illusional.wdlgen-0.0.2.tar.gz", "has_sig": false, "md5_digest": "d7dc07d9ca8b96fe39108fd5face2822", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12103, "upload_time": "2019-01-31T04:26:55", "url": "https://files.pythonhosted.org/packages/56/84/a67ed424018159d674319c46309a8d05bf391a05a19948cadb6f6b2752d6/illusional.wdlgen-0.0.2.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "18205754a2728b879cb8c07ac65c16f2", "sha256": "fa5a795805e69c72ed9875e719733e0611a519ab3c4b7bfc43469a27d8712485" }, "downloads": -1, "filename": "illusional.wdlgen-0.1.0.tar.gz", "has_sig": false, "md5_digest": "18205754a2728b879cb8c07ac65c16f2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13096, "upload_time": "2019-03-01T05:52:25", "url": "https://files.pythonhosted.org/packages/7b/78/de050017c412748123da1994e55125fe864e578d9fd8b04e6131685b24d8/illusional.wdlgen-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "998b233fd527113c8c087dcb924d9d3a", "sha256": "c9fd76446a0bf62d4f0e5dc611e09a56f06945169d77cf16f08d8fdc00b21d2c" }, "downloads": -1, "filename": "illusional.wdlgen-0.2.0.tar.gz", "has_sig": false, "md5_digest": "998b233fd527113c8c087dcb924d9d3a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13240, "upload_time": "2019-04-11T23:44:59", "url": "https://files.pythonhosted.org/packages/d7/dd/4139da88e3da153ff61fc19d1e8b501e6c31502db871350208eb6e7d140f/illusional.wdlgen-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "bf14eced847cac9e2d8f3de95df28576", "sha256": "14ad3e010d5141f5b616aaef9b4e49b39bb6f3c8b5d72f42e427fce06356ff63" }, "downloads": -1, "filename": "illusional.wdlgen-0.2.1.tar.gz", "has_sig": false, "md5_digest": "bf14eced847cac9e2d8f3de95df28576", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13373, "upload_time": "2019-04-28T22:00:38", "url": "https://files.pythonhosted.org/packages/44/9e/9802109a523d21f1cd2d973b6105069f7c96db59b35bd0297f69853cdb9a/illusional.wdlgen-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "3c076e3cbaa4d4fc976b7575183beaec", "sha256": "d5ec9d7e72e3d4a8b65dc3142519b97a58e624a92d1b1e53b25fbeed968987fb" }, "downloads": -1, "filename": "illusional.wdlgen-0.2.2.tar.gz", "has_sig": false, "md5_digest": "3c076e3cbaa4d4fc976b7575183beaec", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13374, "upload_time": "2019-05-09T12:23:30", "url": "https://files.pythonhosted.org/packages/a4/7a/6369f5a260eef7c548d2ef12f996e0158ada8f795c859427a5768308498a/illusional.wdlgen-0.2.2.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "be737598917a3d66a73998c49cd86343", "sha256": "44b3420547daf288f7eb9e5be363f61ecbd4eb43e7cddc5ba7368f46fecd5b58" }, "downloads": -1, "filename": "illusional.wdlgen-0.2.3.tar.gz", "has_sig": false, "md5_digest": "be737598917a3d66a73998c49cd86343", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13474, "upload_time": "2019-07-11T03:59:05", "url": "https://files.pythonhosted.org/packages/78/25/d6b4a320303f762df49ed5afb0004642bde00452c37f5be3114ad6a0e357/illusional.wdlgen-0.2.3.tar.gz" } ], "0.2.5": [ { "comment_text": "", "digests": { "md5": "d9f8a69255623c28daceb58e15ea9789", "sha256": "c80eb4431c97c18cb0a5f1a6657a54e6d5835f1af58b0cda92eed7212c835eca" }, "downloads": -1, "filename": "illusional.wdlgen-0.2.5.tar.gz", "has_sig": false, "md5_digest": "d9f8a69255623c28daceb58e15ea9789", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10883, "upload_time": "2019-09-09T05:03:36", "url": "https://files.pythonhosted.org/packages/02/c1/639283ce6550e2704012b279e29c96c189334a433c4c6fc8d6bcc0c45f58/illusional.wdlgen-0.2.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d9f8a69255623c28daceb58e15ea9789", "sha256": "c80eb4431c97c18cb0a5f1a6657a54e6d5835f1af58b0cda92eed7212c835eca" }, "downloads": -1, "filename": "illusional.wdlgen-0.2.5.tar.gz", "has_sig": false, "md5_digest": "d9f8a69255623c28daceb58e15ea9789", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10883, "upload_time": "2019-09-09T05:03:36", "url": "https://files.pythonhosted.org/packages/02/c1/639283ce6550e2704012b279e29c96c189334a433c4c6fc8d6bcc0c45f58/illusional.wdlgen-0.2.5.tar.gz" } ] }