From 195b4b37e1453a170f4b6fbfb15e7e92af512a02 Mon Sep 17 00:00:00 2001 From: Ted Brookings Date: Thu, 27 Jul 2023 10:35:31 -0400 Subject: [PATCH] Suppress stderr printing when sam indices are older than sam file --- fgpyo/io/__init__.py | 25 +++++++++++++++++++++++++ fgpyo/sam/__init__.py | 8 ++++++-- fgpyo/vcf/__init__.py | 25 ++----------------------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/fgpyo/io/__init__.py b/fgpyo/io/__init__.py index a0490899..16b1ed58 100644 --- a/fgpyo/io/__init__.py +++ b/fgpyo/io/__init__.py @@ -44,9 +44,12 @@ import gzip import io import os +import sys +from contextlib import contextmanager from pathlib import Path from typing import IO from typing import Any +from typing import Generator from typing import Iterable from typing import Iterator from typing import Set @@ -196,3 +199,25 @@ def write_lines(path: Path, lines_to_write: Iterable[Any]) -> None: for line in lines_to_write: writer.write(str(line)) writer.write("\n") + + +@contextmanager +def redirect_dev_null( + file_num: int = sys.stderr.fileno(), +) -> Generator[None, None, None]: + """A context manager that redirects output of file handle to /dev/null + + Args: + file_num: number of filehandle to redirect. Uses stderr by default + """ + # open /dev/null for writing + f_devnull = os.open(os.devnull, os.O_RDWR) + # save old file descriptor and redirect stderr to /dev/null + save_stderr = os.dup(file_num) + os.dup2(f_devnull, file_num) + + yield + + # restore file descriptor and close devnull + os.dup2(save_stderr, file_num) + os.close(f_devnull) diff --git a/fgpyo/sam/__init__.py b/fgpyo/sam/__init__.py index 508aa96d..0100ce38 100644 --- a/fgpyo/sam/__init__.py +++ b/fgpyo/sam/__init__.py @@ -169,6 +169,7 @@ from pysam import AlignmentFile as SamFile from pysam import AlignmentHeader as SamHeader +import fgpyo.io from fgpyo.collections import PeekableIterator SamPath = Union[IO[Any], Path, str] @@ -259,8 +260,11 @@ def _pysam_open( if unmapped and open_for_reading: kwargs["check_sq"] = False - # Open it! - return pysam.AlignmentFile(path, **kwargs) + # Open it alignment file, suppressing stderr in case index files are older than SAM file + with fgpyo.io.redirect_dev_null(): + alignment_file = pysam.AlignmentFile(path, **kwargs) + # now restore stderr and return the alignment file + return alignment_file def reader( diff --git a/fgpyo/vcf/__init__.py b/fgpyo/vcf/__init__.py index 42621ee3..dfc0ca87 100644 --- a/fgpyo/vcf/__init__.py +++ b/fgpyo/vcf/__init__.py @@ -51,8 +51,6 @@ order via the :func:`~variantbuilder.VariantBuilder.to_sorted_list()` method. """ -import os -import sys from abc import ABC from abc import abstractmethod from contextlib import contextmanager @@ -77,6 +75,7 @@ from pysam import VariantFile as VcfWriter from pysam import VariantHeader +import fgpyo.io from fgpyo.sam.builder import SamBuilder Variant = TypeVar("Variant") @@ -143,26 +142,6 @@ class VcfFieldNumber(Enum): UNKNOWN = "." -@contextmanager -def redirect_dev_null(file_num: int = sys.stderr.fileno()) -> Generator[None, None, None]: - """A context manager that redirects output of file handle to /dev/null - - Args: - file_num: number of filehandle to redirect. Uses stderr by default - """ - # open /dev/null for writing - f_devnull = os.open(os.devnull, os.O_RDWR) - # save old file descriptor and redirect stderr to /dev/null - save_stderr = os.dup(file_num) - os.dup2(f_devnull, file_num) - - yield - - # restore file descriptor and close devnull - os.dup2(save_stderr, file_num) - os.close(f_devnull) - - @contextmanager def reader(path: VcfPath) -> Generator[VcfReader, None, None]: """Opens the given path for VCF reading @@ -171,7 +150,7 @@ def reader(path: VcfPath) -> Generator[VcfReader, None, None]: path: the path to a VCF, or an open file handle """ if isinstance(path, (str, Path, TextIO)): - with redirect_dev_null(): + with fgpyo.io.redirect_dev_null(): # to avoid spamming log about index older than vcf, redirect stderr to /dev/null: only # when first opening the file _reader = VariantFile(path, mode="r") # type: ignore