Skip to content

Commit 9f5fff0

Browse files
author
Jørgen Nordmoen
committed
Moved to rich library and more fine grained ticks
1 parent 671e7fa commit 9f5fff0

File tree

4 files changed

+53
-48
lines changed

4 files changed

+53
-48
lines changed

easybuild/framework/easyblock.py

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ def __init__(self, ec):
214214

215215
# Create empty progress bar
216216
self.progressbar = None
217+
self.pbar_task = None
217218

218219
# list of loaded modules
219220
self.loaded_modules = []
@@ -303,12 +304,20 @@ def close_log(self):
303304
self.log.info("Closing log for application name %s version %s" % (self.name, self.version))
304305
fancylogger.logToFile(self.logfile, enable=False)
305306

306-
def set_progressbar(self, progressbar):
307+
def set_progressbar(self, progressbar, task_id):
307308
"""
308309
Set progress bar, the progress bar is needed when writing messages so
309310
that the progress counter is always at the bottom
310311
"""
311312
self.progressbar = progressbar
313+
self.pbar_task = task_id
314+
315+
def advance_progress(self, tick=1.0):
316+
"""
317+
Advance the progress bar forward with `tick`
318+
"""
319+
if self.progressbar and self.pbar_task is not None:
320+
self.progressbar.advance(self.pbar_task, tick)
312321

313322
#
314323
# DRY RUN UTILITIES
@@ -328,7 +337,7 @@ def dry_run_msg(self, msg, *args):
328337
"""Print dry run message."""
329338
if args:
330339
msg = msg % args
331-
dry_run_msg(msg, silent=self.silent, progressbar=self.progressbar)
340+
dry_run_msg(msg, silent=self.silent)
332341

333342
#
334343
# FETCH UTILITY FUNCTIONS
@@ -1647,8 +1656,7 @@ def skip_extensions(self):
16471656
self.log.debug("exit code: %s, stdout/err: %s", ec, cmdstdouterr)
16481657
res.append(ext_inst)
16491658
else:
1650-
print_msg("skipping extension %s" % ext_inst.name, silent=self.silent, log=self.log,
1651-
progressbar=self.progressbar)
1659+
print_msg("skipping extension %s" % ext_inst.name, silent=self.silent, log=self.log)
16521660

16531661
self.ext_instances = res
16541662

@@ -1752,8 +1760,7 @@ def handle_iterate_opts(self):
17521760
self.log.debug("Found list for %s: %s", opt, self.iter_opts[opt])
17531761

17541762
if self.iter_opts:
1755-
print_msg("starting iteration #%s ..." % self.iter_idx, log=self.log, silent=self.silent,
1756-
progressbar=self.progressbar)
1763+
print_msg("starting iteration #%s ..." % self.iter_idx, log=self.log, silent=self.silent)
17571764
self.log.info("Current iteration index: %s", self.iter_idx)
17581765

17591766
# pop first element from all iterative easyconfig parameters as next value to use
@@ -1894,8 +1901,7 @@ def check_readiness_step(self):
18941901
hidden = LooseVersion(self.modules_tool.version) < LooseVersion('7.0.0')
18951902

18961903
self.mod_file_backup = back_up_file(self.mod_filepath, hidden=hidden, strip_fn=strip_fn)
1897-
print_msg("backup of existing module file stored at %s" % self.mod_file_backup, log=self.log,
1898-
progressbar=self.progressbar)
1904+
print_msg("backup of existing module file stored at %s" % self.mod_file_backup, log=self.log)
18991905

19001906
# check if main install needs to be skipped
19011907
# - if a current module can be found, skip is ok
@@ -2431,7 +2437,7 @@ def extensions_step(self, fetch=False, install=True):
24312437
change_dir(self.orig_workdir)
24322438

24332439
tup = (ext.name, ext.version or '', idx + 1, exts_cnt)
2434-
print_msg("installing extension %s %s (%d/%d)..." % tup, silent=self.silent, progressbar=self.progressbar)
2440+
print_msg("installing extension %s %s (%d/%d)..." % tup, silent=self.silent)
24352441
start_time = datetime.now()
24362442

