Rev 3033: Generate percentage complete estimation for a whole TaskStack. in http://people.ubuntu.com/~robertc/baz2.0/nested-pb
Robert Collins
robertc at robertcollins.net
Tue Nov 20 23:23:46 GMT 2007
At http://people.ubuntu.com/~robertc/baz2.0/nested-pb
------------------------------------------------------------
revno: 3033
revision-id:robertc at robertcollins.net-20071120232331-1se1u6rrqgyqfcae
parent: robertc at robertcollins.net-20071120225024-3x716f66hbw4q4c6
committer: Robert Collins <robertc at robertcollins.net>
branch nick: pb.simplify
timestamp: Wed 2007-11-21 10:23:31 +1100
message:
Generate percentage complete estimation for a whole TaskStack.
modified:
bzrlib/progress.py progress.py-20050610070202-df9faaab791964c0
bzrlib/tests/test_progress.py test_progress.py-20060308160359-978c397bc79b7fda
=== modified file 'bzrlib/progress.py'
--- a/bzrlib/progress.py 2007-11-20 22:50:24 +0000
+++ b/bzrlib/progress.py 2007-11-20 23:23:31 +0000
@@ -202,6 +202,24 @@
extra_message = ":" + self.tasks[-1].get_message()
return KnownLengthTask.get_message(self) + extra_message
+ def percent_complete(self):
+ """Return the percentage of the stack that has been completed."""
+ # NB: This almost certainly wants to be cached.
+ result = self.current/float(self.total)
+ scaling_factor = self.tick_size / float(self.total)
+ for task in self.tasks:
+ try:
+ task_percent = task.percent_complete()
+ except AttributeError:
+ # Task does not support percentage estimates.
+ break
+ result += task_percent * scaling_factor
+ # narrow the scaling factor for the next task.
+ scaling_factor = scaling_factor * task.tick_size / task.total
+ if result > 1.0:
+ result = 1.0
+ return result
+
def push_task(self, task):
"""Add task as a sub-task of this stack."""
self.tasks.append(task)
=== modified file 'bzrlib/tests/test_progress.py'
--- a/bzrlib/tests/test_progress.py 2007-11-20 22:50:24 +0000
+++ b/bzrlib/tests/test_progress.py 2007-11-20 23:23:31 +0000
@@ -495,6 +495,79 @@
stack.pop_task(task)
self.assertEqual("pulling", stack.get_message())
+ def test_percent_complete_no_children(self):
+ # with no children, TaskStack behaves like a KnownLengthTask.
+ stack = TaskStack('', 1)
+ # Choose a tick size which will not sum to 100% to test rounding at the
+ # top.
+ stack.tick_size = 0.23
+ self.assertEqualFloat(0.0, stack.percent_complete())
+ stack.tick()
+ self.assertEqualFloat(0.23, stack.percent_complete())
+ stack.tick()
+ self.assertEqualFloat(0.46, stack.percent_complete())
+ stack.tick()
+ self.assertEqualFloat(0.69, stack.percent_complete())
+ stack.tick()
+ self.assertEqualFloat(0.92, stack.percent_complete())
+ # At > 100% it is capped. Alternatively we could error to enforce good
+ # api usage (should be rounding down not up to give monotonic
+ # behaviour, but this seems nice to clients of the api for now.
+ stack.tick()
+ self.assertEqual(1.0, stack.percent_complete())
+
+ def test_percent_complete_counted_task_child(self):
+ # With a CountedTask child, TaskStack's percentage complete does not
+ # advance.
+ stack = TaskStack('', 1)
+ task = CountedTask("parsing")
+ task_2 = KnownLengthTask("reading", 5)
+ # Choose a tick size which will not sum to 100% to test rounding at the
+ # top.
+ stack.push_task(task)
+ self.assertEqualFloat(0.0, stack.percent_complete())
+ task.tick()
+ self.assertEqualFloat(0.0, stack.percent_complete())
+ # adding a KnownLengthTask under the CountedTask is ignored by
+ # percent_complete because the CountedTask prevents estimation.
+ stack.push_task(task_2)
+ self.assertEqualFloat(0.0, stack.percent_complete())
+ task_2.tick()
+ self.assertEqualFloat(0.0, stack.percent_complete())
+ stack.pop_task(task_2)
+ self.assertEqualFloat(0.0, stack.percent_complete())
+ stack.pop_task(task)
+ stack.tick()
+ self.assertEqualFloat(1.0, stack.percent_complete())
+
+ def test_percent_complete_known_length_task_child(self):
+ # With a KnownLengthTask children, TaskStack's percentage complete
+ # advances proportional to the child's advance.
+ stack = TaskStack('', 2)
+ task = KnownLengthTask("parsing", 5)
+ task_2 = KnownLengthTask("reading", 5)
+ stack.tick() # 50%
+ stack.push_task(task)
+ self.assertEqualFloat(0.5, stack.percent_complete())
+ task.tick() # 50% + 0.5 * 20%
+ self.assertEqualFloat(0.5 + 0.5 * 0.2, stack.percent_complete())
+ stack.push_task(task_2) # no progress yet
+ self.assertEqualFloat(0.5 + 0.5 * 0.2, stack.percent_complete())
+ task_2.tick() # 50% + 0.5 * 20% + 0.5*0.2 * 20%
+ self.assertEqualFloat(0.5 + 0.5 * 0.2 + 0.5*0.2*0.2,
+ stack.percent_complete())
+ task_2.tick()
+ self.assertEqualFloat(0.5 + 0.5 * 0.2 + 0.5*0.2*0.4,
+ stack.percent_complete())
+ stack.pop_task(task_2)
+ self.assertEqualFloat(0.5 + 0.5 * 0.2, stack.percent_complete())
+ task.tick() # 50% + 0.5 * 40% in the child
+ self.assertEqualFloat(0.5 + 0.5 * 0.4, stack.percent_complete())
+ stack.pop_task(task)
+ self.assertEqualFloat(0.5, stack.percent_complete())
+ stack.tick() # 100%
+ self.assertEqualFloat(1.0, stack.percent_complete())
+
class TestSilentTaskDisplay(TestCase):
More information about the bazaar-commits
mailing list