[med-svn] [gxargparse] 01/11: Imported Upstream version 0.3.1

Andreas Tille tille at debian.org
Sat Jan 14 11:34:51 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository gxargparse.

commit a915cb4912483b43c7930237feeb2a7c51f3f18a
Author: Anton Khodak <anton.khodak at ukr.net>
Date:   Sat Jan 14 11:24:06 2017 +0200

    Imported Upstream version 0.3.1
---
 .gitignore                                         |  67 +++++
 LICENSE.TXT                                        | 201 +++++++++++++++
 MANIFEST.in                                        |   2 +
 README.md                                          | 168 ++++++++++++
 argparse/__init__.py                               | 183 +++++++++++++
 argparse/argparse_cwl_translation.py               | 131 ++++++++++
 argparse/argparse_galaxy_translation.py            | 252 ++++++++++++++++++
 click/__init__.py                                  |  93 +++++++
 click/click_cwl_translation.py                     | 105 ++++++++
 cmdline2cwl/__init__.py                            | 113 ++++++++
 cmdline2cwl/cwl_tool.py                            |  68 +++++
 cmdline2cwl/templates/cwltool.j2                   |  17 ++
 cmdline2cwl/templates/cwltool_inputs.j2            |  42 +++
 cmdline2cwl/templates/cwltool_outputs.j2           |  17 ++
 example.py                                         |  26 ++
 example.xml                                        |  68 +++++
 .../argparse/cnvkit-tools/check_wrappers_in_dir.sh |   7 +
 examples/argparse/cnvkit-tools/cnvkit-access.cwl   |  55 ++++
 .../argparse/cnvkit-tools/cnvkit-antitarget.cwl    |  50 ++++
 examples/argparse/cnvkit-tools/cnvkit-batch.cwl    | 173 +++++++++++++
 examples/argparse/cnvkit-tools/cnvkit-breaks.cwl   |  45 ++++
 examples/argparse/cnvkit-tools/cnvkit-call.cwl     |  85 ++++++
 examples/argparse/cnvkit-tools/cnvkit-coverage.cwl |  52 ++++
 examples/argparse/cnvkit-tools/cnvkit-diagram.cwl  |  61 +++++
 .../argparse/cnvkit-tools/cnvkit-export-bed.cwl    |  83 ++++++
 .../argparse/cnvkit-tools/cnvkit-export-cdt.cwl    |  33 +++
 .../argparse/cnvkit-tools/cnvkit-export-jtv.cwl    |  33 +++
 .../cnvkit-tools/cnvkit-export-nexus-basic.cwl     |  31 +++
 .../cnvkit-tools/cnvkit-export-nexus-ogt.cwl       |  58 +++++
 .../argparse/cnvkit-tools/cnvkit-export-seg.cwl    |  36 +++
 .../argparse/cnvkit-tools/cnvkit-export-theta.cwl  |  68 +++++
 .../argparse/cnvkit-tools/cnvkit-export-vcf.cwl    |  64 +++++
 examples/argparse/cnvkit-tools/cnvkit-fix.cwl      |  70 +++++
 examples/argparse/cnvkit-tools/cnvkit-gainloss.cwl |  65 +++++
 examples/argparse/cnvkit-tools/cnvkit-gender.cwl   |  40 +++
 examples/argparse/cnvkit-tools/cnvkit-heatmap.cwl  |  46 ++++
 .../argparse/cnvkit-tools/cnvkit-import-picard.cwl |  40 +++
 .../argparse/cnvkit-tools/cnvkit-import-seg.cwl    |  51 ++++
 .../argparse/cnvkit-tools/cnvkit-import-theta.cwl  |  50 ++++
 examples/argparse/cnvkit-tools/cnvkit-loh.cwl      |  68 +++++
 examples/argparse/cnvkit-tools/cnvkit-metrics.cwl  |  43 +++
 .../argparse/cnvkit-tools/cnvkit-reference.cwl     |  80 ++++++
 examples/argparse/cnvkit-tools/cnvkit-rescale.cwl  |  72 ++++++
 examples/argparse/cnvkit-tools/cnvkit-scatter.cwl  | 111 ++++++++
 examples/argparse/cnvkit-tools/cnvkit-segment.cwl  |  79 ++++++
 .../argparse/cnvkit-tools/cnvkit-segmetrics.cwl    | 101 ++++++++
 examples/argparse/cnvkit-tools/cnvkit-target.cwl   |  58 +++++
 examples/argparse/cnvkit-tools/cnvkit-version.cwl  |  18 ++
 examples/argparse/cnvkit-tools/data.json           |   7 +
 examples/argparse/cnvkit-tools/genome2access.cwl   |  65 +++++
 examples/argparse/cnvkit-tools/genome2access.py    |  40 +++
 examples/argparse/cnvkit-tools/output.txt          |   7 +
 examples/click/genmod-tools/genmod-annotate.cwl    | 118 +++++++++
 examples/click/genmod-tools/genmod-build.cwl       |  61 +++++
 examples/click/genmod-tools/genmod-compound.cwl    |  64 +++++
 examples/click/genmod-tools/genmod-filter.cwl      |  74 ++++++
 examples/click/genmod-tools/genmod-models.cwl      | 118 +++++++++
 examples/click/genmod-tools/genmod-score.cwl       |  90 +++++++
 examples/click/genmod-tools/genmod-sort.cwl        |  63 +++++
 gxargparse/__init__.py                             |   1 +
 gxargparse/check_path.py                           |  49 ++++
 requirements.txt                                   |   3 +
 setup.cfg                                          |   2 +
 setup.py                                           |  33 +++
 test/__init__.py                                   |   0
 test/cwl_classes.py                                |  80 ++++++
 test/test-data/index.cwl                           |  29 +++
 test/test-data/index.py                            |  41 +++
 test/test-data/index_new.cwl                       |  34 +++
 test/test-data/inp.txt                             |   4 +
 test/test-data/inp.txt.idx1                        |  10 +
 test/test-data/job.json                            |   7 +
 test/test-data/main.cwl                            |  87 +++++++
 test/test-data/search.cwl                          |  43 +++
 test/test-data/search.py                           |  40 +++
 test/test-data/search_new.cwl                      |  39 +++
 test/test_arg2cwl.py                               | 287 +++++++++++++++++++++
 test/test_click2cwl.py                             | 150 +++++++++++
 test/test_utils.py                                 | 106 ++++++++
 79 files changed, 5231 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..47af8f3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,67 @@
