changeset 39:fe74900d6dc7 draft default tip

planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/cutadapt commit a5b6cb44f81abe57a4269bded1fa4d41f462f9d5
author iuc
date Fri, 17 May 2024 13:32:03 +0000
parents b1c926deaa2d
children
files cutadapt.xml macros.xml test-data/cutadapt_out1_pair_adapters.fq.gz test-data/cutadapt_out2_pair_adapters.fq.gz test-data/cutadapt_rest.json test-data/cutadapt_rest_json.txt
diffstat 6 files changed, 513 insertions(+), 496 deletions(-) [+]
line wrap: on
line diff
--- a/cutadapt.xml	Mon Apr 15 06:31:32 2024 +0000
+++ b/cutadapt.xml	Fri May 17 13:32:03 2024 +0000
@@ -7,17 +7,18 @@
     <expand macro='xrefs'/>
     <expand macro='requirements' />
     <version_command>cutadapt --version</version_command>
-
     <command detect_errors="exit_code"><![CDATA[
-## Link in the input and output files, so Cutadapt can tell their type
-
 #import re
-#set read1 = "input_f"
-#set read2 = "input_r"
-#set paired = False
+
+## set things up for handling inputs and outputs in single- vs paired-end modes
 #set library_type = str($library.type)
+#if $library_type == 'single':
+    #set paired = False
+#else:
+    #set paired = True
+#end if
+
 #if $library_type == 'paired':
-    #set paired = True
     #set input_1 = $library.input_1
     #set input_2 = $library.input_2
     ## Avoid the paired read input files sharing the same name, else the program still runs but 
@@ -28,8 +29,7 @@
         #set read1 = read1 + "_1"
         #set read2 = read2 + "_2"
     #end if
-#else if $library_type == 'paired_collection'
-    #set paired = True
+#elif $library_type == 'paired_collection'
     #set input_1 = $library.input_1.forward
     #set input_2 = $library.input_1.reverse
     #set read1 = re.sub('[^\w\-\s]', '_', str($library.input_1.name)) + "_1"
@@ -50,7 +50,6 @@
     #set ext=ext+".bz2"
 #end if
 
-
 #set read1 = $read1 + $ext
 #set out1 = "out1" + $ext
 #set rest_output = "rest_output" + $ext
@@ -58,7 +57,6 @@
 #set too_short_output = "too_short_output" + $ext
 #set too_long_output = "too_long_output" + $ext
 #set untrimmed_output = "untrimmed_output" + $ext
-ln -f -s '${input_1}' '$read1' &&
 
 #if $paired:
     #if $input_2.is_of_type("fastq", "fastq.gz", "fastq.bz2"):
@@ -76,35 +74,52 @@
     #set too_short_paired_output = "too_short_paired_output" + $ext2
     #set too_long_paired_output = "too_long_paired_output" + $ext2
     #set untrimmed_paired_output = "untrimmed_paired_output" + $ext2
-    ln -f -s '${input_2}' '$read2' &&
 #end if
 
-## Run Cutadapt
-
+## Link in the input and output files, so Cutadapt can tell their type
+ln -f -s '$input_1' '$read1' &&
+#if $paired:
+    ln -f -s '$input_2' '$read2' &&
+#end if
+## Create dedicated output folder if needed
 #if 'multiple_output' in $output_selector:
     mkdir split &&
 #end if
 
+## Run Cutadapt
 cutadapt
 
 -j=\${GALAXY_SLOTS:-4}
 
-#if 'json_stats' in $output_selector:
-    --json stats.json
-#end if
+## Read1 trimming
+#set ADAPTER_ARGUMENT="-a"
+#for $a in $library.r1.adapters
+    @adapter_cli@
+#end for
+#set ADAPTER_ARGUMENT="-b"
+#for $a in $library.r1.anywhere_adapters
+    @adapter_cli@
+#end for
+#set ADAPTER_ARGUMENT="-g"
+#for $a in $library.r1.front_adapters
+    @adapter_cli@
+#end for
 
-#if str( $library.type ) == "single":
-    @read1_options@
-    #if 'multiple_output' in $output_selector:
-        --output='split/{name}.${input_1.ext}'
-    #else:
-        --output='$out1'
-    #end if
-#else:
-    @read1_options@
-    @read2_options@
-    --output='$out1'
-    --paired-output='$out2'
+#if $paired:
+    ## Read2 trimming
+    #set ADAPTER_ARGUMENT="-A"
+    #for $a in $library.r2.adapters2
+        @adapter_cli@
+    #end for
+    #set ADAPTER_ARGUMENT="-B"
+    #for $a in $library.r2.anywhere_adapters2
+        @adapter_cli@
+    #end for
+    #set ADAPTER_ARGUMENT="-G"
+    #for $a in $library.r2.front_adapters2
+        @adapter_cli@
+    #end for
+    $library.pair_adapters
 #end if
 
 --error-rate=$adapter_options.error_rate
@@ -116,53 +131,64 @@
 --action=$adapter_options.action
 $adapter_options.revcomp
 
+#if $other_trimming_options.cut != 0:
+    --cut=$other_trimming_options.cut
+#end if
+#if $paired and $other_trimming_options.cut2 != 0:
+    -U $other_trimming_options.cut2
+#end if
+#if str($other_trimming_options.quality_cutoff) != '0':
+    --quality-cutoff=$other_trimming_options.quality_cutoff
+#end if
+#if $paired and str($other_trimming_options.quality_cutoff2) != '':
+    -Q $other_trimming_options.quality_cutoff2
+#end if
+#if str($other_trimming_options.nextseq_trim) != '0':
+    --nextseq-trim=$other_trimming_options.nextseq_trim
+#end if
+$other_trimming_options.trim_n
+$other_trimming_options.poly_a
+#if str($other_trimming_options.shorten_options.shorten_values) == 'True':
+    #if str($other_trimming_options.shorten_options.shorten_end) == '3prime'
+        --length=$other_trimming_options.shorten_options.length
+    #else
+        --length=-$other_trimming_options.shorten_options.length
+    #end if
+#end if
+
 $filter_options.discard_trimmed
 $filter_options.discard_untrimmed
 
-#if str($filter_options.minimum_length) and str($library.type) != "single" and str($library.minimum_length2) != '':
-    --minimum-length=$filter_options.minimum_length:$library.minimum_length2
-#else if str($filter_options.minimum_length):
+#if $paired and str($filter_options.minimum_length2):
+    --minimum-length=$filter_options.minimum_length:$filter_options.minimum_length2
+#elif $filter_options.minimum_length > 0:
     --minimum-length=$filter_options.minimum_length
 #end if
-#if str($filter_options.maximum_length) and str($library.type) != "single" and str($library.maximum_length2) != '':
-    --maximum-length=$filter_options.maximum_length:$library.maximum_length2
-#else if str($filter_options.maximum_length):
+#if $paired and str($filter_options.maximum_length2):
+    --maximum-length=$filter_options.maximum_length:$filter_options.maximum_length2
+#elif str($filter_options.maximum_length):
     --maximum-length=$filter_options.maximum_length
 #end if
 #if str($filter_options.max_n):
     --max-n=$filter_options.max_n
 #end if
-#if str( $library.type ) != "single":
-    #if $filter_options.pair_filter:
-        --pair-filter=$filter_options.pair_filter
-    #end if
+#if str($filter_options.max_expected_errors):
+    --max-ee=$filter_options.max_expected_errors
 #end if
-#if str($filter_options.max_expected_errors):
-    --max-expected-errors=$filter_options.max_expected_errors
+#if str($filter_options.max_average_error_rate):
+    --max-aer=$filter_options.max_average_error_rate
 #end if
-$filter_options.discard_cassava
+$filter_options.discard_casava
+#if $paired and str($filter_options.pair_filter) != 'any':
+    --pair-filter=$filter_options.pair_filter
+#end if
 
 #if $input_1.ext.startswith("fastqillumina") or $input_1.ext.startswith("fastqsolexa")
     --quality-base=64
 #end if
 
-#if str($read_mod_options.quality_cutoff) != '0':
-   --quality-cutoff=$read_mod_options.quality_cutoff
-#end if
-#if str($read_mod_options.nextseq_trim) != '0':
-    --nextseq-trim=$read_mod_options.nextseq_trim
-#end if
-$read_mod_options.trim_n
-$read_mod_options.poly_a
 #if $read_mod_options.strip_suffix != ''
-    --strip-suffix $read_mod_options.strip_suffix
-#end if
-#if str($read_mod_options.shorten_options.shorten_values) == 'True':
-    #if str($read_mod_options.shorten_options.shorten_end) == '3prime'
-        --length=$read_mod_options.shorten_options.length
-    #else
-        --length=-$read_mod_options.shorten_options.length
-    #end if
+    --strip-suffix='$read_mod_options.strip_suffix'
 #end if
 #if str($read_mod_options.length_tag) != '':
     --length-tag='$read_mod_options.length_tag'
@@ -172,13 +198,49 @@
 #end if
 $read_mod_options.zero_cap
 
+## Outputs handling
+#if 'json_stats' in $output_selector:
+    --json=stats.json
+#end if
+#if 'info_file' in $output_selector:
+    --info-file='$info_file'
+#end if
+#if 'rest_file' in $output_selector:
+    -r='${rest_output}'
+#end if
+#if 'wildcard_file' in $output_selector:
+    --wildcard-file='${wild_output}'
+#end if
+#if 'too_short_file' in $output_selector:
+    --too-short-output='${too_short_output}'
+    #if $paired:
+        --too-short-paired-output='${too_short_paired_output}'
+    #end if
+#end if
+#if 'too_long_file' in $output_selector:
+    --too-long-output='${too_long_output}'
+    #if $paired:
+        --too-long-paired-output='${too_long_paired_output}'
+    #end if
+#end if
+#if 'untrimmed_file' in $output_selector:
+    --untrimmed-output='${untrimmed_output}'
+    #if $paired:
+        --untrimmed-paired-output='${untrimmed_paired_output}'
+    #end if
+#end if
+#if not $paired and 'multiple_output' in $output_selector:
+    -o 'split/{name}.${input_1.ext}'
+#else:
+    -o '$out1'
+    #if $paired:
+        -p '$out2'
+    #end if
+#end if
 
-'${read1}'
+'$read1'
 #if $paired:
-    '${read2}'
-    #if $library.r2.quality_cutoff2:
-        -Q=$library.r2.quality_cutoff2
-    #end if
+    '$read2'
 #end if
 
 #if 'report' in $output_selector:
@@ -186,7 +248,6 @@
 #end if
     ]]></command>
     <inputs>
