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 GNU Public Licence, v2 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] def emit(self, record): pass
[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)