changeset 1:48458b0369aa draft

Uploaded
author fubar
date Sat, 17 Apr 2021 22:50:25 +0000
parents fc50a3f507ab
children 9fd3d83e1bac
files toolfactory/README.md toolfactory/rgToolFactory2.py toolfactory/rgToolFactory2.xml toolfactory/test-data/test1_log.txt
diffstat 4 files changed, 344 insertions(+), 135 deletions(-) [+]
line wrap: on
line diff
--- a/toolfactory/README.md	Sat Apr 10 02:16:35 2021 +0000
+++ b/toolfactory/README.md	Sat Apr 17 22:50:25 2021 +0000
@@ -1,55 +1,255 @@
-**Breaking news! Docker container is recommended as at August 2020**
+## Breaking news! Docker container at https://github.com/fubar2/toolfactory-galaxy-docker recommended as at December 2020
 
-A Docker container can be built - see the docker directory.
-It is highly recommended for isolation. It also has an integrated toolshed to allow installation of new tools back 
-into the Galaxy being used to generate them. 
+### New demonstration of planemo tool_factory command ![Planemo ToolFactory demonstration](images/lintplanemo-2021-01-08_18.02.45.mkv?raw=false "Demonstration inside Planemo")
 
-Built from quay.io/bgruening/galaxy:20.05 but updates the
-Galaxy code to the dev branch - it seems to work fine with updated bioblend>=0.14
-with planemo and the right version of gxformat2 needed by the ToolFactory (TF).
+## This is the original ToolFactory suitable for non-docker situations. Please use the docker container if you can because it's integrated with a Toolshed...
 
-The runclean.sh script run from the docker subdirectory of your local clone of this repository
-should create a container (eventually) and serve it at localhost:8080 with a toolshed at
-localhost:9009.
+# WARNING
 
-Once it's up, please restart Galaxy in the container with 
-```docker exec [container name] supervisorctl restart galaxy: ```
-Jobs just do not seem to run properly otherwise and the next steps won't work!
+Install this tool to a throw-away private Galaxy or Docker container ONLY!
 
-The generated container includes a workflow and 2 sample data sets for the workflow
+Please NEVER on a public or production instance where a hostile user may
+be able to gain access if they can acquire an administrative account login.
 
-Load the workflow. Adjust the inputs for each as labelled. The perl example counts GC in phiX.fasta. 
-The python scripts use the rgToolFactory.py as their input - any text file will work but I like the
-recursion. The BWA example has some mitochondrial reads and reference. Run the workflow and watch.
-This should fill the history with some sample tools you can rerun and play with.
-Note that each new tool will have been tested using Planemo. In the workflow, in Galaxy.
-Extremely cool to watch.
+It only runs for server administrators - the ToolFactory tool will refuse to execute for an ordinary user since
+it can install new tools to the Galaxy server it executes on! This is not something you should allow other than
+on a throw away instance that is protected from potentially hostile users.
 
-*WARNING* 
-
- Install this tool on a throw-away private Galaxy or Docker container ONLY
- Please NEVER on a public or production instance
-
-*Short Story*
+## Short Story
 
 Galaxy is easily extended to new applications by adding a new tool. Each new scientific computational package added as