-
         <!-- Reads -->
         <conditional name="library">
             <param name="type" type="select" label="Single-end or Paired-end reads?">
@@ -194,27 +255,24 @@
                 <option value="paired">Paired-end</option>
                 <option value="paired_collection">Paired-end Collection</option>
             </param>
-
             <when value="single">
                 <param name="input_1" format="@FASTQ_TYPES@" type="data" label="FASTQ/A file" help="Should be of datatype &quot;fastq.gz&quot; or &quot;fasta&quot;" />
-                <expand macro="single_end_options" />
+                <expand macro="read1_adapters" />
             </when>
-
             <when value="paired">
                 <param name="input_1" format="@FASTQ_TYPES@" type="data" label="FASTQ/A file #1" help="Should be of datatype &quot;fastq.gz&quot;or &quot;fasta&quot;" />
                 <param name="input_2" format="@FASTQ_TYPES@" type="data" label="FASTQ/A file #2" help="Should be of datatype &quot;fastq.gz&quot;or &quot;fasta&quot;" />
-                <expand macro="paired_end_options" />
+                <expand macro="read1_adapters" />
+                <expand macro="read2_adapters" />
             </when>
-
             <when value="paired_collection">
                 <param name="input_1" format="@FASTQ_TYPES@" type="data_collection" collection_type="paired" label="Paired Collection" help="Should be of datatype &quot;fastq.gz&quot; or &quot;fasta&quot;" />
-                <expand macro="paired_end_options" />
+                <expand macro="read1_adapters" />
+                <expand macro="read2_adapters" />
             </when>
-
         </conditional>
-
         <!-- Adapter Options -->
-        <section name="adapter_options" title="Adapter Options">
+        <section name="adapter_options" title="Adapter Handling Options">
             <param name="action" type="select" label="What to do if a match is found">
                 <option value="trim" selected="true">Trim: trim adapter and upstream or downstream sequence</option>
                 <option value="retain">Retain: the read is trimmed, but the adapter sequence is not removed</option>
@@ -227,32 +285,19 @@
             <param argument="--times" type="integer" min="1" value="1" label="Match times" help="Try to remove adapters at most COUNT times. Useful when an adapter gets appended multiple times." />
             <param argument="--overlap" type="integer" min="1" value="3" label="Minimum overlap length" help="Minimum overlap length. If the overlap between the adapter and the sequence is shorter than LENGTH, the read is not modified. This reduces the number of bases trimmed purely due to short random adapter matches." />
             <param argument="--match-read-wildcards" type="boolean" checked="false" truevalue="--match-read-wildcards" falsevalue="" label="Match wilcards in reads" help="Interpret IUPAC wildcards in reads"/>
-            <param argument="--no-match-adapter-wildcards" type="boolean" checked="true" truevalue="" falsevalue="--no-match-adapter-wildcards" label="Match wilcards in adapters" help="Interpret IUPAC wildcards in adapters."/>
-            <param argument="--revcomp" type="boolean" checked="false" truevalue="--revcomp" falsevalue="" label="Look for adapters in the reverse complement" help="Check both the read and its reverse complement for adapter matches. If match is on reverse-complemented version, output that one. Default: check only read." />
+            <param argument="--no-match-adapter-wildcards" type="boolean" checked="true" truevalue="" falsevalue="--no-match-adapter-wildcards" label="Match wildcards in adapters" help="Interpret IUPAC wildcards in adapters."/>
+            <param name="revcomp" argument="--rc" type="boolean" checked="false" truevalue="--rc" falsevalue="" label="Look for adapters in the reverse complement" help="Check both the read and its reverse complement for adapter matches. If match is on reverse-complemented version, output that one. Default: check only read." />
         </section>
-
-        <!-- Filter Options -->
-        <section name="filter_options" title="Filter Options">
-            <param argument="--discard-trimmed" type="boolean" checked="false" truevalue="--discard-trimmed" falsevalue="" label="Discard Trimmed Reads" help="Discard reads that contain the adapter instead of trimming them. Use the 'Minimum overlap length' option in order to avoid throwing away too many randomly matching reads!" />
-            <param argument="--discard_untrimmed" type="boolean" checked="false" truevalue="--discard-untrimmed" falsevalue="" label="Discard Untrimmed Reads" help="Discard reads that do not contain the adapter." />
-            <param argument="--minimum-length" type="integer" min="0" optional="true" value="" label="Minimum length (R1)" help="Discard trimmed reads that are shorter than LENGTH.  Reads that are too short even before adapter removal are also discarded." />
-            <param argument="--maximum-length" type="integer" min="0" optional="true" value="" label="Maximum length (R1)" help="Discard trimmed reads that are longer than LENGTH.  Reads that are too long even before adapter removal are also discarded." />
-            <param argument="--max-n" type="float" min="0" optional="true" label="Max N" help="Discard reads with more than this number of 'N' bases. A number between 0 and 1 is interpreted as a fraction of the read length." />
-            <param argument="--pair-filter" type="select" optional="true" label="Pair filter" help="Which of the reads in a paired-end read have to match the filtering criterion in order for the pair to be filtered. Default: any">
-                <option value="any" selected="true">Any: a read pair is discarded (or redirected) if one of the reads (R1 or R2) fulfills the filtering criterion. </option>
-                <option value="both">Both: filtering criteria must apply to both reads in order for a read pair to be discarded. </option>
-                <option value="first">First: will make a decision about the read pair by inspecting whether the filtering criterion applies to the first read, ignoring the second read.</option>
-
+        <section name="other_trimming_options" title="Other Read Trimming Options">
+            <param argument="--cut" type="integer" value="0" label="Bases to cut from R1 reads before adapter trimming" help="Remove bases from each read (first read only if paired). If positive, remove bases from the beginning. If negative, remove bases from the end. This is applied *before* adapter trimming." />
+            <param name="cut2" argument="-U" type="integer" value="0" label="Bases to cut from R2 reads before adapter trimming" help="For paired-end data, you can define here a cut value to apply to R2 reads. Usage is identical to the R1 setting. Default: 0; ignored for single-end data." />
+            <param argument="--quality-cutoff" type="text" value="0" label="Quality cutoff(s) (R1)" help="Trim low-quality bases from 5' and/or 3' ends of each read before adapter removal. If one value is given, only the 3' end is trimmed. If two comma-separated cutoffs are given, the 5' end is trimmed with the first cutoff, the 3' end with the second.">
+                <sanitizer>
+                    <valid initial="string.digits"><add value="," /></valid>
+                </sanitizer>
+                <validator type="regex">[0-9]+(,[0-9])?</validator>
             </param>
-            <param argument="--max-expected-errors" type="float" min="0" optional="true" value="" label="Max expected errors" help="Discard reads whose expected number of errors (computed from quality values) exceeds this value." />
-            <param argument="--max-average-error-rate" type="float" min="0" max="1" optional="true" value="" label="Max average expected errors" help="As --max-expected-errors (see above), but divided by length to account for reads of varying length" />
-            <param argument="--discard-cassava" type="boolean" truevalue="--discard-cassava" falsevalue="" checked="false" label="Discard CASAVA filtering" help="Discard reads that did not pass CASAVA filtering (header has :Y:)." />
-        </section>
-
-        <!-- Read Modification Options -->
-        <section name="read_mod_options" title="Read Modification Options">
-            <param argument="--cut" type="integer" value="0" optional="true" label="Cut bases from reads before adapter trimming" help="Remove bases from each read (first read only if paired). If positive, remove bases from the beginning. If negative, remove bases from the end. This is applied *before* adapter trimming." />
-            <param argument="--quality-cutoff" type="text" value="0" label="Quality cutoff" help=" Trim low-quality bases from 5' and/or 3' ends of each read before adapter removal. Applied to both reads for paired-end data, unless a separate value for the second read is specified. If one value is given, only the 3' end is trimmed. If two comma-separated cutoffs are given, the 5' end is trimmed with the first cutoff, the 3' end with the second.">
+            <param name="quality_cutoff2" argument="-Q" type="text" optional="true" value="" label="Quality cutoff(s) R2" help="For paired-end data, you can set here a separate quality cutoff to apply to R2 reads specifically. Leave empty to reuse the R1 cutoff setting. Ignored for single-end data. Syntax is identical to the R1 setting.">
                 <sanitizer>
                     <valid initial="string.digits"><add value="," /></valid>
                 </sanitizer>
