Skip to content

Commit

Permalink
Use ProxyTextFile also for RestFileWriter, WildcardFileWriter
Browse files Browse the repository at this point in the history
This allows us to also delete OutputPaths and OpenedOutputs.
  • Loading branch information
marcelm committed Jan 26, 2024
1 parent acc873a commit 8136cdb
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 81 deletions.
45 changes: 25 additions & 20 deletions src/cutadapt/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,13 @@
from cutadapt.report import full_report, minimal_report, Statistics
from cutadapt.pipeline import SingleEndPipeline, PairedEndPipeline
from cutadapt.runners import Pipeline, run_pipeline
from cutadapt.files import InputPaths, OutputFiles, FileOpener, OutputPaths
from cutadapt.steps import InfoFileWriter, PairedSingleEndStep
from cutadapt.files import InputPaths, OutputFiles, FileOpener
from cutadapt.steps import (
InfoFileWriter,
PairedSingleEndStep,
RestFileWriter,
WildcardFileWriter,
)
from cutadapt.utils import available_cpu_count, Progress, DummyProgress
from cutadapt.log import setup_logging, REPORT
from cutadapt.qualtrim import HasNoQualities
Expand Down Expand Up @@ -466,12 +471,6 @@ def open_output_files(
args.paired_output,
]
)
paths = OutputPaths(opener=file_opener.xopen)
if args.rest_file:
paths.register(args.rest_file)
if args.wildcard_file:
paths.register(args.wildcard_file)

