def custom_result_renderer(res, **kwargs): from datalad.interface.utils import generic_result_renderer from datalad.ui import ui if res['status'] != 'ok' or 'procedure' not in res.get('action', ''): # it's not our business generic_result_renderer(res) return if kwargs.get('discover', None): ui.message('{name} ({path}){msg}'.format( # bold-faced name, if active name=ac.color_word(res['procedure_name'], ac.BOLD) if res['state'] == 'executable' else res['procedure_name'], path=res['path'], msg=' [{}]'.format( res['message'][0] % res['message'][1:] if isinstance(res['message'], tuple) else res['message']) if 'message' in res else '')) elif kwargs.get('help_proc', None): ui.message('{name} ({path}){help}'.format( name=ac.color_word(res['procedure_name'], ac.BOLD), path=op.relpath(res['path'], res['refds']) if res.get( 'refds', None) else res['path'], help='{nl}{msg}'.format( nl=os.linesep, msg=res['message'][0] % res['message'][1:] if isinstance(res['message'], tuple) else res['message']) if 'message' in res else '')) else: generic_result_renderer(res)
def custom_result_renderer(res, **kwargs): # pragma: more cover if (res['status'] == 'ok' and res['action'] in ('status', 'diff') and res.get('state') == 'clean'): # this renderer will be silent for clean status|diff results return if res['status'] != 'ok' or res['action'] not in ('status', 'diff'): # whatever this renderer cannot account for, send to generic generic_result_renderer(res) return from datalad.ui import ui # when to render relative paths: # 1) if a dataset arg was given # 2) if CWD is the refds refds = res.get('refds', None) refds = refds if kwargs.get('dataset', None) is not None \ or refds == os.getcwd() else None path = res['path'] if refds is None \ else str(ut.Path(res['path']).relative_to(refds)) type_ = res.get('type', res.get('type_src', '')) max_len = len('untracked') state = res.get('state', 'unknown') ui.message(u'{fill}{state}: {path}{type_}'.format( fill=' ' * max(0, max_len - len(state)), state=ac.color_word( state, STATE_COLOR_MAP.get(res.get('state', 'unknown'))), path=path, type_=' ({})'.format( ac.color_word(type_, ac.MAGENTA) if type_ else '')))
def custom_result_renderer(res, **kwargs): dry_run = kwargs.get("dry_run") if dry_run and "dry_run_info" in res: if dry_run == "basic": _display_basic(res) elif dry_run == "command": ui.message(res["dry_run_info"]["cmd_expanded"]) else: raise ValueError(f"Unknown dry-run mode: {dry_run!r}") else: if kwargs.get("on_failure") == "stop" and \ res.get("action") == "run" and res.get("status") == "error": msg_path = res.get("msg_path") if msg_path: ds_path = res["path"] if datalad.get_apimode() == 'python': help = f"\"Dataset('{ds_path}').save(path='.', " \ "recursive=True, message_file='%s')\"" else: help = "'datalad save -d . -r -F %s'" lgr.info( "The command had a non-zero exit code. " "If this is expected, you can save the changes with " f"{help}", # shorten to the relative path for a more concise # message Path(msg_path).relative_to(ds_path)) generic_result_renderer(res)
def custom_result_renderer(res, **kwargs): from datalad.ui import ui # should we attempt to remove an unknown sibling, complain like Git does if res['status'] == 'notneeded' and res['action'] == 'remove-sibling': ui.message('{warn}: No sibling "{name}" in dataset {path}'.format( warn=ac.color_word('Warning', ac.LOG_LEVEL_COLORS['WARNING']), **res)) return if res['status'] != 'ok' or not res.get('action', '').endswith('-sibling'): generic_result_renderer(res) return path = op.relpath(res['path'], res['refds']) if res.get( 'refds', None) else res['path'] got_url = 'url' in res spec = '{}{}{}{}'.format(res.get('url', ''), ' (' if got_url else '', res.get('annex-externaltype', 'git'), ')' if got_url else '') ui.message('{path}: {name}({with_annex}) [{spec}]'.format( **dict( res, path=path, # TODO report '+' for special remotes with_annex='+' if 'annex-uuid' in res \ else ('-' if res.get('annex-ignore', None) else '?'), spec=spec)))
def custom_result_renderer(res, **kwargs): if res['status'] != 'ok' or not res.get('action', None) == 'metadata': generic_result_renderer(res) return # list the path, available metadata keys, and tags path = op.relpath(res['path'], res['refds']) if res.get( 'refds', None) else res['path'] meta = res.get('metadata', {}) ui.message('{path}{type}:{spacer}{meta}{tags}'.format( path=ac.color_word(path, ac.BOLD), type=' ({})'.format(ac.color_word(res['type'], ac.MAGENTA)) if 'type' in res else '', spacer=' ' if len([m for m in meta if m != 'tag']) else '', meta=','.join(k for k in sorted(meta.keys()) if k not in ('tag', '@context', '@id')) if meta else ' -' if 'metadata' in res else ' aggregated', tags='' if 'tag' not in meta else ' [{}]'.format(','.join( ensure_list(meta['tag'])))))
def custom_result_renderer(res, **kwargs): # pragma: more cover # Don't render things like 'status' for clean-info messages - # seems rather meaningless. from os import getcwd import datalad.support.ansi_colors as ac from datalad.interface.utils import generic_result_renderer from datalad.utils import Path if res['action'] == 'clean': # default renderer is just fine return generic_result_renderer(res) elif res['action'] != 'clean [dry-run]': # Result didn't come from within `clean`. # Should be handled elsewhere. return assert res['action'] == 'clean [dry-run]' if res.get('status', None) == 'ok': from datalad.ui import ui # when to render relative paths: # 1) if a dataset arg was given # 2) if CWD is the refds refds = res.get('refds', None) refds = refds if kwargs.get('dataset', None) is not None \ or refds == getcwd() else None path = res['path'] if refds is None \ else str(Path(res['path']).relative_to(refds)) ui.message(u"{path}: {message}".format( path=ac.color_word(path, ac.BOLD), message=(res['message'][0] % res['message'][1:] if isinstance( res['message'], tuple) else res['message']) if res.get( 'message', None) else '')) else: # Any other status than 'ok' is reported the default way. return generic_result_renderer(res)
def test_generic_result_renderer(): # a bunch of bad cases of results testcases = [ # an empty result will surface ({}, ['<action-unspecified>(<status-unspecified>)']), # non-standard status makes it out again (dict(status='funky'), ['<action-unspecified>(funky)']), # just an action result is enough to get some output (dict(action='funky'), ['funky(<status-unspecified>)']), # a plain path produces output, although (dict(path='funky'), ['<action-unspecified>(<status-unspecified>): funky']), # plain type makes it through (dict(type='funky'), ['<action-unspecified>(<status-unspecified>): (funky)']), # plain message makes it through (dict(message='funky', error_message='extra-funky'), ['<action-unspecified>(<status-unspecified>): [funky] [extra-funky]' ]), ] if on_windows: testcases.extend([ # if relpath'ing is not possible, takes the path verbatim (dict(path='C:\\funky', refds='D:\\medina'), ['<action-unspecified>(<status-unspecified>): C:\\funky']), ]) else: testcases.extend([ (dict(path='/funky/cold/medina', refds='/funky'), ['<action-unspecified>(<status-unspecified>): cold/medina']), ]) for result, contenttests in testcases: with swallow_outputs() as cmo: generic_result_renderer(result) for ctest in contenttests: assert_in(ctest, cmo.out)
def custom_result_renderer(res, **kwargs): generic_result_renderer(res)