24372443
if self.dry_run:
@@ -2463,11 +2469,9 @@ def extensions_step(self, fetch=False, install=True):
24632469
if not self.dry_run:
24642470
ext_duration = datetime.now() - start_time
24652471
if ext_duration.total_seconds() >= 1:
2466-
print_msg("\t... (took %s)", time2str(ext_duration), log=self.log, silent=self.silent,
2467-
progressbar=self.progressbar)
2472+
print_msg("\t... (took %s)", time2str(ext_duration), log=self.log, silent=self.silent)
24682473
elif self.logdebug or build_option('trace'):
2469-
print_msg("\t... (took < 1 sec)", log=self.log, silent=self.silent,
2470-
progressbar=self.progressbar)
2474+
print_msg("\t... (took < 1 sec)", log=self.log, silent=self.silent)
24712475

24722476
# cleanup (unload fake module, remove fake module dir)
24732477
if fake_mod_data:
@@ -3265,7 +3269,7 @@ def make_module_step(self, fake=False):
32653269
else:
32663270
diff_msg += 'no differences found'
32673271
self.log.info(diff_msg)
3268-
print_msg(diff_msg, log=self.log, progressbar=self.progressbar)
3272+
print_msg(diff_msg, log=self.log)
32693273

32703274
self.invalidate_module_caches(modpath)
32713275

@@ -3583,9 +3587,10 @@ def run_all_steps(self, run_test_cases):
35833587
return True
35843588

35853589
steps = self.get_steps(run_test_cases=run_test_cases, iteration_count=self.det_iter_cnt())
3590+
# Calculate progress bar tick
3591+
tick = 1.0 / float(len(steps))
35863592

3587-
print_msg("building and installing %s..." % self.full_mod_name, log=self.log, silent=self.silent,
3588-
progressbar=self.progressbar)
3593+
print_msg("building and installing %s..." % self.full_mod_name, log=self.log, silent=self.silent)
35893594
trace_msg("installation prefix: %s" % self.installdir)
35903595

35913596
ignore_locks = build_option('ignore_locks')
@@ -3605,12 +3610,12 @@ def run_all_steps(self, run_test_cases):
36053610
try:
36063611
for (step_name, descr, step_methods, skippable) in steps:
36073612
if self.skip_step(step_name, skippable):
3608-
print_msg("%s [skipped]" % descr, log=self.log, silent=self.silent, progressbar=self.progressbar)
3613+
print_msg("%s [skipped]" % descr, log=self.log, silent=self.silent)
36093614
else:
36103615
if self.dry_run:
36113616
self.dry_run_msg("%s... [DRY RUN]\n", descr)
36123617
else:
3613-
print_msg("%s..." % descr, log=self.log, silent=self.silent, progressbar=self.progressbar)
3618+
print_msg("%s..." % descr, log=self.log, silent=self.silent)
36143619
self.current_step = step_name
36153620
start_time = datetime.now()
36163621
try:
@@ -3619,11 +3624,10 @@ def run_all_steps(self, run_test_cases):
36193624
if not self.dry_run:
36203625
step_duration = datetime.now() - start_time
36213626
if step_duration.total_seconds() >= 1:
3622-
print_msg("... (took %s)", time2str(step_duration), log=self.log, silent=self.silent,
3623-
progressbar=self.progressbar)
3627+
print_msg("... (took %s)", time2str(step_duration), log=self.log, silent=self.silent)
36243628
elif self.logdebug or build_option('trace'):
3625-
print_msg("... (took < 1 sec)", log=self.log, silent=self.silent,
3626-
progressbar=self.progressbar)
3629+
print_msg("... (took < 1 sec)", log=self.log, silent=self.silent)
3630+
self.advance_progress(tick)
36273631

36283632
except StopException:
36293633
pass
@@ -3649,7 +3653,7 @@ def print_dry_run_note(loc, silent=True):
36493653
dry_run_msg(msg, silent=silent)
36503654

36513655