too_short = too_short2 = None
if args.minimum_length is not None:
too_short, too_short2 = file_opener.xopen_pair(
Expand Down Expand Up @@ -549,12 +548,9 @@ def open_output_files(
if out is None:
out = default_outfile

outputs = paths.open()
return OutputFiles(
file_opener=file_opener,
proxied=proxied,
rest=outputs.get(args.rest_file),
wildcard=outputs.get(args.wildcard_file),
too_short=too_short,
too_short2=too_short2,
too_long=too_long,
Expand Down Expand Up @@ -805,21 +801,36 @@ def check_arguments(args, paired: bool) -> None:


class PipelineMaker:
def __init__(self, args, paired, adapters, adapters2):
def __init__(self, args, outfiles, paired, adapters, adapters2):
self.args = args
self.action = None if args.action == "none" else args.action
self.paired = paired
self.adapters = adapters
self.adapters2 = adapters2

def make(self, steps) -> Pipeline: # noqa: C901
steps = []
for step_class, path in (
(RestFileWriter, args.rest_file),
(InfoFileWriter, args.info_file),
(WildcardFileWriter, args.wildcard_file),
):
if path is None:
continue
step: Any = step_class(outfiles.open_text(path))
if paired:
step = PairedSingleEndStep(step)
steps.append(step)
self._steps = steps

def make(self) -> Pipeline: # noqa: C901
"""
Set up a processing pipeline from parsed command-line arguments.
If there are any problems parsing the arguments, a CommandLineError is raised.
Return an instance of Pipeline (SingleEndPipeline or PairedEndPipeline)
"""
steps = self._steps
modifiers = []
modifiers.extend(
make_unconditional_cutters(self.args.cut, self.args.cut2, self.paired)
Expand Down Expand Up @@ -1147,13 +1158,7 @@ def main(cmdlineargs, default_outfile=sys.stdout.buffer) -> Statistics:
adapter_names2,
proxied=cores > 1,
)
steps = []
if args.info_file:
step: Any = InfoFileWriter(outfiles.open_text(args.info_file))
if paired:
step = PairedSingleEndStep(step)
steps.append(step)
pipeline = PipelineMaker(args, paired, adapters, adapters2).make(steps)
pipeline = PipelineMaker(args, outfiles, paired, adapters, adapters2).make()

logger.info(
"Processing %s reads on %d core%s ...",
Expand Down
50 changes: 1 addition & 49 deletions src/cutadapt/files.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import contextlib
import errno
import io
import sys
from typing import BinaryIO, Optional, Dict, Tuple, List, Callable, TextIO
from typing import BinaryIO, Optional, Dict, Tuple, List, TextIO

import dnaio
from xopen import xopen
Expand Down Expand Up @@ -184,8 +183,6 @@ def __init__(
too_short2: Optional[BinaryIO] = None,
too_long: Optional[BinaryIO] = None,
too_long2: Optional[BinaryIO] = None,
rest: Optional[BinaryIO] = None,
wildcard: Optional[BinaryIO] = None,
demultiplex_out: Optional[Dict[str, BinaryIO]] = None,
demultiplex_out2: Optional[Dict[str, BinaryIO]] = None,
combinatorial_out: Optional[Dict[Tuple[str, str], BinaryIO]] = None,
Expand All @@ -208,8 +205,6 @@ def __init__(
self.too_short2 = too_short2
self.too_long = too_long
self.too_long2 = too_long2
self.rest = rest
self.wildcard = wildcard
self.demultiplex_out = demultiplex_out
self.demultiplex_out2 = demultiplex_out2
self.combinatorial_out = combinatorial_out
Expand Down Expand Up @@ -249,8 +244,6 @@ def __iter__(self):
self.too_short2,
self.too_long,
self.too_long2,
self.rest,
self.wildcard,
]:
if f is not None:
yield f
Expand Down Expand Up @@ -284,8 +277,6 @@ def as_bytesio(self) -> "OutputFiles":
"too_short2",
"too_long",
"too_long2",
"rest",
"wildcard",
):
if getattr(self, attr) is not None:
setattr(result, attr, io.BytesIO())
Expand Down Expand Up @@ -313,42 +304,3 @@ def close(self) -> None:
else:
for f in self._text_files.values():
f.close()


class OpenedOutputs:
def __init__(self, files: Dict[str, BinaryIO], closefunc):
self._close = closefunc
self._files = files

def get(self, path: str) -> Optional[BinaryIO]:
return self._files.get(path)

def __close__(self):
self._close()


class OutputPaths:
"""
The paths of all the output files a pipeline produces.
"""

def __init__(self, opener: Callable[[str, str], BinaryIO]):
self._paths: List[str] = []
self._opener = opener

def register(self, path: str):
self._paths.append(path)

def open(self) -> OpenedOutputs:
return self._open(opener=self._opener)

def open_bytesio(self) -> OpenedOutputs:
return self._open(opener=lambda path, mode: io.BytesIO())

def _open(self, opener: Callable[[str, str], BinaryIO]) -> OpenedOutputs:
with contextlib.ExitStack() as stack:
files = {
path: stack.enter_context(opener(path, "wb")) for path in self._paths
}
return OpenedOutputs(files, stack.pop_all().close)
assert False # Avoid complaint from Mypy
12 changes: 0 additions & 12 deletions src/cutadapt/pipeline.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import io
import logging
from abc import ABC, abstractmethod
from pathlib import Path
Expand Down Expand Up @@ -44,8 +43,6 @@
CombinatorialDemultiplexer,
SingleEndStep,
PairedSingleEndStep,
RestFileWriter,
WildcardFileWriter,
)

logger = logging.getLogger()
Expand Down Expand Up @@ -105,15 +102,6 @@ def _set_output(self, outfiles: OutputFiles) -> None: # noqa: C901
self._outfiles = outfiles

steps = []
for step_class, outfile in (
(RestFileWriter, outfiles.rest),
(WildcardFileWriter, outfiles.wildcard),
):
if outfile:
textiowrapper = io.TextIOWrapper(outfile)
self._textiowrappers.append(textiowrapper)
steps.append(self._wrap_single_end_step(step_class(textiowrapper)))

files: List[Optional[BinaryIO]]

# minimum length and maximum length
Expand Down

0 comments on commit 8136cdb

Please sign in to comment.