66 lines
2.5 KiB
Python
Executable File
66 lines
2.5 KiB
Python
Executable File
"""Check (u)BAM files for `@SQ` lines whether they are the same in all headers."""
|
|
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
import pysam
|
|
|
|
from .util import get_named_logger, wf_parser # noqa: ABS101
|
|
|
|
|
|
def main(args):
|
|
"""Run the entry point."""
|
|
logger = get_named_logger("checkBamHdr")
|
|
|
|
if not args.input_path.is_dir():
|
|
raise ValueError(f"Input path '{args.input_path}' must be a directory.")
|
|
|
|
target_files = list(args.input_path.glob("*"))
|
|
if not target_files:
|
|
raise ValueError(f"No files found in input directory '{args.input_path}'.")
|
|
# Loop over target files and check if there are `@SQ` lines in all headers or not.
|
|
# Set `is_unaligned` accordingly. If there are mixed headers (either with some files
|
|
# containing `@SQ` lines and some not or with different files containing different
|
|
# `@SQ` lines), set `mixed_headers` to `True`.
|
|
# Also check if there is the SO line, to validate whether the file is (un)sorted.
|
|
first_sq_lines = None
|
|
mixed_headers = False
|
|
sorted_xam = False
|
|
for xam_file in target_files:
|
|
# get the `@SQ` and `@HD` lines in the header
|
|
with pysam.AlignmentFile(xam_file, check_sq=False) as f:
|
|
sq_lines = f.header.get("SQ")
|
|
hd_lines = f.header.get("HD")
|
|
# Check if it is sorted.
|
|
# When there is more than one BAM, merging/sorting
|
|
# will happen regardless of this flag.
|
|
if hd_lines is not None and hd_lines.get('SO') == 'coordinate':
|
|
sorted_xam = True
|
|
if first_sq_lines is None:
|
|
# this is the first file
|
|
first_sq_lines = sq_lines
|
|
else:
|
|
# this is a subsequent file; check with the first `@SQ` lines
|
|
if sq_lines != first_sq_lines:
|
|
mixed_headers = True
|
|
break
|
|
|
|
# we set `is_unaligned` to `True` if there were no mixed headers and the last file
|
|
# didn't have `@SQ` lines (as we can then be sure that none of the files did)
|
|
is_unaligned = not mixed_headers and not sq_lines
|
|
# write `is_unaligned` and `mixed_headers` out so that they can be set as env.
|
|
# variables
|
|
sys.stdout.write(
|
|
f"IS_UNALIGNED={int(is_unaligned)};" +
|
|
f"MIXED_HEADERS={int(mixed_headers)};" +
|
|
f"IS_SORTED={int(sorted_xam)}"
|
|
)
|
|
logger.info(f"Checked (u)BAM headers in '{args.input_path}'.")
|
|
|
|
|
|
def argparser():
|
|
"""Argument parser for entrypoint."""
|
|
parser = wf_parser("check_bam_headers")
|
|
parser.add_argument("input_path", type=Path, help="Path to target directory")
|
|
return parser
|