@@ -261,7 +306,6 @@
             <param argument="--nextseq-trim" type="integer" value="0" label="NextSeq trimming" help="Experimental option for quality trimming of NextSeq data. This is necessary because that machine cannot distinguish between G and reaching the end of the fragment (it encodes G as ‘black’). This option works like regular quality trimming (where one would use -q 20 instead), except that the qualities of G bases are ignored." />
             <param argument="--trim-n" type="boolean" truevalue="--trim-n" falsevalue="" checked="false" label="Trim Ns" help="Trim N's on ends of reads." />
             <param argument="--poly-a" type="boolean" truevalue="--poly-a" falsevalue="" checked="false" label="Trim poly-A tails" help="Note, this trim poly-T 'heads' on R2"/>
-            <param argument="--strip-suffix" label="Strip suffix" type="text" help="Remove this suffix from read names if present." />
             <conditional name="shorten_options">
                 <param name="shorten_values" type="select" label="Shortening reads to a fixed length" help="If you want to remove a fixed number of bases from each read, use the –cut option instead.">
                     <option value="True">Enabled</option>
@@ -277,6 +321,28 @@
                 <when value="False">
                 </when>
             </conditional>
+        </section>
+        <!-- Filter Options -->
+        <section name="filter_options" title="Read Filtering Options">
+            <param argument="--discard-trimmed" type="boolean" checked="false" truevalue="--discard-trimmed" falsevalue="" label="Discard Trimmed Reads" help="Discard reads that contain the adapter instead of trimming them. Use the 'Minimum overlap length' option in order to avoid throwing away too many randomly matching reads!" />
+            <param argument="--discard_untrimmed" type="boolean" checked="false" truevalue="--discard-untrimmed" falsevalue="" label="Discard Untrimmed Reads" help="Discard reads that do not contain the adapter." />
+            <param argument="--minimum-length" type="integer" min="0" value="1" label="Minimum length (R1)" help="Discard reads that, after processing, are shorter than LENGTH. Note: You can set this parameter to zero to keep empty reads (with zero-length sequence and quality string) in the output, but some downstream tools may have problems with these. Default: 1" />
+            <param name="minimum_length2" type="integer" min="0" value="" optional="true" label="Minimum length (R2)" help="For paired-end data, you can specify here a separate minimum length cutoff to apply to R2 reads. Leave empty to reuse the R1 cutoff set above. Ignored for single-end data." />
+            <param argument="--maximum-length" type="integer" min="0" optional="true" value="" label="Maximum length (R1)" help="Discard trimmed reads that are longer than LENGTH. Reads that are too long even before adapter removal are also discarded." />
+            <param name="maximum_length2" type="integer" min="0" value="" optional="true" label="Maximum length (R2)" help="For paired-end data, you can specify here a separate maximum length cutoff to apply to R2 reads. Leave empty to reuse the R1 cutoff set above. Ignored for single-end data." />
+            <param argument="--max-n" type="float" min="0" optional="true" label="Max N" help="Discard reads with more than this number of 'N' bases. A number between 0 and 1 is interpreted as a fraction of the read length." />
+            <param name="max_expected_errors" argument="--max-ee" type="float" min="0" optional="true" value="" label="Max expected errors" help="Discard reads whose expected number of errors (computed from quality values) exceeds this value." />
+            <param name="max_average_error_rate" argument="--max-aer" type="float" min="0" max="1" optional="true" value="" label="Max average expected errors" help="As --max-expected-errors (see above), but divided by length to account for reads of varying length" />
+            <param argument="--discard-casava" type="boolean" truevalue="--discard-casava" falsevalue="" checked="false" label="Discard CASAVA-filtered reads" help="Discard reads that did not pass CASAVA filtering (header has :Y:)." />
+            <param argument="--pair-filter" type="select" label="Pair filter" help="Which of the reads in a paired-end read have to match the filtering critera above in order for the pair to be filtered. Default: any">
+                <option value="any" selected="true">Any: a read pair is discarded (or redirected) if one of the reads (R1 or R2) fulfills the filtering criterion.</option>
+                <option value="both">Both: filtering criteria must apply to both reads in order for a read pair to be discarded.</option>
+                <option value="first">First: will make a decision about the read pair by inspecting whether the filtering criterion applies to the first read, ignoring the second read.</option>
+            </param>
+        </section>
+        <!-- Read Modification Options -->
+        <section name="read_mod_options" title="Read Modification Options">
+            <param argument="--strip-suffix" label="Strip suffix" type="text" help="Remove this suffix from read names if present." />
             <param argument="--length-tag" label="Length tag" type="text" optional="true" help="Search for TAG followed by a decimal number in the name of the read (description/comment field of the FASTA or FASTQ file). Replace the decimal number with the correct length of the trimmed read. For example, use --length-tag 'length=' to search for fields like 'length=123'." >
                 <sanitizer invalid_char="">
                     <valid initial="string.letters,string.digits">
@@ -304,9 +370,8 @@
             </param>
             <param argument="--zero-cap" type="boolean" truevalue="--zero-cap" falsevalue="" checked="false" label="Change negative quality values to zero" />
         </section>
-
         <!-- Output Options -->
-        <param name="output_selector" type="select" multiple="true" display="checkboxes" label="Outputs selector">
+        <param name="output_selector" type="select" multiple="true" display="checkboxes" label="Additional outputs to generate">
             <option value="report">Report: Cutadapt's per-adapter statistics. You can use this file with MultiQC.</option>
             <option value="info_file">Info file: write information about each read and its adapter matches.</option>
             <option value="rest_file">Rest of read: when the adapter matches in the middle of a read, write the rest (after the adapter).</option>
@@ -318,40 +383,36 @@
             <option value="json_stats">Statistics in JSON format</option>
         </param>
     </inputs>
-
     <outputs>
         <data name="out1" format="fastqsanger" metadata_source="library|input_1" default_identifier_source="library|input_1" from_work_dir="out1.*" label="${tool.name} on ${on_string}: Read 1 Output">
-            <filter>library['type'] != 'paired_collection' and 'multiple_output' not in output_selector</filter>
+            <filter>library['type'] != 'paired_collection'</filter>
+            <filter>not output_selector or 'multiple_output' not in output_selector</filter>
             <expand macro="inherit_format_1" />
         </data>
-
         <data name="out2" format="fastqsanger" metadata_source="library|input_2" default_identifier_source="library|input_2" from_work_dir="out2.*" label="${tool.name} on ${on_string}: Read 2 Output" >
-            <filter>library['type'] == 'paired' and 'multiple_output' not in output_selector</filter>
+            <filter>library['type'] == 'paired'</filter>
+            <filter>not output_selector or 'multiple_output' not in output_selector</filter>
             <expand macro="inherit_format_2" />
         </data>
-
         <collection name="out_pairs" type="paired" format_source="library|input_1" label="${tool.name} on ${on_string}: Reads">
-            <filter>library['type'] == 'paired_collection' and 'multiple_output' not in output_selector</filter>
+            <filter>library['type'] == 'paired_collection'</filter>
+            <filter>not output_selector or 'multiple_output' not in output_selector</filter>
             <data name="forward" from_work_dir="out1.*" />
             <data name="reverse" from_work_dir="out2.*" />
         </collection>
-        
         <data name="report" format="txt" from_work_dir="report.txt" label="${tool.name} on ${on_string}: Report">
             <filter>output_selector and 'report' in output_selector</filter>
         </data>
-        <data  name="info_file" format="txt" metadata_source="library|input_1" label="${tool.name} on ${on_string}: Info File" >
+        <data name="info_file" format="txt" metadata_source="library|input_1" label="${tool.name} on ${on_string}: Info File" >
             <filter>output_selector and 'info_file' in output_selector</filter>
         </data>
-
         <data name="rest_output" format="fastqsanger" metadata_source="library|input_1" from_work_dir="rest_output*" label="${tool.name} on ${on_string}: Rest of Reads (R1 only)" >
             <filter>output_selector and 'rest_file' in output_selector</filter>
             <expand macro="inherit_format_1" />
         </data>
-
         <data name="wild_output" format="txt" metadata_source="library|input_1" from_work_dir="wild_output*" label="${tool.name} on ${on_string}: Wildcard File" >
             <filter>output_selector and 'wildcard_file' in output_selector</filter>
         </data>
-
         <data name="untrimmed_output" format="fastqsanger" metadata_source="library|input_1" default_identifier_source="library|input_1" from_work_dir="untrimmed_output*" label="${tool.name} on ${on_string}: Untrimmed Read 1" >
             <filter>output_selector and 'untrimmed_file' in output_selector</filter>
             <expand macro="inherit_format_1" />
@@ -361,7 +422,6 @@
             <filter>output_selector and 'untrimmed_file' in output_selector </filter>
             <expand macro="inherit_format_2" />
         </data>
-
         <data name="too_short_output" format="fastqsanger" metadata_source="library|input_1" default_identifier_source="library|input_1" from_work_dir="too_short_output*" label="${tool.name} on ${on_string}: Too Short Read 1" >
             <filter>output_selector and 'too_short_file' in output_selector</filter>
             <expand macro="inherit_format_1" />
@@ -388,7 +448,6 @@
             <filter>output_selector and 'multiple_output' in output_selector</filter>
         </collection>
     </outputs>
-
     <tests>
         <!-- Ensure fastq works -->
         <test expect_num_outputs="1">
@@ -444,10 +503,9 @@
             <assert_command>
                 <not_has_text text="--discard-trimmed"/>
                 <not_has_text text="--discard-untrimmed"/>
-                <not_has_text text="--minimum-length"/>
                 <not_has_text text="--maximum-length"/>
                 <not_has_text text="--max-n"/>
-                <has_text text="--pair-filter=any"/>
+                <has_text text="--minimum-length=1 "/>
             </assert_command>
         </test>
         <!-- Ensure paired collection works -->
