Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added option to NuQCJob to annotate filtered fastq. #155

Merged
merged 4 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
55 changes: 55 additions & 0 deletions sequence_processing_pipeline/Commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,58 @@ def demux(id_map, fp, out_d, task, maxtask):
for d in openfps.values():
for f in d.values():
f.close()


def annotate_filtered_fastq(original_path, stripped_path, output_path):
"""
Annotates a FASTQ file w/missing descriptions using original file.
:param original_path: A path to the original, unfiltered file.
:param stripped_path: A path to the filtered file.
:param output_path: A path for the output file.
:return: None
"""
mapping = {}

# Per FASTQ specification: https://en.wikipedia.org/wiki/FASTQ_format
# lines beginning with '@' contain the sequence's identifier and an
charles-cowart marked this conversation as resolved.
Show resolved Hide resolved
# optional description or 'metadata'.

# minimap2 is a tool used to perform host filtering on fastq files.
# The preferred output for this program is SAM format:
# https://en.wikipedia.org/wiki/SAM_(file_format)

# SAM format cannot preserve the optional metadata field and hence the
# metadata will disappear after using minimap2 to filter a file and
# samtools to convert the file from SAM back to FASTQ format.

# It is straightforward to process even large fastq files line by line
# sequence identifier lines are unique and easily identified as they are
# the only lines in a FASTQ file beginning with '@'. It is thus straight-
# forward to process even large files to build a mapping between
# sequence identifiers and optional metadata fields.
with open(original_path, 'r') as f:
for line in f:
if line.startswith('@'):
line = line.strip().split()
if len(line) != 2:
raise ValueError(f"'{original_path}' does not appear to "
charles-cowart marked this conversation as resolved.
Show resolved Hide resolved
"contain sequence identifiers with "
"optional metadata")
# where sequence identifier = line[0] and
# the optional description = line[1].
mapping[line[0]] = line[1]
charles-cowart marked this conversation as resolved.
Show resolved Hide resolved

