7061: Add User.progress context manager

reapply from trunk

svn: r23094
This commit is contained in:
Vassilii Khachaturov 2013-09-12 17:56:50 +00:00
parent 648334623e
commit c4f4bb2128
2 changed files with 67 additions and 2 deletions

View File

@ -32,9 +32,9 @@ import sys
try:
if sys.version_info < (3,3):
from mock import Mock, NonCallableMock
from mock import Mock, patch
else:
from unittest.mock import Mock, NonCallableMock
from unittest.mock import Mock, patch
MOCKING = True
@ -151,5 +151,40 @@ class TestUser_quiet(unittest.TestCase):
assert len(self.user._fileout.method_calls
) == 0, list(self.user._fileout.method_calls)
@unittest.skipUnless(MOCKING, "Requires unittest.mock to run")
class TestUser_progress(unittest.TestCase):
_progress_begin_step_end = \
TestUser_quiet.test_progress_can_begin_step_end.__func__
def setUp(self):
self.user = user.User()
self.user._fileout = Mock(spec=sys.stderr)
def test_can_step_using_with(self):
# Collect baseline output from the old-style interface (begin/step/end)
self._progress_begin_step_end()
self.expected_output = list(self.user._fileout.method_calls)
self.user._fileout.reset_mock()
self.assertTrue(
len(self.user._fileout.method_calls) == 0,
list(self.user._fileout.method_calls))
with self.user.progress("Foo", "Bar", 0) as step:
for i in range(10):
step()
# Output using `with' differs from one with `progress_...'
self.assertEqual(self.expected_output,
list(self.user._fileout.method_calls))
def test_ends_progress_upon_exception_in_with(self):
with patch('gramps.cli.user.User.end_progress') as MockEP:
try:
with self.user.progress("Foo", "Bar", 0) as step:
raise Exception()
except Exception:
pass
self.assertTrue(MockEP.called)
if __name__ == "__main__":
unittest.main()

View File

@ -21,6 +21,7 @@
#
import sys
from contextlib import contextmanager
"""
The User class provides basic interaction with the user.
@ -40,6 +41,8 @@ class User():
def begin_progress(self, title, message, steps):
"""
Start showing a progress indicator to the user.
Don't use this method directly, use progress instead.
@param title: the title of the progress meter
@type title: str
@ -56,6 +59,8 @@ class User():
def step_progress(self):
"""
Advance the progress meter.
Don't use this method directly, use progress instead.
"""
pass
@ -80,8 +85,33 @@ class User():
def end_progress(self):
"""
Stop showing the progress indicator to the user.
Don't use this method directly, use progress instead.
"""
pass
# Context-manager wrapper of the begin/step/end_progress above
@contextmanager
def progress(self, *args, **kwargs):
"""
Preferred form of context reporting.
Parameters: same as for begin_progress.
Usage example (see gramps/cli/test/user_test.py):
with self.user.progress("Foo", "Bar", 0) as step:
for i in range(10):
step()
Ensures end_progress will be called even if an exception was thrown.
"""
self.begin_progress(*args, **kwargs)
try:
yield self.step_progress
except:
raise
finally:
self.end_progress()
def prompt(self, title, message, accept_label, reject_label):
"""