@@ -513,6 +571,39 @@
                 <has_text text="--discard-trimmed"/>
             </assert_command>
         </test>
+        <!-- Ensure pair-adapters option works -->
+        <test expect_num_outputs="2">
+            <param name="type" value="paired" />
+            <param name="input_1" ftype="fastq.gz" value="bwa-mem-fastq1.fq.gz" />
+            <param name="input_2" ftype="fastq.gz" value="bwa-mem-fastq2.fq.gz" />
+            <section name="r1">
+                <repeat name="adapters">
+                    <conditional name="adapter_source">
+                        <param name="adapter_source_list" value="user"/>
+                        <param name="adapter" value="AGATCGGAAGAGC"/>
+                    </conditional>
+                </repeat>
+            </section>
+            <section name="r2">
+                <repeat name="adapters2">
+                    <conditional name="adapter_source">
+                        <param name="adapter_source_list" value="user"/>
+                        <param name="adapter" value="AGATCGGAAGAGC"/>
+                    </conditional>
+                </repeat>
+            </section>
+            <param name="pair_adapters" value="true"/>
+            <output name="out1" decompress="true" file="cutadapt_out1_pair_adapters.fq.gz" ftype="fastq.gz"/>
+            <output name="out2" decompress="true" file="cutadapt_out2_pair_adapters.fq.gz" ftype="fastq.gz"/>
+            <assert_command>
+                <not_has_text text="--discard-trimmed"/>
+                <not_has_text text="--discard-untrimmed"/>
+                <not_has_text text="--maximum-length"/>
+                <not_has_text text="--max-n"/>
+                <has_text text="--pair-adapters"/>
+                <has_text text="--minimum-length=1 "/>
+            </assert_command>
+        </test>
         <!-- Ensure rest file output works, test json output -->
         <test expect_num_outputs="3">
             <param name="input_1" ftype="fasta" value="cutadapt_rest.fa" />
@@ -526,8 +617,8 @@
             </section>
             <param name="output_selector" value="rest_file,json_stats"/>
             <output name="out1" file="cutadapt_rest.out" ftype="fasta"/>
-            <!--allow for differing schema, cutadapt and python version as well as two lines containing the number of cores -->
-            <output name="json_stats" file="cutadapt_rest.json" ftype="json" lines_diff="10"/>
+            <!-- compare to expected reproducible part of json output -->
+            <output name="json_stats" file="cutadapt_rest_json.txt" compare="contains"/>
             <output name="rest_output" file="cutadapt_rest2.out" ftype="fasta"/>
         </test>
         <!-- Ensure nextseq-trim option works -->
@@ -542,7 +633,9 @@
                     </conditional>
                 </repeat>
             </section>
-            <param name="nextseq_trim" value="20" />
+            <section name="other_trimming_options">
+                <param name="nextseq_trim" value="20" />
+            </section>
             <output name="out1" decompress="true" file="cutadapt_nextseq_out.fq.gz" ftype="fastq.gz"/>
         </test>
         <!-- Ensure Report and Info file output work -->
@@ -566,8 +659,6 @@
             </output>
             <output name="info_file" value="cutadapt_info_out.txt" ftype="txt"/>
         </test>
-
-
         <test expect_num_outputs="1">
             <conditional name="library">
                 <param name="type" value="single" />
@@ -599,7 +690,6 @@
                    </element>
              </output_collection>
         </test>
-
         <test expect_num_outputs="1">
             <conditional name="library">
                 <param name="type" value="single" />
@@ -620,7 +710,6 @@
                    <element name="unknown" decompress="true" file="unknown.fastq.gz" ftype="fastq.gz"/>
              </output_collection>
         </test>
-
         <!-- Ensure untrimmed file output works -->
         <test expect_num_outputs="2">
             <param name="type" value="single" />
@@ -682,14 +771,15 @@
             </section>
             <section name="filter_options">
                 <param name="discard_untrimmed" value="true"/>
-                <param name="minimun_length" value="1"/>
+                <param name="minimum_length" value="1"/>
                 <param name="maximum_length" value="1000"/>
                 <param name="max_n" value="0"/>
                 <param name="pair_filter" value="both"/>
             </section>
             <assert_command>
                 <has_text text="--discard-untrimmed"/>
-                <has_text text="--maximum-length=1000"/>
+                <has_text text="--minimum-length=1 " />
+                <has_text text="--maximum-length=1000 "/>
                 <has_text text="--max-n=0"/>
                 <has_text text="--pair-filter=both"/>
             </assert_command>
@@ -706,7 +796,9 @@
                     </conditional>
                 </repeat>
             </section>
-            <param name="cut" value="5"/>
+            <section name="other_trimming_options">
+                <param name="cut" value="5"/>
+            </section>
             <output name="out1" file="cutadapt_small_cut.out" ftype="fastq"/>
         </test>
         <!-- Test rename options -->
@@ -721,7 +813,9 @@
                     </conditional>
                 </repeat>
             </section>
-            <param name="cut" value="5"/>
+            <section name="other_trimming_options">
+                <param name="cut" value="5"/>
+            </section>
             <section name="read_mod_options">
                 <param name="rename" value="{id} barcode={cut_prefix}"/>
             </section>
@@ -833,10 +927,10 @@
                         <param name="adapter" value="CTACAAG"/>
                     </conditional>
                 </repeat>
-                <param name="minimum_length2" value="10"/>
             </section>
             <section name="filter_options">
                 <param name="minimum_length" value="30"/>
+                <param name="minimum_length2" value="10"/>
                 <param name="pair_filter" value="both"/>
             </section>
             <output name="out1" decompress="true" file="cutadapt_out1_min_length.fq.gz" ftype="fastq.gz"/>
@@ -846,7 +940,7 @@
                 <has_text text="--pair-filter=both"/>
             </assert_command>
         </test>
-        <!-- Test maximum lenghth paired-reads -->
+        <!-- Test maximum length paired-reads -->
         <test expect_num_outputs="2">
             <param name="type" value="paired" />
             <param name="input_1" ftype="fastq.gz" value="bwa-mem-fastq1_assimetric.fq.gz" />
@@ -866,11 +960,11 @@
                         <param name="adapter" value="AGATCGGAAGAGC"/>
                     </conditional>
                 </repeat>
-                <param name="maximum_length2" value="30"/>
             </section>
             <section name="filter_options">
                 <param name="pair_filter" value="both"/>
                 <param name="maximum_length" value="50"/>
+                <param name="maximum_length2" value="30"/>
             </section>
             <output name="out1" decompress="true" file="cutadapt_out1_max_length.fq.gz" ftype="fastq.gz"/>
             <output name="out2" decompress="true" file="cutadapt_out2_max_length.fq.gz" ftype="fastq.gz"/>
@@ -899,17 +993,17 @@
                         <param name="adapter2" value="AGATCGGAAGAGC"/>
                     </conditional>
                 </repeat>
-                <param name="maximum_length2" value="30"/>
             </section>
             <section name="filter_options">
                 <param name="pair_filter" value="both"/>
                 <param name="minimum_length" value="10"/>
                 <param name="maximum_length" value="50"/>
+                <param name="maximum_length2" value="30"/>
             </section>
             <output name="out1" decompress="true" file="cutadapt_out1_max_min_01.fq.gz" ftype="fastq.gz"/>
             <output name="out2" decompress="true" file="cutadapt_out2_max_min_01.fq.gz" ftype="fastq.gz"/>
             <assert_command>
-                <has_text text="--minimum-length=10"/>
+                <has_text text="--minimum-length=10 "/>
                 <has_text text="--maximum-length=50:30"/>
                 <has_text text="--pair-filter=both"/>
             </assert_command>
@@ -933,18 +1027,18 @@
                         <param name="adapter2" value="AGATCGGAAGAGC"/>
                     </conditional>
                 </repeat>
-                <param name="minimum_length2" value="10"/>
             </section>
             <section name="filter_options">
                 <param name="pair_filter" value="both"/>
                 <param name="minimum_length" value="10"/>
+                <param name="minimum_length2" value="10"/>
                 <param name="maximum_length" value="50"/>
             </section>
             <output name="out1" decompress="true" file="cutadapt_out1_max_min_02.fq.gz" ftype="fastq.gz"/>
             <output name="out2" decompress="true" file="cutadapt_out2_max_min_02.fq.gz" ftype="fastq.gz"/>
             <assert_command>
                 <has_text text="--minimum-length=10:10"/>
-                <has_text text="--maximum-length=50"/>
+                <has_text text="--maximum-length=50 "/>
                 <has_text text="--pair-filter=both"/>
             </assert_command>
         </test>
@@ -960,13 +1054,16 @@
                     </conditional>
                 </repeat>
             </section>
-            <section name="read_mod_options">
+            <section name="other_trimming_options">
                 <conditional name="shorten_options">
                     <param name="shorten_values" value="True"/>
                     <param name="shorten_end" value="3prime"/>
                     <param name="length" value="10"/>
                 </conditional>
             </section>
+            <section name="filter_options">
+                <param name="minimum_length" value="0"/>
+            </section>
             <output name="out1" file="cutadapt_shorten_3prime.out" ftype="fastq"/>
         </test>
         <test expect_num_outputs="1">
@@ -980,13 +1077,16 @@
                     </conditional>
                 </repeat>
             </section>
-            <section name="read_mod_options">
+            <section name="other_trimming_options">
                 <conditional name="shorten_options">
                     <param name="shorten_values" value="True"/>
                     <param name="shorten_end" value="5prime"/>
                     <param name="length" value="10"/>
                 </conditional>
             </section>