# As the target file is read line by line, it is straightforward to
# annotate each sequence identifier line w/the optional description from
# the original file in place.
with open(stripped_path, 'r') as f:
with open(output_path, 'w') as of:
for line in f:
line = line.strip()
if line.startswith('@'):
if line in mapping:
print(line + ' ' + mapping[line], file=of)
else:
raise ValueError(f"'{line}' is not in mapping!")
else:
print(line, file=of)
21 changes: 19 additions & 2 deletions sequence_processing_pipeline/NuQCJob.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def __init__(self, fastq_root_dir, output_path, sample_sheet_path,
wall_time_limit, jmem, fastp_path, minimap2_path,
samtools_path, modules_to_load, qiita_job_id,
max_array_length, known_adapters_path, movi_path, gres_value,
pmls_path, bucket_size=8, length_limit=100, cores_per_task=4):
pmls_path, bucket_size=8, length_limit=100, cores_per_task=4,
annotate_fastq_files=False):
"""
Submit a slurm job where the contents of fastq_root_dir are processed
using fastp, minimap2, and samtools. Human-genome sequences will be
Expand All @@ -69,6 +70,8 @@ def __init__(self, fastq_root_dir, output_path, sample_sheet_path,
:param bucket_size: the size in GB of each bucket to process
:param length_limit: reads shorter than this will be discarded.
:param cores_per_task: Number of CPU cores per node to request.
:param annotate_fastq_files: If True, copy optional descriptions in
original fastq files to filtered files.
"""
super().__init__(fastq_root_dir,
output_path,
Expand Down Expand Up @@ -96,6 +99,7 @@ def __init__(self, fastq_root_dir, output_path, sample_sheet_path,
self.movi_path = movi_path
self.gres_value = gres_value
self.pmls_path = pmls_path
self.annotate_fastq_files = annotate_fastq_files

# for projects that use sequence_processing_pipeline as a dependency,
# jinja_env must be set to sequence_processing_pipeline's root path,
Expand Down Expand Up @@ -427,9 +431,22 @@ def _generate_mmi_filter_cmds(self, working_dir):
cmds.append(f"[ -e {tmp_file1} ] && rm {tmp_file1}")
cmds.append(f"[ -e {tmp_file2} ] && rm {tmp_file2}")

if self.annotate_fastq_files is True:
annotated_final_output = join(working_dir,
"seqs.interleaved.filter_alignment"
".annotated.fastq")

cmds.append(f"annotate_filtered_fastq {initial_input} "
f"{final_output} {annotated_final_output}")

# if filtered sequence results were re-annotated using metadata
# from the original file, make sure the output from this operation
# becomes the true final output file.
cmds.append(f"mv {annotated_final_output} {final_output}")

return "\n".join(cmds)

def _generate_job_script(self, max_bucket_size):
def _generate_job_script(self, max_bucket_size, annotate_fastq=False):
# bypass generating job script for a force-fail job, since it is
# not needed.
if self.force_job_fail:
Expand Down
27 changes: 27 additions & 0 deletions sequence_processing_pipeline/scripts/annotate_filtered_fastq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env python
import click
from sequence_processing_pipeline.Commands import annotate_filtered_fastq


@click.command()
@click.argument('original_path', required=True)
@click.argument('stripped_path', required=True)
@click.argument('output_path', required=True)
def main(original_path, stripped_path, output_path):
"""
Annotates a stripped fastq file based on descriptions from original.
Additional info appears on stderr.
Exits w/(1) if an id appears in stripped file but not in original.
"""
try:
annotate_filtered_fastq(original_path, stripped_path, output_path)
except ValueError as e:
# explicitly catch known potential errors and ensure they exit w/a
# return value of 1 after politely stating the cause of the error sans
# stacktrace.
print(str(e))
exit(1)


if __name__ == '__main__':
main()
38 changes: 38 additions & 0 deletions sequence_processing_pipeline/tests/data/seqs.interleaved.fastq
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:3900:1600/1 BX:Z:TAGACACGAAGGTTGGAC
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:3900:1600/2 BX:Z:TAGACACGAAGGTTGGAC
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:F:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FF,FFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:7740:1600/1 BX:Z:AAAGATGAGGGCAGTTAA
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:7740:1600/2 BX:Z:AAAGATGAGGGCAGTTAA
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:12790:1600/1 BX:Z:TGGGGGTCGTAACACGAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:12790:1600/2 BX:Z:TGGGGGTCGTAACACGAA
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFF::FFFFF,FFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:13250:1600/1 BX:Z:CGAGGCAGACTTGAATGC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFF:FFFFF:FFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:13250:1600/2 BX:Z:CGAGGCAGACTTGAATGC
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFF:FFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:13520:1600/1 BX:Z:CAGACACGTAGGTGGGAC
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:13520:1600/2 BX:Z:CAGACACGTAGGTGGGAC
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:3900:1600/1
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:3900:1600/2
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:F:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FF,FFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:7740:1600/1
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:7740:1600/2
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:12790:1600/1
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:12790:1600/2
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFF::FFFFF,FFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:13250:1600/1
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFFFFFFFFFFFFFFFFF:FFFFF:FFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:13250:1600/2
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:FFF:FFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:13520:1600/1
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@1::MUX::FS10001773:68:BTR67708-1611:1:1101:13520:1600/2
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
49 changes: 46 additions & 3 deletions sequence_processing_pipeline/tests/test_NuQCJob.py
Original file line number Diff line number Diff line change
Expand Up @@ -2106,9 +2106,52 @@ def test_generate_mmi_filter_cmds(self):

exp = "\n".join(exp)

print(obs)
print("###")
print(exp)
self.assertEqual(obs, exp)

def test_generate_mmi_filter_cmds_w_annotate_fastq(self):
double_db_paths = ["db_path/mmi_1.db", "db_path/mmi_2.db"]
job = NuQCJob(
self.fastq_root_path,
self.output_path,
self.good_sample_sheet_path,
double_db_paths,
"queue_name",
1,
1440,
"8",
"fastp",
"minimap2",
"samtools",
[],
self.qiita_job_id,
1000,
"",
self.movi_path,
self.gres_value,
self.pmls_path,
annotate_fastq_files=True
)

obs = job._generate_mmi_filter_cmds("/my_work_dir")

exp = [
"minimap2 -2 -ax sr -t 2 db_path/mmi_1.db /my_work_dir/seqs."
"interleaved.fastq -a | samtools fastq -@ 2 -f 12 -F 256 > "
"/my_work_dir/foo",
"minimap2 -2 -ax sr -t 2 db_path/mmi_2.db /my_work_dir/foo -a | "
"samtools fastq -@ 2 -f 12 -F 256 > /my_work_dir/bar",
"mv /my_work_dir/bar /my_work_dir/seqs.interleaved.filter_"
"alignment.fastq",
"[ -e /my_work_dir/foo ] && rm /my_work_dir/foo",
"[ -e /my_work_dir/bar ] && rm /my_work_dir/bar",
"annotate_filtered_fastq /my_work_dir/seqs.interleaved.fastq "
"/my_work_dir/seqs.interleaved.filter_alignment.fastq "
"/my_work_dir/seqs.interleaved.filter_alignment.annotated.fastq",
"mv /my_work_dir/seqs.interleaved.filter_alignment.annotated.fastq"
" /my_work_dir/seqs.interleaved.filter_alignment.fastq"
]

exp = "\n".join(exp)

self.assertEqual(obs, exp)

Expand Down
38 changes: 36 additions & 2 deletions sequence_processing_pipeline/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,30 @@
from tempfile import TemporaryDirectory
import gzip
import os
from os.path import join
from sequence_processing_pipeline.Commands import (split_similar_size_bins,
demux)
demux,
annotate_filtered_fastq)
import io
from os.path import abspath, join, exists
from functools import partial
from os import remove


class CommandTests(unittest.TestCase):
def setUp(self):
root = partial(join,
abspath('./sequence_processing_pipeline'),
'tests',
'data')

self.stripped_fastq = root('seqs.interleaved.filter_alignment.fastq')
self.original_fastq = root('seqs.interleaved.fastq')
self.output_fastq = root('output.fastq')

def tearDown(self):
if exists(self.output_fastq):
remove(self.output_fastq)

@patch('os.stat')
@patch('glob.glob')
def test_split_similar_size_bins(self, glob, stat):
Expand Down Expand Up @@ -84,6 +101,23 @@ def test_demux(self):
self.assertFalse(os.path.exists(join(tmp, 'a_R1.fastq.gz')))
self.assertFalse(os.path.exists(join(tmp, 'a_R2.fastq.gz')))

def test_annotate_filtered_fastq(self):
annotate_filtered_fastq(self.original_fastq, self.stripped_fastq,
self.output_fastq)

with open(self.original_fastq, 'r') as exp_fp:
with open(self.output_fastq, 'r') as obs_fp:
# Within the sample fastq files, the first ten sequences of
# the original matched file passed successfully through
# host filtering and are present in the filtered result. Hence,
# the filtered version is the same as the original, minus the
# optional descriptions. Hence, if the optional descriptions
# are restored, the output fastq will be identical to the
# original.
exp = exp_fp.readlines()
obs = obs_fp.readlines()
self.assertEqual(obs, exp)


if __name__ == '__main__':
unittest.main()
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@
],
entry_points={
'console_scripts': ['demux=sequence_processing_pipeline.scripts.cli'
':demux', ], })
':demux',
'annotate_filtered_fastq=sequence_processing_'
'pipeline.scripts.annotate_filtered_fastq:main'],
})
Loading