diff options
author | Doug Hellmann <doug@doughellmann.com> | 2017-09-07 16:15:36 -0400 |
---|---|---|
committer | Dean Troyer <dtroyer@gmail.com> | 2017-09-22 14:35:29 +0000 |
commit | 31ec27dc61cf561ecd699f98fcac627b2d6467fa (patch) | |
tree | 1cf65d96757a12e8d77ec92db59c1483d584f9fe | |
parent | dacbd601d843e91b32a57859a2965055540dd8a2 (diff) | |
download | cliff-31ec27dc61cf561ecd699f98fcac627b2d6467fa.tar.gz |
show the distribution providing the command in help output
When listing all available commands, include the distribution name if
it does not match the distribution of the main application.
When showing the verbose help for a single command, include the
distribution name if it does not match the distribution of the main
application.
Change-Id: I4ddb3327c62cfd0f82167c15e9513ece6a3689c4
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
-rw-r--r-- | cliff/command.py | 56 | ||||
-rw-r--r-- | cliff/help.py | 14 |
2 files changed, 62 insertions, 8 deletions
diff --git a/cliff/command.py b/cliff/command.py index 1c6ac48..1867150 100644 --- a/cliff/command.py +++ b/cliff/command.py @@ -13,11 +13,47 @@ import abc import inspect +import pkg_resources import six from stevedore import extension from cliff import _argparse +_dists_by_mods = None + + +def _get_distributions_by_modules(): + """Return dict mapping module name to distribution names. + + The python package name (the name used for importing) and the + distribution name (the name used with pip and PyPI) do not + always match. We want to report which distribution caused the + command to be installed, so we need to look up the values. + + """ + global _dists_by_mods + if _dists_by_mods is None: + results = {} + for dist in pkg_resources.working_set: + try: + mod_name = dist.get_metadata('top_level.txt').strip() + except KeyError: + # Could not retrieve metadata. Ignore. + pass + else: + results[mod_name] = dist.project_name + _dists_by_mods = results + return _dists_by_mods + + +def _get_distribution_for_module(module): + "Return the distribution containing the module." + dist_name = None + if module: + pkg_name = module.__name__.partition('.')[0] + dist_name = _get_distributions_by_modules().get(pkg_name) + return dist_name + @six.add_metaclass(abc.ABCMeta) class Command(object): @@ -89,17 +125,23 @@ class Command(object): def get_epilog(self): """Return the command epilog.""" + # replace a None in self._epilog with an empty string + parts = [self._epilog or ''] hook_epilogs = filter( None, (h.obj.get_epilog() for h in self._hooks), ) - if hook_epilogs: - # combine them, replacing a None in self._epilog with an - # empty string - parts = [self._epilog or ''] - parts.extend(hook_epilogs) - return '\n\n'.join(parts) - return self._epilog + parts.extend(hook_epilogs) + app_dist_name = _get_distribution_for_module( + inspect.getmodule(self.app) + ) + dist_name = _get_distribution_for_module(inspect.getmodule(self)) + if dist_name and dist_name != app_dist_name: + parts.append( + 'This command is provided by the %s plugin.' % + (dist_name,) + ) + return '\n\n'.join(parts) def get_parser(self, prog_name): """Return an :class:`argparse.ArgumentParser`. diff --git a/cliff/help.py b/cliff/help.py index 40c4874..971e9ad 100644 --- a/cliff/help.py +++ b/cliff/help.py @@ -29,6 +29,13 @@ class HelpAction(argparse.Action): app = self.default parser.print_help(app.stdout) app.stdout.write('\nCommands:\n') + dists_by_module = command._get_distributions_by_modules() + + def dist_for_obj(obj): + name = inspect.getmodule(obj).__name__.partition('.')[0] + return dists_by_module.get(name) + + app_dist = dist_for_obj(app) command_manager = app.command_manager for name, ep in sorted(command_manager): try: @@ -51,7 +58,12 @@ class HelpAction(argparse.Action): traceback.print_exc(file=app.stdout) continue one_liner = cmd.get_description().split('\n')[0] - app.stdout.write(' %-13s %s\n' % (name, one_liner)) + dist_name = dist_for_obj(factory) + if dist_name and dist_name != app_dist: + dist_info = ' (' + dist_name + ')' + else: + dist_info = '' + app.stdout.write(' %-13s %s%s\n' % (name, one_liner, dist_info)) sys.exit(0) |