+            <section name="filter_options">
+                <param name="minimum_length" value="0"/>
+            </section>
             <output name="out1" file="cutadapt_shorten_5prime.out" ftype="fastq"/>
         </test>
         <!-- Test max expected errors options -->
@@ -1107,7 +1207,6 @@
                     <element name="reverse" ftype="fastq.gz" value="bwa-mem-fastq2.fq.gz" />
                 </collection>
             </param>
-            <param name="quality_cutoff" value="5" />
             <section name="r1">
                 <repeat name="adapters">
                     <conditional name="adapter_source">
@@ -1123,6 +1222,9 @@
                         <param name="adapter" value="AGATCGGAAGAGC"/>
                     </conditional>
                 </repeat>
+            </section>
+            <section name="other_trimming_options">
+                <param name="quality_cutoff" value="5"/>
                 <param name="quality_cutoff2" value="15,20"/>
             </section>
             <output_collection name="out_pairs" type="paired">
@@ -1131,7 +1233,7 @@
             </output_collection>
             <assert_command>
                 <has_text text="--quality-cutoff=5"/>
-                <has_text text="-Q=15,20"/>
+                <has_text text="-Q 15,20"/>
             </assert_command>
         </test>
 
@@ -1144,7 +1246,9 @@
                     <element name="reverse" ftype="fasta" value="cutadapt/data/polya.2.fasta" />
                 </collection>
             </param>
-            <param name="poly_a" value="true"/>
+            <section name="other_trimming_options">
+                <param name="poly_a" value="true"/>
+            </section>
             <output_collection name="out_pairs" type="paired">
                 <element name="forward" file="cutadapt/cut/polya.1.fasta" ftype="fasta" />
                 <element name="reverse" file="cutadapt/cut/polya.2.fasta" ftype="fasta" />
@@ -1198,13 +1302,14 @@
         <test expect_num_outputs="1">
             <param name="type" value="single" />
             <param name="input_1" ftype="fasta" value="cutadapt/data/polya.1.fasta" />
-            <param name="poly_a" value="true"/>
+            <section name="other_trimming_options">
+                <param name="poly_a" value="true"/>
+            </section>
             <output name="out1" file="cutadapt/cut/polya.1.fasta" ftype="fasta"/>
             <assert_command>
                 <has_text text="--poly-a"/>
             </assert_command>
         </test>
-
         <!-- fasta.gz input https://github.com/marcelm/cutadapt/blob/e04cc32e392e1cbe0c518b4e0637cdf03533d440/tests/test_commandline.py#L78 
              in contrast to the original test the tool automatically compresses the output -->
         <test expect_num_outputs="1">
@@ -1212,7 +1317,6 @@
             <param name="input_1" ftype="fasta.gz" value="cutadapt/data/simple.fasta.gz" />
             <output name="out1" decompress="true" file="cutadapt/cut/simple.fasta.gz" ftype="fasta.gz"/>
         </test>
-
         <!-- fatstqillumina input https://github.com/marcelm/cutadapt/blob/e04cc32e392e1cbe0c518b4e0637cdf03533d440/tests/test_commandline.py#L252 -->
         <test expect_num_outputs="1">
             <param name="type" value="single" />
@@ -1225,31 +1329,45 @@
                     </conditional>
                 </repeat>
             </section>
-            <param name="quality_cutoff" value="10"/>
+            <section name="other_trimming_options">
+                <param name="quality_cutoff" value="10"/>
+            </section>
+            <section name="filter_options">
+                <param name="minimum_length" value="0"/>
+            </section>
             <output name="out1" file="cutadapt/cut/illumina64.fastq" ftype="fastqillumina"/>
             <assert_command>
                 <has_text text="-a 'XXXXXX'"/>
                 <has_text text="--quality-cutoff=10"/>
                 <has_text text="--quality-base=64"/>
+                <not_has_text text="--minimum-length "/>
             </assert_command>
         </test>
         <!-- fatstqillumina input https://github.com/marcelm/cutadapt/blob/e04cc32e392e1cbe0c518b4e0637cdf03533d440/tests/test_commandline.py#L257 -->
         <test expect_num_outputs="1">
             <param name="type" value="single" />
             <param name="input_1" ftype="fastqillumina" value="cutadapt/data/illumina64.fastq" />
-            <param name="quality_cutoff" value="10"/>
+            <section name="other_trimming_options">
+                <param name="quality_cutoff" value="10"/>
+            </section>
+            <section name="filter_options">
+                <param name="minimum_length" value="0"/>
+            </section>
             <output name="out1" file="cutadapt/cut/illumina64.fastq" ftype="fastqillumina"/>
             <assert_command>
                 <has_text text="--quality-cutoff=10"/>
                 <has_text text="--quality-base=64"/>
+                <not_has_text text="--minimum-length"/>
             </assert_command>
         </test>
-
         <!-- https://github.com/marcelm/cutadapt/blame/3407ac0004d04b11ae7157934a6665ecaf82c328/tests/test_commandline.py#L1028 --> 
         <test expect_num_outputs="3">
             <param name="type" value="single" />
             <param name="input_1" ftype="fastqillumina" value="cutadapt/data/maxee.fastq" />
-            <param name="max_expected_errors" value="0.9"/>
+            <section name="filter_options">
+                <param name="minimum_length" value="0"/>
+                <param name="max_expected_errors" value="0.9"/>
+            </section>
             <param name="output_selector" value="report,info_file"/>
             <output name="out1" file="cutadapt/cut/maxee.fastq" ftype="fastqillumina"/>
             <output name="report">
@@ -1264,10 +1382,9 @@
                 </assert_contents>
             </output>
             <assert_command>
-                <has_text text="--max-expected-errors=0.9"/>
+                <has_text text="--max-ee=0.9"/>
             </assert_command>
         </test>
-
         <!-- https://github.com/marcelm/cutadapt/blob/3407ac0004d04b11ae7157934a6665ecaf82c328/tests/test_commandline.py#L335 -->
         <test expect_num_outputs="1">
             <param name="type" value="single" />
@@ -1289,7 +1406,6 @@
                 <has_text text="-b 'ACGTACGT'"/>
             </assert_command>
         </test>
-
         <!-- https://github.com/marcelm/cutadapt/blob/3407ac0004d04b11ae7157934a6665ecaf82c328/tests/test_commandline.py#L368 -->
         <test expect_num_outputs="1">
             <param name="type" value="single" />
@@ -1346,25 +1462,32 @@
 
 **What it does**
 
--------------------
-
 **Cutadapt** finds and removes adapter sequences, primers, poly-A tails and other types of unwanted sequence from your high-throughput sequencing reads.
 
 Cleaning your data in this way is often required: Reads from small-RNA sequencing contain the 3’ sequencing adapter because the read is longer than the molecule that is sequenced, such as in microRNA, or CRISPR data, or Poly-A tails that are useful for pulling out RNA from your sample but often you don’t want them to be in your reads.
 
-Cutadapt_ helps with these trimming tasks by finding the adapter or primer sequences in an error-tolerant way. It can also modify and filter reads in various ways. Cutadapt searches for the adapter in all reads and removes it when it finds it. Unless you use a filtering option, all reads that were present in the input file will also be present in the output file, some of them trimmed, some of them not. Even reads that were trimmed entirely (because the adapter was found in the very beginning) are output. All of this can be changed with options in the tool form above.
+Cutadapt helps with these trimming tasks by finding the adapter or primer sequences in an error-tolerant way. It can also modify and filter reads in various ways. Cutadapt searches for the adapter in all reads and removes it when it finds it. Unless you use a filtering option, all reads that were present in the input file will also be present in the output file, some of them trimmed, some of them not. Even reads that were trimmed entirely (because the adapter was found in the very beginning) are output. All of this can be changed with options in the tool form above.
+
+See the complete `Cutadapt documentation`_ for additional details.
 
-The tool is based on the **Open Source** Cutadapt_ tool. See the complete `Cutadapt documentation`_ for additional details. If you use Cutadapt, please cite *Marcel, 2011* under **Citations** below.
+If you use Cutadapt, please cite *Marcel, 2011* under **Citations** below.
 
--------------------
+-----
+
+Input Sequences
+***************
 
-**Inputs**
-
--------------------
+Accepted input formats for the tool are:
 
-Input files for Cutadapt need to be:
+- FASTQ.GZ
+- FASTQ.BZ2
+- FASTQ or
+- FASTA
 
-- FASTQ.GZ, FASTQ.BZ2, FASTQ or FASTA
+-----
+
+Specifying Adapters
+*******************
 
 To trim an adapter, input the ADAPTER sequence in plain text or in a FASTA file e.g. AACCGGTT (with the characters: **$**, **^**, **...**, if anchored or linked).
 
@@ -1416,11 +1539,43 @@
 
 The adapter sequences can be found in the document `Illumina TruSeq Adapters De-Mystified`_.
 
+
+-----------
+
+**Paired Adapters**
+
 -----------
 
-**Outputs**
+Normally, the tool looks for adapters on R1 and R2 reads independently. That is, the best matching R1 adapter of each type (3' End, 5' End, Anywhere) is removed from R1 and the best matching R2 adapter of each type is removed from R2.
+
+To change this, you can use the **Pairwise adapter search** (--pair-adapters) option, which causes each R1 adapter to be paired up with its corresponding R2 adapter. The first R1 adapter of a given type that you specify will be paired up with the first R2 adapter of that type, and so on. The adapters are then always removed in pairs from a read pair.
+
+For example, if you specify the following two 3'-end adapters for the R1 reads:
+
+- ``AAAAA``
+- ``GGGGG``
+
+and these two 3'-end adapters for the R2 reads:
+
+- ``CCCC``
+- ``TTTT``
 
