AAFTF 0.7.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
AAFTF/AAFTF_main.py ADDED
@@ -0,0 +1,903 @@
1
+ #!/usr/bin/env python3
2
+ """AAFTF main framework for submodule run."""
3
+
4
+ # note structure of code taken from poretools
5
+ # https://github.com/arq5x/poretools/blob/master/poretools/poretools_main.py
6
+
7
+ import argparse as ap
8
+ import sys
9
+
10
+ # AAFTF imports
11
+ from AAFTF.__version__ import __version__, get_version # noqa: E402
12
+ from AAFTF.utility import status
13
+
14
+ try:
15
+ myversion = get_version()
16
+ except Exception:
17
+ # Fallback to hardcoded version if git isn't available
18
+ myversion = __version__
19
+
20
+
21
+ ALIAS_MAP = {
22
+ "trim_reads": "trim",
23
+ "read_trim": "trim",
24
+ "filter_reads": "filter",
25
+ "read_filter": "filter",
26
+ "asm": "assemble",
27
+ "spades": "assemble",
28
+ "vectorscreen": "vecscreen",
29
+ "vector_blast": "vecscreen",
30
+ "ncbi_fcs": "fcs_screen",
31
+ "ncbi_fcs-screen": "fcs_screen",
32
+ "ncbi_fcs-gx": "fcs_gx_purge",
33
+ "ncbi_fcs_gx": "fcs_gx_purge",
34
+ "gx": "fcs_gx_purge",
35
+ "purge": "sourpurge",
36
+ "dedup": "rmdup",
37
+ "pilon": "polish",
38
+ "polca": "polish",
39
+ "stats": "assess",
40
+ "fix": "fix_tbl",
41
+ "mito_asm": "mito",
42
+ "mitochondria": "mito",
43
+ "coverage": "depth",
44
+ "cov": "depth",
45
+ "configure": "download",
46
+ "install": "download",
47
+ "download_db": "download",
48
+ "setup": "download",
49
+ }
50
+
51
+
52
+ def run_subtool(parser, args):
53
+ """Run the subtool of the AAFTF pipeline."""
54
+ command = ALIAS_MAP.get(args.command, args.command)
55
+ if command == "trim":
56
+ import AAFTF.trim as submodule
57
+ elif command == "filter":
58
+ import AAFTF.filter as submodule
59
+ elif command == "assemble":
60
+ import AAFTF.assemble as submodule
61
+ elif command == "vecscreen":
62
+ import AAFTF.vecscreen as submodule
63
+ elif command == "fcs_screen":
64
+ import AAFTF.fcs_screen as submodule
65
+ elif command == "fcs_gx_purge":
66
+ import AAFTF.fcs_gx_purge as submodule
67
+ elif command == "sourpurge":
68
+ import AAFTF.sourpurge as submodule
69
+ elif command == "rmdup":
70
+ import AAFTF.rmdup as submodule
71
+ elif command == "polish":
72
+ import AAFTF.polish as submodule
73
+ elif command == "assess":
74
+ import AAFTF.assess as submodule
75
+ elif command == "sort":
76
+ import AAFTF.sort as submodule
77
+ elif command == "pipeline":
78
+ import AAFTF.pipeline as submodule
79
+ elif command == "mito":
80
+ import AAFTF.mito as submodule
81
+ elif command == "fix_tbl":
82
+ import AAFTF.fix_tbl as submodule
83
+ elif command == "depth":
84
+ import AAFTF.depth as submodule
85
+ elif command == "download":
86
+ import AAFTF.download as submodule
87
+ else:
88
+ parser.parse_args("")
89
+ return
90
+ # run the chosen submodule.
91
+ submodule.run(parser, args)
92
+
93
+
94
+ class ArgumentParserWithDefaults(ap.ArgumentParser):
95
+ """Argument parsing top level."""
96
+
97
+ def __init__(self, *args, **kwargs):
98
+ """Init function for ArgumentParser."""
99
+ super().__init__(*args, **kwargs)
100
+ self.add_argument("-q", "--quiet", help="Do not output warnings to stderr", action="store_true", dest="quiet")
101
+
102
+ def error(self, message):
103
+ """Error message passing from argument passing."""
104
+ sys.stderr.write(f"error: {message}\n")
105
+ self.print_help()
106
+ sys.exit(2)
107
+
108
+
109
+ def main():
110
+ """Present the main AAFTF module submenus."""
111
+ #########################################
112
+ # create the top-level parser
113
+ #########################################
114
+ parser = ap.ArgumentParser(prog="AAFTF", formatter_class=ap.ArgumentDefaultsHelpFormatter)
115
+ parser.add_argument("-q", "--quiet", help="Do not output warnings to stderr", action="store_true", dest="quiet")
116
+ parser.add_argument("-v", "--version", help="Installed AAFTF version", action="version", version="%(prog)s " + str(myversion))
117
+
118
+ subparsers = parser.add_subparsers(title="[sub-commands]", dest="command", parser_class=ArgumentParserWithDefaults)
119
+
120
+ #########################################
121
+ # setup / database download
122
+ #########################################
123
+ parser_download = subparsers.add_parser(
124
+ "download",
125
+ aliases=["configure", "install", "download_db", "setup"],
126
+ description="Download reference databases to a persistent directory.",
127
+ help="Download AAFTF reference databases",
128
+ )
129
+ parser_download.add_argument(
130
+ "--AAFTF_DB",
131
+ type=str,
132
+ required=False,
133
+ help="Path to AAFTF database directory. Defaults to $AAFTF_DB environment variable.",
134
+ )
135
+ parser_download.add_argument(
136
+ "--force",
137
+ action="store_true",
138
+ help="Re-download files even if they already exist",
139
+ )
140
+ parser_download.add_argument(
141
+ "--skip-core",
142
+ action="store_true",
143
+ help="Skip downloading core contamination databases (UniVec, PhiX, contaminants, mitochondria)",
144
+ )
145
+ parser_download.add_argument(
146
+ "--skip-sourmash",
147
+ action="store_true",
148
+ help="Skip downloading sourmash taxonomy databases",
149
+ )
150
+ parser_download.add_argument(
151
+ "--sourdb-type",
152
+ type=str,
153
+ default="all",
154
+ choices=["gbk", "gtdb", "gtdbrep", "all"],
155
+ dest="sourdb_type",
156
+ help="Which sourmash database(s) to download (default: all)",
157
+ )
158
+ parser_download.add_argument(
159
+ "--skip-fcs",
160
+ action="store_true",
161
+ help="Skip downloading NCBI FCS-adaptor resources",
162
+ )
163
+ parser_download.add_argument("-v", "--debug", action="store_true", help="Provide debugging messages")
164
+ parser_download.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
165
+
166
+ #########################################
167
+ # create the individual tool parsers
168
+ #########################################
169
+
170
+ ##########
171
+ # trim
172
+ ##########
173
+ # arguments
174
+ # --method bbduk*, trimmomatic, fastp
175
+ # --trimmomatic: arguments are path to JAR or application respectively
176
+ # assume java is PATH already for trimmomatic
177
+ # -o / --outdir: write outdir
178
+ # -p / --prefix: outfile prefix
179
+ # -ml / --minlen: min read length
180
+ # --avgqual (default 10)
181
+ # read info, either paired data are required or singleton
182
+ # --left: left or forward reads
183
+ # --right: right or reverse reads
184
+ #
185
+ # --merge: merge reads in fastp
186
+
187
+ parser_trim = subparsers.add_parser("trim", aliases=["trim_reads", "read_trim"], description="This command trims reads in FASTQ format to " + "remove low quality reads and trim adaptor sequences", help="Trim FASTQ input reads")
188
+
189
+ parser_trim.add_argument("-o", "--out", type=str, required=False, dest="basename", help="Output basename, default to base name of --left reads")
190
+
191
+ parser_trim.add_argument("-c", "--cpus", type=int, metavar="cpus", required=False, default=1, help="Number of CPUs/threads to use.")
192
+
193
+ parser_trim.add_argument("-ml", "--minlen", type=int, default=75, required=False, help="Minimum read length after trimming, default: 75")
194
+
195
+ parser_trim.add_argument("-l", "--left", type=str, required=True, help="left/forward reads of paired-end FASTQ or single-end FASTQ.")
196
+
197
+ parser_trim.add_argument("-r", "--right", type=str, required=False, help="right/reverse reads of paired-end FASTQ.")
198
+
199
+ parser_trim.add_argument("-aq", "--avgqual", type=int, default=10, required=False, help="Average Quality of reads must be > than this, default: 10")
200
+
201
+ parser_trim.add_argument("--dedup", action="store_true", required=False, help="Run fastp deuplication of fastq reads (default uses ~4gb mem)" + " default: false")
202
+
203
+ parser_trim.add_argument("--cutfront", action="store_true", required=False, help="Run fastp 5' trimming based on quality. " + "default: false. \n" + "WARNING: this operation will interfere deduplication for SE data")
204
+
205
+ parser_trim.add_argument("--cuttail", action="store_true", required=False, help="Run fastp 3' trimming based on quality. " + "default: false.\n" + "WARNING: this operation will interfere deduplication for SE data")
206
+
207
+ parser_trim.add_argument("--cutright", action="store_true", required=False, help="Run fastp move a sliding window from front to tail, " + "if meet one window with mean quality < threshold. \n" + "default: false.\n" + "WARNING: this operation will interfere deduplication for SE data")
208
+
209
+ parser_trim.add_argument("-v", "--debug", action="store_true", help="Provide debugging messages")
210
+
211
+ parser_trim.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
212
+
213
+ parser_trim.add_argument("--method", default="bbduk", choices=["bbduk", "trimmomatic", "fastp"], help="Program to use for adapter trimming")
214
+
215
+ parser_trim.add_argument("-m", "--memory", type=int, dest="memory", required=False, help="Max Memory (in GB)")
216
+
217
+ parser_trim.add_argument("--merge", action="store_true", help="Merge paired end reads when running fastp")
218
+
219
+ parser_trim.add_argument("--prefix", type=str, required=False, help="Prefix for outfiles")
220
+
221
+ tool_group = parser_trim.add_mutually_exclusive_group(required=False)
222
+
223
+ tool_group.add_argument("--trimmomatic", "--jar", metavar="trimmomatic_jar", type=str, required=False, help="Trimmomatic JAR path")
224
+ trimmomatic_group = parser_trim.add_argument_group(title="Trimmomatic options", description="Trimmomatic trimming options")
225
+
226
+ trimmomatic_group.add_argument("--trimmomatic_adaptors", default="TruSeq3-PE.fa", help="Trimmomatic adaptor file, default: TruSeq3-PE.fa")
227
+
228
+ trimmomatic_group.add_argument("--trimmomatic_clip", default="ILLUMINACLIP:%s:2:30:10", help="Trimmomatic clipping, " + "default: ILLUMINACLIP:TruSeq3-PE.fa:2:30:10")
229
+
230
+ trimmomatic_group.add_argument("--trimmomatic_leadingwindow", default="3", type=int, help="Trimmomatic window processing arguments, default: LEADING:3")
231
+
232
+ trimmomatic_group.add_argument("--trimmomatic_trailingwindow", default="3", type=int, help="Trimmomatic window processing arguments, default: TRAILING:3")
233
+
234
+ trimmomatic_group.add_argument("--trimmomatic_slidingwindow", default="4:15", type=str, help="Trimmomatic window processing arguments, " + "default: SLIDINGWINDOW:4:15")
235
+
236
+ trimmomatic_group.add_argument("--trimmomatic_quality", default="phred33", help="Trimmomatic quality encoding -phred33 or phred64")
237
+
238
+ ##########
239
+ # mito-asm assembly mitochondrial genome
240
+ ##########
241
+
242
+ parser_mito = subparsers.add_parser("mito", aliases=["mito_asm", "mitochondria"], description="De novo assembly of mitochondrial genome using " + "NOVOplasty, takes PE Illumina adapter trimmed data.", help="De novo assembly of mitochondrial genome")
243
+ parser_mito.add_argument("-l", "--left", required=True, help="Left (Forward) reads")
244
+
245
+ parser_mito.add_argument("-r", "--right", required=True, help="Right (Reverse) reads")
246
+
247
+ parser_mito.add_argument("-o", "--out", type=str, required=True, help="Output FASTA file for mitochondrial genome")
248
+
249
+ parser_mito.add_argument("--minlen", default=10000, type=int, help="Minimum expected genome size")
250
+
251
+ parser_mito.add_argument("--maxlen", default=100000, type=int, help="Maximum expected genome size")
252
+
253
+ parser_mito.add_argument("-s", "--seed", required=False, help="Seed sequence, ie related mitochondrial genome." + "default: A. nidulans")
254
+
255
+ parser_mito.add_argument("--starting", required=False, help="FASTA file of start sequence, rotate genome to, default COB")
256
+
257
+ parser_mito.add_argument("--reference", required=False, help="Run NOVOplasty in reference mode")
258
+
259
+ parser_mito.add_argument("-w", "--workdir", "--tmpdir", type=str, dest="workdir", required=False, help="Temporary directory to store datafiles and processes in")
260
+
261
+ parser_mito.add_argument("-v", "--debug", action="store_true", help="Provide debugging messages")
262
+
263
+ parser_mito.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
264
+
265
+ ##########
266
+ # filter
267
+ ##########
268
+ # arguments
269
+ # -i / --indir: input dir
270
+ # -o / --out: in fastq reads and output prefix
271
+ # -a / --screen_accessions: screening sequence GenBank accessions
272
+ # -u / --screen_urls: screening sequence URLs (fasta format)
273
+ # --debug: print debug messages and do no remove contamdb BAM file
274
+ # read info, either paired data are required or singleton
275
+ # --left: left or forward reads
276
+ # --right: right or reverse reads
277
+ # --single: single unpaired reads
278
+ # or value from --prefix
279
+ # --aligner: bbduk bwa, bowtie2, minimap for read alignment to contamdb
280
+
281
+ parser_filter = subparsers.add_parser("filter", aliases=["filter_reads", "read_filter"], description="Filter reads which match " + "contaminant databases such as phiX", help="Filter contaminanting reads")
282
+
283
+ parser_filter.add_argument("-w", "--workdir", type=str, help="temp directory")
284
+
285
+ parser_filter.add_argument("-c", "--cpus", type=int, metavar="cpus", required=False, default=1, help="Number of CPUs/threads to use.")
286
+
287
+ parser_filter.add_argument("-o", "--out", dest="basename", type=str, required=False, help="Output basename")
288
+
289
+ parser_filter.add_argument("-v", "--debug", action="store_true", help="Provide debugging messages and do not remove contamdb " + "matching BAM file")
290
+
291
+ parser_filter.add_argument("-a", "--screen_accessions", type=str, nargs="*", help="Genbank accession number(s) to screen out from initial reads.")
292
+
293
+ parser_filter.add_argument("-u", "--screen_urls", type=str, nargs="*", help="URLs to download and screen out initial reads.")
294
+
295
+ parser_filter.add_argument("-s", "--screen_local", type=str, nargs="+", help="Local FASTA file(s) to use contamination screen")
296
+
297
+ parser_filter.add_argument("-l", "--left", required=True, help="Left (Forward) reads")
298
+
299
+ parser_filter.add_argument("-r", "--right", required=False, help="Right (Reverse) reads")
300
+
301
+ parser_filter.add_argument("--AAFTF_DB", type=str, required=False, help="Path to AAFTF resources, defaults to $AAFTF_DB")
302
+
303
+ parser_filter.add_argument("--aligner", default="bbduk", choices=["bbduk", "bowtie2", "bwa", "minimap2"], help="Aligner to use to map reads to contamination database")
304
+
305
+ parser_filter.add_argument("-m", "--memory", type=int, dest="memory", required=False, help="Max Memory (in GB)")
306
+
307
+ parser_filter.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
308
+
309
+ ##########
310
+ # assemble
311
+ ##########
312
+ # arguments
313
+ # -i / --indir: input folder
314
+ # -o / --outdir: output folder
315
+ # -p / --prefix: input/outfile prefix
316
+ # --paired or --unpaired
317
+ # --spades
318
+ # --merged for merged reads
319
+ # --tmpdir: tempdir for spades
320
+
321
+ parser_asm = subparsers.add_parser("assemble", aliases=["asm", "spades"], description="Run assembler on cleaned reads", help="Assemble reads")
322
+
323
+ parser_asm.add_argument("--method", type=str, choices=["spades", "dipspades", "megahit", "unicycler"], required=False, default="spades", help="Assembly method: spades, dipspades, megahit, unicycler. Default: spades")
324
+
325
+ parser_asm.add_argument(
326
+ "-o",
327
+ "--out",
328
+ type=str,
329
+ required=True, # think about sensible replacement in future
330
+ help="Output assembly FASTA",
331
+ )
332
+
333
+ parser_asm.add_argument("-w", "--workdir", type=str, dest="workdir", help="assembly output directory")
334
+
335
+ parser_asm.add_argument("-c", "--cpus", type=int, metavar="cpus", required=False, default=1, help="Number of CPUs/threads to use.")
336
+
337
+ parser_asm.add_argument("-m", "--memory", type=str, dest="memory", required=False, default="32", help="Memory (in GB) setting for SPAdes. Default is 32gb")
338
+
339
+ parser_asm.add_argument("-l", "--left", required=False, help="Left (Forward) reads")
340
+
341
+ parser_asm.add_argument("-r", "--right", required=False, help="Right (Reverse) reads")
342
+ parser_asm.add_argument("-lr", "--longreads", required=False, help="Long Read fastq (pacbio or ONT)")
343
+ parser_asm.add_argument("--single", "--merged", required=False, dest="merged", help="Merged reads from flash or fastp or just single end reads")
344
+
345
+ parser_asm.add_argument("--careful", required=False, action="store_true", default=True, help="Run --careful mode in spades (Default)", dest="careful")
346
+
347
+ parser_asm.add_argument("--no-careful", required=False, action="store_false", default=True, dest="careful")
348
+
349
+ parser_asm.add_argument("--isolate", required=False, action="store_true", dest="isolate", help="Run in isolate mode (default)")
350
+
351
+ parser_asm.add_argument("--no-isolate", required=False, action="store_false", dest="isolate", help="Don't run --isolate mode")
352
+
353
+ parser_asm.add_argument("-v", "--debug", action="store_true", help="Print Spades stdout to terminal")
354
+
355
+ parser_asm.add_argument("--tmpdir", type=str, required=False, help="Assembler temporary dir")
356
+
357
+ parser_asm.add_argument("--assembler_args", action="append", required=False, help="Additional SPAdes/Megahit arguments")
358
+
359
+ parser_asm.add_argument("--haplocontigs", dest="haplocontigs", default=False, action="store_true", help="For dipSPAdes take the haplocontigs file")
360
+
361
+ parser_asm.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
362
+
363
+ ##########
364
+ # vecscreen
365
+ ##########
366
+ # arguments
367
+ # -i / --input: input assembly file
368
+ # -o / --outfile: output cleaned assembly
369
+ # --prefix: Prefix for output / temp files
370
+ # --tmpdir
371
+ # --pid / percent_id
372
+
373
+ parser_vecscreen = subparsers.add_parser("vecscreen", aliases=["vectorscreen", "vector_blast"], description="Screen contigs for vector and common contaminantion", help="BLASTN Vector and Contaminant Screening of contigs")
374
+
375
+ parser_vecscreen.add_argument("-c", "--cpus", type=int, metavar="cpus", default=1, help="Number of CPUs/threads to use.")
376
+
377
+ parser_vecscreen.add_argument("-i", "--input", "--infile", type=str, required=True, dest="infile", help="Input contigs or scaffold assembly")
378
+
379
+ parser_vecscreen.add_argument("-o", "--outfile", type=str, required=True, help="Output vector screened and cleaned assembly")
380
+
381
+ parser_vecscreen.add_argument("-pid", "--percent_id", type=int, required=False, help="Percent Identity cutoff for vecscreen adaptor matches")
382
+
383
+ parser_vecscreen.add_argument("--prefix", type=str, required=False, help="Prefix for tempfiles")
384
+
385
+ parser_vecscreen.add_argument("-w", "--workdir", "--tmpdir", type=str, help="Working directory to store datafiles and processes in")
386
+
387
+ parser_vecscreen.add_argument("--AAFTF_DB", type=str, required=False, help="Path to AAFTF resources, defaults to $AAFTF_DB")
388
+
389
+ parser_vecscreen.add_argument("-s", "--stringency", default="high", choices=["high", "low"], help="Stringency to filter VecScreen hits")
390
+
391
+ parser_vecscreen.add_argument("-v", "--debug", action="store_true", dest="debug", help="Provide debugging messages")
392
+
393
+ parser_vecscreen.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
394
+
395
+ ##########
396
+ # fcs_screen
397
+ ##########
398
+ # arguments
399
+ # -i / --input: input assembly file
400
+ # -o / --outfile: output cleaned assembly
401
+ # --prefix: Prefix for output / temp files
402
+ # --euk - expect eukaryotic screening
403
+ # --prol - expect prokaryote screening
404
+
405
+ parser_fcs_screen = subparsers.add_parser("fcs_screen", aliases=["ncbi_fcs", "ncbi_fcs-screen"], description="Screen with NCBI fcs tool contigs for vector and common contaminantion", help="NCBI Foreign Contaminant Screening for Vector sequences in contigs")
406
+
407
+ parser_fcs_screen.add_argument("-i", "--input", "--infile", type=str, required=True, dest="infile", help="Input contigs or scaffold assembly")
408
+
409
+ parser_fcs_screen.add_argument("-o", "--outfile", type=str, required=True, help="Output vector screened and cleaned assembly")
410
+
411
+ parser_fcs_screen.add_argument("--prefix", type=str, required=False, help="Prefix for tempfiles")
412
+
413
+ parser_fcs_screen.add_argument("--container_engine", type=str, default="singularity", help="Container engine (singular or docker)")
414
+
415
+ parser_fcs_screen.add_argument("--image", type=str, required=False, help="Container file (or will download and look in AAFTF_DB)")
416
+
417
+ parser_fcs_screen.add_argument("-w", "--workdir", "--tmpdir", type=str, help="Working directory to store datafiles and processes in")
418
+
419
+ parser_fcs_screen.add_argument("--AAFTF_DB", type=str, required=False, help="Path to AAFTF resources, defaults to $AAFTF_DB")
420
+
421
+ parser_fcs_screen.add_argument("--prok", action="store_true", help="Run in Prokaryote matching mode")
422
+
423
+ parser_fcs_screen.add_argument("--euk", action="store_true", help="Run in Eukaryote matching mode (Default)")
424
+
425
+ parser_fcs_screen.add_argument("--fcs_script", type=str, required=False, help="location of the run_fcsadaptor.sh script (or will download automatically)")
426
+
427
+ parser_fcs_screen.add_argument("-v", "--debug", action="store_true", dest="debug", help="Provide debugging messages")
428
+
429
+ parser_fcs_screen.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
430
+
431
+ ##########
432
+ # fcs_gx_purge
433
+ ##########
434
+ # arguments
435
+ # -a / --assembly: input assembly file
436
+ # -o / --out: output cleaned assembly file
437
+ # -p / --prefix: datafile prefix and temp/output file prefix
438
+ # -c / --cpus: number of cpus
439
+ # -d / --db: path to db (this is best if is memory mapped location)
440
+ # -t / --taxid: ncbi taxonid (can be any node in taxonomy)
441
+
442
+ parser_fcsgx = subparsers.add_parser("fcs_gx_purge", aliases=["ncbi_fcs-gx", "ncbi_fcs_gx", "gx"], description="Purge contigs based on fcs_gx results", help="Purge contigs based on contamination search with fcs_gx")
443
+
444
+ parser_fcsgx.add_argument("-i", "--input", type=str, required=True, help="Input contigs or scaffold assembly")
445
+
446
+ parser_fcsgx.add_argument(
447
+ "-o",
448
+ "--outfile",
449
+ type=str,
450
+ required=True, # think about sensible replacement in future
451
+ help="Output fcs_gx cleaned assembly",
452
+ )
453
+
454
+ parser_fcsgx.add_argument("--prefix", type=str, required=False, help="Prefix for tempfiles")
455
+
456
+ parser_fcsgx.add_argument("-t", "--taxid", type=int, required=False, default=4890, help="NCBI Taxonomy ID for contamaination matches, i.e. 4890 for Ascomycota")
457
+
458
+ parser_fcsgx.add_argument("-d", "--db", required=False, default="/my_tmpfs/gxdb/all", help="gxdb database path")
459
+
460
+ parser_fcsgx.add_argument("-c", "--cpus", type=int, metavar="cpus", default=1, help="Number of CPUs/threads to use.")
461
+
462
+ parser_fcsgx.add_argument("-w", "--workdir", "--tmpdir", type=str, dest="workdir", required=False, help="Temporary directory to store datafiles and processes in")
463
+
464
+ parser_fcsgx.add_argument("-v", "--debug", action="store_true", dest="debug", help="Provide debugging messages")
465
+
466
+ parser_fcsgx.add_argument("--AAFTF_DB", type=str, required=False, help="Path to AAFTF resources, defaults to $AAFTF_DB")
467
+
468
+ parser_fcsgx.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
469
+
470
+ ##########
471
+ # sourpurge
472
+ ##########
473
+ # arguments
474
+ # -i / --input: input assembly file
475
+ # -o / --out: output cleaned assembly file
476
+ # -p / --prefix: datafile prefix and temp/output file prefix
477
+ # -l / --left: left read of pair
478
+ # -r / --right: right read of pair
479
+ # -k / --kmer: kmer size when running sourmash (needs to match db), default '31'
480
+ # --sourdb_type gtdb gtdbrep gbk
481
+ # --tmpdir
482
+ # --phylum: phylum to keep
483
+ # -mc / --mincovpct:
484
+
485
+ parser_sour = subparsers.add_parser("sourpurge", aliases=["purge"], description="Purge contigs based on sourmash results", help="Purge contigs based on sourmash results")
486
+
487
+ parser_sour.add_argument("-i", "--input", type=str, required=True, help="Input contigs or scaffold assembly")
488
+
489
+ parser_sour.add_argument(
490
+ "-o",
491
+ "--outfile",
492
+ type=str,
493
+ required=True, # think about sensible replacement in future
494
+ help="Output sourmash cleaned assembly",
495
+ )
496
+
497
+ parser_sour.add_argument("--prefix", type=str, required=False, help="Prefix for tempfiles")
498
+
499
+ parser_sour.add_argument("-l", "--left", required=False, help="Left (Forward) reads")
500
+
501
+ parser_sour.add_argument("-r", "--right", required=False, help="Right (Reverse) reads")
502
+
503
+ parser_sour.add_argument("-p", "--phylum", required=True, nargs="+", help="Phylum or Phyla to keep matches, i.e. Ascomycota")
504
+
505
+ parser_sour.add_argument("--sourdb", required=False, help="SourMash LCA taxonomy database (defaults to k-31)")
506
+
507
+ parser_sour.add_argument("-k", "--kmer", required=False, default="31", help="SourMash LCA kmersize when taxonomy database was built")
508
+
509
+ parser_sour.add_argument("-mc", "--mincovpct", default=5, type=int, help="Minimum percent of N50 coverage to remove")
510
+
511
+ parser_sour.add_argument("-c", "--cpus", type=int, metavar="cpus", default=1, help="Number of CPUs/threads to use.")
512
+
513
+ parser_sour.add_argument("-w", "--workdir", "--tmpdir", type=str, dest="workdir", required=False, help="Temporary directory to store datafiles and processes in")
514
+
515
+ parser_sour.add_argument("-v", "--debug", action="store_true", dest="debug", help="Provide debugging messages")
516
+
517
+ parser_sour.add_argument("--sourdb_type", default="gbk", required=False, choices=["gbk", "gtdbrep", "gtdb"], help="Which sourpurge database to use.")
518
+
519
+ parser_sour.add_argument("--AAFTF_DB", type=str, required=False, help="Path to AAFTF resources, defaults to $AAFTF_DB")
520
+
521
+ parser_sour.add_argument("--just-show-taxonomy", dest="taxonomy", action="store_true", help="Show taxonomy information and exit")
522
+
523
+ parser_sour.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
524
+
525
+ ##########
526
+ # rmdup
527
+ ##########
528
+
529
+ # -i / --input
530
+ # -o / --out
531
+ # --tmpdir
532
+ # --percent_id
533
+ # ---mincovpct
534
+ # -ml / --minlen
535
+ # --exhaustive
536
+ # --debug
537
+
538
+ parser_rmdup = subparsers.add_parser("rmdup", aliases=["dedup"], description="Remove duplicate contigs", help="Remove duplicate contigs")
539
+ parser_rmdup.add_argument("-i", "--input", type=str, required=True, help="Input Assembly fasta file(contigs or scaffolds)")
540
+
541
+ parser_rmdup.add_argument("-o", "--out", type=str, required=True, help="Output new version of assembly with " + "duplicated contigs/scaffolds removed")
542
+
543
+ parser_rmdup.add_argument("-c", "--cpus", type=int, metavar="cpus", required=False, default=1, help="Number of CPUs/threads to use.")
544
+
545
+ parser_rmdup.add_argument("-w", "--workdir", "--tmpdir", dest="workdir", type=str, required=False, help="Temporary directory to store datafiles and processes in")
546
+
547
+ parser_rmdup.add_argument("-pid", "--percent_id", type=int, dest="percent_id", required=False, default=95, help="Percent Identity used in matching contigs for redundancy")
548
+
549
+ parser_rmdup.add_argument("-pcov", "--percent_cov", type=int, dest="percent_cov", required=False, default=95, help="Coverage of contig used to decide if it is redundant")
550
+
551
+ parser_rmdup.add_argument("-ml", "--minlen", type=int, required=False, default=500, help="Minimum contig length to keep, shorter ones are dropped")
552
+
553
+ parser_rmdup.add_argument("--exhaustive", action="store_true", help="Compute overlaps for every contig, " + "otherwise only process contigs for L75 and below")
554
+
555
+ parser_rmdup.add_argument("-v", "--debug", action="store_true", help="Run rmdup in debugging mode for more output")
556
+
557
+ parser_rmdup.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
558
+
559
+ ##########
560
+ # polish
561
+ ##########
562
+ # arguments
563
+ # -i / --in: input assembly file
564
+ # -o / --out: output cleaned assembly
565
+ # --left: left fastq read file (ILLUMINA)
566
+ # --right: right fastq read file (ILLUMINA)
567
+ # --longreads: long reads (ONT/PACBIO) fastq
568
+ # -rp / --reads-prefix: input/outfile reads prefix
569
+ # --method pilon
570
+ # --memory: default 16
571
+ # --iterations: default 5
572
+ # --tmpdir
573
+ # --debug
574
+ # --diploid - inddicate this is a diploid organism
575
+
576
+ parser_polish = subparsers.add_parser("polish", aliases=["pilon", "polca"], description="Polish contig sequences with Pilon, POLCA, NextPolish", help="Polish contig sequences with short reads")
577
+
578
+ parser_polish.add_argument("-o", "--out", "--outfile", type=str, dest="outfile", required=False, help="Output a Polished assembly")
579
+
580
+ parser_polish.add_argument("-i", "--infile", "--input", type=str, dest="infile", required=True, help="Input contigs or scaffold assembly")
581
+
582
+ parser_polish.add_argument("-c", "--cpus", type=int, metavar="cpus", default=1, help="Number of CPUs/threads to use.")
583
+
584
+ parser_polish.add_argument("-m", "--memory", type=int, default=16, dest="memory", required=False, help="Max Memory (in GB) (default is 16gb)")
585
+
586
+ parser_polish.add_argument("-v", "--debug", action="store_true", help="Provide debugging messages")
587
+
588
+ parser_polish.add_argument("-it", "--iterations", type=int, default=5, help="Number of Polishing iterations to run (default is 5)")
589
+ parser_polish.add_argument("--method", type=str, choices=["pilon", "polca", "nextpolish", "racon"], required=False, default="pilon", help="Polishing method: pilon, polca, nextpolish, racon")
590
+
591
+ parser_polish.add_argument("--polca", type=str, default="polca.sh", help="polca exe path - provide full path to deal with samtools mismatch in masurca")
592
+
593
+ parser_polish.add_argument("--polca_samtools", type=str, default=None, metavar="SAMTOOLS_PATH", help="Path to a samtools binary compatible with polca.sh (e.g. samtools < 1.21). polca.sh uses 'samtools sort -f' which was removed in 1.21+; set this to an older samtools when the system default is >= 1.21.")
594
+
595
+ parser_polish.add_argument("-l", "--left", type=str, required=False, help="The name of the left/forward Illumina reads of paired-end " + "FASTQ formatted reads.")
596
+
597
+ parser_polish.add_argument("-r", "--right", type=str, required=False, help="The name of the right/reverse Illumina reads of paired-end " + "FASTQ formatted reads.")
598
+
599
+ parser_polish.add_argument("-lr", "--longreads", required=False, help="Long Read FASTQ (PacBio or ONT)")
600
+ parser_polish.add_argument("-w", "--workdir", "--tmpdir", type=str, dest="workdir", required=False, help="Temporary directory to store datafiles for processes")
601
+
602
+ parser_polish.add_argument("--prefix", type=str, required=False, help="Prefix for readfiles")
603
+
604
+ parser_polish.add_argument("--diploid", action="store_true", help="Run pilon in diploid mode - affects heterozygous SNP calling")
605
+
606
+ parser_polish.add_argument("--ploidy", default=1, type=int, help="Run nextpolish in specific ploidy mode - affects heterozygous SNP calling, default is 1")
607
+
608
+ parser_polish.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
609
+
610
+ ##########
611
+ # sort/rename FASTA headers
612
+ ##########
613
+ # arguments
614
+ # -i / --input: input assembly file
615
+ # -o / --out: output assembly file
616
+ # -n / --name: base name to use default=scaffolds_
617
+
618
+ parser_sort = subparsers.add_parser("sort", description="Sort contigs by length and rename FASTA headers", help="Sort contigs by length and rename FASTA headers")
619
+
620
+ parser_sort.add_argument("-i", "--input", "--infile", required=True, dest="input", help="Input genome assembly FASTA")
621
+
622
+ parser_sort.add_argument("-o", "--out", "--output", required=True, dest="out", help="Output genome assembly FASTA")
623
+
624
+ parser_sort.add_argument("-ml", "--minlen", type=int, required=False, default=0, help="Minimum contig length to keep, shorter ones are dropped")
625
+
626
+ parser_sort.add_argument("-n", "--name", "--basename", default="scaffold", dest="name", help="Basename to rename FASTA headers")
627
+
628
+ parser_sort.add_argument("-v", "--debug", action="store_true", help="Provide debugging messages")
629
+
630
+ parser_sort.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
631
+
632
+ ##########
633
+ # assess completeness
634
+ ##########
635
+ # arguments
636
+ # -i / --input: input assembly file
637
+ # -r / --report: report file (otherwise stdout)
638
+ # -t / --telomere_monomer: telomere repeat monomer pattern (default=[TAA[C]+])
639
+ # -n / --telomere_n_repeats: Minimum number of repeats of telomere monomer (default=2)
640
+
641
+ parser_assess = subparsers.add_parser("assess", aliases=["stats"], description="Assess completeness of genome assembly", help="Assess completeness of genome assembly")
642
+
643
+ parser_assess.add_argument("-i", "--input", "--infile", required=True, help="Input genome assembly to test completeness and " + "provide summary statistics")
644
+
645
+ parser_assess.add_argument("-r", "--report", type=str, help="Filename to save report information otherwise " + "will print to stdout")
646
+
647
+ parser_assess.add_argument("-t", "--telomere_monomer", type=str, help="Telomere repeat monomer to search for. default(TAA[C]+)", default="TAA[C]+")
648
+
649
+ parser_assess.add_argument("-n", "--telomere_n_repeat", type=int, default=2, help="Telomere minimum number of monomer repeats. (default 2)")
650
+
651
+ parser_assess.add_argument("--telomere_window", type=int, default=200, help="Number of bp to scan at each end for telomere repeats. (default 200)")
652
+
653
+ parser_assess.add_argument("-v", "--debug", action="store_true", help="Provide debugging messages")
654
+
655
+ parser_assess.add_argument("--pipe", action="store_true", help="AAFTF is running in pipeline mode")
656
+
657
+ #########
658
+ # fix tbl file from fcs trimmimg
659
+ ##########
660
+ # arguments
661
+ # -t / --table tbl file origina
662
+ # -o / --output output tbl file
663
+ # -r / --report NCBI FCS update report (a 5 column CSV file)
664
+
665
+ parser_fix = subparsers.add_parser("fix_tbl", aliases=["fix"], description="Fix NCBI tbl file from a trim report from NCBI-FCS", help="Fix the TBL file offsets from trimmimg")
666
+
667
+ parser_fix.add_argument("-t", "--table", "--infile", type=ap.FileType("rt"), required=True, help="Table format of annotation (NCBL tbl)")
668
+
669
+ parser_fix.add_argument("-r", "--report", type=ap.FileType("rt"), required=True, help="FCS report (5 column CSV)")
670
+
671
+ parser_fix.add_argument("-o", "--output", type=ap.FileType("wt"), required=True, help="Write fixed TBL file")
672
+
673
+ parser_fix.add_argument("--pipe", action="store_true", default=False, help="AAFTF is running in pipeline mode")
674
+
675
+ parser_fix.add_argument("-v", "--debug", action="store_true", dest="debug", default=False, help="Verbose/debug mode")
676
+
677
+ ##########
678
+ # depth of coverage
679
+ ##########
680
+ # arguments
681
+ # -i / --input: genome assembly FASTA
682
+ # -o / --out: output report file (default: coverage_stats.txt)
683
+ # -l / --left: forward Illumina reads
684
+ # -r / --right: reverse Illumina reads
685
+ # -lr / --longreads: long reads FASTQ (ONT/PacBio)
686
+ # --longread_type: minimap2 preset for long reads
687
+ # --illumina_preset: minimap2 preset for Illumina reads
688
+ # --aligner: minimap2 (default) or bwa for Illumina reads
689
+ # -c / --cpus
690
+ # -w / --workdir
691
+ # -v / --debug
692
+ # --pipe
693
+
694
+ parser_depth = subparsers.add_parser(
695
+ "depth",
696
+ aliases=["coverage", "cov"],
697
+ description=("Calculate depth of coverage by mapping Illumina and/or long reads " "to a genome assembly with minimap2 (or bwa), then running mosdepth " "to compute per-contig depth statistics. Contigs with mean depth " "> assembly_mean + 3*SD are flagged as possible contaminants or " "organellar sequences."),
698
+ help="Calculate read depth of coverage for genome assembly",
699
+ )
700
+
701
+ parser_depth.add_argument(
702
+ "-i",
703
+ "--input",
704
+ "--infile",
705
+ required=True,
706
+ dest="input",
707
+ help="Input genome assembly FASTA (e.g. *.sorted.fasta)",
708
+ )
709
+
710
+ parser_depth.add_argument(
711
+ "-o",
712
+ "--out",
713
+ "--report",
714
+ type=str,
715
+ default="coverage_stats.txt",
716
+ dest="out",
717
+ help="Output coverage report file (default: coverage_stats.txt)",
718
+ )
719
+
720
+ parser_depth.add_argument(
721
+ "-l",
722
+ "--left",
723
+ required=False,
724
+ help="Left (Forward) Illumina reads FASTQ",
725
+ )
726
+
727
+ parser_depth.add_argument(
728
+ "-r",
729
+ "--right",
730
+ required=False,
731
+ help="Right (Reverse) Illumina reads FASTQ",
732
+ )
733
+
734
+ parser_depth.add_argument(
735
+ "-lr",
736
+ "--longreads",
737
+ required=False,
738
+ help="Long reads FASTQ (PacBio or ONT)",
739
+ )
740
+
741
+ parser_depth.add_argument(
742
+ "--longread_type",
743
+ default="map-ont",
744
+ choices=["map-ont", "map-pb", "map-hifi"],
745
+ dest="longread_preset",
746
+ help="minimap2 preset for long reads (default: map-ont)",
747
+ )
748
+
749
+ parser_depth.add_argument(
750
+ "--illumina_preset",
751
+ default="sr",
752
+ choices=["sr", "short"],
753
+ dest="illumina_preset",
754
+ help="minimap2 preset for Illumina reads (default: sr)",
755
+ )
756
+
757
+ parser_depth.add_argument(
758
+ "--aligner",
759
+ default="minimap2",
760
+ choices=["minimap2", "bwa"],
761
+ help="Aligner to use for Illumina reads (default: minimap2)",
762
+ )
763
+
764
+ parser_depth.add_argument(
765
+ "-c",
766
+ "--cpus",
767
+ type=int,
768
+ metavar="cpus",
769
+ required=False,
770
+ default=1,
771
+ help="Number of CPUs/threads to use.",
772
+ )
773
+
774
+ parser_depth.add_argument(
775
+ "-w",
776
+ "--workdir",
777
+ "--tmpdir",
778
+ type=str,
779
+ dest="workdir",
780
+ required=False,
781
+ help="Temporary directory to store intermediate files",
782
+ )
783
+
784
+ parser_depth.add_argument(
785
+ "-v",
786
+ "--debug",
787
+ action="store_true",
788
+ help="Provide debugging messages and retain intermediate files",
789
+ )
790
+
791
+ parser_depth.add_argument(
792
+ "--pipe",
793
+ action="store_true",
794
+ help="AAFTF is running in pipeline mode",
795
+ )
796
+
797
+ parser_depth.add_argument(
798
+ "--min_contig_len",
799
+ type=int,
800
+ default=500,
801
+ help="Minimum contig length to include in depth outlier analysis (default: 500)",
802
+ )
803
+
804
+ parser_depth.add_argument(
805
+ "--plot-format",
806
+ choices=["pdf", "svg", "png"],
807
+ default="pdf",
808
+ dest="plot_format",
809
+ help="Output format for coverage plots (default: pdf; requires matplotlib)",
810
+ )
811
+
812
+ parser_depth.add_argument(
813
+ "--no-plot",
814
+ action="store_true",
815
+ dest="no_plot",
816
+ help="Disable coverage plot generation",
817
+ )
818
+
819
+ parser_depth.add_argument(
820
+ "--quantize",
821
+ default="0:1:4:100:200:",
822
+ dest="quantize",
823
+ help="mosdepth quantize bin boundaries, colon-separated with trailing colon " "(default: 0:1:4:100:200:)",
824
+ )
825
+
826
+ parser_depth.add_argument(
827
+ "--quantize-labels",
828
+ default=None,
829
+ dest="quantize_labels",
830
+ metavar="LABELS",
831
+ help="Comma-separated labels for quantize bins " "(default: NO_COVERAGE,LOW_COVERAGE,CALLABLE,HIGH_COVERAGE,VERY_HIGH_COVERAGE " "for the default bins)",
832
+ )
833
+
834
+ ##########
835
+ # pipeline run it all
836
+ ##########
837
+ # arguments
838
+ # -i / --input: input assembly file
839
+ # -r / --report: report file (otherwise stdout)
840
+ # --tmpdir
841
+
842
+ parser_pipeline = subparsers.add_parser("pipeline", description="Run entire AAFTF pipeline automagically", help="Run AAFTF pipeline")
843
+
844
+ parser_pipeline.add_argument("--tmpdir", type=str, required=False, help="Assembler temporary dir")
845
+ parser_pipeline.add_argument("--assembler_args", action="append", required=False, help="Additional SPAdes/Megahit arguments")
846
+ parser_pipeline.add_argument("--method", type=str, required=False, default="spades", help="Assembly method: spades, dipspades, megahit")
847
+
848
+ parser_pipeline.add_argument("-l", "--left", type=str, required=True, help="left/forward reads of paired-end FASTQ or " + "single-end FASTQ.")
849
+
850
+ parser_pipeline.add_argument("-r", "--right", type=str, required=False, help="right/reverse reads of paired-end FASTQ.")
851
+
852
+ parser_pipeline.add_argument("-o", "--out", type=str, required=True, dest="basename", help="Output basename, default to base name of --left reads")
853
+
854
+ parser_pipeline.add_argument("-c", "--cpus", type=int, metavar="cpus", required=False, default=1, help="Number of CPUs/threads to use.")
855
+
856
+ parser_pipeline.add_argument("-m", "--memory", type=str, dest="memory", required=False, help="Memory (in GB) setting for SPAdes. Default is Auto")
857
+
858
+ parser_pipeline.add_argument("-ml", "--minlen", type=int, default=75, required=False, help="Minimum read length after trimming, default: 75")
859
+
860
+ parser_pipeline.add_argument("-a", "--screen_accessions", type=str, nargs="*", help="Genbank accession number(s) to screen out from initial reads.")
861
+
862
+ parser_pipeline.add_argument("-u", "--screen_urls", type=str, nargs="*", help="URLs to download and screen out initial reads.")
863
+
864
+ parser_pipeline.add_argument("-it", "--iterations", type=int, default=5, help="Number of Pilon Polishing iterations to run")
865
+
866
+ parser_pipeline.add_argument("-mc", "--mincontiglen", type=int, default=500, required=False, help="Minimum length of contigs to keep")
867
+
868
+ parser_pipeline.add_argument("--AAFTF_DB", type=str, required=False, help="Path to AAFTF resources, defaults to $AAFTF_DB")
869
+
870
+ parser_pipeline.add_argument("-w", "--workdir", type=str, help="temp directory")
871
+
872
+ parser_pipeline.add_argument("-v", "--debug", action="store_true", help="Provide debugging messages")
873
+
874
+ parser_pipeline.add_argument("-p", "--phylum", required=True, nargs="+", help="Phylum or Phyla to keep matches, i.e. Ascomycota")
875
+
876
+ parser_pipeline.add_argument("--sourdb", required=False, help="SourMash LCA k-31 taxonomy database")
877
+
878
+ parser_pipeline.add_argument("--mincovpct", default=5, type=int, help="Minimum percent of N50 coverage to remove")
879
+
880
+ parser_pipeline.add_argument("--pipe", action="store_true", default=False, help="AAFTF is running in pipeline mode")
881
+
882
+ # done with menu options
883
+ # set defaults
884
+ parser.set_defaults(func=run_subtool)
885
+
886
+ # process the arguments now
887
+ # if no args then print help and exit
888
+ if len(sys.argv) == 1:
889
+ parser.print_help(sys.stderr)
890
+ sys.exit(1)
891
+
892
+ args = parser.parse_args()
893
+
894
+ try:
895
+ status(f"Running AAFTF v{myversion}")
896
+ args.func(parser, args)
897
+ except OSError as e:
898
+ if e.errno != 32: # ignore SIGPIPE
899
+ raise
900
+
901
+
902
+ if __name__ == "__main__":
903
+ main()