Source code for MDAnalysis.lib.log
# -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*-
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
#
# MDAnalysis --- https://www.mdanalysis.org
# Copyright (c) 2006-2017 The MDAnalysis Development Team and contributors
# (see the file AUTHORS for the full list of names)
#
# Released under the Lesser GNU Public Licence, v2.1 or any higher version
#
# Please cite your use of MDAnalysis in published work:
#
# R. J. Gowers, M. Linke, J. Barnoud, T. J. E. Reddy, M. N. Melo, S. L. Seyler,
# D. L. Dotson, J. Domanski, S. Buchoux, I. M. Kenney, and O. Beckstein.
# MDAnalysis: A Python package for the rapid analysis of molecular dynamics
# simulations. In S. Benthall and S. Rostrup editors, Proceedings of the 15th
# Python in Science Conference, pages 102-109, Austin, TX, 2016. SciPy.
# doi: 10.25080/majora-629e541a-00e
#
# N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and O. Beckstein.
# MDAnalysis: A Toolkit for the Analysis of Molecular Dynamics Simulations.
# J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787
#
"""Setting up logging --- :mod:`MDAnalysis.lib.log`
====================================================
Configure logging for MDAnalysis. Import this module if logging is
desired in application code.
Logging to a file and the console is set up by default as described
under `logging to multiple destinations`_.
The top level logger of the library is named *MDAnalysis* by
convention; a simple logger that writes to the console and logfile can
be created with the :func:`create` function. This only has to be done
*once*. For convenience, the default MDAnalysis logger can be created
with :func:`MDAnalysis.start_logging`::
import MDAnalysis
MDAnalysis.start_logging()
Once this has been done, MDAnalysis will write messages to the logfile
(named `MDAnalysis.log` by default but this can be changed with the
optional argument to :func:`~MDAnalysis.start_logging`).
Any code can log to the MDAnalysis logger by using ::
import logging
logger = logging.getLogger('MDAnalysis.MODULENAME')
# use the logger, for example at info level:
logger.info("Starting task ...")
The important point is that the name of the logger begins with
"MDAnalysis.".
.. _logging to multiple destinations:
http://docs.python.org/library/logging.html?#logging-to-multiple-destinations
Note
----
The :mod:`logging` module in the standard library contains in depth
documentation about using logging.
Convenience functions
---------------------
Two convenience functions at the top level make it easy to start and
stop the default *MDAnalysis* logger.
.. autofunction:: MDAnalysis.start_logging
.. autofunction:: MDAnalysis.stop_logging
Other functions and classes for logging purposes
------------------------------------------------
.. versionchanged:: 2.0.0
Deprecated :class:`MDAnalysis.lib.log.ProgressMeter` has now been removed.
.. autogenerated, see Online Docs
"""
import sys
import logging
import re
from tqdm.auto import tqdm
from .. import version
[docs]
def start_logging(logfile="MDAnalysis.log", version=version.__version__):
"""Start logging of messages to file and console.
The default logfile is named `MDAnalysis.log` and messages are
logged with the tag *MDAnalysis*.
"""
create("MDAnalysis", logfile=logfile)
logging.getLogger("MDAnalysis").info(
"MDAnalysis %s STARTED logging to %r", version, logfile)
[docs]
def stop_logging():
"""Stop logging to logfile and console."""
logger = logging.getLogger("MDAnalysis")
logger.info("MDAnalysis STOPPED logging")
clear_handlers(logger) # this _should_ do the job...
[docs]
def create(logger_name="MDAnalysis", logfile="MDAnalysis.log"):
"""Create a top level logger.
- The file logger logs everything (including DEBUG).
- The console logger only logs INFO and above.
Logging to a file and the console as described under `logging to
multiple destinations`_.
The top level logger of MDAnalysis is named *MDAnalysis*. Note
that we are configuring this logger with console output. If a root
logger also does this then we will get two output lines to the
console.
.. _logging to multiple destinations:
http://docs.python.org/library/logging.html?#logging-to-multiple-destinations
"""
logger = logging.getLogger(logger_name)
logger.setLevel(logging.DEBUG)
# handler that writes to logfile
logfile_handler = logging.FileHandler(logfile)
logfile_formatter = logging.Formatter(
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
logfile_handler.setFormatter(logfile_formatter)
logger.addHandler(logfile_handler)
# define a Handler which writes INFO messages or higher to the sys.stderr
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# set a format which is simpler for console use
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
return logger
[docs]
def clear_handlers(logger):
"""clean out handlers in the library top level logger
(only important for reload/debug cycles...)
"""
for h in logger.handlers:
logger.removeHandler(h)
[docs]
class NullHandler(logging.Handler):
"""Silent Handler.
Useful as a default::
h = NullHandler()
logging.getLogger("MDAnalysis").addHandler(h)
del h
see the advice on logging and libraries in
http://docs.python.org/library/logging.html?#configuring-logging-for-a-library
"""
[docs]
class ProgressBar(tqdm):
r"""Display a visual progress bar and time estimate.
The :class:`ProgressBar` decorates an iterable object, returning an
iterator which acts exactly like the original iterable, but prints a
dynamically updating progressbar every time a value is requested. See the
example below for how to use it when iterating over the frames of a
trajectory.
Parameters
----------
iterable : iterable, optional
Iterable to decorate with a progressbar.
Leave blank to manually manage the updates.
verbose : bool, optional
If ``True`` (the default) then show the progress bar, *unless* the
`disable` keyword is set to ``True`` (`disable` takes precedence over
`verbose`). If `verbose` is set to ``None`` then the progress bar is
displayed (like ``True``), *unless* this is a non-TTY output device
(see `disable`).
desc : str, optional
Prefix for the progressbar.
total : int or float, optional
The number of expected iterations. If unspecified,
``len(iterable)`` is used if possible. If ``float("inf")`` or as a last
resort, only basic progress statistics are displayed
(no ETA, no progressbar).
leave : bool, optional
If [default: ``True``], keeps all traces of the progressbar
upon termination of iteration.
If ``None``, will leave only if `position` is 0.
file : :class:`io.TextIOWrapper` or :class:`io.StringIO`, optional
Specifies where to output the progress messages (default:
:data:`sys.stderr`). Uses :meth:`file.write` and :meth:`file.flush`
methods. For encoding, see `write_bytes`.
ncols : int, optional
The width of the entire output message. If specified,
dynamically resizes the progressbar to stay within this bound.
If unspecified, attempts to use environment width. The
fallback is a meter width of 10 and no limit for the counter and
statistics. If 0, will not print any meter (only stats).
mininterval : float, optional
Minimum progress display update interval [default: 0.1] seconds.
maxinterval : float, optional
Maximum progress display update interval [default: 10] seconds.
Automatically adjusts `miniters` to correspond to `mininterval`
after long display update lag. Only works if `dynamic_miniters`
or monitor thread is enabled.
miniters : int or float, optional
Minimum progress display update interval, in iterations.
If 0 and `dynamic_miniters`, will automatically adjust to equal
`mininterval` (more CPU efficient, good for tight loops).
If > 0, will skip display of specified number of iterations.
Tweak this and `mininterval` to get very efficient loops.
If your progress is erratic with both fast and slow iterations
(network, skipping items, etc) you should set miniters=1.
ascii : bool or str, optional
If unspecified or ``False``, use unicode (smooth blocks) to fill
the meter. The fallback is to use ASCII characters " 123456789#".
disable : bool, optional
Whether to disable the entire progressbar wrapper
[default: ``False``]. If set to None, disable on non-TTY.
unit : str, optional
String that will be used to define the unit of each iteration
[default: it].
unit_scale : bool or int or float, optional
If 1 or True, the number of iterations will be reduced/scaled
automatically and a metric prefix following the
International System of Units standard will be added
(kilo, mega, etc.) [default: ``False``]. If any other non-zero
number, will scale `total` and `n`.
dynamic_ncols : bool, optional
If set, constantly alters `ncols` and `nrows` to the
environment (allowing for window resizes) [default: ``False``].
smoothing : float, optional
Exponential moving average smoothing factor for speed estimates
(ignored in GUI mode). Ranges from 0 (average speed) to 1
(current/instantaneous speed) [default: 0.3].
bar_format : str, optional
Specify a custom bar string formatting. May impact performance.
[default: ``'{l_bar}{bar}{r_bar}'``], where ``l_bar='{desc}:
{percentage:3.0f}%|'`` and ``r_bar='| {n_fmt}/{total_fmt}
[{elapsed}<{remaining}, {rate_fmt}{postfix}]'``
Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt,
percentage, elapsed, elapsed_s, ncols, nrows, desc, unit,
rate, rate_fmt, rate_noinv, rate_noinv_fmt,
rate_inv, rate_inv_fmt, postfix, unit_divisor,
remaining, remaining_s.
Note that a trailing ": " is automatically removed after {desc}
if the latter is empty.
initial : int or float, optional
The initial counter value. Useful when restarting a progress bar
[default: 0]. If using :class:`float`, consider specifying ``{n:.3f}``
or similar in `bar_format`, or specifying `unit_scale`.
position : int, optional
Specify the line offset to print this bar (starting from 0)
Automatic if unspecified.
Useful to manage multiple bars at once (e.g., from threads).
postfix : dict or \*, optional
Specify additional stats to display at the end of the bar.
Calls ``set_postfix(**postfix)`` if possible (:class:`dict`).
unit_divisor : float, optional
[default: 1000], ignored unless `unit_scale` is ``True``.
write_bytes : bool, optional
If (default: ``None``) and `file` is unspecified,
bytes will be written in Python 2. If `True` will also write
bytes. In all other cases will default to unicode.
lock_args : tuple, optional
Passed to `refresh` for intermediate output
(initialisation, iterating, and updating).
nrows : int, optional
The screen height. If specified, hides nested bars outside this
bound. If unspecified, attempts to use environment height.
The fallback is 20.
Returns
-------
out : decorated iterator.
Example
-------
To get a progress bar when analyzing a trajectory::
from MDAnalysis.lib.log import ProgressBar
...
for ts in ProgressBar(u.trajectory):
# perform analysis
will produce something similar to ::
30%|███████████ | 3/10 [00:13<00:30, 4.42s/it]
in a terminal or Jupyter notebook.
See Also
--------
The :class:`ProgressBar` is derived from :class:`tqdm.auto.tqdm`; see the
`tqdm documentation`_ for further details on how to use it.
.. _`tqdm documentation`: https://tqdm.github.io/
"""
def __init__(self, *args, **kwargs):
""""""
# ^^^^ keep the empty doc string to avoid Sphinx doc errors with the
# original doc string from tqdm.auto.tqdm
verbose = kwargs.pop('verbose', True)
# disable: Whether to disable the entire progressbar wrapper [default: False].
# If set to None, disable on non-TTY.
# disable should be the opposite of verbose unless it's None
disable = verbose if verbose is None else not verbose
# disable should take precedence over verbose if both are set
kwargs['disable'] = kwargs.pop('disable', disable)
super(ProgressBar, self).__init__(*args, **kwargs)