------------
+then, with this option enabled, the tool will trim a pair of reads only if:
+
+- either ``AAAAA`` is found in R1 and ``CCCCC`` is found in R2,
+- or ``GGGG`` is found in R1 and ``TTTT`` is found in R2.
+
+Two limitations exist in this mode:
+
+1. You need to provide equal numbers of R1 and R2 adapters of each type to allow pair formation, or  the tool run will fail.
+2. The algorithm identifies the best-matching R1 adapter first and then checks whether it can find its corresponding R2 adapter. If not, the read pair remains unchanged, even though it is, in theory, possible that a different R1 adapter that does not fit as well would have had a corresponding R2 adapter present, i.e., some legitimate adapter pairs might remain unhandled.
+
+This mode is useful, for example, for `demultiplexing Illumina unique dual indices (UDIs)`_.
+
+-----
+
+Outputs
+*******
 
 - Trimmed reads
 
@@ -1429,10 +1584,13 @@
     * Report
     * Info file
 
+-----------
 
 **Report**
 
-Cutadapt can output per-adapter statistics if you select to output the report above.
+-----------
+
+Cutadapt can output per-adapter statistics if you select to generate the report above.
 
 Example:
 
@@ -1461,9 +1619,12 @@
         Read 1:        24,090 bp
         Read 2:        24,081 bp
 
+-----------
 
 **Info file**
 
+-----------
+
 The info file contains information about the found adapters. The output is a tab-separated text file. Each line corresponds to one read of the input file.
 
 Columns contain the following data:
@@ -1493,13 +1654,10 @@
 
 If the --times option is used and greater than 1, each read can appear more than once in the info file. There will be one line for each found adapter, all with identical read names. Only for the first of those lines will the concatenation of columns 5-7 be identical to the original read sequence (and accordingly for columns 9-11). For subsequent lines, the shown sequence are the ones that were used in subsequent rounds of adapter trimming, that is, they get successively shorter.
 
-
 --------------------
 
-**Rename Reads**
-
---------------------
-
+Renaming Reads
+**************
 
 The --rename option expects a template string such as {id} extra_info {adapter_name} as a parameter. It can contain regular text and placeholders that consist of a name enclosed in curly braces ({placeholdername}).
 
@@ -1523,27 +1681,17 @@
 In addition, it is possible to write a placeholder as {r1.placeholdername} or {r2.placeholdername}, which always takes the replacement value from R1 or R2, respectively.
 The {r1.placeholder} and {r2.placeholder} notation is available for all placeholders except {rn} and {id} because the read ID needs to be identical for both reads.
 
---------------------
-
-**More Information**
-
---------------------
-
-See the excellent `Cutadapt documentation`_
-
-.. _Cutadapt: https://cutadapt.readthedocs.io/en/stable/
-.. _`Cutadapt documentation`: https://cutadapt.readthedocs.io/en/latest/index.html
-.. _`Illumina TruSeq Adapters De-Mystified`: http://tucf-genomics.tufts.edu/documents/protocols/TUCF_Understanding_Illumina_TruSeq_Adapters.pdf
-
-
---------------------
+-----
 
 **Galaxy Wrapper Development**
 
---------------------
+Original author: Lance Parsons <lparsons@princeton.edu>
+
+-----
 
-Author: Lance Parsons <lparsons@princeton.edu>
-
+.. _`Cutadapt documentation`: https://cutadapt.readthedocs.io
+.. _`Illumina TruSeq Adapters De-Mystified`: http://tucf-genomics.tufts.edu/documents/protocols/TUCF_Understanding_Illumina_TruSeq_Adapters.pdf
+.. _`demultiplexing Illumina unique dual indices (UDIs)`: https://cutadapt.readthedocs.io/en/stable/guide.html#unique-dual-indices
     ]]></help>
     <expand macro="citations" />
 </tool>
--- a/macros.xml	Mon Apr 15 06:31:32 2024 +0000
+++ b/macros.xml	Fri May 17 13:32:03 2024 +0000
@@ -1,9 +1,9 @@
 <macros>
     <token name="@TOOL_VERSION@">4.8</token>
-    <token name="@VERSION_SUFFIX@">0</token>
+    <token name="@VERSION_SUFFIX@">1</token>
     <token name="@FASTQ_TYPES@">fastq.bz2,fastq.gz,fastq,fasta.bz2,fasta.gz,fasta</token>
     <xml name="edam_ontology">
-        <edam_topics>                                                                                  
+        <edam_topics>
             <edam_topic>topic_0632</edam_topic>
         </edam_topics>
         <edam_operations>
@@ -25,237 +25,127 @@
             <xref type='bio.tools'>cutadapt</xref>
         </xrefs>
     </xml>
-
     <!-- parametrized token - you need to set `$ADAPTER_ARGUMENT` -->
     <token name="@adapter_cli@">
         #if $a.adapter_source.adapter_source_list == 'builtin':
             $ADAPTER_ARGUMENT '${a.adapter_source.adapter.fields.name}'='${a.adapter_source.adapter}${a.single_noindels}'
-        #else if $a.adapter_source.adapter_source_list == 'file':
+        #elif $a.adapter_source.adapter_source_list == 'file':
             $ADAPTER_ARGUMENT file:'${a.adapter_source.adapter_file}${a.single_noindels}'
-        #else if str($a.adapter_source.adapter_name) != "":
+        #elif str($a.adapter_source.adapter_name) != "":
             $ADAPTER_ARGUMENT '${a.adapter_source.adapter_name}'='${a.adapter_source.adapter}${a.single_noindels}'
-        #else
+        #else:
             $ADAPTER_ARGUMENT '${a.adapter_source.adapter}${a.single_noindels}'
-         #end if
-    </token>
-
-     <token name="@read1_options@"><![CDATA[
-
-        ## Read1 trimming
-
-        #set ADAPTER_ARGUMENT="-a"
-        #for $a in $library.r1.adapters
-            @adapter_cli@
-        #end for
-        
-        #set ADAPTER_ARGUMENT="-b"
-        #for $a in $library.r1.anywhere_adapters
-            @adapter_cli@
-        #end for
-        
-        #set ADAPTER_ARGUMENT="-g"
-        #for $a in $library.r1.front_adapters
-            @adapter_cli@
-        #end for
-
-        #if str($cut) != '0':
-            -u $cut
-        #end if
-
-        ## Additional Outputs
-
-        #if 'info_file' in $output_selector:
-            --info-file=$info_file
-        #end if
-        #if 'rest_file' in $output_selector:
-            --rest-file='${rest_output}'
-        #end if
-        #if 'wildcard_file' in $output_selector:
-            --wildcard-file='${wild_output}'
-        #end if
-        #if 'too_short_file' in $output_selector:
-            --too-short-output='${too_short_output}'
-        #end if
-        #if 'too_long_file' in $output_selector:
-            --too-long-output='${too_long_output}'
-        #end if
-        #if 'untrimmed_file' in $output_selector:
-            --untrimmed-output='${untrimmed_output}'
-        #end if
-
-    ]]></token>
-
-    <token name="@read2_options@"><![CDATA[
-
-        ## Read2 trimming
-
-        #set ADAPTER_ARGUMENT="-A"
-        #for $a in $library.r2.adapters2
-            @adapter_cli@
-        #end for
-        #set ADAPTER_ARGUMENT="-B"
-        #for $a in $library.r2.anywhere_adapters2
-            @adapter_cli@
-        #end for
-        #set ADAPTER_ARGUMENT="-G"
-        #for $a in $library.r2.front_adapters2
-            @adapter_cli@
-        #end for
-
-        #if str($library.r2.cut2) != '0':
-            -U $library.r2.cut2
         #end if
-
-        ## Additional Outputs - Read 2
-
-        #if 'too_short_file' in $output_selector:
-            --too-short-paired-output='${too_short_paired_output}'
-        #end if
-        #if 'too_long_file' in $output_selector:
-            --too-long-paired-output='${too_long_paired_output}'
-        #end if
-        #if 'untrimmed_file' in $output_selector:
-            --untrimmed-paired-output='${untrimmed_paired_output}'
-        #end if
-
-    ]]></token>
-
-        <xml name="adapter_sanitizer">
-            <sanitizer>
-                <valid initial="string.digits">
-                    <add value="A"/><!--standard nucleotides-->
-                    <add value="T"/>
-                    <add value="C"/>
-                    <add value="G"/>
-                    
-                    <add value="U"/><!--ambiguous nucleotides-->
-                    <add value="R"/>
-                    <add value="Y"/>
-                    <add value="S"/>
-                    <add value="W"/>
-                    <add value="K"/>
-                    <add value="M"/>
-                    <add value="B"/>
-                    <add value="D"/>
-                    <add value="H"/>
-                    <add value="V"/>
-                    <add value="N"/>
-
-                    <add value="X"/><!-- don't match any nucleotide-->
-                    
-                    <add value="{"/><!--specify repeats .. needs digits which are added as default-->
-                    <add value="}"/>
-
-                    <add value="^"/><!--anchoring-->
-                    <add value="$"/>
-                    <add value="."/>
-                    <add value="("/><!--specify what to keep-->
-                    <add value=")"/>
-
-                </valid>
-            </sanitizer>
-        </xml>
-        
-        <xml name="adapter_conditional" tokens="adapter_type,argument">
-            <conditional name="adapter_source">
-                <param name="adapter_source_list" type="select" label="Source" >
-                    <option value="builtin" selected="true">Standard (select from the list below)</option>
-                    <option value="user">Enter custom sequence</option>
-                    <option value="file">File from history</option>
+    </token>
+    <xml name="adapter_sanitizer">
+        <sanitizer>
+            <valid initial="string.digits">
+                <add value="A"/><!--standard nucleotides-->
+                <add value="T"/>
+                <add value="C"/>
+                <add value="G"/>
+                <add value="U"/><!--ambiguous nucleotides-->
+                <add value="R"/>
+                <add value="Y"/>
+                <add value="S"/>
+                <add value="W"/>
+                <add value="K"/>
+                <add value="M"/>
+                <add value="B"/>
+                <add value="D"/>
+                <add value="H"/>
+                <add value="V"/>
+                <add value="N"/>
+                <add value="X"/><!-- don't match any nucleotide-->
+                <add value="{"/><!--specify repeats .. needs digits which are added as default-->
+                <add value="}"/>
+                <add value="^"/><!--anchoring-->
+                <add value="$"/>
+                <add value="."/>
+                <add value="("/><!--specify what to keep-->
+                <add value=")"/>
+            </valid>
+        </sanitizer>
+    </xml>
+    <xml name="adapter_conditional" tokens="adapter_type,argument">
+        <conditional name="adapter_source">
+            <param name="adapter_source_list" type="select" label="Source" >
+                <option value="builtin" selected="true">Standard (select from the list below)</option>
+                <option value="user">Enter custom sequence</option>
+                <option value="file">File from history</option>
+            </param>
+            <when value="user">
+                <param name="adapter_name" type="text" value="" optional="true" label="Custom @ADAPTER_TYPE@ adapter name" help="Optional if 'Multiple output' is selected in the Outputs selector'" />
+                <param name="adapter" argument="@ARGUMENT@" type="text" value="AATTGGCC" label="Custom @ADAPTER_TYPE@ adapter sequence">
+                    <expand macro="adapter_sanitizer"/>
                 </param>
