Context manager for optionally redirected I / O

I often come across a situation that, depending on some command line argument, can be entered either from a file or from standard input. The same goes for the conclusion. I really like the way context managers work in python 3, and so I try to make all my calls openpart of some operator with. But in this case I am having problems.

if args.infile:
    with open(args.infile, "r") as f:
        process(f)
else:
    process(sys.stdin)

already awkward, and with input and output, I would have to serve four combinations. I would like something easier, for example.

with (open(args.infile, "r") if args.infile
      else DummyManager(sys.stdin)) as f:
    process(f)

Is there something like this DummyManager in python standard libraries? Something that implements the context manager protocol, but only to return a fixed value from its method __enter__? I think, most likely, the place for such a class will be contextlib , and since I did not find anything like it there, maybe there is no such thing. Are there any other elegant solutions you can offer?

+4
source share
4 answers

In your case, you can use fileinputmodule :

from fileinput import FileInput

with FileInput(args.infile) as file:
    process(file)
# sys.stdin is still open here

args.infile='-', sys.stdin. inplace=True, sys.stdout . . , , stdin.

:

import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--log', default=sys.stdout, type=argparse.FileType('w'))
args = parser.parse_args()
with args.log:
    args.log.write('log message')
# sys.stdout may be closed here

, stdout .

sys.stdin / sys.stdout, ExitStack :

from contextlib import ExitStack

with ExitStack() as stack:
    if not args.files:
       files = [sys.stdin]
    else:
       files = [stack.enter_context(open(name)) for name in args.files]

    if not args.output:
       output_file = sys.stdout
       stack.callback(output_file.flush) # flush instead of closing 
    else:
       output_file = stack.enter_context(open(args.output, 'w'))

    process(files, output_file)
+2

@contextlib.contextmanager decorator:

from contextlib import contextmanager

@contextmanager
def dummy_manager(ob):
    yield ob

; , , ob , __exit__ .

:

f = open(args.infile, "r") if args.infile else dummy_manager(sys.stdin)
with f:
    process(f)
+2

. sys.stdin, , .

with (open(args.infile, "r") if args.infile else sys.stdin) as f:
    process(f)

, __exit__ sys.stdin close d ( / ), .

+1

ArgParse, . click:

with click.open_file(filename) as lines:
    for line in lines:
        process(line)

sys.stdin, filename - -, open close, finally.

0

Source: https://habr.com/ru/post/1538128/


All Articles