3652-
def build_and_install_one(ecdict, init_env, progressbar=None):
3656+
def build_and_install_one(ecdict, init_env, progressbar=None, task_id=None):
36533657
"""
36543658
Build the software
36553659
:param ecdict: dictionary contaning parsed easyconfig + metadata
@@ -3667,7 +3671,7 @@ def build_and_install_one(ecdict, init_env, progressbar=None):
36673671

36683672
if dry_run:
36693673
dry_run_msg('', silent=silent)
3670-
print_msg("processing EasyBuild easyconfig %s" % spec, log=_log, silent=silent, progressbar=progressbar)
3674+
print_msg("processing EasyBuild easyconfig %s" % spec, log=_log, silent=silent)
36713675

36723676
if dry_run:
36733677
# print note on interpreting dry run output (argument is reference to location of dry run messages)
@@ -3698,8 +3702,8 @@ def build_and_install_one(ecdict, init_env, progressbar=None):
36983702
silent=silent)
36993703

37003704
# Setup progressbar
3701-
if progressbar:
3702-
app.set_progressbar(progressbar)
3705+
if progressbar and task_id is not None:
3706+
app.set_progressbar(progressbar, task_id)
37033707
_log.info("Updated progressbar instance for easyblock %s" % easyblock)
37043708
# application settings
37053709
stop = build_option('stop')
@@ -3878,16 +3882,15 @@ def ensure_writable_log_dir(log_dir):
38783882
application_log = app.logfile
38793883

38803884
req_time = time2str(end_timestamp - start_timestamp)
3881-
print_msg("%s: Installation %s %s (took %s)" % (summary, ended, succ, req_time), log=_log, silent=silent,
3882-
progressbar=progressbar)
3885+
print_msg("%s: Installation %s %s (took %s)" % (summary, ended, succ, req_time), log=_log, silent=silent)
38833886

38843887
# check for errors
38853888
if run.errors_found_in_log > 0:
38863889
_log.warning("%d possible error(s) were detected in the "
38873890
"build logs, please verify the build.", run.errors_found_in_log)
38883891

38893892
if app.postmsg:
3890-
print_msg("\nWARNING: %s\n" % app.postmsg, log=_log, silent=silent, progressbar=progressbar)
3893+
print_msg("\nWARNING: %s\n" % app.postmsg, log=_log, silent=silent)
38913894

38923895
if dry_run:
38933896
# print note on interpreting dry run output (argument is reference to location of dry run messages)
@@ -3901,8 +3904,7 @@ def ensure_writable_log_dir(log_dir):
39013904
if application_log:
39023905
# there may be multiple log files, or the file name may be different due to zipping
39033906
logs = glob.glob('%s*' % application_log)
3904-
print_msg("Results of the build can be found in the log file(s) %s" % ', '.join(logs), log=_log, silent=silent,
3905-
progressbar=progressbar)
3907+
print_msg("Results of the build can be found in the log file(s) %s" % ', '.join(logs), log=_log, silent=silent)
39063908

39073909
del app
39083910

easybuild/main.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import os
4040
import stat
4141
import sys
42-
import tqdm
4342
import traceback
4443

4544
# IMPORTANT this has to be the first easybuild import as it customises the logging
@@ -74,6 +73,7 @@
7473
from easybuild.tools.parallelbuild import submit_jobs
7574
from easybuild.tools.repository.repository import init_repository
7675
from easybuild.tools.testing import create_test_report, overall_test_report, regtest, session_state
76+
from rich.progress import Progress, TextColumn, BarColumn, TimeElapsedColumn
7777

7878
_log = None
7979

@@ -112,13 +112,17 @@ def build_and_install_software(ecs, init_session_state, exit_on_failure=True, pr
112112
# e.g. via easyconfig.handle_allowed_system_deps
113113
init_env = copy.deepcopy(os.environ)
114114

115+
# Initialize progress bar with overall installation task
116+
if progress:
117+
task_id = progress.add_task("", total=len(ecs))
115118
res = []
116119
for ec in ecs:
117120
if progress:
118-
progress.set_description("Installing %s" % ec['short_mod_name'])
121+
progress.update(task_id, description=ec['short_mod_name'])
119122
ec_res = {}
120123
try:
121-
(ec_res['success'], app_log, err) = build_and_install_one(ec, init_env, progressbar=progress)
124+
(ec_res['success'], app_log, err) = build_and_install_one(ec, init_env, progressbar=progress,
125+
task_id=task_id)
122126
ec_res['log_file'] = app_log
123127
if not ec_res['success']:
124128
ec_res['err'] = EasyBuildError(err)
@@ -156,8 +160,6 @@ def build_and_install_software(ecs, init_session_state, exit_on_failure=True, pr
156160
raise EasyBuildError(test_msg)
157161

158162
res.append((ec, ec_res))
159-
if progress:
160-
progress.update()
161163

162164
return res
163165

@@ -526,12 +528,17 @@ def main(args=None, logfile=None, do_build=None, testing=False, modtool=None):
526528
if not testing or (testing and do_build):
527529
exit_on_failure = not (options.dump_test_report or options.upload_test_report)
528530
# Create progressbar around software to install
529-
progress_bar = tqdm.tqdm(total=len(ordered_ecs), desc="EasyBuild",
530-
leave=False, unit='EB')
531-
ecs_with_res = build_and_install_software(
532-
ordered_ecs, init_session_state, exit_on_failure=exit_on_failure,
533-
progress=progress_bar)
534-
progress_bar.close()
531+
progress_bar = Progress(
532+
TextColumn("[bold blue]Installing {task.description} ({task.completed:.0f}/{task.total})"),
533+
BarColumn(),
534+
"[progress.percentage]{task.percentage:>3.1f}%",
535+
"•",
536+
TimeElapsedColumn()
537+
)
538+
with progress_bar:
539+
ecs_with_res = build_and_install_software(
540+
ordered_ecs, init_session_state, exit_on_failure=exit_on_failure,
541+
progress=progress_bar)
535542
else:
536543
ecs_with_res = [(ec, {}) for ec in ordered_ecs]
537544

easybuild/tools/build_log.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,6 @@ def print_msg(msg, *args, **kwargs):
258258
prefix = kwargs.pop('prefix', True)
259259
newline = kwargs.pop('newline', True)
260260
stderr = kwargs.pop('stderr', False)
261-
pbar = kwargs.pop('progressbar', None)
262261
if kwargs:
263262
raise EasyBuildError("Unknown named arguments passed to print_msg: %s", kwargs)
264263

@@ -273,8 +272,6 @@ def print_msg(msg, *args, **kwargs):
273272

274273
if stderr:
275274
sys.stderr.write(msg)
276-
elif pbar:
277-
pbar.write(msg, end='')
278275
else:
279276
sys.stdout.write(msg)
280277

@@ -307,15 +304,14 @@ def dry_run_msg(msg, *args, **kwargs):
307304
msg = msg % args
308305

309306
silent = kwargs.pop('silent', False)
310-
pbar = kwargs.pop('progressbar', None)
311307
if kwargs:
312308
raise EasyBuildError("Unknown named arguments passed to dry_run_msg: %s", kwargs)
313309

314310
for dry_run_var in [DRY_RUN_BUILD_DIR, DRY_RUN_MODULES_INSTALL_DIR, DRY_RUN_SOFTWARE_INSTALL_DIR]:
315311
if dry_run_var is not None:
316312
msg = dry_run_var[0].sub(dry_run_var[1], msg)
317313

318-
print_msg(msg, silent=silent, prefix=False, progressbar=pbar)
314+
print_msg(msg, silent=silent, prefix=False)
319315

320316

321317
def dry_run_warning(msg, *args, **kwargs):

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,4 @@ archspec; python_version >= '2.7'
6363
cryptography==3.3.2; python_version == '2.7'
6464
cryptography; python_version >= '3.5'
6565

66-
tqdm; python_version >= '2.7'
66+
rich; python_version >= '2.7'

0 commit comments

Comments
 (0)