Skip to content

Commit

Permalink
Remove ProgressMeter (#2743)
Browse files Browse the repository at this point in the history
* removes PM from package

* Remove PM tests

* updates CHANGELOG

* Remove tests

* Adds docstring versionchange
  • Loading branch information
IAlibay authored Jun 13, 2020
1 parent 105e47a commit bf74d65
Show file tree
Hide file tree
Showing 6 changed files with 10 additions and 288 deletions.
1 change: 1 addition & 0 deletions package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Fixes
Enhancements

Changes
* Removes deprecated ProgressMeter (Issue #2739)
* Removes deprecated MDAnalysis.units.N_Avogadro (PR #2737)
* Dropped Python 2 support

Expand Down
3 changes: 1 addition & 2 deletions package/MDAnalysis/analysis/density.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,7 @@
from MDAnalysis import NoDataError, MissingDataWarning
from .. import units
from ..lib import distances
from MDAnalysis.lib.log import ProgressBar
from MDAnalysis.lib.log import ProgressMeter # remove in 2.0
from MDAnalysis.lib.log import ProgressBar
from MDAnalysis.lib.util import deprecate

from .base import AnalysisBase
Expand Down
4 changes: 2 additions & 2 deletions package/MDAnalysis/analysis/hbonds/hbond_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -897,8 +897,8 @@ def run(self, start=None, stop=None, step=None, verbose=None, **kwargs):
read every `step` between `start` (included) and `stop` (excluded),
``None`` selects 1. [``None``]
verbose : bool (optional)
toggle progress meter output :class:`~MDAnalysis.lib.log.ProgressMeter`
[``True``]
toggle progress meter output
:class:`~MDAnalysis.lib.log.ProgressBar` [``True``]
debug : bool (optional)
enable detailed logging of debugging information; this can create
*very big* log files so it is disabled (``False``) by default; setting
Expand Down
194 changes: 5 additions & 189 deletions package/MDAnalysis/lib/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,18 @@
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
"""
from __future__ import print_function, division, absolute_import
from __future__ import absolute_import

import sys
import logging
import re
import warnings

from tqdm.auto import tqdm

Expand Down Expand Up @@ -224,193 +227,6 @@ def _guess_string_format(template):
return _legacy_format


class ProgressMeter(object):
r"""Simple progress meter (Deprecated)
..Warning:
This class is deprecated and will be removed in version 2.0.
Please use :class:`MDAnalysis.lib.log.ProgressBar` instead.
The :class:`ProgressMeter` class can be used to show running progress such
as frames processed or percentage done to give the user feedback on the
duration and progress of a task. It is structures as a class that is
customized on instantation (e.g., using a custom `format` string and the
expected total number of frames to be processed). Within a processing loop,
call :meth:`echo` with the current frame number to print the output to
stderr.
Parameters
----------
numsteps: int
total number of steps
interval: int
only calculate and print progress every `interval` steps [10]
format: str
a format string with Python variable interpolation. Allowed
values:
* *step*: current step
* *numsteps*: total number of steps as supplied in *numsteps*
* *percentage*: percentage of total
The last call to :meth:`ProgressMeter.print` will automatically
issue a newline ``\n``.
If *format* is ``None`` then the default is used::
Step {step:5d}/{numsteps} [{percentage:5.1f}%]
offset: int
number to add to *step*; e.g. if *step* is 0-based (as in MDAnalysis)
then one should set *offset* = 1; for 1-based steps, choose 0. [1]
verbose: bool
If ``False``, disable all output, ``True`` print all messages as
specified, [``True``]
dynamic: bool
If ``True``, each line will be printed on top of the previous one.
This is done by prepedind the format with ``\r``. [``True``]
format_handling: str
how to handle the format string. Allowed values are:
* *new*: the format string uses {}-based formating
* *legacy*: the format string uses %-basedd formating
* *auto*: default, try to guess how the format string should be
handled
Examples
--------
The typical use case is to show progress as frames of a trajectory are
processed::
u = Universe(PSF, DCD)
pm = ProgressMeter(u.trajectory.n_frames, interval=100)
for ts in u.trajectory:
pm.echo(ts.frame)
...
For a trajectory with 10000 frames this will produce output such
as ::
Step 100/10000 [ 1.0%]
Step 200/10000 [ 2.0%]
...
The default *format* string is::
Step {step:5d}/{numsteps} [{percentage:5.1f}%]
By default, each line of the progress meter is displayed on top of the
previous one. To prevent this behaviour, set the `dynamic` keyword to
``False``.
It is possible to embed (almost) arbitrary additional data in the
format string, for example a current RMSD value::
format_line = "RMSD {rmsd:5.2f} at {step:5d}/{numsteps} [{percentage:5.1f}%]"
pm = ProgressMeter(u.trajectory.n_frames,
interval=100, format=format_line)
for ts in u.trajectory:
pm.echo(ts.frame, rmsd=current_rmsd)
...
This will print something like::
RMSD 1.02 at 100/10000 [ 1.0%]
RMSD 1.89 at 200/10000 [ 2.0%]
...
.. versionchanged:: 0.8
Keyword argument *quiet* was added.
.. versionchanged:: 0.16
Keyword argument *dynamic* replaces ``\r`` in the format.
.. deprecated:: 0.16
Keyword argument *quiet* is deprecated in favor of *verbose*.
.. deprecated:: 1.0
This class is deprecated in favor of *ProgressBar*.
"""

def __init__(self, numsteps, format=None, interval=10, offset=1,
verbose=True, dynamic=True,
format_handling='auto'):
warnings.warn(
"This class is deprecated as of MDAnalysis version 1.0. "
"It will be removed in MDAnalysis version 2.0. "
"Please use MDAnalysis.lib.log.ProgressBar instead.",
category=DeprecationWarning
)
self.numsteps = numsteps
self.interval = int(interval)
self.offset = int(offset)
self.verbose = verbose
self.dynamic = dynamic
self.numouts = -1

if format is None:
format = "Step {step:5d}/{numsteps} [{percentage:5.1f}%]"
self.format_handler = _new_format
else:
if format_handling == 'auto':
self.format_handler = _guess_string_format(format)
else:
self.format_handler = {'new': _new_format,
'legacy': _legacy_format}[format_handling]
self.format = format
self.step = 0
self.percentage = 0.0
assert numsteps > 0, "numsteps step must be >0"
assert interval > 0, "interval step must be >0"

def update(self, step, **kwargs):
"""Update the state of the ProgressMeter.
*kwargs* are additional attributes that can be references in
the format string.
"""
self.step = step + self.offset
self.percentage = 100. * self.step / self.numsteps
for k, v in kwargs.items():
setattr(self, k, v)

self.numouts += 1

def echo(self, step, **kwargs):
"""Print the state to stderr, but only every *interval* steps.
1) calls :meth:`~ProgressMeter.update`
2) writes step and percentage to stderr with :func:`echo`,
using the format string (in :attr:`ProgressMeter.format`)
The last step is always shown, even if not on an *interval*, and a
carriage return is replaced with a new line for a cleaner display.
*kwargs* are additional attributes that can be references in
the format string.
.. Note:: If *verbose* = ``False`` has been set in the
constructor or if :attr:`ProgressMeter.verbose` has
been set to ``False``, then no messages will be
printed.
"""
if not self.verbose:
return
self.update(step, **kwargs)
format = self.format
newline = not self.dynamic
if self.step == self.numsteps:
newline = True
elif self.numouts % self.interval == 0:
pass
else:
return
echo(self.format_handler(format, vars(self)),
replace=self.dynamic, newline=newline)


class ProgressBar(tqdm):
def __init__(self, *args, **kwargs):
verbose = kwargs.pop('verbose', True)
Expand Down
25 changes: 1 addition & 24 deletions testsuite/MDAnalysisTests/lib/test_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,9 @@
import warnings
import pytest

from MDAnalysis.lib.log import ProgressMeter, ProgressBar
from MDAnalysis.lib.log import ProgressBar


class TestProgressMeter(object):

def test_deprecated(self, capsys):
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")
# Trigger a warning.
pm = ProgressMeter(10)
# Verify the warning
assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning)
assert "MDAnalysis.lib.log.ProgressBar" in str(w[-1].message)

def test_output(self, capsys):
pm = ProgressMeter(10, interval=1)
for i in range(10):
pm.echo(i)
out, err = capsys.readouterr()
expected = 'Step 10/10 [100.0%]'
actual = err.strip().split('\r')[-1]
assert actual == expected


class TestProgressBar(object):

def test_output(self, capsys):
Expand Down
71 changes: 0 additions & 71 deletions testsuite/MDAnalysisTests/utils/test_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,74 +72,3 @@ def buffer():
def _assert_in(output, string):
assert string in output, "Output '{0}' does not match required format '{1}'.".format(output.replace('\r', '\\r'), string.replace('\r', '\\r'))


def test_default_ProgressMeter(buffer, n=101, interval=10):
template = "Step {step:5d}/{numsteps} [{percentage:5.1f}%]"
with RedirectedStderr(buffer):
pm = MDAnalysis.lib.log.ProgressMeter(n, interval=interval)
for frame in range(n):
pm.echo(frame)
buffer.seek(0)
output = "".join(buffer.readlines())
_assert_in(output, ('\r' + template).format(**{'step': 1, 'numsteps': n, 'percentage': 100./n}))
# last line always ends with \n!
_assert_in(output,
('\r' + template + '\n').format(**{'step': n, 'numsteps': n,
'percentage': 100.}))


def test_custom_ProgressMeter(buffer, n=51, interval=7):
template = "RMSD {rmsd:5.2f} at {step:03d}/{numsteps:4d} [{percentage:5.1f}%]"
with RedirectedStderr(buffer):
pm = MDAnalysis.lib.log.ProgressMeter(n, interval=interval,
format=template, offset=1)
for frame in range(n):
# n+1/n correction for 0-based frame vs 1-based counting
rmsd = 0.02 * frame * (n+1)/ n
pm.echo(frame, rmsd=rmsd)
buffer.seek(0)
output = "".join(buffer.readlines())
_assert_in(output,
('\r' + template).format(**{'rmsd': 0.0, 'step': 1,
'numsteps': n, 'percentage': 100./n}))
# last line always ends with \n!
_assert_in(output,
('\r' + template + '\n').format(
**{'rmsd': 0.02*n, 'step': n,
'numsteps': n, 'percentage': 100.0}))


def test_legacy_ProgressMeter(buffer, n=51, interval=7):
template = "RMSD %(rmsd)5.2f at %(step)03d/%(numsteps)4d [%(percentage)5.1f%%]"
with RedirectedStderr(buffer):
pm = MDAnalysis.lib.log.ProgressMeter(n, interval=interval,
format=template, offset=1)
for frame in range(n):
# n+1/n correction for 0-based frame vs 1-based counting
rmsd = 0.02 * frame * (n+1)/ n
pm.echo(frame, rmsd=rmsd)
buffer.seek(0)
output = "".join(buffer.readlines())
_assert_in(output,
('\r' + template) % {'rmsd': 0.0, 'step': 1,
'numsteps': n, 'percentage': 100./n})
# last line always ends with \n!
_assert_in(output,
('\r' + template + '\n') % {'rmsd': 0.02*n, 'step': n,
'numsteps': n, 'percentage': 100.0})


@pytest.mark.parametrize('step, percentage', [
(1, 100./51),
(51, 100.)
])
def test_not_dynamic_ProgressMeter(buffer, step, percentage, n=51, interval=10):
template = "Step {step:5d}/{numsteps} [{percentage:5.1f}%]"
with RedirectedStderr(buffer):
pm = MDAnalysis.lib.log.ProgressMeter(n, interval=interval,
dynamic=False)
for frame in range(n):
pm.echo(frame)
buffer.seek(0)
output = "".join(buffer.readlines())
_assert_in(output, (template + '\n').format(**{'step': step, 'numsteps': n, 'percentage': percentage}))

0 comments on commit bf74d65

Please sign in to comment.