-                <when value="user">
-                    <param name="adapter_name" type="text" value="" optional="true" label="Custom @ADAPTER_TYPE@ adapter name" help="Optional if 'Multiple output' is selected in the Outputs selector'" />
-                    <param name="adapter" argument="@ARGUMENT@" type="text" value="AATTGGCC" label="Custom @ADAPTER_TYPE@ adapter sequence">
-                        <expand macro="adapter_sanitizer"/>
-                    </param>
+            </when>
+            <when value="builtin">
+                <param name="adapter" argument="@ARGUMENT@" type="select" label="@ADAPTER_TYPE@ adapter">
+                    <options from_data_table="adapters">
+                        <filter type="sort_by" column="1" />
+                        </options>
+                    <expand macro="adapter_sanitizer"/>
+                </param>
+            </when>
+            <when value="file">
+                <param name="adapter_file" argument="@ARGUMENT@" format="fasta" type="data"  label="File containing @ADAPTER_TYPE@ adapters" help="Should be of datatype FASTA" />
+            </when>
+        </conditional>
+        <param name="single_noindels" type="boolean" truevalue=";noindels" falsevalue="" checked="false" label="Disallow indels for this adapter"/>
+    </xml>
+    <xml name="read1_adapters" >
+        <section name="r1" title="Read 1 Adapters" expanded="true">
+            <repeat name="adapters" title="3' (End) Adapters" help="Sequence of an adapter ligated to the 3' end (paired data: of the first read). The adapter and subsequent bases are trimmed. If a '$' character is appended ('anchoring'), the adapter is only found if it is a suffix of the read. To search for a linked adapter, separate the 2 sequences with 3 dots (ADAPTER1...ADAPTER2), see Help below.">
+                <expand macro="adapter_conditional" argument="-a" adapter_type="3'"/>
+            </repeat>
+            <repeat name="front_adapters" title="5' (Front) Adapters" help="Sequence of an adapter ligated to the 5' end (paired data: of the first read). The adapter and any preceding bases are trimmed. Partial matches at the 5' end are allowed. If a '^' character is prepended ('anchoring'), the adapter is only found if it is a prefix of the read. To search for a linked adapter, separate the 2 sequences with 3 dots (ADAPTER1...ADAPTER2), see Help below.">
+                <expand macro="adapter_conditional" argument="-g" adapter_type="5'"/>
+            </repeat>
+            <repeat name="anywhere_adapters" title="5' or 3' (Anywhere) Adapters" help="Sequence of an adapter that may be ligated to the 5' or 3' end (paired data: of the first read). Both types of matches as described under 3' und 5' Adapters are allowed. If the first base of the read is part of the match, the behavior is as with 5' Adapters, otherwise as with 3' Adapters. This option is mostly for rescuing failed library preparations - do not use if you know which end your adapter was ligated to!">
+                <expand macro="adapter_conditional" argument="-b" adapter_type="5' or 3'"/>
+            </repeat>
+        </section>
+    </xml>
+    <xml name="read2_adapters">
+        <section name="r2" title="Read 2 Adapters" expanded="true">
+            <repeat name="adapters2" title="3' (End) Adapters" help="Sequence of an adapter ligated to the 3' end of the second read in each pair. The adapter and subsequent bases are trimmed. If a '$' character is appended ('anchoring'), the adapter is only found if it is a suffix of the read. To search for a linked adapter, separate the 2 sequences with 3 dots (ADAPTER1...ADAPTER2), see Help below.">
+                <expand macro="adapter_conditional" argument="-A" adapter_type="3'"/>
+            </repeat>
+            <repeat name="front_adapters2" title="5' (Front) Adapters" help="Sequence of an adapter ligated to the 5' end of the second read in each pair. The adapter and any preceding bases are trimmed. Partial matches at the 5' end are allowed. If a '^' character is prepended ('anchoring'), the adapter is only found if it is a prefix of the read. To search for a linked adapter, separate the 2 sequences with 3 dots (ADAPTER1...ADAPTER2), see Help below.">
+                <expand macro="adapter_conditional" argument="-G" adapter_type="5'"/>
+            </repeat>
+            <repeat name="anywhere_adapters2" title="5' or 3' (Anywhere) Adapters" help="Sequence of an adapter that may be ligated to the 5' or 3' end of the second read in each pair. Both types of matches as described under under 3' und 5' Adapters are allowed. If the first base of the read is part of the match, the behavior is as with 5' Adapters, otherwise as with 3' Adapters. This option is mostly for rescuing failed library preparations - do not use if you know which end your adapter was ligated to!">
+                <expand macro="adapter_conditional" argument="-B" adapter_type="5' or 3'"/>
+            </repeat>
+        </section>
+        <param argument="--pair-adapters" type="boolean" truevalue="--pair-adapters" falsevalue="" label="Pairwise adapter search" help="The tool will normally look for R1 and R2 read adapters independently. By enabling this option you can have the lists of R1 and R2 read adapters handled pairwise instead. In this mode you need to provide equal numbers of R1 and R2 adapters of each type, or the tool will fail. For a more detailed explanation see the section Paired Adapters in the tool help below."/>
+    </xml>
+    <xml name="inherit_format_1">
+        <actions>
+            <conditional name="library.type">
+                <when value="single">
+                    <action type="format">
+                        <option type="from_param" name="library.input_1" param_attribute="ext" />
+                    </action>
                 </when>
-                <when value="builtin">
-                    <param name="adapter" argument="@ARGUMENT@" type="select" label="@ADAPTER_TYPE@ adapter">
-                        <options from_data_table="adapters">
-                            <filter type="sort_by" column="1" />
-                            </options>
-                        <expand macro="adapter_sanitizer"/>
-                    </param>
-                </when>
-                <when value="file">
-                    <param name="adapter_file" argument="@ARGUMENT@" format="fasta" type="data"  label="File containing @ADAPTER_TYPE@ adapters" help="Should be of datatype FASTA" />
+                <when value="paired">
+                    <action type="format">
+                        <option type="from_param" name="library.input_1" param_attribute="ext" />
+                    </action>
                 </when>
             </conditional>
