How to set custom output handlers for argparse in Python?

后端 未结 3 1192
不思量自难忘°
不思量自难忘° 2021-02-15 17:31

I have configured logger to print both onto terminal stdout and to a file so I can have an archive of logging messages that I can refer to.

Tha

相关标签:
3条回答
  • 2021-02-15 18:02

    There seems to be no way to do this through the API.

    However, you can do the following:

    class LoggingArgumentParser(argparse.ArgumentParser):
        """Custom ArgumentPaarser that overrides _print_message"""
    
        def _print_message(self, message, file=None):
            if message:
                logger.write(message)
    
    0 讨论(0)
  • 2021-02-15 18:14

    Looking at the argparse.py source code there doesn't seem to be a way to configure this behaviour.

    My suggestion(s) would be:

    • File a bug report with a patch :)

    Override/patch:

    • print_* method(s)
    • error method.

    The print_* method(s) seem to take an optional file argument which defaults to _sys.stdout.

    Update: Alternatively you could do something like this whereby you redirect sys.stdout temporarily while you parse arguments:

    from contextlib import contextmanager
    
    @contextmanager
    def redirect_stdout_stderr(stream):
        old_stdout = sys.stdout
        old_stderr = sys.stderr
        sys.stdout = stream
        sys.stderr = stream
        try:
            yield
        finally:
            sys.stdout = old_stdout
            sys.stderr = old_stderr
    
    
    with redirct_stdout_stderr(logstream):
        args = parser.parse_args()
    
    0 讨论(0)
  • 2021-02-15 18:18

    While the answer given by @James Mills is great and solves the issue, there is no need for a generator in this case. Hence, the yield is redundant. Another way of achieving the same (without the generator) would be to write your own context manager without using the inbuilt contextlib.contextmanager decorator. Like the following.

    class redirect_stdout_stderr(object):
        def __init__(self, stream):
            # Save the old std streams
            self.old_stream = sys.stdout
            self.old_error_stream = sys.stderr
            self.fstream = stream
    
        def __enter__(self):
            # Change the std streams to your streams when entering
            sys.stdout = self.fstream
            sys.stderr = self.fstream
    
        def __exit__(self, exc_type, exc_value, exc_traceback):
            # Change the std streams back to the original streams while exiting
            sys.stdout = self.old_stream
            sys.stderr = self.old_error_stream
    

    In your case you can do something as follows.

    with redirect_stdout_stderr(logstream):
        # __enter__() is executed
        args = parser.parse_args()
        # __exit__() is executed
    

    Hope this helps!

    0 讨论(0)
提交回复
热议问题