Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.0
1.1.0
51 changes: 38 additions & 13 deletions src/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@

# Constants
# Handling different input filetypes, i.e illumina
# fastq files, bam, cram, vcf, tsv, csv, ont fastqs,
# ont fast5, ont pod5, etc. The input_type is defined
# in config/config.json under options.input_type, so
# the type is never inferred from filenames.
# fastq files, fasta, bam, cram, vcf, tsv, csv, ont
# fastqs, ont fast5, ont pod5, etc. The input_type is
# defined in config/config.json under options.input_type,
# so the type is never inferred from filenames.
SUPPORTED_INPUT_FILETYPES = {
"illumina_fastq": {"fastq": True, "is_dir": False, "exts": [".R1.fastq.gz", ".R2.fastq.gz"]},
"ont_fastq": {"fastq": True, "is_dir": False, "exts": [".fastq.gz", ".fq.gz", ".fastq", ".fq"]},
"ont_fastq": {"fastq": True, "is_dir": False, "exts": [".fastq.gz"]},
"ont_fast5": {"fastq": False, "is_dir": True, "exts": [".fast5"]},
"ont_pod5": {"fastq": False, "is_dir": True, "exts": [".pod5"]},
"fasta": {"fastq": False, "is_dir": False, "exts": [".fa.gz"]},
"bam": {"fastq": False, "is_dir": False, "exts": [".bam"]},
"cram": {"fastq": False, "is_dir": False, "exts": [".cram"]},
"vcf": {"fastq": False, "is_dir": False, "exts": [".vcf.gz", ".vcf"]},
Expand Down Expand Up @@ -69,7 +70,7 @@
# Endedness signal written to config['project']['nends'].
NENDS_SINGLE = 1 # single-end / single-file-per-sample
NENDS_PAIRED = 2 # paired-end Illumina FastQ
NENDS_OTHER = -1 # non-fastq (bam, cram, vcf, tables, ont signal dirs)
NENDS_OTHER = -1 # non-fastq (fasta, bam, cram, vcf, tables, ont signal dirs)
NENDS_LABELS = {NENDS_SINGLE: "single-end", NENDS_PAIRED: "paired-end", NENDS_OTHER: "other"}

# Colorized output for user-facing messages
Expand Down Expand Up @@ -279,8 +280,8 @@ def matches_type(filename, input_type):
Declared input type from config
@return <bool>
"""
name = os.path.basename(filename).lower()
return any(name.endswith(ext.lower()) for ext in extensions_for(input_type))
name = os.path.basename(filename)
return any(name.endswith(ext) for ext in extensions_for(input_type))


def strip_ext(filename, input_type):
Expand All @@ -298,7 +299,7 @@ def strip_ext(filename, input_type):
if input_type == "illumina_fastq":
return ILLUMINA_MATE_RE.split(name)[0]
for ext in sorted(extensions_for(input_type), key=len, reverse=True):
if name.lower().endswith(ext.lower()):
if name.endswith(ext):
return name[: -len(ext)]
return name

Expand Down Expand Up @@ -341,7 +342,7 @@ def rename(filename, input_type):
raise NameError(_fatal_message(
f"Input '{filename}' does not match declared input_type '{input_type}'!\n"
f"Expected one of the following extensions: {', '.join(extensions_for(input_type))}\n"
"Please correct options.input_type in config.json or remove this file."
"Please rename the file, correct options.input_type in config.json, or remove this file."
))
return filename

Expand Down Expand Up @@ -506,7 +507,8 @@ def sym_safe(input_data, target, input_type, input_dirname="inputs"):
"""Creates re-named symlinks for each input file in target/inputs/.
Illumina FastQs are normalized to canonical .R1/.R2 names. All other
supported types are validated and linked as-is. Existing symlinks are not
recreated; relative source paths are converted to absolute paths.
recreated; relative source paths are converted to absolute paths. Raises
if two or more inputs would map to the same symlink name.
@param input_data list[<str>]:
Input files to symlink to target/input_dirname
@param target <str>:
Expand All @@ -526,11 +528,34 @@ def sym_safe(input_data, target, input_type, input_dirname="inputs"):
os.makedirs(input_dir)

renamed_inputs = []
renamed_to_sources = {}
for file in input_data:
filename = os.path.basename(file)
renamed = os.path.join(input_dir, rename(filename, input_type))
renamed_name = rename(filename, input_type)
renamed = os.path.join(input_dir, renamed_name)
renamed_inputs.append(renamed)
renamed_to_sources.setdefault(renamed_name, []).append(file)

collisions = {
renamed_name: sources
for renamed_name, sources in renamed_to_sources.items()
if len(sources) > 1
}
if collisions:
details = "\n".join(
f"{name}: {', '.join(files)}"
for name, files in sorted(collisions.items())
)
raise NameError(_fatal_message(
"Input filename collision detected while creating symlinks.\n"
"Two or more inputs would produce the same target filename in "
f"'{input_dirname}/':\n"
f"{details}\n"
"Please ensure every input has a unique basename (or rename files "
"before running)."
))

for file, renamed in zip(input_data, renamed_inputs):
if not exists(renamed):
# Follow source symlinks to resolve any binding issues
os.symlink(os.path.abspath(os.path.realpath(file)), renamed)
Expand Down Expand Up @@ -931,4 +956,4 @@ def runner(mode, outdir, alt_cache, logger, additional_bind_paths="",
"-j", jobname, "-b", str(bindpaths),
"-o", str(outdir), "-c", str(cache),
"-t", f"'{tmp_dir}'",
], cwd=outdir, stderr=subprocess.STDOUT, stdout=logger, env=env)
], cwd=outdir, stderr=subprocess.STDOUT, stdout=logger, env=env)
3 changes: 2 additions & 1 deletion src/setup-wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
# pipeline's own definition is what lets the wizard rewrite the template safely.
SUPPORTED_INPUT_FILETYPES = {
"illumina_fastq": {"fastq": True, "exts": [".R1.fastq.gz", ".R2.fastq.gz"], "primary_ext": ".R1.fastq.gz", "label": "FastQ", "paired": True},
"ont_fastq": {"fastq": True, "exts": [".fastq.gz", ".fq.gz", ".fastq", ".fq"], "primary_ext": ".fastq.gz", "label": "FastQ", "paired": False},
"ont_fastq": {"fastq": True, "exts": [".fastq.gz"], "primary_ext": ".fastq.gz", "label": "FastQ", "paired": False},
"fasta": {"fastq": False, "exts": [".fa.gz"], "primary_ext": ".fa.gz", "label": "FASTA", "paired": False},
"bam": {"fastq": False, "exts": [".bam"], "primary_ext": ".bam", "label": "BAM", "paired": False},
"cram": {"fastq": False, "exts": [".cram"], "primary_ext": ".cram", "label": "CRAM", "paired": False},
"vcf": {"fastq": False, "exts": [".vcf.gz", ".vcf"], "primary_ext": ".vcf.gz", "label": "VCF", "paired": False},
Expand Down