+# Created by https://www.gitignore.io
+
+### vim ###
+[._]*.s[a-w][a-z]
+[._]s[a-w][a-z]
+*.un~
+Session.vim
+.netrwhist
+*~
+
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   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.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..efe73a6
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+include README.md
+include cmdline2cwl/templates/*.j2
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0caa98d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,168 @@
+`gxargparse` was originally designed to generate Galaxy XML from Python tools which use argparse, but then it was extended to support [Common Workflow Language] (http://www.commonwl.org/v1.0/CommandLineTool.html) command-line tools generation, and not only for argparse, but also for [click](click.pocoo.org/6/) argument parser. For more info about CWL generation jump straight to [argparse2cwl](#argparse2cwl).
+
+
+# `gxargparse`
+
+Galaxy argparse aims to be a drop-in replacement for argparse, quite literally.
+You can write use your normal import
+
+```python
+import argparse
+```
+
+and continue writing code. All functions are passed straight through to
+argparse, but `gxargparse` captures them and copies some information along the
+way. This information captured is used to produce [Galaxy Tool XML](https://github.com/erasche/galaxyxml) when it's
+requested with the `--generate_galaxy_xml` flag.
+
+## How it works
+
+Internally, `gxargparse`, masquerading as `argparse` attempts to find and
+import the **real** argparse. It then stores a reference to the code module for
+the system argparse, and presents the user with all of the functions that
+stdlib's argparse provides. Every function call is passed through the system
+argparse. However, gxargparse captures the details of those calls and when Tool
+XML is requested, it builds up the tool definition according to IUC tool
+standards.
+
+## Examples
+
+You can see the `example.py` file for an example with numerous types of
+arguments and options that you might see in real tools. Accordingly there is an `example.xml` file with the output.
+
+## It doesn't work!!
+
+If you are not able to use the `--generate_galaxy_xml` flag after
+installing, it is probably because of module load order. gxargparse must
+precede argparse in the path. Certain cases seem to work correctly (`python
+setup.py install` in a virtualenv) while other cases do not (`pip install
+gxargparse`).
+
+To easily correct this, run the tool `gxargparse_check_path` which is installed
+as part of this package. Correctly functioning paths will produce the
+following:
+
+```console
+$ gxargparse_check_path
+Ready to go!
+```
+
+while incorrectly ordered paths will produce a helpful error message:
+
+```console
+$ gxargparse_check_path
+Incorrect ordering, please set
+
+    PYTHONPATH=/home/users/esr/Projects/test/.venv/local/lib/python2.7/site-packages
+
+```
+
+This can even be used inline:
+
+```console
+user at host:$ PYTHONPATH=$(gxargparse_check_path -q) python my_script.py --generate_galaxy_xml
+```
+
+## TODO
+
+This code doesn't cover the entirety of the `argparse` API yet, and there are some bugs to work out on the XML generation side:
+
+- argparse
+    - groups not supported (in galaxy, everything should still work in argparse)
+    - some features like templating of the version string (please submit bugs)
+- galaxyxml
+    - bugs in conditionals/whens (probably)
+    - bugs, bugs, bugs!
+- gxargparse
+    - support help text
+    - support declaring output files in an `argparse`-esque manner
+
+
+# argparse2cwl<a name="argparse2cwl"></a>
+
+`argparse2cwl` forms CWL tool descriptions from programs which use `argparse` as their argument parser. 
+No code changes are required, just use the normal import:
+
+	import argparse
+
+and continue writing code. All functions are passed straight through to `argparse`, but `argparse2cwl` captures them and copies some information along the way. This information captured is used to produce CWL tool definition when it's requested with the `--generate_cwl_tool` flag.
+
+
+## Installing ##
+
+Installation process:
+
+1. Clone the source repository:
+	
+		$ git clone https://github.com/common-workflow-language/gxargparse.git
+
+2. Run 
+
+		$ cd gxargparse
+		$ python setup.py install
+
+You can ensure it's working when you pass `--help_arg2cwl` flag to any command-line program inside your environment. If the option is not recognized, try
+	
+	$ gxargparse_check_path
+
+which is installed as part of this package. It will produce a helpful error message if the paths are incorrectly ordered. Also make sure you have installed it under proper Python version.
+
+
+## Running ##
+
+To run `argparse2cwl`, call your tool as usually without actual arguments with `--generate_cwl_tool` option:
+
+	$ <tool command> --generate_cwl_tool <other options>
+
+Simple example
+	
+	$ python example.py --generate_cwl_tool
+
+Example for [CNVkit](https://github.com/etal/cnvkit) toolkit:
+
+	$ cnvkit.py batch --generate_cwl_tool -d ~/cnvkit-tools/ --generate_outputs
+
+
+If there are subcommands in the provided command, all possible tools will be generated, for instance, for CNVkit
+
+	$ cnvkit.py --generate_cwl_tool
+
+will produce CWL tool descriptions for `cnvkit.py batch`, `cnvkit.py access`, `cnvkit.py export bed`, `cnvkit.py export cdt` and all other subcommands.
+
+
+Other options (which work only with `--generate_cwl_tool` provided, except for help message) are:
+
+* `-o FILENAME`, `--output_section FILENAME`: File with manually filled output section which is put to a formed CWL tool. Argparse2cwl is not very good at generating outputs, it recognizes output files only if they have type `argparse.FileType('w')`, so output section is often blank and should be filled manually.
+
+* `-go`, `--generate_outputs`: flag for generating outputs not only from arguments that are instances of `argparse.FileType('w')`, but also from every argument which contains `output` keyword in its name. For instance, argument `--output-file` with no type will also be placed to output section. However, '--output-directory' argument will also be treated like File, so generated tools must be checked carefully if when this option is selected.
+
+* `-b`, `basecommand`: command which appears in `basecommand` field in a resulting tool. It is handy to use this option when you run tool with shebang, but want `python` to be in `basecommand` field and the file amidst arguments. 
+Example:
+
+	```$ .search.py --generate_cwl_tool -b python```. 
+
+Basecommand of the formed tool will be `['python']`, and `search` will be a positional argument on position 0.
+
+* `-d`, `--directory`: directory for storing tool descriptions.
+
+* `--help_arg2cwl`: prints this help message.
+
+
+
+## Argparse notes ##
+
+Some of argparse features can not be ported to CWL. 
+
+1. `nargs=N`. Number of arguments can not be specified in CWL (yet).
+2. `const` argument of `add_argument()`. All constants must be specified in job files.
+3. Custom types and custom actions are not supported.
+4. Argument groups don't work in CWL as arguments are sorted with a [special algorithm](http://www.commonwl.org/draft-3/CommandLineTool.html#Input_binding)
+5. Mutual exclusion is not supported.
+
+#	 click2cwl
+
+*click2cwl* shares absolutely the same logic as argparse2cwl, the only difference is it is adjusted to work with [click](http://click.pocoo.org/) argument parser. Whenever click is imported, gxargparse grabs its commands, arguments, options and forms CWL parameters out of them. 
+
+# License
+
+- Apache License, v2
diff --git a/argparse/__init__.py b/argparse/__init__.py
new file mode 100644
index 0000000..8fa1180
--- /dev/null
+++ b/argparse/__init__.py
@@ -0,0 +1,183 @@
+from __future__ import absolute_import
+from __future__ import print_function
+
+import re
+import sys
+from cmdline2cwl import Arg2CWLParser, load_argparse
+
+ap = load_argparse()
+import galaxyxml.tool as gxt
+import galaxyxml.tool.parameters as gxtp
+from . import argparse_galaxy_translation as agt
+from . import argparse_cwl_translation as act
+from cmdline2cwl import cwl_tool as cwlt
+
+# This fetches a reference to ourselves
+__selfmodule__ = sys.modules[__name__]
+# Static list of imports
+__argparse_exports__ = list(filter(lambda x: not x.startswith('__'), dir(ap)))
+# Set the attribute on ourselves.
+for x in __argparse_exports__:
+    setattr(__selfmodule__, x, getattr(ap, x))
+
+tools = []
+
+
+
+
+class ArgumentParser(ap.ArgumentParser):
+
+
+    def __init__(self,
+                 prog=None,
+                 usage=None,
+                 description=None,
+                 epilog=None,
+                 parents=[],
+                 formatter_class=HelpFormatter,
+                 prefix_chars='-',
+                 fromfile_prefix_chars=None,
+                 argument_default=None,
+                 conflict_handler='error',
+                 add_help=True):
+
+        self.argument_list = []
+        self.argument_names = []
+        tools.append(self)
+        super(ArgumentParser, self).__init__(prog=prog,
+                                             usage=usage,
+                                             description=description,
+                                             epilog=epilog,
+                                             parents=parents,
+                                             formatter_class=formatter_class,
+                                             prefix_chars=prefix_chars,
+                                             fromfile_prefix_chars=fromfile_prefix_chars,
+                                             argument_default=argument_default,
+                                             conflict_handler=conflict_handler,
+                                             add_help=add_help)
+
+    def add_argument(self, *args, **kwargs):
+        result = ap.ArgumentParser.add_argument(self, *args, **kwargs)
+        # to avoid duplicate ids when there's a positional and an optional param with the same dest
+        if result.dest in self.argument_names:
+            if result.__class__.__name__ == '_AppendConstAction':
+                # append_const params with the same dest are populated in job.json
+                return
+            else:
+                result.dest = '_' + result.dest
+        self.argument_list.append(result)
+        self.argument_names.append(result.dest)
+
+    def parse_args(self, *args, **kwargs):
+
+        arg2cwl_parser = Arg2CWLParser()
+        if '--generate_cwl_tool' in sys.argv:
+            kwargs = arg2cwl_parser.process_arguments()
+            self.parse_args_cwl(*args, **kwargs)
+
+        elif '--generate_galaxy_xml' in sys.argv:
+            self.parse_args_galaxy_nouse(*args, **kwargs)
+
+        elif '--help_arg2cwl' in sys.argv:
+            arg2cwl_parser.parser.print_help()
+            sys.exit()
+        else:
+            return ap.ArgumentParser.parse_args(self, *args, **kwargs)
+
+    def parse_args_cwl(self, *args, **kwargs):
+        for argp in tools:
+            # make subparser description out of its help message
+            if argp._subparsers:
+                # there were cases during testing, when instances other than _SubParsesAction type
+                # got into ._subparsers._group_actions
+                for subparser in filter(lambda action: isinstance(action, _SubParsersAction),
+                                        argp._subparsers._group_actions):
+                    for choice_action in subparser._choices_actions:
+                        subparser.choices[choice_action.dest].description = choice_action.help
+            # if the command is subparser itself, we don't need its CWL wrapper
+            else:
+                # if user provides a generic command like `cnvkit.py` - all possible descriptions are generated
+                # if a specific command like `cnvkit.py batch` is given and
+                # there are no subparsers - only this description is built
+                if kwargs.get('command', argp.prog) in argp.prog:
+                    tool = cwlt.CWLTool(argp.prog,
+                                        argp.description,
+                                        kwargs['formcommand'],
+                                        kwargs.get('basecommand', ''),
+                                        kwargs.get('output_section', ''))
+                    at = act.ArgparseCWLTranslation(kwargs.get('generate_outputs', False))
+                    for result in argp._actions:
+                        argument_type = result.__class__.__name__
+                        if hasattr(at, argument_type):
+                            methodToCall = getattr(at, argument_type)
+                            cwlt_parameter = methodToCall(result)
+                            if cwlt_parameter is not None:
+                                tool.inputs.append(cwlt_parameter)
+                                if isinstance(cwlt_parameter, cwlt.OutputParam):
+                                    tool.outputs.append(cwlt_parameter)
+
+                    if argp.epilog is not None:
+                        tool.description += argp.epilog
+
+                    data = tool.export()
+                    # if there is more than one file, ignore specified filename
+                    if 'filename' in kwargs and len(tools)==1:
+                        filename = kwargs['filename']
+                    else:
+                        filename = '{0}.cwl'.format(tool.name.replace('.py',''))
+                        filename = re.sub('\s+', '-', filename)
+                    directory = kwargs.get('directory', '')
+                    if directory and directory[-1] != '/':
+                        directory += '/'
+                    filename = directory + filename
+                    with open(filename, 'w') as f:
+                        f.write(data)
+                    if 'verbose' in kwargs:
+                        print(data)
+                else:
+                    continue
+        sys.exit(0)
+
+    def parse_args_galaxy_nouse(self, *args, **kwargs):
+        self.tool = gxt.Tool(
+                self.prog,
+                self.prog,
+                self.print_version() or '1.0',
+                self.description,
+                self.prog,
+                interpreter='python',
+                version_command='python %s --version' % sys.argv[0])
+
+        self.inputs = gxtp.Inputs()
+        self.outputs = gxtp.Outputs()
+
+        self.at = agt.ArgparseGalaxyTranslation()
+        # Only build up arguments if the user actually requests it
+        for result in self.argument_list:
+            # I am SO thankful they return the argument here. SO useful.
+            argument_type = result.__class__.__name__
+            # http://stackoverflow.com/a/3071
+            if hasattr(self.at, argument_type):
+                methodToCall = getattr(self.at, argument_type)
+                gxt_parameter = methodToCall(result, tool=self.tool)
+                if gxt_parameter is not None:
+                    if isinstance(gxt_parameter, gxtp.InputParameter):
+                        self.inputs.append(gxt_parameter)
+                    else:
+                        self.outputs.append(gxt_parameter)
+
+        # TODO: replace with argparse-esque library to do this.
+        stdout = gxtp.OutputParameter('default', 'txt')
+        stdout.command_line_override = '> $default'
+        self.outputs.append(stdout)
+
+        self.tool.inputs = self.inputs
+        self.tool.outputs = self.outputs
+        if self.epilog is not None:
+            self.tool.help = self.epilog
+        else:
+            self.tool.help = "TODO: Write help"
+
+        data = self.tool.export()
+        print(data)
+        sys.exit()
diff --git a/argparse/argparse_cwl_translation.py b/argparse/argparse_cwl_translation.py
new file mode 100644
index 0000000..061cc76
--- /dev/null
+++ b/argparse/argparse_cwl_translation.py
@@ -0,0 +1,131 @@
+from __future__ import absolute_import
+
+import sys
+
+from cmdline2cwl import cwl_tool as cwlt
+
+PY_TO_CWL_TYPES = {
+    'str': 'string',
+    'bool': 'boolean',
+    'int': 'int',
+    'float': 'float',
+    'list': 'array',
+    'TextIOWrapper': 'File',
+    'open': 'File'
+}
+
+class ArgparseCWLTranslation:
+
+    def __init__(self, generate_outputs=False):
+        self.positional_count = 0
+        # generate_outputs option allows to form output arguments in CWL tool description from arguments
+        # which merely contain keyword `output` in their name
+        # Example: parser.add_argument('--output-file', help='some file for output') will be placed into
+        # output section (normally only files with FileType('w') are placed into output section
+        # However, such behaviour is tricky as '--output-directory' argument will also be treated like File
+        # so check generated tools carefully if you choose this option
+        self.generate_outputs = generate_outputs
+
+    def __cwl_param_from_type(self, param):
+        """Based on a type, convert to appropriate cwlt class
+        """
+        from argparse import FileType
+        if param.default == sys.stdout:
+            param.default = None
+        if hasattr(param, 'optional'):
+            optional = param.optional
+        else:
+            optional = False
+        if not hasattr(param, 'items_type'):
+            param.items_type = None
+        prefix = None
+        if param.option_strings:
+            prefix = param.option_strings[-1]
+            if not param.required:
+                optional = True
+        if param.option_strings:
+            position = None
+        else:
+            self.positional_count += 1
+            position = self.positional_count
+        kwargs_positional = {'id': param.dest,
+                             'position': position,
+                             'description': param.help,
+                             'default': param.default,
+                             'prefix': prefix,
+                             'optional': optional,
+                             'items_type': param.items_type,
+                             'type': self.get_cwl_type(param.type) or 'str'}
+
+        if param.choices is not None:
+            kwargs_positional['choices'] = param.choices
+            kwargs_positional['type'] = 'enum'
+        if (isinstance(param.type, FileType) and 'w' in param.type._mode)\
+          or (self.generate_outputs and 'output' in param.dest):
+            cwlparam = cwlt.OutputParam(**kwargs_positional)
+        else:
+            cwlparam = cwlt.Param(**kwargs_positional)
+        return cwlparam
+
+
+    def __args_from_nargs(self, param):
+        if param.nargs:
+            if not param.nargs == '?':
+                param.items_type = self.get_cwl_type(param.type)
+                param.type = list
+
+            if param.nargs == '?' or param.nargs == '*':
+                param.optional = True
+                param.required = False
+
+        return param
+
+    def _StoreAction(self, param):
+        param = self.__args_from_nargs(param)
+        cwlparam = self.__cwl_param_from_type(param)
+        return cwlparam
+
+
+    def _StoreTrueAction(self, param):
+        return self.__StoreBoolAction(param)
+
+    def _StoreFalseAction(self, param):
+        return self.__StoreBoolAction(param)
+
+    def _AppendAction(self, param, **kwargs):
+        param.items_type = self.get_cwl_type(param.type)
+        param.type = list
+        cwlparam = self.__cwl_param_from_type(param)
+        cwlparam.items_type = param.items_type
+        return cwlparam
+
+    def _AppendConstAction(self, param):
+        """
+        AppendConst argument is formed once from `dest` field. `Const` option is ignored
+        and must be provided again in job.json
+        """
+        param.type = list
+        param.optional = True
+        cwlparam = self.__cwl_param_from_type(param)
+        return cwlparam
+
+    def __StoreBoolAction(self, param):
+        param.type = bool
+        cwlparam = self.__cwl_param_from_type(param)
+        return cwlparam
+
+    @staticmethod
+    def get_cwl_type(py_type):
+        """
+        converts given Python type to a CWL type
+        >>> ArgparseCWLTranslation.get_cwl_type(list)
+        'array'
+        """
+        if py_type is None:
+            return None
+        if type(py_type) is type:
+            return PY_TO_CWL_TYPES[py_type.__name__]
+        elif type(py_type).__name__ == 'builtin_function_or_method' or type(py_type).__name__ == 'FileType':
+            return 'File'
+        else:  # type given as a string: 'str', 'int' etc.
+            return PY_TO_CWL_TYPES[py_type]
diff --git a/argparse/argparse_galaxy_translation.py b/argparse/argparse_galaxy_translation.py
new file mode 100644
index 0000000..a7a6fa5
--- /dev/null
+++ b/argparse/argparse_galaxy_translation.py
@@ -0,0 +1,252 @@
+import galaxyxml.tool.parameters as gxtp
+
+class ArgparseGalaxyTranslation(object):
+
+    def __gxtp_param_from_type(self, param, flag, label, num_dashes, gxparam_extra_kwargs, default=None):
+        from argparse import FileType
+        """Based on a type, convert to appropriate gxtp class
+        """
+        if default is None and (param.type in (int, float)):
+            default = 0
+
+        if param.choices is not None:
+            choices = {k: k for k in param.choices}
+            gxparam = gxtp.SelectParam(flag, default=default, label=label,
+                    num_dashes=num_dashes, options=choices, **gxparam_extra_kwargs)
+        elif param.type == int:
+            gxparam = gxtp.IntegerParam(flag, default, label=label,
+                    num_dashes=num_dashes, **gxparam_extra_kwargs)
+        elif param.type == float:
+            gxparam = gxtp.FloatParam(flag, default, label=label,
+                    num_dashes=num_dashes, **gxparam_extra_kwargs)
+        elif param.type == None or param.type == str:
+            gxparam = gxtp.TextParam(flag, default=default, label=label,
+                    num_dashes=num_dashes, **gxparam_extra_kwargs)
+        elif param.type == file:
+            gxparam = gxtp.DataParam(flag, label=label,
+                    num_dashes=num_dashes, **gxparam_extra_kwargs)
+        elif isinstance(param.type, FileType):
+            if 'w' in param.type._mode:
+                gxparam = gxtp.OutputParameter(
+                    flag, format='data', default=default, label=label,
+                    num_dashes=num_dashes, **gxparam_extra_kwargs)
+            else:
+                gxparam = gxtp.DataParam(
+                    flag, default=default, label=label, num_dashes=num_dashes,
+                    **gxparam_extra_kwargs)
+        else:
+            gxparam = None
+
+        return gxparam
+
+    def __args_from_nargs(self, param, repeat_name, repeat_var_name, positional, flag):
+        """Based on param.nargs, return the appropriate overrides
+        """
+        gxrepeat_args = []
+        gxrepeat_kwargs = {}
+        gxrepeat_cli_after = None
+        gxrepeat_cli_before = None
+        gxrepeat_cli_actual = None
+
+        gxparam_cli_before = None
+        gxparam_cli_after = None
+
+        if positional:
+            gxrepeat_cli_actual = '"$%s"' % (repeat_var_name)
+        else:
+            gxrepeat_cli_actual = '%s "$%s"' % (param.option_strings[0], repeat_var_name)
+
+        if isinstance(param.nargs, int):
+            # N (an integer). N arguments from the command line will be
+            # gathered together into a list. For example:
+            if param.nargs > 1:
+                gxrepeat_args = [repeat_name, 'repeat_title']
+                gxrepeat_kwargs = {
+                        'min': param.nargs,
+                        'max': param.nargs,
+                        }
+            else:
+                # If we have only one, we don't want a gxrepeat, so we leave well
+                # enough alone
+                gxrepeat_args = None
+        elif param.nargs == '?':
+            # '?'. One argument will be consumed from the command line if
+            # possible, and produced as a single item. If no command-line
+            # argument is present, the value from default will be produced.
+            # Note that for optional arguments, there is an additional case -
+            # the option string is present but not followed by a command-line
+            # argument. In this case the value from const will be produced
+
+            # This does NOT provide a way to access the value in const, but
+            # that seems like a HORRIBLE idea anyway. Seriously, who does that.
+            gxparam_cli_before = """\n#if $%s and $%s is not None:""" % (flag, flag)
+            gxparam_cli_after = '#end if'
+
+            gxrepeat_args = None
+        elif param.nargs is None:
+            # Very similar to '?' but without the case of "optional + specified
+            # withouth an argument" being OK
+            #
+            # This has changed over time, we're (probably) going overboard here.
+            gxparam_cli_before = """\n#if $%s and $%s is not None:""" % (flag, flag)
+            gxparam_cli_after = '#end if'
+            gxrepeat_args = None
+        elif param.nargs == '*':
+            # '*'. All command-line arguments present are gathered into a list.
+            # Note that it generally doesn't make much sense to have more than
+            # one positional argument with nargs='*', but multiple optional
+            # arguments with nargs='*' is possible. For example:
+
+            # This needs to be handled with a
+            #set files = '" "'.join( [ str( $file ) for $file in $inputB ] )
+
+            gxrepeat_args = [repeat_name, 'repeat_title']
+            #gxrepeat_cli_after = '#end if\n'
+            gxrepeat_cli_after = ''
+            gxrepeat_cli_before = """\n#set %s = '" "'.join([ str($var.%s) for $var in $%s ])""" % (repeat_var_name, flag, repeat_name)
+        elif param.nargs == '+':
+            # '+'. Just like '*', all command-line args present are gathered
+            # into a list. Additionally, an error message will be generated if
+            # there wasn't at least one command-line argument present. For
+            # example:
+            gxrepeat_args = [repeat_name, 'repeat_title']
+            gxrepeat_kwargs = {'min': 1}
+            gxrepeat_cli_after = ''
+            gxrepeat_cli_before = """\n#set %s = '" "'.join([ str($var.%s) for $var in $%s ])""" % (repeat_var_name, flag, repeat_name)
+        else:
+            raise Exception("TODO: Handle argparse.REMAINDER")
+
+        return (gxrepeat_args, gxrepeat_kwargs, gxrepeat_cli_after,
+                gxrepeat_cli_before, gxrepeat_cli_actual, gxparam_cli_before, gxparam_cli_after)
+
+
+    def __init__(self):
+        self.repeat_count = 0
+        self.positional_count = 0
+
+    def _VersionAction(self, param, tool=None):
+        # passing tool is TERRIBLE, I know.
+        # TODO handle their templating of version
+
+        # This is kinda ugly but meh.
+        tool.root.attrib['version'] = param.version
+
+        # Count the repeats for unique names
+        # TODO improve
+
+
+    def _StoreAction(self, param, tool=None):
+        """
+        Parse argparse arguments action type of "store", the default.
+
+        param: argparse.Action
+        """
+        gxparam = None
+        gxrepeat = None
+        self.repeat_count += 1
+        gxparam_extra_kwargs = {}
+
+        if not param.required:
+            gxparam_extra_kwargs['optional'] = True
+
+        # Positional arguments don't have an option strings
+        positional = len(param.option_strings) == 0
+
+        if not positional:
+            flag = max(param.option_strings, key=len)  # Pick the longest of
+                                                       # the options strings
+        else:
+            flag = ''
+            self.positional_count += 1
+
+        repeat_name = 'repeat_%s' % self.repeat_count
+        repeat_var_name = 'repeat_var_%s' % self.repeat_count
+
+        # TODO: Replace with logic supporting characters other than -
+        flag_wo_dashes = flag.lstrip('-')
+        num_dashes = len(flag) - len(flag_wo_dashes)
+
+        # Moved because needed in developing repeat CLI
+        if positional:
+            flag_wo_dashes = 'positional_%s' % self.positional_count
+            # SO unclean
+            gxparam_extra_kwargs['positional'] = True
+
+
+        # Figure out parameters and overrides from param.nargs, mainly.
+        # This is really unpleasant.
+        (gxrepeat_args, gxrepeat_kwargs, gxrepeat_cli_after,
+         gxrepeat_cli_before, gxrepeat_cli_actual, gxparam_cli_before,
+         gxparam_cli_after) = \
+            self.__args_from_nargs(param, repeat_name, repeat_var_name, positional, flag_wo_dashes)
+
+
+
+        # Build the gxrepeat if it's needed
+        if gxrepeat_args is not None:
+            gxrepeat = gxtp.Repeat(*gxrepeat_args, **gxrepeat_kwargs)
+            if gxrepeat_cli_before is not None:
+                gxrepeat.command_line_before_override = gxrepeat_cli_before
+            if gxrepeat_cli_after is not None:
+                gxrepeat.command_line_after_override = gxrepeat_cli_after
+            if gxrepeat_cli_actual is not None:
+                gxrepeat.command_line_override = gxrepeat_cli_actual
+        else:
+            gxrepeat = None
+
+
+        gxparam = self.__gxtp_param_from_type(param, flag_wo_dashes,
+                param.help, num_dashes, gxparam_extra_kwargs, default=param.default)
+
+        # Not really happy with this way of doing this
+        if gxparam_cli_before is not None:
+            gxparam.command_line_before_override = gxparam_cli_before
+
+        if gxparam_cli_after is not None:
+            gxparam.command_line_after_override = gxparam_cli_after
+
+        # if positional argument, wipe out the CLI flag that's usually present
+        if positional:
+            gxparam.command_line_override = '$%s' % flag_wo_dashes
+
+        if gxrepeat is not None and gxparam is not None:
+            gxrepeat.append(gxparam)
+            return gxrepeat
+        elif gxrepeat is None and gxparam is not None:
+            return gxparam
+        else:
+            raise Exception("huh")
+        return None
+
+    def _StoreTrueAction(self, param, **kwargs):
+        return self._StoreConstAction(param, **kwargs)
+
+    def _StoreFalseAction(self, param, **kwargs):
+        return self._StoreConstAction(param, **kwargs)
+
+    def _AppendAction(self, param, **kwargs):
+        self.repeat_count += 1
+        repeat_name = 'repeat_%s' % self.repeat_count
+        # TODO: Replace with logic supporting characters other than -
+        flag = max(param.option_strings, key=len)  # Pick one of the options
+                                                   # strings
+        flag_wo_dashes = flag.lstrip('-')
+        num_dashes = len(flag) - len(flag_wo_dashes)
+
+        gxparam = self.__gxtp_param_from_type(param, flag_wo_dashes, param.help, num_dashes, {})
+        gxrepeat = gxtp.Repeat(repeat_name, 'Repeated Variable')
+        gxrepeat.command_line_override = '%s $%s.%s' % (param.option_strings[0], 'i', flag_wo_dashes)
+        gxrepeat.append(gxparam)
+        return gxrepeat
+
+
+    def _StoreConstAction(self, param, **kwargs):
+        flag = max(param.option_strings, key=len)  # Pick one of the options
+                                                   # strings
+        flag_wo_dashes = flag.lstrip('-')
+        num_dashes = len(flag) - len(flag_wo_dashes)
+
+        gxparam = gxtp.BooleanParam(flag_wo_dashes, label=param.help,
+                num_dashes=num_dashes)
+
+        return gxparam
diff --git a/click/__init__.py b/click/__init__.py
new file mode 100644
index 0000000..16e07a4
--- /dev/null
+++ b/click/__init__.py
@@ -0,0 +1,93 @@
+from __future__ import absolute_import
+from __future__ import print_function
+
+import os
+import re
+import sys
+
+from click import click_cwl_translation as cct
+from cmdline2cwl import cwl_tool as cwlt
+from cmdline2cwl import load_conflicting_package, Arg2CWLParser
+
+CLICK_NUMBER = 5
+click = load_conflicting_package('click', 'gxargparse', CLICK_NUMBER)
+__selfmodule__ = sys.modules[__name__]
+# This fetches a reference to ourselves
+
+__click_exports__ = list(filter(lambda x: not x.startswith('__'), dir(click)))
+# Set the attribute on ourselves.
+for x in __click_exports__:
+    setattr(__selfmodule__, x, getattr(click, x))
+
+
+class Arg2CWLMixin:
+    def __call__(self, *args, **kwargs):
+        arg2cwl_parser = Arg2CWLParser()
+        if '--generate_cwl_tool' in sys.argv:
+
+            arg2cwl_options = arg2cwl_parser.process_arguments()
+            if hasattr(self, 'commands'):
+                for command in self.commands.values():
+                    self.form_tool(arg2cwl_options, command)
+            else:
+                self.form_tool(arg2cwl_options)
+
+        elif '--help_arg2cwl' in sys.argv:
+            arg2cwl_parser.parser.print_help()
+            sys.exit()
+        else:
+            click.BaseCommand.__call__(self, *args, **kwargs)
+
+    def form_tool(self, arg2cwl_options, command=None):
+        name = os.path.basename(sys.argv[0])
+        if command is None:
+            command = self
+        else:
+            name += ' %s' % command.name
+
+        tool = cwlt.CWLTool(name,
+                            command.help,
+                            arg2cwl_options['formcommand'],
+                            arg2cwl_options.get('basecommand', ''),
+                            arg2cwl_options.get('output_section', ''))
+
+        ct = cct.ClickCWLTranslation()
+        for option in command.params:
+            cwl_param = ct.get_cwl_param(option)
+            if cwl_param is not None:
+                tool.inputs.append(cwl_param)
+                if isinstance(cwl_param, cwlt.OutputParam):
+                    tool.outputs.append(cwl_param)
+        data = tool.export()
+        self._write_tool(tool, data, arg2cwl_options.get('directory', ''))
+
+    def _write_tool(self, tool, data, directory):
+        filename = '{0}.cwl'.format(tool.name.replace('.py', ''))
+        filename = re.sub('\s+', '-', filename)
+        if directory and directory[-1] != '/':
+            directory += '/'
+        filename = directory + filename
+        with open(filename, 'w') as f:
+            f.write(data)
+        print(data)
+
+
+class Arg2CWLCommand(Arg2CWLMixin, click.Command):
+    pass
+
+
+class Arg2CWLGroup(Arg2CWLMixin, click.Group):
+    pass
+
+
+def command(name=None, cls=Arg2CWLCommand, **attrs):
+    """override click function 'command' """
+
+    return click.command(name, cls, **attrs)
+
+
+def group(name=None, **attrs):
+    """override click function 'group' """
+
+    attrs.setdefault('cls', Arg2CWLGroup)
+    return command(name, **attrs)
diff --git a/click/click_cwl_translation.py b/click/click_cwl_translation.py
new file mode 100644
index 0000000..6a0523c
--- /dev/null
+++ b/click/click_cwl_translation.py
@@ -0,0 +1,105 @@
+from __future__ import absolute_import
+
+import sys
+
+import click
+from cmdline2cwl import cwl_tool as cwlt
+
+PY_TO_CWL_TYPES = {
+    'str': 'string',
+    'bool': 'boolean',
+    'int': 'int',
+    'float': 'float',
+    'list': 'array',
+    'TextIOWrapper': 'File',
+    'open': 'File'
+}
+
+CLICK_TO_CWL_TYPES = {
+    'integer': 'int',
+    'text': 'string',
+    'choice': 'enum',
+    'integer range': 'array',
+    'float range': 'array',
+    'float': 'float',
+    'boolean': 'boolean',
+    'uuid': 'string',
+    'filename': 'File',
+    'file': 'File',
+    'directory': 'Directory',
+    'path': 'string'
+}
+
+
+class ClickCWLTranslation:
+    def __init__(self, generate_outputs=False):
+        self.positional_count = 0
+        # generate_outputs option allows to form output arguments in CWL tool description from arguments
+        # which merely contain keyword `output` in their name
+        # Example: parser.add_argument('--output-file', help='some file for output') will be placed into
+        # output section (normally only files with FileType('w') are placed into output section
+        # However, such behaviour is tricky as '--output-directory' argument will also be treated like File
+        # so check generated tools carefully if you choose this option
+        self.generate_outputs = generate_outputs
+
+    def __cwl_param_from_type(self, param):
+        """Based on a type, convert to appropriate cwlt class
+        """
+        if param.default == sys.stdout:
+            param.default = None
+        if hasattr(param, 'optional'):
+            optional = param.optional
+        else:
+            optional = False
+        if not hasattr(param, 'items_type'):
+            param.items_type = None
+        prefix = None
+        position = None
+        if param.param_type_name == 'option':
+            prefix = param.opts[-1]
+        if not param.required:
+            optional = True
+        else:
+            self.positional_count += 1
+            position = self.positional_count
+        param_type = self.get_cwl_type(param.type) or 'str'
+        kwargs_positional = {'id': param.name,
+                             'position': position,
+                             'description': getattr(param, 'help', param.human_readable_name),
+                             'default': param.default,
+                             'prefix': prefix,
+                             'optional': optional,
+                             'items_type': param.items_type,
+                             'type': param_type}
+
+        if type(param.type) is click.Choice:
+            kwargs_positional['choices'] = param.type.choices
+        if (isinstance(param.type, click.types.File) and 'w' in param.type.mode) \
+          or (self.generate_outputs and 'output' in param.dest):
+            cwlparam = cwlt.OutputParam(**kwargs_positional)
+        else:
+            cwlparam = cwlt.Param(**kwargs_positional)
+        return cwlparam
+
+    def __args_from_nargs(self, param):
+        if param.nargs == '-1':
+            param.items_type = self.get_cwl_type(param.type)
+            param.type = list
+        return param
+
+    def get_cwl_param(self, param):
+        param = self.__args_from_nargs(param)
+        cwlparam = self.__cwl_param_from_type(param)
+        return cwlparam
+
+    @staticmethod
+    def get_cwl_type(py_type):
+        if py_type is None:
+            return None
+        elif isinstance(py_type, click.types.ParamType):
+            if isinstance(py_type, click.types.Tuple):
+                return str(list(map(lambda click_type: CLICK_TO_CWL_TYPES[click_type.name], py_type.types))).strip('[]')
+            cwl_type = CLICK_TO_CWL_TYPES[py_type.name]
+            return cwl_type
+        else:
+            return PY_TO_CWL_TYPES[py_type.__name__]
diff --git a/cmdline2cwl/__init__.py b/cmdline2cwl/__init__.py
new file mode 100644
index 0000000..89b4bde
--- /dev/null
+++ b/cmdline2cwl/__init__.py
@@ -0,0 +1,113 @@
+import logging
+import re
+import sys
+from builtins import range
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+__version__ = '0.3.1'
+
+
+def load_argparse():
+    ARGPARSE_NUMBER = 1
+    return load_conflicting_package('argparse', 'gxargparse', ARGPARSE_NUMBER)
+
+
+def load_conflicting_package(name, not_name, module_number):
+    """Load a conflicting package
+    Some assumptions are made, namely that your package includes the "official"
+    one as part of the name. E.g. gxargparse/argparse, you would call this with:
+
+        >>> real_argparse = load_conflicting_package('argparse', 'gxargparse', 1)
+
+     http://stackoverflow.com/a/6032023
+    """
+    import imp
+    for i in range(0, 100):
+        random_name = 'random_name_%d' % (i,)
+        if random_name not in sys.modules:
+            break
+        else:
+            random_name = None
+    if random_name is None:
+        raise RuntimeError("Couldn't manufacture an unused module name.")
+    # NB: This code is unlikely to work for nonstdlib overrides.
+    # This will hold the correct sys.path for the REAL argparse
+    for path in sys.path:
+        try:
+            (f, pathname, desc) = imp.find_module(name, [path])
+            if not_name not in pathname and desc[2] == module_number:
+                module = imp.load_module(random_name, f, pathname, desc)
+                # f.close()
+                return sys.modules[random_name]
+        except:
+            # Many sys.paths won't contain the module of interest
+            pass
+    return None
+
+
+class Arg2CWLParser:
+    def __init__(self):
+        ap = load_argparse()  # avoid circular imports
+        help_text = """
+        argparse2cwl forms CWL command line tool from Python tool
+        Example: $ python program.py --generate_cwl_tool -b python
+        """
+        arg2cwl_parser = ap.ArgumentParser(prog=sys.argv[0], description=help_text,
+                                           formatter_class=ap.RawDescriptionHelpFormatter, add_help=False)
+        arg2cwl_parser.add_argument('tools', nargs='*',
+                                    help='Command for running your tool(s), without arguments')
+        arg2cwl_parser.add_argument('-d', '--directory',
+                                    help='Directory to store CWL tool descriptions')
+        arg2cwl_parser.add_argument('-f', '--filename',
+                                    help='Name of the generated file (if single). Default - the name of the running command')
+        arg2cwl_parser.add_argument('-v', '--verbose', action='store_true',
+                                    help='Print generated file(s) to stdout')
+        arg2cwl_parser.add_argument('-b', '--basecommand',
+                                    help='Command that appears in `basecommand` field in CWL tool '
+                                         'instead of the default one')
+        arg2cwl_parser.add_argument('-o', '--output_section', metavar='FILENAME',
+                                    help='File with output section which will be put to a formed CWL tool')
+        arg2cwl_parser.add_argument('-go', '--generate_outputs', action='store_true',
+                                    help='Form output section from args than contain `output` keyword in their names')
+        arg2cwl_parser.add_argument('--help_arg2cwl',
+                                    help='Show this help message and exit', action='help')
+        self.parser = arg2cwl_parser
+
+    def process_arguments(self):
+        self.parser.add_argument('--generate_cwl_tool', action='store_true')
+        self.args = self.parser.parse_args()
+        logger.debug('sys argv: ', sys.argv)
+        commands = [self.parser.prog.split('/')[-1]]
+        if self.args.tools:
+            commands.extend(self.args.tools)
+        command = ' '.join(commands)
+        kwargs = dict()
+        kwargs['command'] = command.strip()
+
+        shebang = re.search(r'\./[\w-]*?.py$', self.parser.prog)
+        if shebang:
+            kwargs['basecommand'] = shebang.group(0)
+
+        formcommand = ''
+        if kwargs.get('basecommand', ''):
+            formcommand += kwargs['basecommand']
+        else:
+            formcommand += kwargs['command']
+
+        attrs = ['directory', 'filename', 'output_section', 'basecommand', 'generate_outputs', 'verbose']
+        for arg in attrs:
+            if getattr(self.args, arg):
+                kwargs[arg] = getattr(self.args, arg)
+
+        if kwargs.get('output_section', ''):
+            formcommand += ' -o FILENAME'
+        if kwargs.get('filename', ''):
+            formcommand += ' -f FILENAME'
+        if kwargs.get('basecommand', ''):
+            formcommand += ' -b {0}'.format(kwargs['basecommand'])
+        if kwargs.get('generate_outputs', ''):
+            formcommand += ' -go'
+        kwargs['formcommand'] = formcommand
+        return kwargs
diff --git a/cmdline2cwl/cwl_tool.py b/cmdline2cwl/cwl_tool.py
new file mode 100644
index 0000000..56b4033
--- /dev/null
+++ b/cmdline2cwl/cwl_tool.py
@@ -0,0 +1,68 @@
+import re
+import os
+
+from jinja2 import Environment, FileSystemLoader
+
+from cmdline2cwl import __version__
+
+class Param:
+    def __init__(self, id, type, position=None, description=None, default=None, prefix=None, optional=False, items_type=None, **kwargs):
+        self.id = id
+        self.position = position
+        self.type = type
+        self.default = default
+        self.prefix = prefix
+        self.optional = optional
+        self.items_type = items_type
+        if description:
+            self.description = description.replace(':', ' -') \
+                .replace('\n', ' ')  # `:` is a special character and must be replaced with smth
+            self.description = re.sub('\s{2,}', ' ', self.description)
+        else:
+            self.description = None
+        if self.type == 'enum':
+            self.choices = list(kwargs.pop('choices', []))
+
+
+class OutputParam(Param):
+    pass
+
+class CWLTool(object):
+
+    def __init__(self, name, description, formcommand, basecommand=None, output_file=None):
+        self.name = name
+        self.output_file = output_file  # file with manually filled output section
+        if description:
+            self.description = description.replace('\n', '\n  ')
+        else:
+            self.description = None
+        self.env = Environment(
+            loader=FileSystemLoader(os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates'))),
+            trim_blocks=True,
+            lstrip_blocks=True)
+        if basecommand:
+            self.basecommands = [basecommand]
+        else:
+            self.basecommands = self.name.split()
+        self.formcommand = formcommand
+        self.inputs = []
+        self.outputs = []
+
+    def export(self):
+        inputs_template = self.env.get_template('cwltool_inputs.j2')
+        outputs_template = self.env.get_template('cwltool_outputs.j2')
+        main_template = self.env.get_template('cwltool.j2')
+        inputs = inputs_template.render(tool=self, basecommand=self.basecommands)
+        if self.output_file:
+            with open(self.output_file) as f:
+                outputs = f.read()
+        else:
+            outputs = outputs_template.render(tool=self)
+        import argparse
+        return main_template.render(tool=self,
+                                    version=__version__,
+                                    formcommand=self.formcommand,
+                                    stripped_options_command=re.sub('-.*', '', self.formcommand),
+                                    basecommand=self.basecommands,
+                                    inputs=inputs,
+                                    outputs=outputs)
diff --git a/cmdline2cwl/templates/cwltool.j2 b/cmdline2cwl/templates/cwltool.j2
new file mode 100644
index 0000000..e1d2f03
--- /dev/null
+++ b/cmdline2cwl/templates/cwltool.j2
@@ -0,0 +1,17 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. {{ version }}
+# To generate again: $ {{ formcommand }} --generate_cwl_tool
+# Help: $ {{ stripped_options_command }} --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: {{ basecommand }}
+
+doc: |
+  {{ tool.description }}
+
+inputs:
+  {{ inputs }}
+
+{{ outputs }}
\ No newline at end of file
diff --git a/cmdline2cwl/templates/cwltool_inputs.j2 b/cmdline2cwl/templates/cwltool_inputs.j2
new file mode 100644
index 0000000..243f9c6
--- /dev/null
+++ b/cmdline2cwl/templates/cwltool_inputs.j2
@@ -0,0 +1,42 @@
+{% if 'python' in basecommand[0] %}
+{{ tool.name }}:
+    type: File
+    default:
+      class: File
+      path: {{ tool.name }}
+    inputBinding:
+      position: 0
+{% endif %}
+{% for param in tool.inputs %}
+{% set param_attrs %}
+{% if param.type == "enum" or param.type == "array"%}
+  type:
+    {% if param.optional %}  - "null"
+  - type: {{ param.type }}{% else %}
+    type: {{ param.type }}{% endif %}
+      {% if param.type == "array" %}
+
+    items: {{ param.items_type or "string" }}
+      {% elif param.type == "enum" %}
+
+    symbols: {{ param.choices }}{% endif %}{% else %}
+  type: {% if param.optional %}["null", {{ param.type }}]{% else %}{{ param.type }}
+  {% endif %}
+  {% endif %}
+
+  {% if param.default != None %}
+  default: {{ param.default }}
+  {% endif %}
+  {% if param.description %}  doc: {{ param.description }}{% endif %}
+  {% if param.position or param.prefix %}
+
+  inputBinding:
+{% if param.position %}    position: {{ param.position }}{% endif %}
+{% if param.prefix %}    prefix: {{ param.prefix }} {% endif %}
+    {% endif %}
+    {% endset %}
+
+  {{ param.id }}:
+  {{ param_attrs|indent(2) }}
+{% endfor %}
+
diff --git a/cmdline2cwl/templates/cwltool_outputs.j2 b/cmdline2cwl/templates/cwltool_outputs.j2
new file mode 100644
index 0000000..1eff431
--- /dev/null
+++ b/cmdline2cwl/templates/cwltool_outputs.j2
@@ -0,0 +1,17 @@
+outputs:
+{% for param in tool.outputs %}
+
+{% set param_attrs %}
+  type: File
+  {% if param.default %}  default: {{ param.default }} {% endif %}
+
+{% if param.description %}  doc: {{ param.description }}{% endif %}
+
+  outputBinding:
+    glob: $(inputs.{{ param.id }}.path)
+{% endset %}
+  {{ param.id + '_out'}}:
+  {{ param_attrs|indent(2) }}
+{% else %}
+    []
+{% endfor %}
\ No newline at end of file
diff --git a/example.py b/example.py
new file mode 100644
index 0000000..4f4de62
--- /dev/null
+++ b/example.py
@@ -0,0 +1,26 @@
+# /usr/bin/python3
+import argparse
+
+parser = argparse.ArgumentParser(description='Process some integers.', prefix_chars='-+', epilog="here's some epilog text", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+parser.add_argument('keyword', metavar='Q', type=str, nargs=1,
+        help='action keyword')
+
+parser.add_argument('integers', metavar='N', type=int, nargs='+',
+        help='an integer for the accumulator')
+
+parser.add_argument('--sum', '-s', dest='accumulate', action='store_const',
+        const=sum, default=max, help='sum the integers (default: find the max)')
+
+parser.add_argument('--foo', nargs='?', help='foo help')
+parser.add_argument('--bar', nargs='*', default=[1, 2, 3], help='BAR!')
+parser.add_argument('--true', action='store_true', help='Store a true')
+parser.add_argument('--false', action='store_false', help='Store a false')
+parser.add_argument('--append', action='append', help='Append a value')
+
+parser.add_argument('--nargs2', nargs=2, help='nargs2')
+
+parser.add_argument('--mode', choices=['rock', 'paper', 'scissors'], default='scissors')
+
+
+parser.add_argument('--version', action='version', version='2.0')
+args = parser.parse_args()
diff --git a/example.xml b/example.xml
new file mode 100644
index 0000000..be49d29
--- /dev/null
+++ b/example.xml
@@ -0,0 +1,68 @@
+<tool id="example.py" name="example.py" version="2.0">
+  <description>Process some integers.</description>
+  <stdio>
+    <exit_code level="fatal" range="1:"/>
+  </stdio>
+  <version_command>python example.py --version</version_command>
+  <command interpreter="python"><![CDATA[example.py $positional_1
+
+#set repeat_var_2 = '" "'.join([ str($var.positional_2) for $var in $repeat_2 ])
+"$repeat_var_2"
+
+$sum
+
+#if $foo and $foo is not None:
+--foo $foo
+#end if
+
+#if $file and $file is not None:
+--file $file
+#end if
+
+#set repeat_var_5 = '" "'.join([ str($var.bar) for $var in $repeat_5 ])
+--bar "$repeat_var_5"
+
+$true
+$false
+#for $i in $repeat_6:
+--append $i.append
+#end for
+#for $i in $repeat_7:
+--nargs2 "$repeat_var_7"
+#end for
+
+#if $mode and $mode is not None:
+--mode $mode
+#end if
+> $default]]></command>
+  <inputs>
+    <param area="false" label="action keyword (positional_1)" name="positional_1" type="text"/>
+    <repeat min="1" name="repeat_2" title="repeat_title">
+      <param label="an integer for the accumulator (positional_2)" name="positional_2" type="integer" value="0"/>
+    </repeat>
+    <param checked="false" label="sum the integers (default: find the max) (--sum)" name="sum" type="boolean" truevalue="--sum" falsevalue=""/>
+    <param area="false" label="foo help (--foo)" name="foo" type="text"/>
+    <param label="foo help (--file)" name="file" type="data"/>
+    <repeat name="repeat_5" title="repeat_title">
+      <param area="false" default="1" label="BAR! (--bar)" name="bar" type="text"/>
+    </repeat>
+    <param checked="false" label="Store a true (--true)" name="true" type="boolean" truevalue="--true" falsevalue=""/>
+    <param checked="false" label="Store a false (--false)" name="false" type="boolean" truevalue="--false" falsevalue=""/>
+    <repeat name="repeat_6" title="Repeated Variable">
+      <param area="false" label="Append a value (--append)" name="append" type="text"/>
+    </repeat>
+    <repeat max="2" min="2" name="repeat_7" title="repeat_title">
+      <param area="false" label="nargs2 (--nargs2)" name="nargs2" type="text"/>
+    </repeat>
+    <param label="Author did not provide help for this parameter...  (--mode)" name="mode">
+      <option checked="" name="scissors">scissors</option>
+      <option name="paper">paper</option>
+      <option name="rock">rock</option>
+    </param>
+  </inputs>
+  <outputs>
+    <data format="txt" hidden="false" name="default"/>
+  </outputs>
+  <help><![CDATA[here's some epilog text]]></help>
+</tool>
+
diff --git a/examples/argparse/cnvkit-tools/check_wrappers_in_dir.sh b/examples/argparse/cnvkit-tools/check_wrappers_in_dir.sh
new file mode 100644
index 0000000..5551734
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/check_wrappers_in_dir.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+for file in {.,}*;
+do
+    echo "$file";
+    cwl-runner "$file" data.json;
+done
\ No newline at end of file
diff --git a/examples/argparse/cnvkit-tools/cnvkit-access.cwl b/examples/argparse/cnvkit-tools/cnvkit-access.cwl
new file mode 100644
index 0000000..dce3365
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-access.cwl
@@ -0,0 +1,55 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'access']
+
+description: |
+  List the locations of accessible sequence regions in a FASTA file.
+
+inputs:
+  
+  fa_fname:
+    type: string
+  
+    description: Genome FASTA file name
+    inputBinding:
+      position: 1
+
+  min_gap_size:
+    type: ["null", int]
+    default: 5000
+    description: Minimum gap size between accessible sequence regions. Regions separated by less than this distance will be joined together. [Default - %(default)s]
+    inputBinding:
+      prefix: --min-gap-size 
+
+  exclude:
+    type:
+    - "null"
+    - type: array
+      items: string
+  
+    default: []
+    description: Additional regions to exclude, in BED format. Can be used multiple times.
+    inputBinding:
+      prefix: --exclude 
+
+  output:
+    type: ["null", File]
+    description: Output file name
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+
+  output_out:
+    type: File
+  
+    description: Output file name
+    outputBinding:
+      glob: $(inputs.output.path)
diff --git a/examples/argparse/cnvkit-tools/cnvkit-antitarget.cwl b/examples/argparse/cnvkit-tools/cnvkit-antitarget.cwl
new file mode 100644
index 0000000..f8f84f3
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-antitarget.cwl
@@ -0,0 +1,50 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'antitarget']
+
+description: |
+  Derive a background/antitarget BED file from a target BED file.
+
+inputs:
+  
+  interval:
+    type: string
+  
+    description: BED or interval file listing the targeted regions.
+    inputBinding:
+      position: 1
+
+  access:
+    type: ["null", string]
+    description: Regions of accessible sequence on chromosomes (.bed), as output by genome2access.py.
+    inputBinding:
+      prefix: --access 
+
+  avg_size:
+    type: ["null", int]
+    default: 100000
+    description: Average size of antitarget bins (results are approximate). [Default - %(default)s]
+    inputBinding:
+      prefix: --avg-size 
+
+  min_size:
+    type: ["null", int]
+    description: Minimum size of antitarget bins (smaller regions are dropped). [Default - 1/16 avg size, calculated]
+    inputBinding:
+      prefix: --min-size 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-batch.cwl b/examples/argparse/cnvkit-tools/cnvkit-batch.cwl
new file mode 100644
index 0000000..38b5c69
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-batch.cwl
@@ -0,0 +1,173 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.3.0
+# To generate again: $ cnvkit.py batch -go --generate_cwl_tool
+# Help: $ cnvkit.py batch  --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'batch']
+
+description: |
+  Run the complete CNVkit pipeline on one or more BAM files.
+
+inputs:
+  
+  bam_files:
+    type:
+    - "null"
+    - type: array
+      items: string
+  
+    description: Mapped sequence reads (.bam)
+    inputBinding:
+      position: 1
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Use or assume a male reference (i.e. female samples will have +1 log-CNR of chrX; otherwise male samples would have -1 chrX).
+    inputBinding:
+      prefix: --male-reference 
+
+  count_reads:
+    type: ["null", boolean]
+    default: False
+    description: Get read depths by counting read midpoints within each bin. (An alternative algorithm).
+    inputBinding:
+      prefix: --count-reads 
+
+  processes:
+    type: ["null", int]
+    default: 1
+    description: Number of subprocesses used to running each of the BAM files in parallel. Give 0 or a negative value to use the maximum number of available CPUs. [Default - process each BAM in serial]
+    inputBinding:
+      prefix: --processes 
+
+  rlibpath:
+    type: ["null", str]
+    description: Path to an alternative site-library to use for R packages.
+    inputBinding:
+      prefix: --rlibpath 
+
+  normal:
+    type:
+    - "null"
+    - type: array
+      items: string
+  
+    description: Normal samples (.bam) to construct the pooled reference. If this option is used but no files are given, a "flat" reference will be built.
+    inputBinding:
+      prefix: --normal 
+
+  fasta:
+    type: ["null", str]
+    description: Reference genome, FASTA format (e.g. UCSC hg19.fa)
+    inputBinding:
+      prefix: --fasta 
+
+  targets:
+    type: ["null", str]
+    description: Target intervals (.bed or .list)
+    inputBinding:
+      prefix: --targets 
+
+  antitargets:
+    type: ["null", str]
+    description: Antitarget intervals (.bed or .list)
+    inputBinding:
+      prefix: --antitargets 
+
+  annotate:
+    type: ["null", str]
+    description: UCSC refFlat.txt or ensFlat.txt file for the reference genome. Pull gene names from this file and assign them to the target regions.
+    inputBinding:
+      prefix: --annotate 
+
+  short_names:
+    type: ["null", boolean]
+    default: False
+    description: Reduce multi-accession bait labels to be short and consistent.
+    inputBinding:
+      prefix: --short-names 
+
+  split:
+    type: ["null", boolean]
+    default: False
+    description: Split large tiled intervals into smaller, consecutive targets.
+    inputBinding:
+      prefix: --split 
+
+  target_avg_size:
+    type: ["null", int]
+    description: Average size of split target bins (results are approximate).
+    inputBinding:
+      prefix: --target-avg-size 
+
+  access:
+    type: ["null", str]
+    description: Regions of accessible sequence on chromosomes (.bed), as output by the 'access' command.
+    inputBinding:
+      prefix: --access 
+
+  antitarget_avg_size:
+    type: ["null", int]
+    description: Average size of antitarget bins (results are approximate).
+    inputBinding:
+      prefix: --antitarget-avg-size 
+
+  antitarget_min_size:
+    type: ["null", int]
+    description: Minimum size of antitarget bins (smaller regions are dropped).
+    inputBinding:
+      prefix: --antitarget-min-size 
+
+  output_reference:
+    type: ["null", str]
+    description: Output filename/path for the new reference file being created. (If given, ignores the -o/--output-dir option and will write the file to the given path. Otherwise, "reference.cnn" will be created in the current directory or specified output directory.) 
+    inputBinding:
+      prefix: --output-reference 
+
+  reference:
+    type: ["null", str]
+    description: Copy number reference file (.cnn).
+    inputBinding:
+      prefix: --reference 
+
+  output_dir:
+    type: ["null", str]
+    default: .
+    description: Output directory.
+    inputBinding:
+      prefix: --output-dir 
+
+  scatter:
+    type: ["null", boolean]
+    default: False
+    description: Create a whole-genome copy ratio profile as a PDF scatter plot.
+    inputBinding:
+      prefix: --scatter 
+
+  diagram:
+    type: ["null", boolean]
+    default: False
+    description: Create a diagram of copy ratios on chromosomes as a PDF.
+    inputBinding:
+      prefix: --diagram 
+
+
+outputs:
+
+  output_reference_out:
+    type: File
+  
+    description: Output filename/path for the new reference file being created. (If given, ignores the -o/--output-dir option and will write the file to the given path. Otherwise, "reference.cnn" will be created in the current directory or specified output directory.) 
+    outputBinding:
+      glob: $(inputs.output_reference.path)
+
+  output_dir_out:
+    type: File
+    default: . 
+    description: Output directory.
+    outputBinding:
+      glob: $(inputs.output_dir.path)
diff --git a/examples/argparse/cnvkit-tools/cnvkit-breaks.cwl b/examples/argparse/cnvkit-tools/cnvkit-breaks.cwl
new file mode 100644
index 0000000..dec12f6
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-breaks.cwl
@@ -0,0 +1,45 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'breaks']
+
+description: |
+  List the targeted genes in which a copy number breakpoint occurs.
+
+inputs:
+  
+  filename:
+    type: string
+  
+    description: Processed sample coverage data file (*.cnr), the output of the 'fix' sub-command.
+    inputBinding:
+      position: 1
+
+  segment:
+    type: string
+  
+    description: Segmentation calls (.cns), the output of the 'segment' command).
+    inputBinding:
+      position: 2
+
+  min_probes:
+    type: ["null", int]
+    default: 1
+    description: Minimum number of within-gene probes on both sides of a breakpoint to report it. [Default - %(default)d]
+    inputBinding:
+      prefix: --min-probes 
+
+  output:
+    type: ["null", string]
+    description: Output table file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-call.cwl b/examples/argparse/cnvkit-tools/cnvkit-call.cwl
new file mode 100644
index 0000000..395eee7
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-call.cwl
@@ -0,0 +1,85 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'call']
+
+description: |
+  Call copy number variants from segmented log2 ratios.
+
+inputs:
+  
+  filename:
+    type: string
+  
+    description: Copy ratios (.cnr or .cns).
+    inputBinding:
+      position: 1
+
+  center:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['mean', 'median', 'mode', 'biweight']
+    description: Re-center the log2 ratio values using this estimate of the center or average value.
+    inputBinding:
+      prefix: --center 
+
+  method:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['threshold', 'clonal', 'none']
+    default: threshold
+    description: Calling method. [Default - %(default)s]
+    inputBinding:
+      prefix: --method 
+
+  ploidy:
+    type: ["null", int]
+    default: 2
+    description: Ploidy of the sample cells. [Default - %(default)d]
+    inputBinding:
+      prefix: --ploidy 
+
+  purity:
+    type: ["null", float]
+    description: Estimated tumor cell fraction, a.k.a. purity or cellularity.
+    inputBinding:
+      prefix: --purity 
+
+  vcf:
+    type: ["null", string]
+    description: VCF file name containing variants for assigning allele frequencies and copy number.
+    inputBinding:
+      prefix: --vcf 
+
+  gender:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['m', 'male', 'Male', 'f', 'female', 'Female']
+    description: Specify the sample's gender as male or female. (Otherwise guessed from chrX copy number).
+    inputBinding:
+      prefix: --gender 
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Was a male reference used? If so, expect half ploidy on chrX and chrY; otherwise, only chrY has half ploidy. In CNVkit, if a male reference was used, the "neutral" copy number (ploidy) of chrX is 1; chrY is haploid for either gender reference.
+    inputBinding:
+      prefix: --male-reference 
+
+  output:
+    type: ["null", string]
+    description: Output table file name (CNR-like table of segments, .cns).
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-coverage.cwl b/examples/argparse/cnvkit-tools/cnvkit-coverage.cwl
new file mode 100644
index 0000000..2dde7aa
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-coverage.cwl
@@ -0,0 +1,52 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'coverage']
+
+description: |
+  Calculate coverage in the given regions from BAM read depths.
+
+inputs:
+  
+  bam_file:
+    type: string
+  
+    description: Mapped sequence reads (.bam)
+    inputBinding:
+      position: 1
+
+  interval:
+    type: string
+  
+    description: Intervals (.bed or .list)
+    inputBinding:
+      position: 2
+
+  count:
+    type: ["null", boolean]
+    default: False
+    description: Get read depths by counting read midpoints within each bin. (An alternative algorithm).
+    inputBinding:
+      prefix: --count 
+
+  min_mapq:
+    type: ["null", int]
+    default: 0
+    description: Minimum mapping quality score (phred scale 0-60) to count a read for coverage depth. [Default - %(default)s]
+    inputBinding:
+      prefix: --min-mapq 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-diagram.cwl b/examples/argparse/cnvkit-tools/cnvkit-diagram.cwl
new file mode 100644
index 0000000..84f796c
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-diagram.cwl
@@ -0,0 +1,61 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'diagram']
+
+description: |
+  Draw copy number (log2 coverages, CBS calls) on chromosomes as a diagram.
+  
+      If both the raw probes and segments are given, show them side-by-side on
+      each chromosome (segments on the left side, probes on the right side).
+      
+
+inputs:
+  
+  filename:
+    type: ["null", string]
+    description: Processed coverage data file (*.cnr), the output of the 'fix' sub-command.
+    inputBinding:
+      position: 1
+
+  segment:
+    type: ["null", string]
+    description: Segmentation calls (.cns), the output of the 'segment' command.
+    inputBinding:
+      prefix: --segment 
+
+  threshold:
+    type: ["null", float]
+    default: 0.5
+    description: Copy number change threshold to label genes. [Default - %(default)s]
+    inputBinding:
+      prefix: --threshold 
+
+  min_probes:
+    type: ["null", int]
+    default: 3
+    description: Minimum number of covered probes to label a gene. [Default - %(default)d]
+    inputBinding:
+      prefix: --min-probes 
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Assume inputs are already corrected against a male reference (i.e. female samples will have +1 log-CNR of chrX; otherwise male samples would have -1 chrX).
+    inputBinding:
+      prefix: --male-reference 
+
+  output:
+    type: ["null", string]
+    description: Output PDF file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-export-bed.cwl b/examples/argparse/cnvkit-tools/cnvkit-export-bed.cwl
new file mode 100644
index 0000000..e51f479
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-export-bed.cwl
@@ -0,0 +1,83 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'export', 'bed']
+
+description: |
+  Convert segments to BED format.
+  
+      Input is a segmentation file (.cns) where, preferably, log2 ratios have
+      already been adjusted to integer absolute values using the 'call' command.
+      
+
+inputs:
+  
+  segments:
+    type:
+      type: array
+      items: string
+  
+    description: Segmented copy ratio data files (*.cns), the output of the 'segment' or 'call' sub-commands.
+    inputBinding:
+      position: 1
+
+  sample_id:
+    type: ["null", string]
+    description: Identifier to write in the 4th column of the BED file. [Default - use the sample ID, taken from the file name]
+    inputBinding:
+      prefix: --sample-id 
+
+  ploidy:
+    type: ["null", int]
+    default: 2
+    description: Ploidy of the sample cells. [Default - %(default)d]
+    inputBinding:
+      prefix: --ploidy 
+
+  gender:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['m', 'male', 'Male', 'f', 'female', 'Female']
+    description: Specify the sample's gender as male or female. (Otherwise guessed from chrX copy number).
+    inputBinding:
+      prefix: --gender 
+
+  show:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['ploidy', 'variant', 'all']
+    default: ploidy
+    description: Which segmented regions to show - 'all' = all segment regions; 'variant' = CNA regions with non-neutral copy number; 'ploidy' = CNA regions with non-default ploidy. [Default - %(default)s]
+    inputBinding:
+      prefix: --show 
+
+  show_all:
+    type: ["null", boolean]
+    default: False
+    description: Write all segmented regions. [DEPRECATED; use "--show all" instead]
+    inputBinding:
+      prefix: --show-all 
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Was a male reference used? If so, expect half ploidy on chrX and chrY; otherwise, only chrY has half ploidy. In CNVkit, if a male reference was used, the "neutral" copy number (ploidy) of chrX is 1; chrY is haploid for either gender reference.
+    inputBinding:
+      prefix: --male-reference 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-export-cdt.cwl b/examples/argparse/cnvkit-tools/cnvkit-export-cdt.cwl
new file mode 100644
index 0000000..0474848
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-export-cdt.cwl
@@ -0,0 +1,33 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'export', 'cdt']
+
+description: |
+  Convert log2 ratios to CDT format. Compatible with Java TreeView.
+
+inputs:
+  
+  filenames:
+    type:
+      type: array
+      items: string
+  
+    description: Log2 copy ratio data file(s) (*.cnr), the output of the 'fix' sub-command.
+    inputBinding:
+      position: 1
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-export-jtv.cwl b/examples/argparse/cnvkit-tools/cnvkit-export-jtv.cwl
new file mode 100644
index 0000000..553a713
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-export-jtv.cwl
@@ -0,0 +1,33 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'export', 'jtv']
+
+description: |
+  Convert log2 ratios to Java TreeView's native format.
+
+inputs:
+  
+  filenames:
+    type:
+      type: array
+      items: string
+  
+    description: Log2 copy ratio data file(s) (*.cnr), the output of the 'fix' sub-command.
+    inputBinding:
+      position: 1
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-export-nexus-basic.cwl b/examples/argparse/cnvkit-tools/cnvkit-export-nexus-basic.cwl
new file mode 100644
index 0000000..2bf12b5
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-export-nexus-basic.cwl
@@ -0,0 +1,31 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'export', 'nexus-basic']
+
+description: |
+  Convert bin-level log2 ratios to Nexus Copy Number "basic" format.
+
+inputs:
+  
+  filename:
+    type: string
+  
+    description: Log2 copy ratio data file (*.cnr), the output of the 'fix' sub-command.
+    inputBinding:
+      position: 1
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-export-nexus-ogt.cwl b/examples/argparse/cnvkit-tools/cnvkit-export-nexus-ogt.cwl
new file mode 100644
index 0000000..830a510
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-export-nexus-ogt.cwl
@@ -0,0 +1,58 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'export', 'nexus-ogt']
+
+description: |
+  Convert log2 ratios and b-allele freqs to Nexus "Custom-OGT" format.
+
+inputs:
+  
+  filename:
+    type: string
+  
+    description: Log2 copy ratio data file (*.cnr), the output of the 'fix' sub-command.
+    inputBinding:
+      position: 1
+
+  vcf:
+    type: string
+  
+    description: VCF of SNVs for the same sample, to calculate b-allele frequencies.
+    inputBinding:
+      position: 2
+
+  sample_id:
+    type: ["null", string]
+    description: Specify the name of the sample in the VCF to use to extract b-allele frequencies.
+    inputBinding:
+      prefix: --sample-id 
+
+  min_variant_depth:
+    type: ["null", int]
+    default: 20
+    description: Minimum read depth for a SNV to be included in the b-allele frequency calculation. [Default - %(default)s]
+    inputBinding:
+      prefix: --min-variant-depth 
+
+  min_weight:
+    type: ["null", float]
+    default: 0.0
+    description: Minimum weight (between 0 and 1) for a bin to be included in the output. [Default - %(default)s]
+    inputBinding:
+      prefix: --min-weight 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-export-seg.cwl b/examples/argparse/cnvkit-tools/cnvkit-export-seg.cwl
new file mode 100644
index 0000000..6bd4ef2
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-export-seg.cwl
@@ -0,0 +1,36 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'export', 'seg']
+
+description: |
+  Convert segments to SEG format.
+  
+      Compatible with IGV and GenePattern.
+      
+
+inputs:
+  
+  filenames:
+    type:
+      type: array
+      items: string
+  
+    description: Segmented copy ratio data file(s) (*.cns), the output of the 'segment' sub-command.
+    inputBinding:
+      position: 1
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-export-theta.cwl b/examples/argparse/cnvkit-tools/cnvkit-export-theta.cwl
new file mode 100644
index 0000000..6a3f27b
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-export-theta.cwl
@@ -0,0 +1,68 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'export', 'theta']
+
+description: |
+  Convert segments to THetA2 input file format (*.input).
+
+inputs:
+  
+  tumor_segment:
+    type: string
+  
+    description: Tumor-sample segmentation file from CNVkit (.cns).
+    inputBinding:
+      position: 1
+
+  normal_reference:
+    type: ["null", string]
+    description: Reference copy number profile (.cnn), or normal-sample bin-level log2 copy ratios (.cnr). [DEPRECATED]
+    inputBinding:
+      position: 2
+
+  reference:
+    type: ["null", string]
+    description: Reference copy number profile (.cnn), or normal-sample bin-level log2 copy ratios (.cnr). Use if the tumor_segment input file does not contain a "weight" column.
+    inputBinding:
+      prefix: --reference 
+
+  vcf:
+    type: ["null", string]
+    description: VCF file containing SNVs observed in both the tumor and normal samples. Tumor sample ID should match the `tumor_segment` filename or be specified with -i/--sample-id.
+    inputBinding:
+      prefix: --vcf 
+
+  sample_id:
+    type: ["null", string]
+    description: Specify the name of the tumor sample in the VCF (given with -v/--vcf). [Default - taken the tumor_segment file name]
+    inputBinding:
+      prefix: --sample-id 
+
+  normal_id:
+    type: ["null", string]
+    description: Corresponding normal sample ID in the input VCF.
+    inputBinding:
+      prefix: --normal-id 
+
+  min_depth:
+    type: ["null", int]
+    default: 20
+    description: Minimum read depth for a SNP in the VCF to be counted. [Default - %(default)s]
+    inputBinding:
+      prefix: --min-depth 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-export-vcf.cwl b/examples/argparse/cnvkit-tools/cnvkit-export-vcf.cwl
new file mode 100644
index 0000000..9b6367e
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-export-vcf.cwl
@@ -0,0 +1,64 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'export', 'vcf']
+
+description: |
+  Convert segments to VCF format.
+  
+      Input is a segmentation file (.cns) where, preferably, log2 ratios have
+      already been adjusted to integer absolute values using the 'call' command.
+      
+
+inputs:
+  
+  segments:
+    type: string
+  
+    description: Segmented copy ratio data file (*.cns), the output of the 'segment' or 'call' sub-commands.
+    inputBinding:
+      position: 1
+
+  sample_id:
+    type: ["null", string]
+    description: Sample name to write in the genotype field of the output VCF file. [Default - use the sample ID, taken from the file name]
+    inputBinding:
+      prefix: --sample-id 
+
+  ploidy:
+    type: ["null", int]
+    default: 2
+    description: Ploidy of the sample cells. [Default - %(default)d]
+    inputBinding:
+      prefix: --ploidy 
+
+  gender:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['m', 'male', 'Male', 'f', 'female', 'Female']
+    description: Specify the sample's gender as male or female. (Otherwise guessed from chrX copy number).
+    inputBinding:
+      prefix: --gender 
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Was a male reference used? If so, expect half ploidy on chrX and chrY; otherwise, only chrY has half ploidy. In CNVkit, if a male reference was used, the "neutral" copy number (ploidy) of chrX is 1; chrY is haploid for either gender reference.
+    inputBinding:
+      prefix: --male-reference 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-fix.cwl b/examples/argparse/cnvkit-tools/cnvkit-fix.cwl
new file mode 100644
index 0000000..0c53e86
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-fix.cwl
@@ -0,0 +1,70 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'fix']
+
+description: |
+  Combine target and antitarget coverages and correct for biases.
+  
+      Adjust raw coverage data according to the given reference, correct potential
+      biases and re-center.
+      
+
+inputs:
+  
+  target:
+    type: string
+  
+    description: Target coverage file (.targetcoverage.cnn).
+    inputBinding:
+      position: 1
+
+  antitarget:
+    type: string
+  
+    description: Antitarget coverage file (.antitargetcoverage.cnn).
+    inputBinding:
+      position: 2
+
+  reference:
+    type: string
+  
+    description: Reference coverage (.cnn).
+    inputBinding:
+      position: 3
+
+  do_gc:
+    type: ["null", boolean]
+    default: True
+    description: Skip GC correction.
+    inputBinding:
+      prefix: --no-gc 
+
+  do_edge:
+    type: ["null", boolean]
+    default: True
+    description: Skip edge-effect correction.
+    inputBinding:
+      prefix: --no-edge 
+
+  do_rmask:
+    type: ["null", boolean]
+    default: True
+    description: Skip RepeatMasker correction.
+    inputBinding:
+      prefix: --no-rmask 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-gainloss.cwl b/examples/argparse/cnvkit-tools/cnvkit-gainloss.cwl
new file mode 100644
index 0000000..6542c5d
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-gainloss.cwl
@@ -0,0 +1,65 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'gainloss']
+
+description: |
+  Identify targeted genes with copy number gain or loss.
+
+inputs:
+  
+  filename:
+    type: string
+  
+    description: Processed sample coverage data file (*.cnr), the output of the 'fix' sub-command.
+    inputBinding:
+      position: 1
+
+  segment:
+    type: ["null", string]
+    description: Segmentation calls (.cns), the output of the 'segment' command).
+    inputBinding:
+      prefix: --segment 
+
+  threshold:
+    type: ["null", float]
+    default: 0.2
+    description: Copy number change threshold to report a gene gain/loss. [Default - %(default)s]
+    inputBinding:
+      prefix: --threshold 
+
+  min_probes:
+    type: ["null", int]
+    default: 3
+    description: Minimum number of covered probes to report a gain/loss. [Default - %(default)d]
+    inputBinding:
+      prefix: --min-probes 
+
+  drop_low_coverage:
+    type: ["null", boolean]
+    default: False
+    description: Drop very-low-coverage bins before segmentation to avoid false-positive deletions in poor-quality tumor samples.
+    inputBinding:
+      prefix: --drop-low-coverage 
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Assume inputs are already corrected against a male reference (i.e. female samples will have +1 log-coverage of chrX; otherwise male samples would have -1 chrX).
+    inputBinding:
+      prefix: --male-reference 
+
+  output:
+    type: ["null", string]
+    description: Output table file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-gender.cwl b/examples/argparse/cnvkit-tools/cnvkit-gender.cwl
new file mode 100644
index 0000000..af91b5e
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-gender.cwl
@@ -0,0 +1,40 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'gender']
+
+description: |
+  Guess samples' gender from the relative coverage of chromosome X.
+
+inputs:
+  
+  targets:
+    type:
+      type: array
+      items: string
+  
+    description: Copy number or copy ratio files (*.cnn, *.cnr).
+    inputBinding:
+      position: 1
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Assume inputs are already normalized to a male reference (i.e. female samples will have +1 log-coverage of chrX; otherwise male samples would have -1 chrX).
+    inputBinding:
+      prefix: --male-reference 
+
+  output:
+    type: ["null", string]
+    description: Output table file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-heatmap.cwl b/examples/argparse/cnvkit-tools/cnvkit-heatmap.cwl
new file mode 100644
index 0000000..3d93b03
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-heatmap.cwl
@@ -0,0 +1,46 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'heatmap']
+
+description: |
+  Plot copy number for multiple samples as a heatmap.
+
+inputs:
+  
+  filenames:
+    type:
+      type: array
+      items: string
+  
+    description: Sample coverages as raw probes (.cnr) or segments (.cns).
+    inputBinding:
+      position: 1
+
+  chromosome:
+    type: ["null", string]
+    description: Chromosome (e.g. 'chr1') or chromosomal range (e.g. 'chr1 -2333000-2444000') to display. If a range is given, all targeted genes in this range will be shown, unless '--gene'/'-g' is already given.
+    inputBinding:
+      prefix: --chromosome 
+
+  desaturate:
+    type: ["null", boolean]
+    default: False
+    description: Tweak color saturation to focus on significant changes.
+    inputBinding:
+      prefix: --desaturate 
+
+  output:
+    type: ["null", string]
+    description: Output PDF file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-import-picard.cwl b/examples/argparse/cnvkit-tools/cnvkit-import-picard.cwl
new file mode 100644
index 0000000..407cc8e
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-import-picard.cwl
@@ -0,0 +1,40 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'import-picard']
+
+description: |
+  Convert Picard CalculateHsMetrics tabular output to CNVkit .cnn files.
+  
+      The input file is generated by the PER_TARGET_COVERAGE option in the
+      CalculateHsMetrics script in Picard tools.
+      
+
+inputs:
+  
+  targets:
+    type:
+    - "null"
+    - type: array
+      items: string
+  
+    default: ['.']
+    description: Sample coverage .csv files (target and antitarget), or the directory that contains them.
+    inputBinding:
+      position: 1
+
+  output_dir:
+    type: ["null", string]
+    default: .
+    description: Output directory name.
+    inputBinding:
+      prefix: --output-dir 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-import-seg.cwl b/examples/argparse/cnvkit-tools/cnvkit-import-seg.cwl
new file mode 100644
index 0000000..38448d9
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-import-seg.cwl
@@ -0,0 +1,51 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'import-seg']
+
+description: |
+  Convert a SEG file to CNVkit .cns files.
+
+inputs:
+  
+  segfile:
+    type: string
+  
+    description: Input file in SEG format. May contain multiple samples.
+    inputBinding:
+      position: 1
+
+  chromosomes:
+    type: ["null", string]
+    description: Mapping of chromosome indexes to names. Syntax - "from1 -to1,from2 -to2". Or use "human" for the preset - "23 -X,24 -Y,25 -M".
+    inputBinding:
+      prefix: --chromosomes 
+
+  prefix:
+    type: ["null", string]
+    description: Prefix to add to chromosome names (e.g 'chr' to rename '8' in the SEG file to 'chr8' in the output).
+    inputBinding:
+      prefix: --prefix 
+
+  from_log10:
+    type: ["null", boolean]
+    default: False
+    description: Convert base-10 logarithm values in the input to base-2 logs.
+    inputBinding:
+      prefix: --from-log10 
+
+  output_dir:
+    type: ["null", string]
+    default: .
+    description: Output directory name.
+    inputBinding:
+      prefix: --output-dir 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-import-theta.cwl b/examples/argparse/cnvkit-tools/cnvkit-import-theta.cwl
new file mode 100644
index 0000000..6d64100
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-import-theta.cwl
@@ -0,0 +1,50 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'import-theta']
+
+description: |
+  Convert THetA output to a BED-like, CNVkit-like tabular format.
+  
+      Equivalently, use the THetA results file to convert CNVkit .cns segments to
+      integer copy number calls.
+      
+
+inputs:
+  
+  tumor_cns:
+    type: string
+  
+  
+    inputBinding:
+      position: 1
+
+  theta_results:
+    type: string
+  
+  
+    inputBinding:
+      position: 2
+
+  ploidy:
+    type: ["null", int]
+    default: 2
+    description: Ploidy of normal cells. [Default - %(default)d]
+    inputBinding:
+      prefix: --ploidy 
+
+  output_dir:
+    type: ["null", string]
+    default: .
+    description: Output directory name.
+    inputBinding:
+      prefix: --output-dir 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-loh.cwl b/examples/argparse/cnvkit-tools/cnvkit-loh.cwl
new file mode 100644
index 0000000..eda7f2f
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-loh.cwl
@@ -0,0 +1,68 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'loh']
+
+description: |
+  [DEPRECATED] Plot allelic frequencies at each variant position in a VCF file.
+  
+      Divergence from 0.5 indicates loss of heterozygosity in a tumor sample.
+  
+      Instead, use the command "scatter -v".
+      
+
+inputs:
+  
+  variants:
+    type: string
+  
+    description: Sample variants in VCF format.
+    inputBinding:
+      position: 1
+
+  segment:
+    type: ["null", string]
+    description: Segmentation calls (.cns), the output of the 'segment' command.
+    inputBinding:
+      prefix: --segment 
+
+  min_depth:
+    type: ["null", int]
+    default: 20
+    description: Minimum read depth for a variant to be displayed. [Default - %(default)s]
+    inputBinding:
+      prefix: --min-depth 
+
+  sample_id:
+    type: ["null", string]
+    description: Sample name to use for LOH calculations from the input VCF.
+    inputBinding:
+      prefix: --sample-id 
+
+  normal_id:
+    type: ["null", string]
+    description: Corresponding normal sample ID in the input VCF.
+    inputBinding:
+      prefix: --normal-id 
+
+  trend:
+    type: ["null", boolean]
+    default: False
+    description: Draw a smoothed local trendline on the scatter plot.
+    inputBinding:
+      prefix: --trend 
+
+  output:
+    type: ["null", string]
+    description: Output PDF file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-metrics.cwl b/examples/argparse/cnvkit-tools/cnvkit-metrics.cwl
new file mode 100644
index 0000000..71e1ebb
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-metrics.cwl
@@ -0,0 +1,43 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'metrics']
+
+description: |
+  Compute coverage deviations and other metrics for self-evaluation.
+      
+
+inputs:
+  
+  cnarrays:
+    type:
+      type: array
+      items: string
+  
+    description: One or more bin-level coverage data files (*.cnn, *.cnr).
+    inputBinding:
+      position: 1
+
+  segments:
+    type:
+      type: array
+      items: string
+  
+    description: One or more segmentation data files (*.cns, output of the 'segment' command). If more than one file is given, the number must match the coverage data files, in which case the input files will be paired together in the given order. Otherwise, the same segments will be used for all coverage files.
+    inputBinding:
+      prefix: --segments 
+
+  output:
+    type: ["null", string]
+    description: Output table file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-reference.cwl b/examples/argparse/cnvkit-tools/cnvkit-reference.cwl
new file mode 100644
index 0000000..3c7978f
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-reference.cwl
@@ -0,0 +1,80 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'reference']
+
+description: |
+  Compile a coverage reference from the given files (normal samples).
+
+inputs:
+  
+  references:
+    type:
+    - "null"
+    - type: array
+      items: string
+  
+    description: Normal-sample target or antitarget .cnn files, or the directory that contains them.
+    inputBinding:
+      position: 1
+
+  fasta:
+    type: ["null", string]
+    description: Reference genome, FASTA format (e.g. UCSC hg19.fa)
+    inputBinding:
+      prefix: --fasta 
+
+  targets:
+    type: ["null", string]
+    description: Target intervals (.bed or .list)
+    inputBinding:
+      prefix: --targets 
+
+  antitargets:
+    type: ["null", string]
+    description: Antitarget intervals (.bed or .list)
+    inputBinding:
+      prefix: --antitargets 
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Create a male reference - shift female samples' chrX log-coverage by -1, so the reference chrX average is -1. Otherwise, shift male samples' chrX by +1, so the reference chrX average is 0.
+    inputBinding:
+      prefix: --male-reference 
+
+  do_gc:
+    type: ["null", boolean]
+    default: True
+    description: Skip GC correction.
+    inputBinding:
+      prefix: --no-gc 
+
+  do_edge:
+    type: ["null", boolean]
+    default: True
+    description: Skip edge-effect correction.
+    inputBinding:
+      prefix: --no-edge 
+
+  do_rmask:
+    type: ["null", boolean]
+    default: True
+    description: Skip RepeatMasker correction.
+    inputBinding:
+      prefix: --no-rmask 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-rescale.cwl b/examples/argparse/cnvkit-tools/cnvkit-rescale.cwl
new file mode 100644
index 0000000..3a5d853
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-rescale.cwl
@@ -0,0 +1,72 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'rescale']
+
+description: |
+  [DEPRECATED] Rescale segment copy ratios given known purity and ploidy.
+  
+      Instead, use the command "call -m none".
+      
+
+inputs:
+  
+  filename:
+    type: string
+  
+    description: Copy ratios (.cnr or .cns).
+    inputBinding:
+      position: 1
+
+  center:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['mean', 'median', 'mode', 'biweight']
+    description: Re-center the log2 ratio values using this estimate of the center or average value.
+    inputBinding:
+      prefix: --center 
+
+  ploidy:
+    type: ["null", int]
+    default: 2
+    description: Ploidy of the sample cells. [Default - %(default)d]
+    inputBinding:
+      prefix: --ploidy 
+
+  purity:
+    type: ["null", float]
+    description: Estimated tumor cell fraction, a.k.a. purity or cellularity.
+    inputBinding:
+      prefix: --purity 
+
+  gender:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['m', 'male', 'Male', 'f', 'female', 'Female']
+    description: Specify the sample's gender as male or female. (Otherwise guessed from chrX copy number).
+    inputBinding:
+      prefix: --gender 
+
+  male_reference:
+    type: ["null", boolean]
+    default: False
+    description: Was a male reference used? If so, expect half ploidy on chrX and chrY; otherwise, only chrY has half ploidy. In CNVkit, if a male reference was used, the "neutral" copy number (ploidy) of chrX is 1; chrY is haploid for either gender reference.
+    inputBinding:
+      prefix: --male-reference 
+
+  output:
+    type: ["null", string]
+    description: Output table file name (CNR-like table of segments, .cns).
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-scatter.cwl b/examples/argparse/cnvkit-tools/cnvkit-scatter.cwl
new file mode 100644
index 0000000..ee3105a
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-scatter.cwl
@@ -0,0 +1,111 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'scatter']
+
+description: |
+  Plot probe log2 coverages and segmentation calls together.
+
+inputs:
+  
+  filename:
+    type: ["null", string]
+    description: Processed bin-level copy ratios (*.cnr), the output of the 'fix' sub-command.
+    inputBinding:
+      position: 1
+
+  segment:
+    type: ["null", string]
+    description: Segmentation calls (.cns), the output of the 'segment' command.
+    inputBinding:
+      prefix: --segment 
+
+  chromosome:
+    type: ["null", string]
+    description: Chromosome (e.g. 'chr1') or chromosomal range (e.g. 'chr1 -2333000-2444000') to display. If a range is given, all targeted genes in this range will be shown, unless '--gene'/'-g' is already given.
+    inputBinding:
+      prefix: --chromosome 
+
+  gene:
+    type: ["null", string]
+    description: Name of gene or genes (comma-separated) to display.
+    inputBinding:
+      prefix: --gene 
+
+  range_list:
+    type: ["null", string]
+    description: File listing the chromosomal ranges to display, as BED, interval list or "chr -start-end" text. Creates focal plots similar to -c/--chromosome for each listed region, combined into a multi-page PDF. The output filename must also be specified (-o/--output).
+    inputBinding:
+      prefix: --range-list 
+
+  sample_id:
+    type: ["null", string]
+    description: Specify the name of the sample in the VCF to use for b-allele frequency extraction and to show in plot title.
+    inputBinding:
+      prefix: --sample-id 
+
+  normal_id:
+    type: ["null", string]
+    description: Corresponding normal sample ID in the input VCF.
+    inputBinding:
+      prefix: --normal-id 
+
+  background_marker:
+    type: ["null", string]
+    description: Plot antitargets with this symbol, in zoomed/selected regions. [Default - same as targets]
+    inputBinding:
+      prefix: --background-marker 
+
+  trend:
+    type: ["null", boolean]
+    default: False
+    description: Draw a smoothed local trendline on the scatter plot.
+    inputBinding:
+      prefix: --trend 
+
+  vcf:
+    type: ["null", string]
+    description: VCF file name containing variants to plot for SNV allele frequencies.
+    inputBinding:
+      prefix: --vcf 
+
+  min_variant_depth:
+    type: ["null", int]
+    default: 20
+    description: Minimum read depth for a SNV to be displayed in the b-allele frequency plot. [Default - %(default)s]
+    inputBinding:
+      prefix: --min-variant-depth 
+
+  width:
+    type: ["null", float]
+    default: 1000000.0
+    description: Width of margin to show around the selected gene or region on the chromosome (use with --gene or --region). [Default - %(default)d]
+    inputBinding:
+      prefix: --width 
+
+  y_min:
+    type: ["null", float]
+    description: y-axis lower limit.
+    inputBinding:
+      prefix: --y-min 
+
+  y_max:
+    type: ["null", float]
+    description: y-axis upper limit.
+    inputBinding:
+      prefix: --y-max 
+
+  output:
+    type: ["null", string]
+    description: Output table file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-segment.cwl b/examples/argparse/cnvkit-tools/cnvkit-segment.cwl
new file mode 100644
index 0000000..334deee
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-segment.cwl
@@ -0,0 +1,79 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'segment']
+
+description: |
+  Infer copy number segments from the given coverage table.
+
+inputs:
+  
+  filename:
+    type: string
+  
+    description: Bin-level log2 ratios (.cnr file), as produced by 'fix'.
+    inputBinding:
+      position: 1
+
+  output:
+    type: ["null", string]
+    description: Output table file name (CNR-like table of segments, .cns).
+    inputBinding:
+      prefix: --output 
+
+  dataframe:
+    type: ["null", string]
+    description: File name to save the raw R dataframe emitted by CBS or Fused Lasso. (Useful for debugging.)
+    inputBinding:
+      prefix: --dataframe 
+
+  method:
+    type:
+    - "null"
+    - type: enum
+      symbols: ['cbs', 'haar', 'flasso']
+    default: cbs
+    description: Segmentation method (CBS, HaarSeg, or Fused Lasso). [Default - %(default)s]
+    inputBinding:
+      prefix: --method 
+
+  threshold:
+    type: ["null", float]
+    description: Significance threshold (p-value or FDR, depending on method) to accept breakpoints during segmentation.
+    inputBinding:
+      prefix: --threshold 
+
+  vcf:
+    type: ["null", string]
+    description: VCF file name containing variants for segmentation by allele frequencies.
+    inputBinding:
+      prefix: --vcf 
+
+  drop_low_coverage:
+    type: ["null", boolean]
+    default: False
+    description: Drop very-low-coverage bins before segmentation to avoid false-positive deletions in poor-quality tumor samples.
+    inputBinding:
+      prefix: --drop-low-coverage 
+
+  drop_outliers:
+    type: ["null", float]
+    default: 10
+    description: Drop outlier bins more than this many multiples of the 95th quantile away from the average within a rolling window. Set to 0 for no outlier filtering. [Default - %(default)g]
+    inputBinding:
+      prefix: --drop-outliers 
+
+  rlibpath:
+    type: ["null", string]
+    description: Path to an alternative site-library to use for R packages.
+    inputBinding:
+      prefix: --rlibpath 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-segmetrics.cwl b/examples/argparse/cnvkit-tools/cnvkit-segmetrics.cwl
new file mode 100644
index 0000000..58b1c96
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-segmetrics.cwl
@@ -0,0 +1,101 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'segmetrics']
+
+description: |
+  Compute segment-level metrics from bin-level log2 ratios.
+
+inputs:
+  
+  cnarray:
+    type: string
+  
+    description: Bin-level copy ratio data file (*.cnn, *.cnr).
+    inputBinding:
+      position: 1
+
+  segments:
+    type: string
+  
+    description: Segmentation data file (*.cns, output of the 'segment' command).
+    inputBinding:
+      prefix: --segments 
+
+  drop_low_coverage:
+    type: ["null", boolean]
+    default: False
+    description: Drop very-low-coverage bins before segmentation to avoid false-positive deletions in poor-quality tumor samples.
+    inputBinding:
+      prefix: --drop-low-coverage 
+
+  output:
+    type: ["null", string]
+    description: Output table file name.
+    inputBinding:
+      prefix: --output 
+
+  stdev:
+    type: ["null", boolean]
+    default: False
+    description: Standard deviation.
+    inputBinding:
+      prefix: --stdev 
+
+  mad:
+    type: ["null", boolean]
+    default: False
+    description: Median absolute deviation (standardized).
+    inputBinding:
+      prefix: --mad 
+
+  iqr:
+    type: ["null", boolean]
+    default: False
+    description: Inter-quartile range.
+    inputBinding:
+      prefix: --iqr 
+
+  bivar:
+    type: ["null", boolean]
+    default: False
+    description: Tukey's biweight midvariance.
+    inputBinding:
+      prefix: --bivar 
+
+  ci:
+    type: ["null", boolean]
+    default: False
+    description: Confidence interval (by bootstrap).
+    inputBinding:
+      prefix: --ci 
+
+  pi:
+    type: ["null", boolean]
+    default: False
+    description: Prediction interval.
+    inputBinding:
+      prefix: --pi 
+
+  alpha:
+    type: ["null", float]
+    default: 0.05
+    description: Level to estimate confidence and prediction intervals; use with --ci and --pi. [Default - %(default)s]
+    inputBinding:
+      prefix: --alpha 
+
+  bootstrap:
+    type: ["null", int]
+    default: 100
+    description: Number of bootstrap iterations to estimate confidence interval; use with --ci. [Default - %(default)d]
+    inputBinding:
+      prefix: --bootstrap 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-target.cwl b/examples/argparse/cnvkit-tools/cnvkit-target.cwl
new file mode 100644
index 0000000..56cccc4
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-target.cwl
@@ -0,0 +1,58 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'target']
+
+description: |
+  Transform bait intervals into targets more suitable for CNVkit.
+
+inputs:
+  
+  interval:
+    type: string
+  
+    description: BED or interval file listing the targeted regions.
+    inputBinding:
+      position: 1
+
+  annotate:
+    type: ["null", string]
+    description: UCSC refFlat.txt or ensFlat.txt file for the reference genome. Pull gene names from this file and assign them to the target regions.
+    inputBinding:
+      prefix: --annotate 
+
+  short_names:
+    type: ["null", boolean]
+    default: False
+    description: Reduce multi-accession bait labels to be short and consistent.
+    inputBinding:
+      prefix: --short-names 
+
+  split:
+    type: ["null", boolean]
+    default: False
+    description: Split large tiled intervals into smaller, consecutive targets.
+    inputBinding:
+      prefix: --split 
+
+  avg_size:
+    type: ["null", int]
+    default: 266.6666666666667
+    description: Average size of split target bins (results are approximate). [Default - %(default)s]
+    inputBinding:
+      prefix: --avg-size 
+
+  output:
+    type: ["null", string]
+    description: Output file name.
+    inputBinding:
+      prefix: --output 
+
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/cnvkit-version.cwl b/examples/argparse/cnvkit-tools/cnvkit-version.cwl
new file mode 100644
index 0000000..5f98b4e
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/cnvkit-version.cwl
@@ -0,0 +1,18 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.2.8
+# To generate again: $ cnvkit.py --generate_cwl_tool
+# Help: $ cnvkit.py --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['cnvkit.py', 'version']
+
+description: |
+  Display this program's version.
+
+inputs:
+  
+
+outputs:
+    []
diff --git a/examples/argparse/cnvkit-tools/data.json b/examples/argparse/cnvkit-tools/data.json
new file mode 100644
index 0000000..eea068a
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/data.json
@@ -0,0 +1,7 @@
+{
+ "file": {
+   "class": "File",
+    "path": "inp.txt"
+ },
+  "term":"here"
+}
\ No newline at end of file
diff --git a/examples/argparse/cnvkit-tools/genome2access.cwl b/examples/argparse/cnvkit-tools/genome2access.cwl
new file mode 100644
index 0000000..7853f3d
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/genome2access.cwl
@@ -0,0 +1,65 @@
+#!/usr/bin/env cwl-runner
+
+cwlVersion: "cwl:draft-3.dev2"
+
+class: CommandLineTool
+baseCommand: ["python"]
+
+requirements:
+  - class: InlineJavascriptRequirement
+
+description: |
+  List the locations of accessible sequence regions in a FASTA file.
+  
+  Inaccessible regions, e.g. telomeres and centromeres, are masked out with N in
+  the reference genome sequence; this script scans those to identify the
+  coordinates of the accessible regions (those between the long spans of N's).
+  
+  DEPRECATED -- use "cnvkit.py access" instead.
+  
+
+inputs:
+
+- id: fa_fname
+  type: string
+  description: Genome FASTA file name
+  inputBinding:
+    position: 1
+
+- id: min_gap_size
+  type: int
+  default: 5000
+  description: Minimum gap size between accessible sequence
+                regions.  Regions separated by less than this distance will
+                be joined together. [Default- %(default)s]
+  inputBinding:
+    position: 2
+
+- id: exclude
+  type: 
+    type: array
+    items: string
+  description: Additional regions to exclude, in BED format. Can be
+                used multiple times.
+  inputBinding:
+    position: 3
+
+- id: output
+  type: File
+  description: Output file name
+  inputBinding:
+    position: 4
+- id: genome2access.py
+  type: File
+  default:
+    class: File
+    path: genome2access.py
+  inputBinding:
+    position: 0
+
+outputs:
+- id: output_out
+  type: File
+  description: Output file name
+  outputBinding:
+    glob: $(inputs.output.path)
diff --git a/examples/argparse/cnvkit-tools/genome2access.py b/examples/argparse/cnvkit-tools/genome2access.py
new file mode 100644
index 0000000..193e769
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/genome2access.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+"""List the locations of accessible sequence regions in a FASTA file.
+
+Inaccessible regions, e.g. telomeres and centromeres, are masked out with N in
+the reference genome sequence; this script scans those to identify the
+coordinates of the accessible regions (those between the long spans of N's).
+
+DEPRECATED -- use "cnvkit.py access" instead.
+"""
+
+import argparse
+import sys
+
+import logging
+logging.basicConfig(level=logging.INFO, format="%(message)s")
+
+
+
+AP = argparse.ArgumentParser(description=__doc__)
+AP.add_argument("fa_fname",
+                help="Genome FASTA file name")
+AP.add_argument("-s", "--min-gap-size", type=int, default=5000,
+                help="""Minimum gap size between accessible sequence
+                regions.  Regions separated by less than this distance will
+                be joined together. [Default: %(default)s]""")
+AP.add_argument("-x", "--exclude", action="append", default=[],
+                help="""Additional regions to exclude, in BED format. Can be
+                used multiple times.""")
+AP.add_argument("-o", "--output",
+                type=argparse.FileType('w'), default=sys.stdout,
+                help="Output file name")
+args = AP.parse_args()
+
+# Closes over args.output
+def write_row(chrom, run_start, run_end):
+    args.output.write("%s\t%s\t%s\n" % (chrom, run_start, run_end))
+    args.output.flush()
+
+
diff --git a/examples/argparse/cnvkit-tools/output.txt b/examples/argparse/cnvkit-tools/output.txt
new file mode 100644
index 0000000..8728d3b
--- /dev/null
+++ b/examples/argparse/cnvkit-tools/output.txt
@@ -0,0 +1,7 @@
+outputs:
+- id: outfile
+  type: File
+  source: "#main/search/result"
+- id: indexedfile
+  type: File
+  source: "#main/index/result"
\ No newline at end of file
diff --git a/examples/click/genmod-tools/genmod-annotate.cwl b/examples/click/genmod-tools/genmod-annotate.cwl
new file mode 100644
index 0000000..86dfcb2
--- /dev/null
+++ b/examples/click/genmod-tools/genmod-annotate.cwl
@@ -0,0 +1,118 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.3.0
+# To generate again: $ genmod --generate_cwl_tool
+# Help: $ genmod --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['genmod', 'annotate']
+
+description: |
+  Annotate vcf variants.
+  
+  Annotate variants with a number of different sources.
+  Please use --help for more info.
+
+inputs:
+  
+  variant_file:
+    type: File
+  
+    description: <vcf_file> or -
+    inputBinding:
+      position: 1
+
+  annotate_regions:
+    type: ["null", boolean]
+    default: False
+    description: Increase output verbosity.
+    inputBinding:
+      prefix: --annotate_regions 
+
+  cadd_file:
+    type: ["null", string]
+    description: Specify the path to a bgzipped cadd file (with index) with variant scores. This command can be used multiple times if multiple cadd files.
+    inputBinding:
+      prefix: --cadd_file 
+
+  thousand_g:
+    type: ["null", string]
+    description: Specify the path to a bgzipped vcf file (with index) with 1000g variants
+    inputBinding:
+      prefix: --thousand_g 
+
+  exac:
+    type: ["null", string]
+    description: Specify the path to a bgzipped vcf file (with index) with exac variants.
+    inputBinding:
+      prefix: --exac 
+
+  cosmic:
+    type: ["null", string]
+    description: Specify the path to a bgzipped vcf file (with index) with COSMIC variants.
+    inputBinding:
+      prefix: --cosmic 
+
+  max_af:
+    type: ["null", boolean]
+    default: False
+    description: If the MAX AF should be annotated
+    inputBinding:
+      prefix: --max_af 
+
+  spidex:
+    type: ["null", string]
+    description: Specify the path to a bgzipped tsv file (with index) with spidex information.
+    inputBinding:
+      prefix: --spidex 
+
+  annotation_dir:
+    type: ["null", string]
+    default: /usr/local/lib/python2.7/dist-packages/genmod/annotations
+    description: Specify the path to the directory where the annotation databases are. Default is the gene pred files that comes with the distribution.
+    inputBinding:
+      prefix: --annotation_dir 
+
+  cadd_raw:
+    type: ["null", boolean]
+    default: False
+    description: If the raw cadd scores should be annotated.
+    inputBinding:
+      prefix: --cadd_raw 
+
+  processes:
+    type: ["null", int]
+    default: 4
+    description: Define how many processes that should be use for annotation.
+    inputBinding:
+      prefix: --processes 
+
+  outfile:
+    type: ["null", File]
+    description: Specify the path to a file where results should be stored.
+    inputBinding:
+      prefix: --outfile 
+
+  silent:
+    type: ["null", boolean]
+    default: False
+    description: Do not print the variants.
+    inputBinding:
+      prefix: --silent 
+
+  temp_dir:
+    type: ["null", string]
+    description: Path to tempdir
+    inputBinding:
+      prefix: --temp_dir 
+
+
+outputs:
+
+  outfile_out:
+    type: File
+  
+    description: Specify the path to a file where results should be stored.
+    outputBinding:
+      glob: $(inputs.outfile.path)
diff --git a/examples/click/genmod-tools/genmod-build.cwl b/examples/click/genmod-tools/genmod-build.cwl
new file mode 100644
index 0000000..d9e5551
--- /dev/null
+++ b/examples/click/genmod-tools/genmod-build.cwl
@@ -0,0 +1,61 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.3.0
+# To generate again: $ genmod --generate_cwl_tool
+# Help: $ genmod --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['genmod', 'build']
+
+description: |
+  Build a new annotation database
+  
+  Build an annotation database from an annotation file.
+
+inputs:
+  
+  annotation_file:
+    type: string
+  
+    description: ANNOTATION_FILE
+    inputBinding:
+      position: 1
+
+  outdir:
+    type: ["null", string]
+    description: Specify the path to a folder where the annotation files should be stored.
+    inputBinding:
+      prefix: --outdir 
+
+  annotation_type:
+    type:
+    - "null"
+    - type: enum
+      symbols: []
+    default: gene_pred
+    description: Specify the format of the annotation file.
+    inputBinding:
+      prefix: --annotation_type 
+
+  splice_padding:
+    type: ["null", int]
+    default: 2
+    description: Specify the the number of bases that the exons should be padded with. Default is 2 bases.
+    inputBinding:
+      prefix: --splice_padding 
+
+  verbose:
+    type:
+    - "null"
+    - type: array
+      items: string
+  
+    default: 0
+    description: Increase output verbosity.
+    inputBinding:
+      prefix: --verbose 
+
+
+outputs:
+    []
diff --git a/examples/click/genmod-tools/genmod-compound.cwl b/examples/click/genmod-tools/genmod-compound.cwl
new file mode 100644
index 0000000..e346afb
--- /dev/null
+++ b/examples/click/genmod-tools/genmod-compound.cwl
@@ -0,0 +1,64 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.3.0
+# To generate again: $ genmod --generate_cwl_tool
+# Help: $ genmod --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['genmod', 'compound']
+
+description: |
+  Score compound variants in a vcf file based on their rank score.
+
+inputs:
+  
+  variant_file:
+    type: File
+  
+    description: <vcf_file> or -
+    inputBinding:
+      position: 1
+
+  silent:
+    type: ["null", boolean]
+    default: False
+    description: Do not print the variants.
+    inputBinding:
+      prefix: --silent 
+
+  outfile:
+    type: ["null", File]
+    description: Specify the path to a file where results should be stored.
+    inputBinding:
+      prefix: --outfile 
+
+  processes:
+    type: ["null", int]
+    default: 4
+    description: Define how many processes that should be use for annotation.
+    inputBinding:
+      prefix: --processes 
+
+  temp_dir:
+    type: ["null", string]
+    description: Path to tempdir
+    inputBinding:
+      prefix: --temp_dir 
+
+  vep:
+    type: ["null", boolean]
+    default: False
+    description: If variants are annotated with the Variant Effect Predictor.
+    inputBinding:
+      prefix: --vep 
+
+
+outputs:
+
+  outfile_out:
+    type: File
+  
+    description: Specify the path to a file where results should be stored.
+    outputBinding:
+      glob: $(inputs.outfile.path)
diff --git a/examples/click/genmod-tools/genmod-filter.cwl b/examples/click/genmod-tools/genmod-filter.cwl
new file mode 100644
index 0000000..aa2ee0a
--- /dev/null
+++ b/examples/click/genmod-tools/genmod-filter.cwl
@@ -0,0 +1,74 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.3.0
+# To generate again: $ genmod --generate_cwl_tool
+# Help: $ genmod --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['genmod', 'filter']
+
+description: |
+  Filter vcf variants.
+  
+  Filter variants based on their annotation
+
+inputs:
+  
+  variant_file:
+    type: File
+  
+    description: <vcf_file> or -
+    inputBinding:
+      position: 1
+
+  annotation:
+    type: ["null", string]
+    default: 1000GAF
+    description: Specify the info annotation to search for. Default 1000GAF
+    inputBinding:
+      prefix: --annotation 
+
+  threshold:
+    type: ["null", float]
+    default: 0.05
+    description: Threshold for filter variants. Default 0.05
+    inputBinding:
+      prefix: --threshold 
+
+  discard:
+    type: ["null", boolean]
+    default: False
+    description: If variants without the annotation should be discarded
+    inputBinding:
+      prefix: --discard 
+
+  greater:
+    type: ["null", boolean]
+    default: False
+    description: If greater than threshold should be used instead of less thatn threshold.
+    inputBinding:
+      prefix: --greater 
+
+  silent:
+    type: ["null", boolean]
+    default: False
+    description: Do not print the variants.
+    inputBinding:
+      prefix: --silent 
+
+  outfile:
+    type: ["null", File]
+    description: Specify the path to a file where results should be stored.
+    inputBinding:
+      prefix: --outfile 
+
+
+outputs:
+
+  outfile_out:
+    type: File
+  
+    description: Specify the path to a file where results should be stored.
+    outputBinding:
+      glob: $(inputs.outfile.path)
diff --git a/examples/click/genmod-tools/genmod-models.cwl b/examples/click/genmod-tools/genmod-models.cwl
new file mode 100644
index 0000000..0535c4d
--- /dev/null
+++ b/examples/click/genmod-tools/genmod-models.cwl
@@ -0,0 +1,118 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.3.0
+# To generate again: $ genmod --generate_cwl_tool
+# Help: $ genmod --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['genmod', 'models']
+
+description: |
+  Annotate genetic models for vcf variants. 
+  
+  Checks what patterns of inheritance that are followed in a VCF file.
+  The analysis is family based so each family that are specified in the family
+  file and exists in the variant file will get it's own annotation.
+
+inputs:
+  
+  variant_file:
+    type: File
+  
+    description: <vcf_file> or -
+    inputBinding:
+      position: 1
+
+  family_file:
+    type: ["null", File]
+  
+    inputBinding:
+      prefix: --family_file 
+
+  family_type:
+    type:
+    - "null"
+    - type: enum
+      symbols: []
+    default: ped
+    description: If the analysis use one of the known setups, please specify which one.
+    inputBinding:
+      prefix: --family_type 
+
+  reduced_penetrance:
+    type: ["null", File]
+    description: File with gene ids that have reduced penetrance.
+    inputBinding:
+      prefix: --reduced_penetrance 
+
+  vep:
+    type: ["null", boolean]
+    default: False
+    description: If variants are annotated with the Variant Effect Predictor.
+    inputBinding:
+      prefix: --vep 
+
+  phased:
+    type: ["null", boolean]
+    default: False
+    description: If data is phased use this flag.
+    inputBinding:
+      prefix: --phased 
+
+  strict:
+    type: ["null", boolean]
+    default: False
+    description: If strict model annotations should be used(see documentation).
+    inputBinding:
+      prefix: --strict 
+
+  processes:
+    type: ["null", int]
+    default: 4
+    description: Define how many processes that should be use for annotation.
+    inputBinding:
+      prefix: --processes 
+
+  silent:
+    type: ["null", boolean]
+    default: False
+    description: Do not print the variants.
+    inputBinding:
+      prefix: --silent 
+
+  whole_gene:
+    type: ["null", boolean]
+    default: False
+    description: If compounds should be checked over the whole gene.
+    inputBinding:
+      prefix: --whole_gene 
+
+  keyword:
+    type: ["null", string]
+    default: Annotation
+    description: What annotation keyword that should be used when searching for features.
+    inputBinding:
+      prefix: --keyword 
+
+  outfile:
+    type: ["null", File]
+    description: Specify the path to a file where results should be stored.
+    inputBinding:
+      prefix: --outfile 
+
+  temp_dir:
+    type: ["null", string]
+    description: Path to tempdir
+    inputBinding:
+      prefix: --temp_dir 
+
+
+outputs:
+
+  outfile_out:
+    type: File
+  
+    description: Specify the path to a file where results should be stored.
+    outputBinding:
+      glob: $(inputs.outfile.path)
diff --git a/examples/click/genmod-tools/genmod-score.cwl b/examples/click/genmod-tools/genmod-score.cwl
new file mode 100644
index 0000000..3448669
--- /dev/null
+++ b/examples/click/genmod-tools/genmod-score.cwl
@@ -0,0 +1,90 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.3.0
+# To generate again: $ genmod --generate_cwl_tool
+# Help: $ genmod --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['genmod', 'score']
+
+description: |
+  Score variants in a vcf file using a Weighted Sum Model.
+  
+  The specific scores should be defined in a config file, see examples on 
+  github.
+
+inputs:
+  
+  variant_file:
+    type: File
+  
+    description: <vcf_file> or -
+    inputBinding:
+      position: 1
+
+  family_id:
+    type: ["null", string]
+    default: 1
+  
+    inputBinding:
+      prefix: --family_id 
+
+  family_file:
+    type: ["null", File]
+  
+    inputBinding:
+      prefix: --family_file 
+
+  family_type:
+    type:
+    - "null"
+    - type: enum
+      symbols: []
+    default: ped
+    description: If the analysis use one of the known setups, please specify which one.
+    inputBinding:
+      prefix: --family_type 
+
+  silent:
+    type: ["null", boolean]
+    default: False
+    description: Do not print the variants.
+    inputBinding:
+      prefix: --silent 
+
+  skip_plugin_check:
+    type: ["null", boolean]
+    default: False
+    description: If continue even if plugins does not exist in vcf.
+    inputBinding:
+      prefix: --skip_plugin_check 
+
+  rank_results:
+    type: ["null", boolean]
+    default: False
+    description: Add a info field that shows how the different categories contribute to the rank score.
+    inputBinding:
+      prefix: --rank_results 
+
+  outfile:
+    type: ["null", File]
+    description: Specify the path to a file where results should be stored.
+    inputBinding:
+      prefix: --outfile 
+
+  score_config:
+    type: ["null", string]
+    description: The plug-in config file(.ini)
+    inputBinding:
+      prefix: --score_config 
+
+
+outputs:
+
+  outfile_out:
+    type: File
+  
+    description: Specify the path to a file where results should be stored.
+    outputBinding:
+      glob: $(inputs.outfile.path)
diff --git a/examples/click/genmod-tools/genmod-sort.cwl b/examples/click/genmod-tools/genmod-sort.cwl
new file mode 100644
index 0000000..d6e5672
--- /dev/null
+++ b/examples/click/genmod-tools/genmod-sort.cwl
@@ -0,0 +1,63 @@
+#!/usr/bin/env cwl-runner
+# This tool description was generated automatically by argparse2cwl ver. 0.3.0
+# To generate again: $ genmod --generate_cwl_tool
+# Help: $ genmod --help_arg2cwl
+
+cwlVersion: "cwl:v1.0"
+
+class: CommandLineTool
+baseCommand: ['genmod', 'sort']
+
+description: |
+  Sort a VCF file based on rank score.
+
+inputs:
+  
+  variant_file:
+    type: File
+  
+    description: <vcf_file> or -
+    inputBinding:
+      position: 1
+
+  outfile:
+    type: ["null", File]
+    description: Specify the path to a file where results should be stored.
+    inputBinding:
+      prefix: --outfile 
+
+  family_id:
+    type: ["null", string]
+    description: Specify the family id for sorting.
+    inputBinding:
+      prefix: --family_id 
+
+  silent:
+    type: ["null", boolean]
+    default: False
+    description: Do not print the variants.
+    inputBinding:
+      prefix: --silent 
+
+  temp_dir:
+    type: ["null", string]
+    description: Path to tempdir
+    inputBinding:
+      prefix: --temp_dir 
+
+  position:
+    type: ["null", boolean]
+    default: False
+    description: If variants should be sorted by position.
+    inputBinding:
+      prefix: --position 
+
+
+outputs:
+
+  outfile_out:
+    type: File
+  
+    description: Specify the path to a file where results should be stored.
+    outputBinding:
+      glob: $(inputs.outfile.path)
diff --git a/gxargparse/__init__.py b/gxargparse/__init__.py
new file mode 100644
index 0000000..ccdcf67
--- /dev/null
+++ b/gxargparse/__init__.py
@@ -0,0 +1 @@
+"""Stub for gxargparse"""
diff --git a/gxargparse/check_path.py b/gxargparse/check_path.py
new file mode 100644
index 0000000..2521206
--- /dev/null
+++ b/gxargparse/check_path.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+"""gxargparse_check_path checks for proper ordering of the system path
+
+If gxargparse appears after python stdlib's argparse, it won't behave properly,
+thus we provide a small check utility to ensure proper ordering and provide
+suggestions if not functional.
+"""
+from __future__ import print_function
+import sys, imp, os
+import argparse
+
+def get_args():
+    help_text = """Check the path for the correct setting to be able to take advantage
+of gxargparse.
+"""
+    parser = argparse.ArgumentParser(prog='gxargparse_check_path', description=help_text)
+    parser.add_argument('-q', dest='quiet', action='store_true', help='run quietly')
+    return parser.parse_args()
+
+def main():
+    args = get_args()
+
+    good_paths = []
+    incorrect_ordering = False
+    for path in sys.path:
+      try:
+        (handle, pathname, desc) = imp.find_module('argparse', [path])
+        if desc[2] == 5:
+            good_paths.append(pathname)
+        elif len(good_paths) == 0:
+            incorrect_ordering = True
+      except:
+          pass
+
+    if incorrect_ordering:
+        if len(good_paths) == 0:
+            if not args.quiet:
+                print("gxargparse not installed")
+        else:
+            if args.quiet:
+                print(os.path.dirname(good_paths[0]))
+            else:
+                print("Incorrect ordering, please set\n\n\tPYTHONPATH=%s\n" % (os.path.dirname(good_paths[0])))
+    else:
+        if not args.quiet:
+            print("Ready to go!")
+
+if __name__ == '__main__':
+    main()
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..e1556bd
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+galaxyxml
+jinja2>=2.8
+future
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..5e40900
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[wheel]
+universal = 1
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..9ae06b1
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,33 @@
+import os
+import sys
+
+from setuptools import setup
+
+from cmdline2cwl import __version__
+
+if sys.argv[-1] == 'publish':
+    os.system("python setup.py sdist bdist_wheel upload; git push")
+    sys.exit()
+
+setup(name="gxargparse",
+        version=__version__,
+        description='Instrument for forming Galaxy XML and CWL tool descriptions from argparse arguments',
+        author='Eric Rasche, Anton Khodak',
+        author_email='rasche.eric at yandex.ru, anton.khodak at ukr.net',
+        install_requires=['galaxyxml', 'jinja2', 'future'],
+        url='https://github.com/common-workflow-language/gxargparse',
+        packages=["argparse", "gxargparse", "click", "cmdline2cwl"],
+        entry_points={
+            'console_scripts': [
+                    'gxargparse_check_path = gxargparse.check_path:main',
+                ]
+            },
+        classifiers=[
+            'Development Status :: 3 - Alpha',
+            'Operating System :: OS Independent',
+            'Intended Audience :: Developers',
+            'Environment :: Console',
+            'License :: OSI Approved :: Apache Software License',
+            ],
+        include_package_data=True,
+        )
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/test/cwl_classes.py b/test/cwl_classes.py
new file mode 100644
index 0000000..5c48585
--- /dev/null
+++ b/test/cwl_classes.py
@@ -0,0 +1,80 @@
+from yaml import load
+from collections import OrderedDict
+
+
+class InputBinding:
+    def __init__(self, ib):
+        self.position = ib.get('position', None)
+        self.prefix = ib.get('prefix', None)
+
+
+class OutputBinding:
+    def __init__(self, ob):
+        self.glob = ob.get('glob', None)
+
+
+class Param:
+
+    def __init__(self, param):
+        self.id = param['id']
+        self.type = param.get('type', None)
+        self.description = param.get('doc', param.get('description', None))
+
+
+class InputParam(Param):
+
+    def __init__(self, param):
+        super(InputParam, self).__init__(param)
+        if type(self.type) is list and self.type[0] == 'null':
+            self.optional = True
+        else:
+            self.optional = False
+        self.default = param.get('default', None)
+        input_binding = param.get('inputBinding', None)
+        if input_binding:
+            self.input_binding = InputBinding(input_binding)
+
+
+class OutputParam(Param):
+
+    def __init__(self, param):
+        super(OutputParam, self).__init__(param)
+        output_binding = param.get('outputBinding', None)
+        if output_binding:
+            self.output_binding = OutputBinding(output_binding)
+
+
+class Tool:
+
+    def __init__(self, filename):
+
+        with open(filename) as f:
+            tool = load(f)
+        self.tool_class = tool['class']
+        if self.tool_class != 'CommandLineTool':
+            raise ValueError('Wrong tool class')
+        self.basecommand = tool['baseCommand']
+        self.inputs = OrderedDict()
+        if type(tool['inputs']) is list:  # ids not mapped
+            for param_dict in tool['inputs']:
+                param = InputParam(param_dict)
+                self.inputs[param.id] = param
+        elif type(tool['inputs']) is dict:  # ids mapped
+            for id, param_dict in tool['inputs'].items():
+                param_dict['id'] = id
+                param = InputParam(param_dict)
+                self.inputs[id] = param
+        self.outputs = OrderedDict()
+        if tool['outputs']:
+            if type(tool['outputs']) is list:  # ids not mapped
+                for param_dict in tool['outputs']:
+                    param = OutputParam(param_dict)
+                    self.outputs[param.id] = param
+            elif type(tool['outputs']) is dict:  # ids mapped
+                for id, param_dict in tool['outputs'].items():
+                    param_dict['id'] = id
+                    param = OutputParam(param_dict)
+                    self.outputs[id] = param
+        self.description = tool.get('doc', tool.get('description', ''))
+        self.cwl_version = tool.get('cwlVersion', '')
+
diff --git a/test/test-data/index.cwl b/test/test-data/index.cwl
new file mode 100644
index 0000000..d4a5beb
--- /dev/null
+++ b/test/test-data/index.cwl
@@ -0,0 +1,29 @@
+cwlVersion: cwl:draft-3
+class: CommandLineTool
+baseCommand: python
+requirements:
+- class: CreateFileRequirement
+  fileDef:
+    - filename: input.txt
+      fileContent: $(inputs.file)
+
+inputs:
+- id: file
+  type: File
+  inputBinding:
+    position: 1
+- id: index.py
+  type: File
+  default:
+    class: File
+    path: index.py
+  inputBinding:
+    position: 0
+outputs:
+- id: result
+  type: File
+  outputBinding:
+    glob: input.txt
+  secondaryFiles:
+    - ".idx1"
+    - "^.idx2"
\ No newline at end of file
diff --git a/test/test-data/index.py b/test/test-data/index.py
new file mode 100644
index 0000000..3e0cc76
--- /dev/null
+++ b/test/test-data/index.py
@@ -0,0 +1,41 @@
+from builtins import str
+#!/usr/bin/env python
+
+# Toy program to generate inverted index of word to line.
+# Takes input text file on stdin and prints output index on stdout.
+
+import sys
+import os
+
+# to invoke own argparse from this directory (test-data) we must put it on the first place in sys.path
+argparse_dir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', '..'))
+sys.path.insert(0, argparse_dir)
+
+import argparse
+
+
+words = {}
+
+parser = argparse.ArgumentParser(description='Generate inverted index of word to line')
+parser.add_argument('mainfile', type=argparse.FileType('r'), help='Text file to be indexed')
+
+args = parser.parse_args()
+
+mainfile = args.mainfile
+indexfile = mainfile.name + ".idx1"
+
+main = mainfile
+index = open(indexfile, "w")
+
+linenum = 0
+for l in main:
+    linenum += 1
+    l = l.rstrip().lower().replace(".", "").replace(",", "").replace(";", "").replace("-", " ")
+    for w in l.split(" "):
+        if w:
+            if w not in words:
+                words[w] = set()
+            words[w].add(linenum)
+
+for w in sorted(words.keys()):
+    index.write("%s: %s" % (w, ", ".join((str(i) for i in words[w]))) + "\n")
diff --git a/test/test-data/index_new.cwl b/test/test-data/index_new.cwl
new file mode 100644
index 0000000..6f80af5
--- /dev/null
+++ b/test/test-data/index_new.cwl
@@ -0,0 +1,34 @@
+#!/usr/bin/env cwl-runner
+
+cwlVersion: "cwl:draft-3.dev2"
+
+class: CommandLineTool
+baseCommand: ["python"]
+
+requirements:
+  - $import: envvar-global.cwl
+  - $import: linux-sort-docker.cwl
+  - class: InlineJavascriptRequirement
+
+description: |
+  Generate inverted index of word to line
+
+inputs:
+
+
+- id: mainfile
+  type: File
+  inputBinding:
+    position: 1
+
+- id: index.py
+  type: File
+  default:
+    class: File
+    path: index.py
+  inputBinding:
+    position: 0
+
+
+outputs:
+  []
\ No newline at end of file
diff --git a/test/test-data/inp.txt b/test/test-data/inp.txt
new file mode 100644
index 0000000..4e8be6a
--- /dev/null
+++ b/test/test-data/inp.txt
@@ -0,0 +1,4 @@
+Some text here
+and here
+and again some here
+asdfasdf 99992 2 3  kj
\ No newline at end of file
diff --git a/test/test-data/inp.txt.idx1 b/test/test-data/inp.txt.idx1
new file mode 100644
index 0000000..16f010b
--- /dev/null
+++ b/test/test-data/inp.txt.idx1
@@ -0,0 +1,10 @@
+2: 4
+3: 4
+99992: 4
+again: 3
+and: 2, 3
+asdfasdf: 4
+here: 1, 2, 3
+kj: 4
+some: 1, 3
+text: 1
diff --git a/test/test-data/job.json b/test/test-data/job.json
new file mode 100644
index 0000000..fad98ec
--- /dev/null
+++ b/test/test-data/job.json
@@ -0,0 +1,7 @@
+{
+ "file": {
+   "class": "File",
+    "path": "inp.txt"
+ },
+  "term":"here"
+}
diff --git a/test/test-data/main.cwl b/test/test-data/main.cwl
new file mode 100644
index 0000000..9b09206
--- /dev/null
+++ b/test/test-data/main.cwl
@@ -0,0 +1,87 @@
+cwlVersion: cwl:draft-3
+$graph:
+- id: index
+  class: CommandLineTool
+  baseCommand: python
+  requirements:
+    - class: CreateFileRequirement
+      fileDef:
+        - filename: input.txt
+          fileContent: $(inputs.file)
+    - class: InlineJavascriptRequirement
+
+  inputs:
+    - id: file
+      type: File
+      inputBinding:
+        position: 1
+    - id: index.py
+      type: File
+      default:
+        class: File
+        path: index.py
+      inputBinding:
+        position: 0
+  outputs:
+     []
+
+- id: search
+  class: CommandLineTool
+  baseCommand: python
+  requirements:
+    - class: InlineJavascriptRequirement
+  inputs:
+    - id: file
+      type: File
+      inputBinding:
+        position: 1
+      secondaryFiles:
+        - ".idx1"
+    - id: search.py
+      type: File
+      default:
+        class: File
+        path: search.py
+      inputBinding:
+        position: 0
+    - id: term
+      type: string
+      inputBinding:
+        position: 2
+  outputs:
+    - id: result
+      type: File
+      outputBinding:
+        glob: result.txt
+  stdout: result.txt
+
+- id: main
+  class: Workflow
+  inputs:
+    - id: infile
+      type: File
+    - id: term
+      type: string
+  outputs:
+    - id: outfile
+      type: File
+      source: "#main/search/result"
+    - id: indexedfile
+      type: File
+      source: "#main/index/result"
+
+  steps:
+    - id: index
+      run: "#index"
+      inputs:
+        - { id: file, source: "#main/infile" }
+      outputs:
+        - id: result
+
+    - id: search
+      run: "#search"
+      inputs:
+        - { id: file, source: "#main/index/result" }
+        - { id: term, source: "#main/term" }
+      outputs:
+        - id: result
\ No newline at end of file
diff --git a/test/test-data/search.cwl b/test/test-data/search.cwl
new file mode 100644
index 0000000..5fdebc1
--- /dev/null
+++ b/test/test-data/search.cwl
@@ -0,0 +1,43 @@
+#!/usr/bin/env cwl-runner
+# This tool description was formed automatically by argparse2cwl ver. 0.2.5
+# To form again: $ python --generate_cwl_tool
+# Help: $ python --help_arg2cwl
+
+cwlVersion: "cwl:draft-3"
+
+class: CommandLineTool
+baseCommand: ['python']
+
+requirements:
+  - class: InlineJavascriptRequirement
+
+description: |
+  Toy program to search inverted index and print out each line the term appears
+
+inputs:
+  
+- id: search.py
+  type: File
+  default:
+    class: File
+    path: search.py
+  inputBinding:
+    position: 0
+
+
+- id: mainfile
+  type: File
+
+  description: Text file to be indexed
+  inputBinding:
+    position: 1
+
+- id: term
+  type: string
+
+  description: Term for search
+  inputBinding:
+    position: 2
+
+outputs:
+    []
diff --git a/test/test-data/search.py b/test/test-data/search.py
new file mode 100644
index 0000000..2f1edf0
--- /dev/null
+++ b/test/test-data/search.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+import os
+import sys
+
+# to invoke own argparse from this directory (test-data) we must put it on the first place in sys.path
+argparse_dir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', '..'))
+sys.path.insert(0, argparse_dir)
+
+import argparse
+
+
+parser = argparse.ArgumentParser(description="Toy program to search inverted index and "
+                                             "print out each line the term appears")
+
+parser.add_argument('mainfile', type=argparse.FileType('r'), help='Text file to be indexed')
+parser.add_argument('term', type=str, help='Term for search')
+
+args = parser.parse_args()
+
+mainfile = args.mainfile
+indexfile = mainfile.name + ".idx1"
+term = args.term
+
+main = mainfile
+index = open(indexfile)
+
+st = term + ": "
+
+for a in index:
+    if a.startswith(st):
+        n = [int(i) for i in a[len(st):].split(", ") if i]
+        linenum = 0
+        for l in main:
+            linenum += 1
+            if linenum in n:
+                print(linenum, l.rstrip())
+        break
+
diff --git a/test/test-data/search_new.cwl b/test/test-data/search_new.cwl
new file mode 100644
index 0000000..06eabe0
--- /dev/null
+++ b/test/test-data/search_new.cwl
@@ -0,0 +1,39 @@
+#!/usr/bin/env cwl-runner
+
+cwlVersion: "cwl:draft-3.dev2"
+
+class: CommandLineTool
+baseCommand: ["python"]
+
+requirements:
+  - $import: envvar-global.cwl
+  - $import: linux-sort-docker.cwl
+  - class: InlineJavascriptRequirement
+
+description: |
+  Toy program to search inverted index and print out each line the term appears
+
+inputs:
+
+
+- id: mainfile
+  type: File
+  inputBinding:
+    position: 1
+
+- id: term
+  type: string
+  inputBinding:
+    position: 2
+
+- id: search.py
+  type: File
+  default:
+    class: File
+    path: search.py
+  inputBinding:
+    position: 0
+
+
+outputs:
+  []
\ No newline at end of file
diff --git a/test/test_arg2cwl.py b/test/test_arg2cwl.py
new file mode 100644
index 0000000..361547c
--- /dev/null
+++ b/test/test_arg2cwl.py
@@ -0,0 +1,287 @@
+import sys
+import os
+import shutil
+import unittest
+from itertools import chain
+from unittest import mock
+from io import StringIO
+
+import yaml
+
+import argparse
+from cmdline2cwl import Arg2CWLParser
+from argparse.argparse_cwl_translation import ArgparseCWLTranslation as ac
+from test.cwl_classes import Tool
+
+
+class GeneralTestCase(unittest.TestCase):
+    maxDiff = None
+
+    @staticmethod
+    def prepare_argument_parser(name=None, add_help=True):
+        parser = argparse.ArgumentParser(prog=name, description='test program', add_help=add_help)
+        parser.add_argument('keyword', metavar='Q', type=str, nargs=1,
+                            help='action keyword')
+        parser.add_argument('integers', metavar='N', type=int, nargs='+',
+                            help='an integer for \n'
+                                 'the accumulator')
+        parser.add_argument('choices', type=int, choices=range(5, 10))
+        parser.add_argument('foo', type=str,
+                            help='positional argument with the same dest as optional argument')
+        parser.add_argument('positional_nargs_asteriks', nargs='*',
+                            help='positional argument with nargs = *')
+        parser.add_argument('positional_nargs_question_mark', nargs='?',
+                            help='positional argument with nargs = ?')
+        parser.add_argument('positional_with_choices', choices=['rock', 'paper', 'scissors'])
+        parser.add_argument('--req', required=True, help='required optional')
+        parser.add_argument('--foo', nargs='?', help='foo help')
+        parser.add_argument('--open', type=open, help='argument with type `open`')
+        parser.add_argument('--file', nargs='?', help='foo help', type=argparse.FileType('w'))
+        parser.add_argument('--bar', nargs='*', default=[1, 2, 3], help='BAR!')
+        parser.add_argument('--true_p', action='store_true', help='Store a true')
+        parser.add_argument('--false_p', action='store_false', help='Store a false')
+        parser.add_argument('--append', action='append', help='Append a value')
+        parser.add_argument('--str', dest='types', action='append_const', const=str, help='Append a value')
+        parser.add_argument('--int', dest='types', action='append_const', const=int, help='Append a value')
+        parser.add_argument('--output-file', help='Output file')
+
+        parser.add_argument('--nargs2', nargs=2, help='nargs2')
+
+        parser.add_argument('--mode', choices=['rock', 'paper', 'scissors'], default='scissors')
+
+        parser.add_argument('--version', action='version', version='2.0')
+        parser.set_defaults(foo='Lorem Ipsum')
+        return parser
+
+
+    def test_help_message(self):
+        tool_parser = self.prepare_argument_parser(name='test_help_message')
+        testargs = ["test.py", "--help_arg2cwl"]
+        with mock.patch('sys.stdout', new=StringIO()) as fakeOutput, mock.patch.object(sys, 'argv', testargs):
+            arg2cwl_parser = Arg2CWLParser().parser
+            with self.assertRaises(SystemExit) as result:
+                tool_parser.parse_args()
+                self.assertEqual(result.exception.code, 0)
+            help_message_actual = fakeOutput.getvalue().strip()
+            # flushing stdout
+            fakeOutput.truncate(0)
+            fakeOutput.seek(0)
+            arg2cwl_parser.print_help()
+            help_message_desired = fakeOutput.getvalue().strip()
+            self.assertEqual(help_message_actual, help_message_desired)
+
+    def test_subparser(self):
+        """
+        Tests if tools with subparsers run without errors
+        """
+        parser = self.prepare_argument_parser(name="test_subparser")
+        subparsers = parser.add_subparsers()
+        subparser = subparsers.add_parser('sub', help='test subparser')
+        subparser.add_argument('keyword', type=str)
+        testargs = ["test.py", "sub", "--generate_cwl_tool"]
+        with self.assertRaises(SystemExit) as result:
+            with unittest.mock.patch.object(sys, 'argv', testargs):
+                parser.parse_args()
+        self.assertEqual(result.exception.code, 0)
+
+    def test_output_directory_storage_for_CWL_tool(self):
+        parser = self.prepare_argument_parser(name="test-directory.py")
+        directory = os.path.dirname(__file__)
+        new_dir = 'test/'
+        os.mkdir(new_dir)
+        testargs = ["test-directory.py", "--generate_cwl_tool", "-d", new_dir]
+        with mock.patch.object(sys, 'argv', testargs):
+            with self.assertRaises(SystemExit) as result:
+                parser.parse_args()
+                self.assertEqual(result.exception.code, 0)
+            filepath = os.path.join(directory, new_dir, 'test-directory.cwl')
+            self.assertTrue(os.path.isfile(filepath))
+            shutil.rmtree(new_dir)
+
+
+class CWLTestCase(unittest.TestCase):
+    test_dir = "test_dir/"
+
+    def setUp(self):
+        if os.path.exists(self.test_dir):
+            shutil.rmtree(self.test_dir)
+        os.mkdir(self.test_dir)
+
+    def tearDown(self):
+        shutil.rmtree(self.test_dir)
+
+    def get_simple_tool(self, parser_name, testargs=None, add_help=True):
+        parser = GeneralTestCase.prepare_argument_parser(parser_name, add_help)
+        if not testargs:
+            testargs = [parser_name, "--generate_cwl_tool", "-d", self.test_dir]
+        with mock.patch.object(sys, 'argv', testargs):
+            with self.assertRaises(SystemExit) as result:
+                parser.parse_args()
+                self.assertEqual(result.exception.code, 0)
+        return parser, Tool(self.test_dir + parser_name.replace('.py', '.cwl').strip('./'))
+
+    @staticmethod
+    def _strip_help_version_actions(actions):
+        return filter(lambda action: type(action).__name__ not in ('_HelpAction', '_VersionAction'), actions)
+
+    def test_position(self):
+        parser_name = "test-position.py"
+        parser, tool = self.get_simple_tool(parser_name)
+        positional_count = 1
+        for positional in parser._positionals._group_actions:
+            self.assertEqual(positional_count, tool.inputs[positional.dest].input_binding.position)
+            positional_count += 1
+        for optional in self._strip_help_version_actions(parser._optionals._group_actions):
+            self.assertRaises(AttributeError, tool.inputs[optional.dest].input_binding.position)
+            self.assertIs(tool.inputs[optional.dest].input_binding.position, None)
+
+    def test_shebang(self):
+        parser_name = './test-shebang.py'
+        parser, tool = self.get_simple_tool(parser_name)
+        self.assertEqual([parser_name], tool.basecommand)
+
+    def test_basecommand(self):
+        """
+        if `basecommand` is provided in a program which is run with shebang,
+        it replaces autogenerated shebang basecommand
+        """
+        parser_name = './test-shebang.py'
+        file_name = parser_name.strip('./')
+        testargs = [parser_name, "--generate_cwl_tool", "-d", self.test_dir, "-b", "python3"]
+        parser, tool = self.get_simple_tool(file_name, testargs)
+        self.assertEqual(['python3'], tool.basecommand)
+        self.assertEqual(file_name, tool.inputs[file_name].id)
+
+    def test_default(self):
+        parser, tool = self.get_simple_tool('test-default.py')
+        for action in self._strip_help_version_actions(parser._actions):
+            tool_default = tool.inputs[action.dest].default
+            if action.default == 'null':
+                action.default = None
+            self.assertEqual(action.default, tool_default)
+
+    def test_optional(self):
+        parser, tool = self.get_simple_tool('test-optional.py')
+        for action in self._strip_help_version_actions(parser._actions):
+            if (action.option_strings and not action.required) or action.nargs in ('*', '?'):
+                self.assertEqual('null', tool.inputs[action.dest].type[0])
+            else:
+                self.assertNotIsInstance(tool.inputs[action.dest].type, list)
+
+    def test_type(self):
+        parser, tool = self.get_simple_tool('test-optional.py')
+        for action in self._strip_help_version_actions(parser._actions):
+            arg_type = tool.inputs[action.dest].type
+            if type(arg_type) is list:  # if argument is optional, the first type in list is `null`
+                arg_type = arg_type[1]  # the second is the actual type
+            if action.choices:
+                if type(action.choices) is range:
+                    self.assertEqual(list(action.choices), arg_type['symbols'])
+                else:
+                    self.assertEqual(action.choices, arg_type['symbols'])
+                self.assertEqual('enum', arg_type['type'])
+            if action.type:
+                if isinstance(action.type, argparse.FileType):
+                    action_type = 'File'
+                else:
+                    action_type = ac.get_cwl_type(action.type)
+                if (action.nargs and action.nargs != '?') \
+                        or type(action).__name__.startswith("_Append"):
+                    self.assertEqual('array', arg_type['type'])
+                    self.assertEqual(action.items_type or 'string', arg_type['items'])
+                elif action.choices:
+                    self.assertTrue(all(isinstance(x, action.type) for x in arg_type['symbols']))
+                else:
+                    self.assertEqual(action_type, arg_type)
+
+    def test_output_replacement(self):
+        """
+        `--output_section FILENAME` option
+        """
+        output_section = \
+        {'outputs':[
+            {'id': 'outfile1',
+             'type': 'File',
+             'description': 'output file',
+             'outputBinding':{
+                 'glob': '$(inputs.outputPrefix+".vcf.gz")',
+             }
+            }
+          ]
+        }
+        output_file = self.test_dir + 'example_output.cwl'
+        with open(output_file, 'w') as f:
+            yaml.dump(output_section, f)
+        filename = 'test_output.py'
+        testargs = [filename, "--generate_cwl_tool", "-d", self.test_dir, "-o", output_file]
+        parser, tool = self.get_simple_tool(filename, testargs)
+        output_0_name = output_section['outputs'][0]['id']
+        self.assertEqual(output_section['outputs'][0]['id'], tool.outputs[output_0_name].id)
+        self.assertEqual(output_section['outputs'][0]['outputBinding']['glob'],
+                         tool.outputs[output_0_name].output_binding.glob)
+
+    def test_outputs(self):
+        parser_name = 'test-outputs.py'
+        testargs = [parser_name, "--generate_cwl_tool", "-d", self.test_dir, "-go"]
+        parser, tool = self.get_simple_tool(parser_name, testargs)
+        for action in self._strip_help_version_actions(parser._actions):
+            if 'output' in action.dest:
+                self.assertTrue(tool.outputs[action.dest+'_out'].id)
+
+    def test_parents(self):
+        mum, mum_tool = self.get_simple_tool('mum.py', add_help=False)
+        dad = argparse.ArgumentParser(prog='daddy.py', description='test program', add_help=False)
+        dad.add_argument('pos_arg', type=int)
+        dad.add_argument('--opt_arg', action='store_true')
+        kid_name = 'kid.py'
+        kid = argparse.ArgumentParser(prog=kid_name, parents=[mum, dad])
+        kid.add_argument('--kids_argument', nargs='*')
+        testargs = [kid_name, "--generate_cwl_tool", "-d", self.test_dir]
+        with mock.patch.object(sys, 'argv', testargs):
+            with self.assertRaises(SystemExit) as result:
+                kid.parse_args()
+                self.assertEqual(result.exception.code, 0)
+        tool = Tool(self.test_dir + kid_name.replace('.py', '.cwl').strip('./'))
+        actions = list(chain(self._strip_help_version_actions(mum._actions),
+                           self._strip_help_version_actions(dad._actions)))
+        arguments = [arg.dest for arg in actions]
+        arguments.append('kids_argument')
+        for arg in arguments:
+            self.assertIn(arg, tool.inputs.keys())
+
+    def test_prefixes(self):
+        parser_name = 'test-prefix-chars.py'
+        parser = argparse.ArgumentParser(prog=parser_name,
+                                         prefix_chars='-+',
+                                         description='test prefix chars program')
+        parser.add_argument('keyword', type=str, nargs=1,
+                            help='action keyword')
+        parser.add_argument('integers', metavar='N', type=int, nargs='+',
+                            help='an integer for \n'
+                                 'the accumulator')
+        parser.add_argument('choices', type=int, choices=range(5, 10))
+        parser.add_argument('foo', type=str,
+                            help='positional argument with the same dest as optional argument')
+        parser.add_argument('--req', required=True, help='required optional')
+        parser.add_argument('++foo', nargs='?', help='foo help')
+        parser.add_argument('+open', type=open, help='argument with type `open`')
+        parser.add_argument('-file', nargs='?', help='foo help', type=argparse.FileType('w'))
+        parser.add_argument('--bar', nargs='*', default=[1, 2, 3], help='BAR!')
+        testargs = [parser_name, "--generate_cwl_tool", "-d", self.test_dir]
+        with mock.patch.object(sys, 'argv', testargs):
+            with self.assertRaises(SystemExit) as result:
+                parser.parse_args()
+                self.assertEqual(result.exception.code, 0)
+        tool = Tool(self.test_dir + parser_name.replace('.py', '.cwl').strip('./'))
+        for optional in self._strip_help_version_actions(parser._optionals._group_actions):
+            self.assertEqual(tool.inputs[optional.dest].input_binding.prefix, optional.option_strings[0])
+
+    def test_type_conversions(self):
+        self.assertEqual(ac.get_cwl_type(open), 'File')
+        self.assertEqual(ac.get_cwl_type(argparse.FileType('r')), 'File')
+        self.assertEqual(ac.get_cwl_type(str), 'string')
+        self.assertEqual(ac.get_cwl_type('str'), 'string')
+
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/test/test_click2cwl.py b/test/test_click2cwl.py
new file mode 100644
index 0000000..ff8df93
--- /dev/null
+++ b/test/test_click2cwl.py
@@ -0,0 +1,150 @@
+import os
+import shutil
+import sys
+import unittest
+from unittest import mock
+
+import click
+from test.cwl_classes import Tool
+
+
+class CWLTestCase(unittest.TestCase):
+    maxDiff = None
+    test_dir = "test_dir/"
+
+
+    def setUp(self):
+        if os.path.exists(self.test_dir):
+            shutil.rmtree(self.test_dir)
+        os.mkdir(self.test_dir)
+
+    def tearDown(self):
+        shutil.rmtree(self.test_dir)
+
+    def standard_testargs(self, parser_name):
+        return [parser_name, "--generate_cwl_tool", "-d", self.test_dir]
+
+    def open_tool(self, parser_name):
+        return Tool(self.test_dir + parser_name.replace('.py', '.cwl').strip('./'))
+
+    def generate_and_open_test_tool(self, testargs, function, parser_name):
+        with mock.patch.object(sys, 'argv', testargs):
+            function()
+        return self.open_tool(parser_name)
+
+    @staticmethod
+    def prepare_argument_parser():
+        @click.command()
+        @click.argument('keyword', type=click.STRING)
+        @click.option('--choices', type=click.Choice(['md5', 'sha1']))
+        @click.option('--double-type', type=(str, int), default=(None, None))
+        def function():
+            pass
+
+        return function
+
+    def get_simple_tool(self, parser_name, testargs=None, add_help=True):
+        parser = self.prepare_argument_parser()
+        if not testargs:
+            testargs = self.standard_testargs(parser_name)
+        return parser, self.generate_and_open_test_tool(testargs, parser, parser_name)
+
+    def test_subparser(self):
+        """
+        Tests if tools with subparsers run without errors
+        """
+        @click.group()
+        @click.pass_context
+        @click.option('--debug', default=False)
+        def cli(debug):
+            pass
+
+        @cli.command()
+        @click.option('-s', '--some-option')
+        def sync(some_option):
+            pass
+
+        @cli.command()
+        @click.option('-o', '--some-other-option')
+        def async(some_option):
+            pass
+
+        parser_name = 'test-group.py'
+        with mock.patch.object(sys, 'argv', self.standard_testargs(parser_name)):
+            cli()
+        sync_tool = self.open_tool('test-group-sync.cwl')
+        async_tool = self.open_tool('test-group-async.cwl')
+        self.assertEqual(sync_tool.inputs['some_option'].input_binding.prefix, '--some-option')
+        self.assertEqual(async_tool.inputs['some_other_option'].input_binding.prefix, '--some-other-option')
+
+    def test_basecommand(self):
+        """
+        if `basecommand` is provided in a program which is run with shebang,
+        it replaces autogenerated shebang basecommand
+        """
+        parser_name = './test-shebang.py'
+        file_name = parser_name.strip('./')
+        testargs = [parser_name, "--generate_cwl_tool", "-d", self.test_dir, "-b", "python3"]
+        parser, tool = self.get_simple_tool(file_name, testargs)
+        self.assertEqual(['python3'], tool.basecommand)
+        self.assertEqual(file_name, tool.inputs[file_name].id)
+
+    def test_choices(self):
+        choices = ['rock', 'scissors', 'paper']
+
+        @click.command()
+        @click.option('--item', type=click.Choice(choices))
+        def function(item):
+            pass
+
+        parser_name = 'test-choices.py'
+        tool = self.generate_and_open_test_tool(self.standard_testargs(parser_name), function, parser_name)
+        self.assertEqual(tool.inputs['item'].type[1]['symbols'], choices)
+
+    def test_tuples(self):
+        @click.command()
+        @click.option('--item', type=(str, int), default=(None, None))
+        def function(item):
+            pass
+
+        parser_name = 'test-type.py'
+        tool = self.generate_and_open_test_tool(self.standard_testargs(parser_name), function, parser_name)
+        self.assertEqual(tool.inputs['item'].type, ['null', 'string', 'int'])
+
+    def test_flags(self):
+        @click.command()
+        @click.option('--shout/--no-shout', default=False)
+        @click.option('--simple-shout', is_flag=True)
+        def function(shout):
+            pass
+
+        parser_name = 'test-flags.py'
+        tool = self.generate_and_open_test_tool(self.standard_testargs(parser_name), function, parser_name)
+        self.assertEqual(tool.inputs['shout'].type, ['null', 'boolean'])
+        self.assertEqual(tool.inputs['simple_shout'].type, ['null', 'boolean'])
+        self.assertEqual(tool.inputs['shout'].default, False)
+        self.assertEqual(tool.inputs['simple_shout'].default, False)
+
+    def test_prefix_chars(self):
+        @click.command()
+        @click.option('+w/-w')
+        def function(w):
+            pass
+
+        parser_name = 'test-prefix-chars.py'
+        tool = self.generate_and_open_test_tool(self.standard_testargs(parser_name), function, parser_name)
+        self.assertEqual(tool.inputs['w'].type, ['null', 'boolean'])
+
+    def test_docstring(self):
+        @click.command()
+        @click.argument('argument')
+        def function(w):
+            """This script prints hello NAME COUNT times."""
+            pass
+
+        parser_name = 'test-docstring.py'
+        tool = self.generate_and_open_test_tool(self.standard_testargs(parser_name), function, parser_name)
+        self.assertEqual(tool.description.strip('\n'), function.__doc__)
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/test/test_utils.py b/test/test_utils.py
new file mode 100644
index 0000000..4c269ad
--- /dev/null
+++ b/test/test_utils.py
@@ -0,0 +1,106 @@
+from __future__ import print_function
+from builtins import str
+from builtins import range
+import sys
+import itertools
+import hashlib
+import copy
+
+if sys.version_info < (2, 7):
+    from unittest2 import TestCase
+else:
+    from unittest import TestCase
+
+
+class GeneralTests(TestCase):
+
+    def test_load(self):
+        gxap = sys.modules['gxargparse']
+        ap = sys.modules['argparse']
+        # Ensure we've loaded the correct argparse ;)
+        self.assertTrue('gxargparse/argparse' in str(ap))
+        self.assertTrue('gxargparse/gxargparse' in str(gxap))
+
+        import argparse as fake_ap
+        # Do we have a ref to the real ap
+        self.assertTrue('ap' in dir(fake_ap))
+        # Is it the real argparse?
+        self.assertTrue('_os' in dir(fake_ap.ap))
+
+    def __gen_id(self, kwargs):
+        key = ""
+        for x in sorted(kwargs.keys()):
+            key += str(kwargs[x])
+        digest = hashlib.sha1(key).hexdigest()
+        repl = 'qrstuvwxyz'
+        for c in range(10):
+            digest = digest.replace(str(c), repl[c])
+        return digest
+
+    def dict_product(self, odl, key_name, new_key_list):
+        for x in new_key_list:
+            if x is None:
+                for od in odl:
+                    yield od
+            else:
+                for od in odl:
+                    od2 = copy.deepcopy(od)
+                    od2[key_name] = x
+                    yield od2
+
+    def test_dict_product(self):
+        a = [{'a': 0}, {'a': 1}]
+        correct = [
+            {'a': 0},
+            {'a': 1},
+            {'a': 0, 'b': 1},
+            {'a': 1, 'b': 1},
+        ]
+
+        results = list(self.dict_product(a, 'b', [None, 1]))
+        self.assertCountEqual(correct, results)
+
+    def __blacklist(self, item_list):
+        for i in item_list:
+            try:
+                if i['action'] in ('store_true', 'store_false', 'count', 'version', 'help'):
+                    if 'type' not in i and 'nargs' not in i:
+                        yield i
+                else:
+                    yield i
+            except Exception:
+                yield i
+
+    def arg_gen(self):
+        import argparse
+        prefixes = ['--']
+        types = [None, str, int, float, argparse.FileType('w'), argparse.FileType('r')]
+        nargs = [None, 1, 2, '+', '*', '?']
+        actions = [None, 'store', 'store_true', 'store_false',
+                   'append', 'count', 'version', 'help']
+
+        a0 = list(self.dict_product([{}], 'type', types))
+        a1 = list(self.dict_product(a0, 'nargs', nargs))
+        a2 = list(self.dict_product(a1, 'action', actions))
+        a3 = list(self.dict_product(a2, 'prefix', prefixes))
+
+        for x in self.__blacklist(a3):
+            prefix = x['prefix']
+            id = self.__gen_id(x)
+            del x['prefix']
+            yield {'args': prefix + id,
+                   'kwargs': x}
+
+
+    def parse_args(self, args, **setup):
+        import argparse
+        parser = argparse.ArgumentParser(**setup)
+
+        for arg in self.arg_gen():
+            print(arg)
+            parser.add_argument(arg['args'], **arg['kwargs'])
+        return parser.parse_args(args)
+
+
+class SimpleTests(TestCase):
+    pass

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/gxargparse.git



More information about the debian-med-commit mailing list