Skip to content

Commit

Permalink
contrib.logging: cleanup & docs
Browse files Browse the repository at this point in the history
  • Loading branch information
casperdcl committed Apr 5, 2021
1 parent e86b9b1 commit 7458666
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 170 deletions.
27 changes: 27 additions & 0 deletions .meta/.readme.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,33 @@ A reusable canonical example is given below:
# After the `with`, printing is restored
print("Done!")
Redirecting ``logging``
~~~~~~~~~~~~~~~~~~~~~~~

Similar to ``sys.stdout``/``sys.stderr`` as detailed above, console ``logging``
may also be redirected to ``tqdm.write()``.

Warning: if also redirecting ``sys.stdout``/``sys.stderr``, make sure to
redirect ``logging`` first if needed.

Helper methods are available in ``tqdm.contrib.logging``. For example:

.. code:: python
import logging
from tqdm import trange
from tqdm.contrib.logging import logging_redirect_tqdm
LOG = logging.getLogger(__name__)
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
with logging_redirect_tqdm():
for i in trange(9):
if i == 4:
LOG.info("console logging redirected to `tqdm.write()`")
# logging restored
Monitoring thread, intervals and miniters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
58 changes: 16 additions & 42 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1321,58 +1321,32 @@ A reusable canonical example is given below:
# After the `with`, printing is restored
print("Done!")
Redirecting console logging to tqdm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Redirecting ``logging``
~~~~~~~~~~~~~~~~~~~~~~~

Similar to redirecting ``sys.stdout`` directly as detailed in the previous section,
you may want to redirect logging that would otherwise go to the
console (``sys.stdout`` or ``sys.stderr``) to ``tqdm``.
Similar to ``sys.stdout``/``sys.stderr`` as detailed above, console ``logging``
may also be redirected to ``tqdm.write()``.

Note: if you are also replace ``sys.stdout`` and ``sys.stderr`` at the same time,
then the logging should be redirected first. Otherwise it won't be able to detect
the console logging handler.
Warning: if also redirecting ``sys.stdout``/``sys.stderr``, make sure to
redirect ``logging`` first if needed.

For that you may use ``redirect_logging_to_tqdm`` or ``tqdm_with_logging_redirect``
from ``tqdm.contrib.logging``. Both methods accept the following optional parameters:

- ``loggers``: A list of loggers to update. Defaults to ``logging.root``.
- ``tqdm``: A ``tqdm`` class. Defaults to ``tqdm.tqdm``.

An example redirecting the console logging to tqdm:
Helper methods are available in ``tqdm.contrib.logging``. For example:

.. code:: python
import logging
from tqdm.contrib.logging import redirect_logging_to_tqdm
LOGGER = logging.getLogger(__name__)
if __name__ == '__main__':
logging.basicConfig(level='INFO')
with redirect_logging_to_tqdm():
# logging to the console is now redirected to tqdm
LOGGER.info('some message')
# logging is now restored
An similar example, wrapping tqdm while redirecting console logging:

.. code:: python
import logging
from tqdm.contrib.logging import tqdm_with_logging_redirect
from tqdm import trange
from tqdm.contrib.logging import logging_redirect_tqdm
LOGGER = logging.getLogger(__name__)
LOG = 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
logging.basicConfig(level=logging.INFO)
with logging_redirect_tqdm():
for i in trange(9):
if i == 4:
LOG.info("console logging redirected to `tqdm.write()`")
# logging restored
Monitoring thread, intervals and miniters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
Empty file removed tests/contrib/__init__.py
Empty file.
23 changes: 11 additions & 12 deletions tests/contrib/tests_logging.py → tests/tests_contrib_logging.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# pylint: disable=missing-module-docstring, missing-class-docstring
# pylint: disable=missing-function-docstring, no-self-use

from __future__ import absolute_import

import logging
Expand All @@ -13,9 +12,9 @@
from tqdm import tqdm
from tqdm.contrib.logging import _get_first_found_console_logging_formatter
from tqdm.contrib.logging import _TqdmLoggingHandler as TqdmLoggingHandler
from tqdm.contrib.logging import redirect_logging_to_tqdm, tqdm_with_logging_redirect
from tqdm.contrib.logging import logging_redirect_tqdm, tqdm_logging_redirect

