forked from bartvdbraak/blender
Add some basic report/timing/logging tool as util py module progress_report
.
It supports any level of sub-steps, timing, messaging, and uses WindowManage.progress API to report progress in UI, in addition to console printing.
This commit is contained in:
parent
114e7eaa09
commit
03d8907ca7
165
release/scripts/modules/progress_report.py
Normal file
165
release/scripts/modules/progress_report.py
Normal file
@ -0,0 +1,165 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
import time
|
||||
|
||||
class ProgressReport:
|
||||
"""
|
||||
A basic 'progress report' using either simple prints in console, or WindowManager's 'progress' API.
|
||||
|
||||
This object can be used as a context manager.
|
||||
|
||||
It supports multiple levels of 'substeps' - you shall always enter at least one substep (because level 0
|
||||
has only one single step, representing the whole 'area' of the progress stuff).
|
||||
|
||||
You should give the expected number of substeps each time you enter a new one (you may then step more or less then
|
||||
given number, but this will give incoherent progression).
|
||||
|
||||
Leaving a substep automatically steps by one the parent level.
|
||||
|
||||
with ProgressReport() as progress: # Not giving a WindowManager here will default to console printing.
|
||||
progress.enter_substeps(10)
|
||||
for i in range(10):
|
||||
progress.enter_substeps(100)
|
||||
for j in range(100):
|
||||
progress.step()
|
||||
progress.leave_substeps() # No need to step here, this implicitly does it.
|
||||
progress.leave_substeps("Finished!") # You may pass some message too.
|
||||
"""
|
||||
__slots__ = ('wm', 'running', 'steps', 'curr_step', 'start_time')
|
||||
|
||||
def __init__(self, wm=None):
|
||||
self_wm = getattr(self, 'wm', None)
|
||||
if self_wm:
|
||||
self.finalize()
|
||||
self.running = False
|
||||
|
||||
self.wm = wm
|
||||
self.steps = [100000]
|
||||
self.curr_step = [0]
|
||||
|
||||
initialize = __init__
|
||||
|
||||
def __enter__(self):
|
||||
self.start_time = [time.time()]
|
||||
if self.wm:
|
||||
self.wm.progress_begin(0, self.steps[0])
|
||||
self.update()
|
||||
self.running = True
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type=None, exc_value=None, traceback=None):
|
||||
self.running = False
|
||||
if self.wm:
|
||||
self.wm.progress_end()
|
||||
self.wm = None
|
||||
print("\n")
|
||||
self.steps = [100000]
|
||||
self.curr_step = [0]
|
||||
self.start_time = [time.time()]
|
||||
|
||||
def start(self):
|
||||
self.__enter__()
|
||||
|
||||
def finalize(self):
|
||||
self.__exit__()
|
||||
|
||||
def update(self, msg=""):
|
||||
steps = sum(s * cs for (s, cs) in zip(self.steps, self.curr_step))
|
||||
steps_percent = steps / self.steps[0] * 100.0
|
||||
tm = time.time()
|
||||
loc_tm = tm - self.start_time[-1]
|
||||
tm -= self.start_time[0]
|
||||
if self.wm and self.running:
|
||||
self.wm.progress_update(steps)
|
||||
if msg:
|
||||
prefix = " " * (len(self.steps) - 1)
|
||||
print(prefix + "(%8.4f sec | %8.4f sec) %s\nProgress: %6.2f%%\r" % (tm, loc_tm, msg, steps_percent), end='')
|
||||
else:
|
||||
print("Progress: %6.2f%%\r" % (steps_percent,), end='')
|
||||
|
||||
def enter_substeps(self, nbr, msg=""):
|
||||
if msg:
|
||||
self.update(msg)
|
||||
self.steps.append(self.steps[-1] / nbr)
|
||||
self.curr_step.append(0)
|
||||
self.start_time.append(time.time())
|
||||
|
||||
def step(self, msg="", nbr=1):
|
||||
self.curr_step[-1] += nbr
|
||||
self.update(msg)
|
||||
|
||||
def leave_substeps(self, msg=""):
|
||||
if (msg):
|
||||
self.update(msg)
|
||||
assert(len(self.steps) > 1)
|
||||
del self.steps[-1]
|
||||
del self.curr_step[-1]
|
||||
del self.start_time[-1]
|
||||
self.step()
|
||||
|
||||
|
||||
class ProgressReportSubstep:
|
||||
"""
|
||||
A sub-step context manager for ProgressReport.
|
||||
|
||||
It can be used to generate other sub-step contexts too, and can act as a (limited) proxy of its real ProgressReport.
|
||||
|
||||
Its exit method always ensure ProgressReport is back on 'level' it was before entering this context.
|
||||
This means it is especially useful to ensure a coherent behavior around code that could return/continue/break
|
||||
from many places, without having to bother to explicitly leave substep in each and every possible place!
|
||||
|
||||
with ProgressReport() as progress: # Not giving a WindowManager here will default to console printing.
|
||||
with ProgressReportSubstep(progress, 10, final_msg="Finished!") as subprogress1:
|
||||
for i in range(10):
|
||||
with ProgressReportSubstep(subprogress1, 100) as subprogress2:
|
||||
for j in range(100):
|
||||
subprogress2.step()
|
||||
"""
|
||||
__slots__ = ('progress', 'nbr', 'msg', 'final_msg', 'level')
|
||||
|
||||
def __init__(self, progress, nbr, msg="", final_msg=""):
|
||||
# Allows to generate a subprogress context handler from another one.
|
||||
progress = getattr(progress, 'progress', progress)
|
||||
|
||||
self.progress = progress
|
||||
self.nbr = nbr
|
||||
self.msg = msg
|
||||
self.final_msg = final_msg
|
||||
|
||||
def __enter__(self):
|
||||
self.level = len(self.progress.steps)
|
||||
self.progress.enter_substeps(self.nbr, self.msg)
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
assert(len(self.progress.steps) > self.level)
|
||||
while len(self.progress.steps) > self.level + 1:
|
||||
self.progress.leave_substeps()
|
||||
self.progress.leave_substeps(self.final_msg)
|
||||
|
||||
def enter_substeps(self, nbr, msg=""):
|
||||
self.progress.enter_substeps(nbr, msg)
|
||||
|
||||
def step(self, msg="", nbr=1):
|
||||
self.progress.step(msg, nbr)
|
||||
|
||||
def leave_substeps(self, msg=""):
|
||||
self.progress.leave_substeps(msg)
|
Loading…
Reference in New Issue
Block a user