-a tool to Galaxy requires some special instructions to be written. This is sometimes termed "wrapping" the package
-because the instructions tell Galaxy how to run the package as a new Galaxy tool. Any tool in a Galaxy is 
-readily available to all the users through a consistent and easy to use interface.
+a tool to Galaxy requires an XML document describing how the application interacts with Galaxy.
+This is sometimes termed "wrapping" the package because the instructions tell Galaxy how to run the package
+as a new Galaxy tool. Any tool that has been wrapped is readily available to all the users through a consistent
+and easy to use interface once installed in the local Galaxy server.
+
+Most Galaxy tool wrappers have been manually prepared by skilled programmers, many using Planemo because it
+automates much of the boilerplate and makes the process much easier.
+The ToolFactory (TF) now uses Planemo under the hood for testing, but hides the command
+line complexities. The user will still need appropriate skills in terms of describing the interface between
+Galaxy and the new application, but will be helped by a Galaxy tool form to collect all the needed
+settings, together with automated testing and uploading to a toolshed with optional local installation.
+
+
+## ToolFactory generated tools are ordinary Galaxy tools
+
+A TF generated tool that passes the Planemo test is ready to publish in any Galaxy Toolshed and ready to install in any running Galaxy instance.
+They are fully workflow compatible and work exactly like any hand-written tool. The user can select input files of the specified type(s) from their
+history and edit each of the specified parameters. The tool form will show all the labels and help text supplied when the tool was built. When the tool
+is executed, the dependent binary or script will be passed all the i/o files and parameters as specified, and will write outputs to the specified new
+history datasets - just like any other Galaxy tool.
+
+## Models for tool command line construction
+
+The key to turning any software package into a Galaxy tool is the automated construction of a suitable command line.
+
+The TF can build a new tool that will allow the tool user to select input files from their history, set any parameters and when run will send the
+new output files to the history as specified when the tool builder completed the form and built the new tool.
+
+That tool can contain instructions to run any Conda dependency or a system executable like bash. Whether a bash script you have written or
+a Conda package like bwa, the executable will expect to find settings for input, output and parameters on a command line.
+
+These are often passed as "--name value" (argparse style) or in a fixed order (positional style).
+
+The ToolFactory allows either, or for "filter" applications that process input from STDIN and write processed output to STDOUT.
+
+The simplest tool model wraps a simple script or Conda dependency package requiring only input and output files, with no user supplied settings illustrated by
+the Tacrev demonstration tool found in the Galaxy running in the ToolFactory docker container. It passes a user selected input file from the current history on STDIN
+to a bash script. The bash script runs the unix tac utility (reverse cat) piped to the unix rev (reverse lines in a text file) utility. It's a one liner:
+
+`tac | rev`
+
+The tool building form allows zero or more Conda package name(s) and version(s) and an optional script to be executed by either a system
+executable like ``bash`` or the first of any named Conda dependency package/version. Tacrev uses a tiny bash script shown above and uses the system
+bash. Conda bash can be specified if it is important to use the same version consistently for the tool.
+
+On the tool form, the repeat section allowing zero or more input files was set to be a text file to be selected by the tool user and
+in the repeat section allowing one or more outputs, a new output file with special value `STDOUT` as the positional parameter, causes the TF to
+generate a command to capture STDOUT and send it to the new history file containing the reversed input text.
+
+By reversed, we mean really, truly reversed.
+
+That simple model can be made much more complicated, and can pass inputs and outputs as named or positional parameters,
+to allow more complicated scripts or dependent binaries that require:
+
+1. Any number of input data files selected by the user from existing history data
+2. Any number of output data files written to the user's history
+3. Any number of user supplied parameters. These can be passed as command line arguments to the script or the dependency package. Either
+positional or named (argparse) style command line parameter passing can be used.
+
+More complex models can be seen in the Sedtest, Pyrevpos and Pyrevargparse tools illustrating positional and argparse parameter passing.
+
+The most complex demonstration is the Planemo advanced tool tutorial BWA tool. There is one version using a command-override to implement
+exactly the same command structure in the Planemo tutorial. A second version uses a bash script and positional parameters to achieve the same
+result. Some tool builders may find the bash version more familiar and cleaner but the choice is yours.
+
+## Overview
+
+![IHello example ToolFactory tool form](files/hello_toolfactory_form.png?raw=true "Part of the Hello world example ToolFactory tool form")
+
+
+Steps in building a new Galaxy tool are all conducted through Galaxy running in the docker container:
+
+1. Login to the Galaxy running in the container at http://localhost:8080 using an admin account. They are specified in config/galaxy.yml and
+    in the documentation at
+    and the ToolFactory will error out and refuse to run for non-administrative tool builders as a minimal protection from opportunistic hostile use.
+
+2. Start the TF and fill in the form, providing sample inputs and parameter values to suit the Conda package being wrapped.
+
+3. Execute the tool to create a new XML tool wrapper using the sample inputs and parameter settings for the inbuilt tool test. Planemo runs twice.
+    firstly to generate the test outputs and then to perform a proper test. The completed toolshed archive is written to the history
+    together with the planemo test report. Optionally the new tool archive can be uploaded
+    to the toolshed running in the same container (http://localhost:9009) and then installed inside the Galaxy in the container for further testing.
+
+4. If the test fails, rerun the failed history job and correct errors on the tool form before rerunning until everything works correctly.
+
+![How it works](files/TFasIDE.png?raw=true "Overview of the ToolFactory as an Integrated Development Environment")
+
+## Planning and building new Galaxy tool wrappers.
+
+It is best to have all the required planning done to wrap any new script or binary before firing up the TF.
+Conda is the only current dependency manager supported. Before starting, at the very least, the tool builder will need
+to know the required software package name in Conda and the version to use, how the command line for
+the package must be constructed, and there must be sample inputs in the working history for each of the required data inputs
+for the package, together with values for every parameter to suit these sample inputs. These are required on the TF form
+for preparing the inbuilt tool test. That test is run using Planemo, as part of the tool generation process.
+
+A new tool is specified by filling in the usual Galaxy tool form.
+
+The form starts with a new tool name. Most tools will need dependency packages and versions
+for the executable. Only Conda is currently supported.
+
+If a script is needed, it can be pasted into a text box and the interpreter named. Available system executables
+can be used such as bash, or an interpreter such as python, perl or R can be nominated as conda dependencies
+to ensure reproducible analyses.
+
+The tool form will be generated from the input data and the tool builder supplied parameters. The command line for the
+executable is built using positional or argparse (named e.g. --input_file /foo/baz) style
+parameters and is completely dependent on the executable. These can include:
+
+1. Any number of input data sets needed by the executable. Each appears to the tool user on the run form and is included
+on the command line for the executable. The tool builder must supply a small representative sample for each one as
+an input for the automated tool test.
 
-Most Galaxy tool wrappers have been manually prepared by skilled programmers, many using Planemo because it 
-automates much of the basic boilerplate and makes the process much easier. The ToolFactory (TF) 
-uses Planemo under the hood for many functions, but hides the command
-line complexities from the TF user. 
+2. Any number of output data sets generated by the package can be added to the command line and will appear in
+the user's history at the end of the job
+
+3. Any number of text or numeric parameters. Each will appear to the tool user on the run form and are included
+on the command line to the executable. The tool builder must supply a suitable representative value for each one as
+the value to be used for the automated tool test.
+
+Once the form is completed, executing the TF will build a new XML tool wrapper
+including a functional test based on the sample settings and data.
+
+If the Planemo test passes, the tool can be optionally uploaded to the local Galaxy used in the image for more testing.
+
+A local toolshed runs inside the container to allow an automated installation, although any toolshed and any accessible
+Galaxy can be specified for this process by editing the default URL and API keys to provide appropriate credentials.
+
+## Generated Tool Dependency management
+
+Conda is used for all dependency management although tools that use system utilities like sed, bash or awk
+may be available on job execution nodes. Sed and friends are available as Conda (conda-forge) dependencies if necessary.
+Versioned Conda dependencies are always baked-in to the tool and will be used for reproducible calculation.
+
+## Requirements
+
+These are all managed automagically. The TF relies on galaxyxml to generate tool xml and uses ephemeris and
+bioblend to load tools to the toolshed and to Galaxy. Planemo is used for testing and runs in a biocontainer currently at
+https://quay.io/fubar2/planemo-biocontainer
+
+## Caveats
+
+This docker image requires privileged mode so exposes potential security risks if hostile tool builders gain access.
+Please, do not run it in any situation where that is a problem - never, ever on a public facing Galaxy server.
+On a laptop or workstation should be fine in a non-hostile environment.
+
+
+## Example generated XML
 
-*More Explanation*
+For the bwa-mem example, a supplied bash script is included as a configfile and so has escaped characters.
+```
+<tool name="bwatest" id="bwatest" version="0.01">
+  <!--Cite: Creating re-usable tools from scripts doi:10.1093/bioinformatics/bts573-->
+  <!--Source in git at: https://github.com/fubar2/toolfactory-->
+  <!--Created by admin@galaxy.org at 30/11/2020 07:12:10 using the Galaxy Tool Factory.-->
+  <description>Planemo advanced tool building sample bwa mem mapper as a ToolFactory demo</description>
+  <requirements>
+    <requirement version="0.7.15" type="package">bwa</requirement>
+    <requirement version="1.3" type="package">samtools</requirement>
+  </requirements>
+  <configfiles>
+    <configfile name="runme"><![CDATA[
+REFFILE=\$1
+FASTQ=\$2
+BAMOUT=\$3
+rm -f "refalias"
+ln -s "\$REFFILE" "refalias"
+bwa index -a is "refalias"
+bwa mem -t "2"  -v 1 "refalias" "\$FASTQ"  > tempsam
+samtools view -Sb tempsam > temporary_bam_file.bam
+samtools sort -o "\$BAMOUT" temporary_bam_file.bam
 
-The TF is an unusual Galaxy tool, designed to allow a skilled user to make new Galaxy tools. 
+]]></configfile>
+  </configfiles>
+  <version_command/>
+  <command><![CDATA[bash
+$runme
+$input1
+$input2
+$bam_output]]></command>
+  <inputs>
+    <param optional="false" label="Reference sequence for bwa to map the fastq reads against" help="" format="fasta" multiple="false" type="data" name="input1" argument="input1"/>
+    <param optional="false" label="Reads as fastqsanger to align to the reference sequence" help="" format="fastqsanger" multiple="false" type="data" name="input2" argument="input2"/>
+  </inputs>
+  <outputs>
+    <data name="bam_output" format="bam" label="bam_output" hidden="false"/>
+  </outputs>
+  <tests>
+    <test>
+      <output name="bam_output" value="bam_output_sample" compare="sim_size" format="bam" delta_frac="0.1"/>
+      <param name="input1" value="input1_sample"/>
+      <param name="input2" value="input2_sample"/>
+    </test>
+  </tests>
+  <help><![CDATA[
+
+**What it Does**
+
+Planemo advanced tool building sample bwa mem mapper
+
+Reimagined as a bash script for a ToolFactory demonstration
+
+
+------
+
+Script::
+
+    REFFILE=$1
+    FASTQ=$2
+    BAMOUT=$3
+    rm -f "refalias"
+    ln -s "$REFFILE" "refalias"
+    bwa index -a is "refalias"
+    bwa mem -t "2"  -v 1 "refalias" "$FASTQ"  > tempsam
+    samtools view -Sb tempsam > temporary_bam_file.bam
+    samtools sort -o "$BAMOUT" temporary_bam_file.bam
+
+]]></help>
+</tool>
+
+```
+
+
+
+## More Explanation
+
+The TF is an unusual Galaxy tool, designed to allow a skilled user to make new Galaxy tools.
 It appears in Galaxy just like any other tool but outputs include new Galaxy tools generated
 using instructions provided by the user and the results of Planemo lint and tool testing using
 small sample inputs provided by the TF user. The small samples become tests built in to the new tool.
 
-It offers a familiar Galaxy form driven way to define how the user of the new tool will 
+It offers a familiar Galaxy form driven way to define how the user of the new tool will
 choose input data from their history, and what parameters the new tool user will be able to adjust.
 The TF user must know, or be able to read, enough about the tool to be able to define the details of
 the new Galaxy interface and the ToolFactory offers little guidance on that other than some examples.
@@ -57,8 +257,8 @@
 Tools always depend on other things. Most tools in Galaxy depend on third party
 scientific packages, so TF tools usually have one or more dependencies. These can be
 scientific packages such as BWA or scripting languages such as Python and are
-usually managed by Conda. If the new tool relies on a system utility such as bash or awk 
-where the importance of version control on reproducibility is low, these can be used without 
+managed by Conda. If the new tool relies on a system utility such as bash or awk
+where the importance of version control on reproducibility is low, these can be used without
 Conda management - but remember the potential risks of unmanaged dependencies on computational
 reproducibility.
 
@@ -72,7 +272,7 @@
 environment is actually possible, but not recommended being somewhat clumsy and inefficient.
 
 Tools nearly always take one or more data sets from the user's history as input. TF tools
-allow the TF user to define what Galaxy datatypes the tool end user will be able to choose and what 
+allow the TF user to define what Galaxy datatypes the tool end user will be able to choose and what
 names or positions will be used to pass them on a command line to the package or script.
 
 Tools often have various parameter settings. The TF allows the TF user to define how each
@@ -83,7 +283,7 @@
 
 Best practice Galaxy tools have one or more automated tests. These should use small sample data sets and
 specific parameter settings so when the tool is tested, the outputs can be compared with their expected
-values. The TF will automatically create a test for the new tool. It will use the sample data sets 
+values. The TF will automatically create a test for the new tool. It will use the sample data sets
 chosen by the TF user when they built the new tool.
 
 The TF works by exposing *unrestricted* and therefore extremely dangerous scripting
@@ -91,108 +291,86 @@
 run scripts in R, python, sh and perl. For this reason, a Docker container is
 available to help manage the associated risks.
 
-*Scripting uses*
+## Scripting uses
 
 To use a scripting language to create a new tool, you must first prepared and properly test a script. Use small sample
 data sets for testing. When the script is working correctly, upload the small sample datasets
 into a new history, start configuring a new ToolFactory tool, and paste the script into the script text box on the TF form.
 
-*Outputs*
-
-Once the script runs sucessfully, a new Galaxy tool that runs your script
-can be generated. Select the "generate" option and supply some help text and
-names. The new tool will be generated in the form of a new Galaxy datatype
-*tgz* - as the name suggests, it's an archive ready to upload to a
-Galaxy ToolShed as a new tool repository.
+### Outputs
 
-It is also possible to run a tool to generate test outputs, then test it
-using planemo. A toolshed is built in to the Docker container and configured
-so a tool can be tested, sent to that toolshed, then installed in the Galaxy
-where the TF is running.
+The TF will generate the new tool described on the TF form, and test it
+using planemo. Optionally if a local toolshed is running, it can be used to
+install the new tool back into the generating Galaxy.
 
-If the tool requires a command or test XML override, then planemo is 
-needed to generate test outputs to make a complete tool, rerun to test 
-and if required upload to the local toolshed and install in the Galaxy 
-where the TF is running.
+A toolshed is built in to the Docker container and configured
+so a tool can be tested, sent to that toolshed, then installed in the Galaxy
+where the TF is running using the default toolshed and Galaxy URL and API keys.
 
 Once it's in a ToolShed, it can be installed into any local Galaxy server
 from the server administrative interface.
 
-Once the new tool is installed, local users can run it - each time, the 
+Once the new tool is installed, local users can run it - each time, the
 package and/or script that was supplied when it was built will be executed with the input chosen
 from the user's history, together with user supplied parameters. In other words, the tools you generate with the
-ToolFactory run just like any other Galaxy tool.
+TF run just like any other Galaxy tool.
 
 TF generated tools work as normal workflow components.
 
 
-*Limitations*
+## Limitations
 
 The TF is flexible enough to generate wrappers for many common scientific packages
 but the inbuilt automation will not cope with all possible situations. Users can
 supply overrides for two tool XML segments - tests and command and the BWA
-example in the supplied samples workflow illustrates their use.  
-
-*Installation*
+example in the supplied samples workflow illustrates their use. It does not deal with
+repeated elements or conditional parameters such as allowing a user to choose to see "simple"
+or "advanced" parameters (yet) and there will be plenty of packages it just
+won't cover - but it's a quick and efficient tool for the other 90% of cases. Perfect for
+that bash one liner you need to get that workflow functioning correctly for this
+afternoon's demonstration!
 
-The Docker container is the best way to use the TF because it is preconfigured
-to automate new tool testing and has a built in local toolshed where each new tool
-is uploaded. If you grab the docker container, it should just work. 
+## Installation
 
-If you build the container, there are some things to watch out for. Let it run for 10 minutes
-or so once you build it - check with top until conda has finished fussing. Once everything quietens
-down, find the container with
-```docker ps```
-and use
-```docker exec [containername] supervisorctl restart galaxy:```
-That colon is not a typographical mistake.
-Not restarting after first boot seems to leave the job/worflow system confused and the workflow
-just will not run properly until Galaxy has restarted.
+The Docker container https://github.com/fubar2/toolfactory-galaxy-docker/blob/main/README.md
+is the best way to use the TF because it is preconfigured
+to automate new tool testing and has a built in local toolshed where each new tool
+is uploaded. If you grab the docker container, it should just work after a restart and you
+can run a workflow to generate all the sample tools. Running the samples and rerunning the ToolFactory
+jobs that generated them allows you to add fields and experiment to see how things work.
 
-Login as admin@galaxy.org with password "password". Feel free to change it once you are logged in. 
-There should be a companion toolshed at localhost:9090. The history should have some sample data for
-the workflow.
-
-Run the workflow and make sure the right dataset is selected for each of the input files. Most of the 
-examples use text files so should run, but the bwa example needs the right ones to work properly.
-
-When the workflow is finished, you will have half a dozen examples to rerun and play with. They have also 
-all been tested and installed so you should find them in your tool menu under "Generated Tools"
-
-It is easy to install without Docker, but you will need to make some 
+It can be installed like any other tool from the Toolshed, but you will need to make some
 configuration changes (TODO write a configuration). You can install it most conveniently using the
 administrative "Search and browse tool sheds" link. Find the Galaxy Main
 toolshed at https://toolshed.g2.bx.psu.edu/ and search for the toolfactory
 repository in the Tool Maker section. Open it and review the code and select the option to install it.
 
-Otherwise, if not already there pending an accepted PR,
-please add:
-<datatype extension="tgz" type="galaxy.datatypes.binary:Binary"
-mimetype="multipart/x-gzip" subclass="True" />
-to your local data_types_conf.xml.
+If not already there please add:
+
+```
+<datatype extension="tgz" type="galaxy.datatypes.binary:Binary" mimetype="multipart/x-gzip" subclass="True" />
+```
+
+to your local config/data_types_conf.xml.
 
 
-*Restricted execution*
+## Restricted execution
+
+The tool factory tool itself will ONLY run for admin users -
+people with IDs in config/galaxy.yml "admin_users".
 
-The tool factory tool itself will then be usable ONLY by admin users -
-people with IDs in admin_users. **Yes, that's right. ONLY
-admin_users can run this tool** Think about it for a moment. If allowed to
-run any arbitrary script on your Galaxy server, the only thing that would
-impede a miscreant bent on destroying all your Galaxy data would probably
-be lack of appropriate technical skills.
+*ONLY admin_users can run this tool*
 
-**Generated tool Security**
+That doesn't mean it's safe to install on a shared or exposed instance - please don't.
+
+## Generated tool Security
 
 Once you install a generated tool, it's just
 another tool - assuming the script is safe. They just run normally and their
 user cannot do anything unusually insecure but please, practice safe toolshed.
 Read the code before you install any tool. Especially this one - it is really scary.
 
-**Send Code**
-
-Pull requests and suggestions welcome as git issues please?
-
-**Attribution**
+## Attribution
 
 Creating re-usable tools from scripts: The Galaxy Tool Factory
 Ross Lazarus; Antony Kaspi; Mark Ziemann; The Galaxy Team
@@ -200,12 +378,3 @@
 
 http://bioinformatics.oxfordjournals.org/cgi/reprint/bts573?ijkey=lczQh1sWrMwdYWJ&keytype=ref
 
-**Licensing**
-
-Copyright Ross Lazarus 2010
-ross lazarus at g mail period com
-
-All rights reserved.
-
-Licensed under the LGPL
-
--- a/toolfactory/rgToolFactory2.py	Sat Apr 10 02:16:35 2021 +0000
+++ b/toolfactory/rgToolFactory2.py	Sat Apr 17 22:50:25 2021 +0000
@@ -28,12 +28,15 @@
 import tempfile
 import time
 
+from bioblend import ConnectionError
+from bioblend import toolshed
+
 import galaxyxml.tool as gxt
 import galaxyxml.tool.parameters as gxtp
+
 import lxml
+
 import yaml
-from bioblend import ConnectionError
-from bioblend import toolshed
 
 myversion = "V2.2 February 2021"
 verbose = True
@@ -76,7 +79,7 @@
 
     """
 
-    def __init__(self, args=None):
+    def __init__(self, args=None):  # noqa
         """
         prepare command line cl for running the tool here
         and prepare elements needed for galaxyxml tool generation
@@ -229,20 +232,25 @@
         clsuffix = []
         xclsuffix = []
         for i, p in enumerate(self.infiles):
+            nam = p["infilename"]
             if p["origCL"].strip().upper() == "STDIN":
                 appendme = [
-                    p["infilename"],
-                    p["infilename"],
-                    "< %s" % p["infilename"],
+                    nam,
+                    nam,
+                    "< %s" % nam,
                 ]
                 xappendme = [
-                    p["infilename"],
-                    p["infilename"],
-                    "< $%s" % p["infilename"],
+                    nam,
+                    nam,
+                    "< $%s" % nam,
                 ]
             else:
+                rep = p["repeat"] == "1"
+                over = ""
+                if rep:
+                    over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for'
                 appendme = [p["CL"], p["CL"], ""]
-                xappendme = [p["CL"], "$%s" % p["CL"], ""]
+                xappendme = [p["CL"], "$%s" % p["CL"], over]
             clsuffix.append(appendme)
             xclsuffix.append(xappendme)
         for i, p in enumerate(self.outfiles):
@@ -256,7 +264,7 @@
             nam = p["name"]
             rep = p["repeat"] == "1"
             if rep:
-                over = f" #for $rep in $R_{nam}:\n--{nam} $rep.{nam}\n#end for"
+                over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for'
             else:
                 over = p["override"]
             clsuffix.append([p["CL"], nam, over])
@@ -423,7 +431,7 @@
         return ndash
 
     def doXMLparam(self):
-        """flake8 made me do this..."""
+        """Add all needed elements to tool"""  # noqa
         for p in self.outfiles:
             newname = p["name"]
             newfmt = p["format"]
@@ -486,7 +494,7 @@
             newname = p["infilename"]
             newfmt = p["format"]
             ndash = self.getNdash(newname)
-            reps = p.get("repeat", 0) == 1
+            reps = p.get("repeat", "0") == "1"
             if not len(p["label"]) > 0:
                 alab = p["CL"]
             else:
@@ -674,7 +682,7 @@
             tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname)
             self.testparam.append(tp)
 