-            <param name="single_noindels" type="boolean" truevalue=";noindels" falsevalue="" checked="false" label="Disallow indels for this adapter"/>
-        </xml>
-
-        <xml name="single_end_options" >
-            <section name="r1" title="Read 1 Options" expanded="true">
-                <repeat name="adapters" title="3' (End) Adapters" help="Sequence of an adapter ligated to the 3' end (paired data: of the first read). The adapter and subsequent bases are trimmed. If a '$' character is appended ('anchoring'), the adapter is only found if it is a suffix of the read. To search for a linked adapter, separate the 2 sequences with 3 dots (ADAPTER1...ADAPTER2), see Help below.">
-                    <expand macro="adapter_conditional" argument="-a" adapter_type="3'"/>
-                </repeat>
-                <repeat name="front_adapters" title="5' (Front) Adapters" help="Sequence of an adapter ligated to the 5' end (paired data: of the first read). The adapter and any preceding bases are trimmed. Partial matches at the 5' end are allowed. If a '^' character is prepended ('anchoring'), the adapter is only found if it is a prefix of the read. To search for a linked adapter, separate the 2 sequences with 3 dots (ADAPTER1...ADAPTER2), see Help below.">
-                    <expand macro="adapter_conditional" argument="-g" adapter_type="5'"/>
-                </repeat>
-                <repeat name="anywhere_adapters" title="5' or 3' (Anywhere) Adapters" help="Sequence of an adapter that may be ligated to the 5' or 3' end (paired data: of the first read). Both types of matches as described under 3' und 5' Adapters are allowed. If the first base of the read is part of the match, the behavior is as with 5' Adapters, otherwise as with 3' Adapters. This option is mostly for rescuing failed library preparations - do not use if you know which end your adapter was ligated to!">
-                    <expand macro="adapter_conditional" argument="-b" adapter_type="5' or 3'"/>
-                </repeat>
-            </section>
-        </xml>
-
-        <xml name="paired_end_options" >
-
-            <!-- Read 1 Options -->
-            <expand macro="single_end_options" />
-
-            <!-- Read 2 Options -->
-            <section name="r2" title="Read 2 Options" expanded="true">
-                <repeat name="adapters2" title="3' (End) Adapters" help="Sequence of an adapter ligated to the 3' end of the second read in each pair. The adapter and subsequent bases are trimmed. If a '$' character is appended ('anchoring'), the adapter is only found if it is a suffix of the read. To search for a linked adapter, separate the 2 sequences with 3 dots (ADAPTER1...ADAPTER2), see Help below.">
-                    <expand macro="adapter_conditional" argument="-A" adapter_type="3'"/>
-                </repeat>
-                <repeat name="front_adapters2" title="5' (Front) Adapters" help="Sequence of an adapter ligated to the 5' end of the second read in each pair. The adapter and any preceding bases are trimmed. Partial matches at the 5' end are allowed. If a '^' character is prepended ('anchoring'), the adapter is only found if it is a prefix of the read. To search for a linked adapter, separate the 2 sequences with 3 dots (ADAPTER1...ADAPTER2), see Help below.">
-                    <expand macro="adapter_conditional" argument="-G" adapter_type="5'"/>
-                </repeat>
-                <repeat name="anywhere_adapters2" title="5' or 3' (Anywhere) Adapters" help="Sequence of an adapter that may be ligated to the 5' or 3' end of the second read in each pair. Both types of matches as described under under 3' und 5' Adapters are allowed. If the first base of the read is part of the match, the behavior is as with 5' Adapters, otherwise as with 3' Adapters. This option is mostly for rescuing failed library preparations - do not use if you know which end your adapter was ligated to!">
-                    <expand macro="adapter_conditional" argument="-B" adapter_type="5' or 3'"/>
-                </repeat>
-
-                <!-- read modification -->
-                <param name="cut2" argument="-U" type="integer" value="0" optional="true" label="Cut bases from the second read in each pair." help="Remove bases from the beginning or end of each read before trimming adapters. If positive, the bases are removed from the beginning of each read. If negative, the bases are removed from the end of each read." />
-                <param name="quality_cutoff2" argument="-Q" type="text" optional="true" label="Optional separate quality cutoff for Read 2" help="Trim low-quality bases from 5' and/or 3' ends of each read before adapter removal. If one value is given, only the 3' end is trimmed. If two comma-separated cutoffs are given, the 5' end is trimmed with the first cutoff, the 3' end with the second. Leave blank to use the same value as for Read 1">
-                    <sanitizer>
-                        <valid initial="string.digits"><add value="," /></valid>
-                    </sanitizer>
-                    <validator type="regex">[0-9]+(,[0-9])?</validator>
-                </param>
-                <!-- read filtering-->
-                <param name="minimum_length2" type="integer" min="0" value="" optional="true" label="Minimum length (R2)" />
-                <param name="maximum_length2" type="integer" min="0" value="" optional="true" label="Maximum length (R2)" />
-            </section>
-        </xml>
-
-        <xml name="inherit_format_1">
-            <actions>
-                <conditional name="library.type">
-                    <when value="single">
-                        <action type="format">
-                            <option type="from_param" name="library.input_1" param_attribute="ext" />
-                        </action>
-                    </when>
-                    <when value="paired">
-                        <action type="format">
-                            <option type="from_param" name="library.input_1" param_attribute="ext" />
-                        </action>
-                    </when>
-                </conditional>
-            </actions>
-        </xml>
-
-        <xml name="inherit_format_2">
-            <actions>
-                <conditional name="library.type">
-                    <when value="paired">
-                        <action type="format">
-                            <option type="from_param" name="library.input_2" param_attribute="ext" />
-                        </action>
-                    </when>
-                </conditional>
-            </actions>
-        </xml>
-
+        </actions>
+    </xml>
+    <xml name="inherit_format_2">
+        <actions>
+            <conditional name="library.type">
+                <when value="paired">
+                    <action type="format">
+                        <option type="from_param" name="library.input_2" param_attribute="ext" />
+                    </action>
+                </when>
+            </conditional>
+        </actions>
+    </xml>
 </macros>
Binary file test-data/cutadapt_out1_pair_adapters.fq.gz has changed
Binary file test-data/cutadapt_out2_pair_adapters.fq.gz has changed
--- a/test-data/cutadapt_rest.json	Mon Apr 15 06:31:32 2024 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-{
-  "tag": "Cutadapt report",
-  "schema_version": [0, 1],
-  "cutadapt_version": "3.5",
-  "python_version": "3.9.7",
-  "command_line_arguments": [
-    "-j=1",
-    "--json",
-    "stats.json",
-    "-a",
-    "AAAGATG",
-    "--rest-file=rest_output.fa",
-    "--output=out1.fa",
-    "--error-rate=0.1",
-    "--times=1",
-    "--overlap=3",
-    "--action=trim",
-    "cutadapt_rest_fa.fa"
-  ],
-  "cores": 1,
-  "input": {
-    "path1": "cutadapt_rest_fa.fa",
-    "path2": null,
-    "paired": false
-  },
-  "read_counts": {
-    "input": 5,
-    "filtered": {
-      "too_short": null,
-      "too_long": null,
-      "too_many_n": null,
-      "too_many_expected_errors": null,
-      "casava_filtered": null,
-      "discard_trimmed": null,
-      "discard_untrimmed": null
-    },
-    "output": 5,
-    "reverse_complemented": null,
-    "read1_with_adapter": 5,
-    "read2_with_adapter": null
-  },
-  "basepair_counts": {
-    "input": 97,
-    "input_read1": 97,
-    "input_read2": null,
-    "quality_trimmed": null,
-    "quality_trimmed_read1": null,
-    "quality_trimmed_read2": null,
-    "poly_a_trimmed": null,
-    "poly_a_trimmed_read1": null,
-    "poly_a_trimmed_read2": null,
-    "output": 35,
-    "output_read1": 35,
-    "output_read2": null
-  },
-  "adapters_read1": [
-    {
-      "name": "1",
-      "total_matches": 5,
-      "on_reverse_complement": null,
-      "linked": false,
-      "five_prime_end": null,
-      "three_prime_end": {
-        "type": "regular_three_prime",
-        "sequence": "AAAGATG",
-        "error_rate": 0.1,
-        "indels": true,
-        "error_lengths": [7],
-        "matches": 5,
-        "adjacent_bases": {
-          "A": 0,
-          "C": 0,
-          "G": 5,
-          "T": 0,
-          "": 0
-        },
-        "dominant_adjacent_base": null,
-        "trimmed_lengths": [
-          {"len": 7, "expect": 0.0, "counts": [1]},
-          {"len": 12, "expect": 0.0, "counts": [1]},
-          {"len": 14, "expect": 0.0, "counts": [2]},
-          {"len": 15, "expect": 0.0, "counts": [1]}
-        ]
-      }
-    }
-  ],
-  "adapters_read2": null,
-  "poly_a_trimmed_read1": null,
-  "poly_a_trimmed_read2": null
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/cutadapt_rest_json.txt	Fri May 17 13:32:03 2024 +0000
@@ -0,0 +1,69 @@
+  "input": {
+    "path1": "cutadapt_rest_fa.fa",
+    "path2": null,
+    "paired": false
+  },
+  "read_counts": {
+    "input": 5,
+    "filtered": {
+      "too_short": 0,
+      "too_long": null,
+      "too_many_n": null,
+      "too_many_expected_errors": null,
+      "casava_filtered": null,
+      "discard_trimmed": null,
+      "discard_untrimmed": null
+    },
+    "output": 5,
+    "reverse_complemented": null,
+    "read1_with_adapter": 5,
+    "read2_with_adapter": null
+  },
+  "basepair_counts": {
+    "input": 97,
+    "input_read1": 97,
+    "input_read2": null,
+    "quality_trimmed": null,
+    "quality_trimmed_read1": null,
+    "quality_trimmed_read2": null,
+    "poly_a_trimmed": null,
+    "poly_a_trimmed_read1": null,
+    "poly_a_trimmed_read2": null,
+    "output": 35,
+    "output_read1": 35,
+    "output_read2": null
+  },
+  "adapters_read1": [
+    {
+      "name": "1",
+      "total_matches": 5,
+      "on_reverse_complement": null,
+      "linked": false,
+      "five_prime_end": null,
+      "three_prime_end": {
+        "type": "regular_three_prime",
+        "sequence": "AAAGATG",
+        "error_rate": 0.1,
+        "indels": true,
+        "error_lengths": [7],
+        "matches": 5,
+        "adjacent_bases": {
+          "A": 0,
+          "C": 0,
+          "G": 5,
+          "T": 0,
+          "": 0
+        },
+        "dominant_adjacent_base": null,
+        "trimmed_lengths": [
+          {"len": 7, "expect": 0.0, "counts": [1]},
+          {"len": 12, "expect": 0.0, "counts": [1]},
+          {"len": 14, "expect": 0.0, "counts": [2]},
+          {"len": 15, "expect": 0.0, "counts": [1]}
+        ]
+      }
+    }
+  ],
+  "adapters_read2": null,
+  "poly_a_trimmed_read1": null,
+  "poly_a_trimmed_read2": null