This is somewhat related to #296, which is about stdout and stderr.
I believe the proposed example to redirect stdout and stderr doesn't work with logging, because it will already have saved the reference to stdout and stderr.
This seems to be a common "problem" with many related snippets. Rather than copy and pasting an example, it might be worth to have an option include with tqdm?
Here is one possible solution:
import logging
import sys
from contextlib import contextmanager
from typing import List
from tqdm import tqdm
class TqdmLoggingHandler(logging.StreamHandler):
def emit(self, record):
try:
msg = self.format(record)
tqdm.write(msg)
self.flush()
except (KeyboardInterrupt, SystemExit):
raise
except: # noqa pylint: disable=bare-except
self.handleError(record)
def _is_console_logging_handler(handler: logging.Handler) -> bool:
return isinstance(handler, logging.StreamHandler) and handler.stream in {sys.stdout, sys.stderr}
def _get_console_formatter(handlers: List[logging.Handler]) -> logging.Formatter:
for handler in handlers:
if _is_console_logging_handler(handler):
return handler.formatter
return None
@contextmanager
def redirect_logging_to_tqdm(logger: logging.Logger = None):
if logger is None:
logger = logging.root
tqdm_handler = TqdmLoggingHandler()
original_handlers = logger.handlers
tqdm_handler.setFormatter(_get_console_formatter(original_handlers))
try:
logger.handlers = [
handler
for handler in logger.handlers
if not _is_console_logging_handler(handler)
] + [tqdm_handler]
yield
finally:
logger.handlers = original_handlers
@contextmanager
def tqdm_with_logging_redirect(*args, logger: logging.Logger = None, **kwargs):
with tqdm(*args, **kwargs) as pbar:
with redirect_logging_to_tqdm(logger=logger):
yield pbar
And it could be used like this:
import logging
from <source package> import tqdm_with_logging_redirect
LOGGER = logging.getLogger(__name__)
if __name__ == '__main__':
logging.basicConfig(level='INFO')
file_list = ['file1', 'file2']
with tqdm_with_logging_redirect(total=len(file_list)) as pbar:
# logging to the console is now redirected to tqdm
for filename in file_list:
LOGGER.info('processing file: %s', filename)
pbar.update(1)
# logging is now restored
This is just an example.
(I could also provide tests for the above implementation if it's of any use)
This is somewhat related to #296, which is about stdout and stderr.
I believe the proposed example to redirect stdout and stderr doesn't work with logging, because it will already have saved the reference to stdout and stderr.
This seems to be a common "problem" with many related snippets. Rather than copy and pasting an example, it might be worth to have an option include with
tqdm?Here is one possible solution:
And it could be used like this:
This is just an example.
(I could also provide tests for the above implementation if it's of any use)