-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Closed
Labels
c1-quick 🕐Complexity lowComplexity lowp3-enhancement 🔥Much new such featureMuch new such featuresubmodule ⊂Periphery/subclassesPeriphery/subclassesto-merge ↰ImminentImminent
Milestone
Description
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)
GiovanH, hollowgalaxy, Querela and ftrofin
Metadata
Metadata
Assignees
Labels
c1-quick 🕐Complexity lowComplexity lowp3-enhancement 🔥Much new such featureMuch new such featuresubmodule ⊂Periphery/subclassesPeriphery/subclassesto-merge ↰ImminentImminent