-    def makeXML(self):
+    def makeXML(self):  # noqa
         """
         Create a Galaxy xml tool wrapper for the new script
         Uses galaxyhtml
@@ -712,6 +720,10 @@
             safertext = safertext + "\n".join(scr)
         self.newtool.help = safertext
         self.newtool.version_command = f'echo "{self.args.tool_version}"'
+        std = gxtp.Stdios()
+        std1 = gxtp.Stdio()
+        std.append(std1)
+        self.newtool.stdios = std
         requirements = gxtp.Requirements()
         if self.args.packages:
             for d in self.args.packages.split(","):
@@ -725,7 +737,7 @@
                 requirements.append(
                     gxtp.Requirement("package", packg.strip(), ver.strip())
                 )
-            self.newtool.requirements = requirements
+        self.newtool.requirements = requirements
         if self.args.parampass == "0":
             self.doNoXMLparam()
         else:
@@ -1042,6 +1054,8 @@
         cll = [
             "planemo",
             "test",
+            "--galaxy_python_version",
+            self.args.python_version,
             "--conda_auto_init",
             "--test_data",
             os.path.abspath(self.testdir),
@@ -1062,6 +1076,36 @@
         tout.close()
         return p.returncode
 
+    def set_planemo_galaxy_root(self, galaxyroot='/galaxy-central', config_path=".planemo.yml"):
+        # bug in planemo - bogus '--dev-wheels' passed to run_tests.sh as at april 2021 - need a fiddled copy so it is ignored until fixed
+        CONFIG_TEMPLATE = """## Planemo Global Configuration File.
+## Everything in this file is completely optional - these values can all be
+## configured via command line options for the corresponding commands.
+
+## Specify a default galaxy_root for test and server commands here.
+galaxy_root: %s
+## Username used with toolshed(s).
+#shed_username: "<TODO>"
+sheds:
+  # For each tool shed you wish to target, uncomment key or both email and
+  # password.
+  toolshed:
+    #key: "<TODO>"
+    #email: "<TODO>"
+    #password: "<TODO>"
+  testtoolshed:
+    #key: "<TODO>"
+    #email: "<TODO>"
+    #password: "<TODO>"
+  local:
+    #key: "<TODO>"
+    #email: "<TODO>"
+    #password: "<TODO>"
+"""
+        if not os.path.exists(config_path):
+            with open(config_path, "w") as f:
+                f.write(CONFIG_TEMPLATE % galaxyroot)
+
 
 def main():
     """