from ..tests_tqdm import importorskip
from .tests_tqdm import importorskip

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -101,7 +100,7 @@ def test_should_return_stream_handler_formatter_if_stream_is_stderr(self):
class TestRedirectLoggingToTqdm:
def test_should_add_and_remove_tqdm_handler(self):
logger = logging.Logger('test')
with redirect_logging_to_tqdm(loggers=[logger]):
with logging_redirect_tqdm(loggers=[logger]):
assert len(logger.handlers) == 1
assert isinstance(logger.handlers[0], TqdmLoggingHandler)
assert not logger.handlers
Expand All @@ -111,7 +110,7 @@ def test_should_remove_and_restore_console_handlers(self):
stderr_console_handler = logging.StreamHandler(sys.stderr)
stdout_console_handler = logging.StreamHandler(sys.stderr)
logger.handlers = [stderr_console_handler, stdout_console_handler]
with redirect_logging_to_tqdm(loggers=[logger]):
with logging_redirect_tqdm(loggers=[logger]):
assert len(logger.handlers) == 1
assert isinstance(logger.handlers[0], TqdmLoggingHandler)
assert logger.handlers == [stderr_console_handler, stdout_console_handler]
Expand All @@ -122,14 +121,14 @@ def test_should_inherit_console_logger_formatter(self):
console_handler = logging.StreamHandler(sys.stderr)
console_handler.setFormatter(formatter)
logger.handlers = [console_handler]
with redirect_logging_to_tqdm(loggers=[logger]):
with logging_redirect_tqdm(loggers=[logger]):
assert logger.handlers[0].formatter == formatter

def test_should_not_remove_stream_handlers_not_fot_stdout_or_stderr(self):
logger = logging.Logger('test')
stream_handler = logging.StreamHandler(StringIO())
logger.addHandler(stream_handler)
with redirect_logging_to_tqdm(loggers=[logger]):
with logging_redirect_tqdm(loggers=[logger]):
assert len(logger.handlers) == 2
assert logger.handlers[0] == stream_handler
assert isinstance(logger.handlers[1], TqdmLoggingHandler)
Expand All @@ -139,15 +138,15 @@ def test_should_not_remove_stream_handlers_not_fot_stdout_or_stderr(self):
class TestTqdmWithLoggingRedirect:
def test_should_add_and_remove_handler_from_root_logger_by_default(self):
original_handlers = list(logging.root.handlers)
with tqdm_with_logging_redirect(total=1) as pbar:
with tqdm_logging_redirect(total=1) as pbar:
assert isinstance(logging.root.handlers[-1], TqdmLoggingHandler)
LOGGER.info('test')
pbar.update(1)
assert logging.root.handlers == original_handlers

def test_should_add_and_remove_handler_from_custom_logger(self):
logger = logging.Logger('test')
with tqdm_with_logging_redirect(total=1, loggers=[logger]) as pbar:
with tqdm_logging_redirect(total=1, loggers=[logger]) as pbar:
assert len(logger.handlers) == 1
assert isinstance(logger.handlers[0], TqdmLoggingHandler)
logger.info('test')
Expand All @@ -157,7 +156,7 @@ def test_should_add_and_remove_handler_from_custom_logger(self):
def test_should_not_fail_with_logger_without_console_handler(self):
logger = logging.Logger('test')
logger.handlers = []
with tqdm_with_logging_redirect(total=1, loggers=[logger]):
with tqdm_logging_redirect(total=1, loggers=[logger]):
logger.info('test')
assert not logger.handlers

Expand All @@ -169,14 +168,14 @@ def test_should_format_message(self):
))
logger.handlers = [console_handler]
CustomTqdm.messages = []
with tqdm_with_logging_redirect(loggers=[logger], tqdm=CustomTqdm):
with tqdm_logging_redirect(loggers=[logger], tqdm_class=CustomTqdm):
logger.info('test')
assert CustomTqdm.messages == ['prefix:test']

def test_use_root_logger_by_default_and_write_to_custom_tqdm(self):
logger = logging.root
CustomTqdm.messages = []
with tqdm_with_logging_redirect(total=1, tqdm=CustomTqdm) as pbar:
with tqdm_logging_redirect(total=1, tqdm_class=CustomTqdm) as pbar:
assert isinstance(pbar, CustomTqdm)
logger.info('test')
assert CustomTqdm.messages == ['test']
Loading

0 comments on commit 7458666

Please sign in to comment.