@@ -1105,6 +1149,7 @@
     a("--galaxy_venv", default="/galaxy_venv")
     a("--collection", action="append", default=[])
     a("--include_tests", default=False, action="store_true")
+    a("--python_version", default="3.9")
     args = parser.parse_args()
     assert not args.bad_user, (
         'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \
@@ -1124,9 +1169,6 @@
         r.moveRunOutputs()
         r.makeToolTar()
     else:
-        # r.planemo_test(genoutputs=True)  # this fails :( - see PR
-        # r.moveRunOutputs()
-        # r.makeToolTar(report_fail=False)
         r.planemo_test_once()
         r.moveRunOutputs()
         r.makeToolTar(report_fail=True)
--- a/toolfactory/rgToolFactory2.xml	Sat Apr 10 02:16:35 2021 +0000
+++ b/toolfactory/rgToolFactory2.xml	Sat Apr 17 22:50:25 2021 +0000
@@ -180,13 +180,12 @@
   </macros>
 
 <requirements>
-   <requirement type="package" version="0.4.13">galaxyxml</requirement>
-   <requirement type="package" version="0.14.0">bioblend</requirement>
-   <requirement type="package" version="0.10.6">ephemeris</requirement>
+   <requirement type="package" version="0.4.14">galaxyxml</requirement>
    <requirement type="package" version="0.74.3">planemo</requirement>
+   <container type="docker">quay.io/biocontainers/mulled-v2-0a86ccf22d71945a175383bcea5edd6b51c25ed0:55f1b8132a10ad91f0016ba9f4c692627ca2d25b-0</container>
 </requirements>
 
-  <command ><![CDATA[
+<command detect_errors="exit_code"><![CDATA[
 #import os
 #set dev_env = os.environ.get('GALAXY_DEVELOPMENT_ENVIRONMENT', '0') == '1'
 #if not $dev_env and ( $__user_email__ not in $__admin_users__ ):
--- a/toolfactory/test-data/test1_log.txt	Sat Apr 10 02:16:35 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-## Executing Toolfactory generated command line = python /tmp/pyrevposq5dmcdy1.python /tmp/tmpqrksf8sd/files/5/b/9/dataset_5b952a86-87df-44ad-a415-ea549f3f0cee.dat output2