Blacken code base
Change-Id: I85e02280517bd045936381a984fe2c1f708456a8 Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
This commit is contained in:
parent
bc56deae91
commit
088b1e200f
.pre-commit-config.yaml
cliff
_argparse.pyapp.pycolumns.pycommand.pycommandmanager.pycomplete.pydisplay.py
formatters
help.pyinteractive.pylister.pyshow.pysphinxext.pytests
base.pytest__argparse.pytest_app.pytest_columns.pytest_command.pytest_command_hooks.pytest_commandmanager.pytest_complete.pytest_formatters_csv.pytest_formatters_json.pytest_formatters_shell.pytest_formatters_table.pytest_formatters_value.pytest_formatters_yaml.pytest_help.pytest_interactive.pytest_lister.pytest_show.pytest_sphinxext.pytest_utils.pyutils.py
utils.pydemoapp
doc/source
setup.cfgsetup.pytox.ini@ -4,7 +4,7 @@ default_language_version:
|
|||||||
python: python3
|
python: python3
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.4.0
|
rev: v4.5.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: mixed-line-ending
|
- id: mixed-line-ending
|
||||||
@ -18,16 +18,16 @@ repos:
|
|||||||
files: .*\.(yaml|yml)$
|
files: .*\.(yaml|yml)$
|
||||||
exclude: '^zuul.d/.*$'
|
exclude: '^zuul.d/.*$'
|
||||||
- repo: https://github.com/PyCQA/bandit
|
- repo: https://github.com/PyCQA/bandit
|
||||||
rev: 1.7.5
|
rev: 1.7.7
|
||||||
hooks:
|
hooks:
|
||||||
- id: bandit
|
- id: bandit
|
||||||
args: ['-c', 'bandit.yaml']
|
args: ['-c', 'bandit.yaml']
|
||||||
# - repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
# rev: 23.3.0
|
rev: 24.2.0
|
||||||
# hooks:
|
hooks:
|
||||||
# - id: black
|
- id: black
|
||||||
# args: ['-S', '-l', '79']
|
args: ['-S', '-l', '79']
|
||||||
- repo: https://github.com/pycqa/flake8
|
- repo: https://github.com/pycqa/flake8
|
||||||
rev: 6.1.0
|
rev: 7.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
|
@ -19,7 +19,6 @@ from autopage import argparse
|
|||||||
|
|
||||||
|
|
||||||
class _ArgumentContainerMixIn(object):
|
class _ArgumentContainerMixIn(object):
|
||||||
|
|
||||||
# NOTE(dhellmann): We have to override the methods for creating
|
# NOTE(dhellmann): We have to override the methods for creating
|
||||||
# groups to return our objects that know how to deal with the
|
# groups to return our objects that know how to deal with the
|
||||||
# special conflict handler.
|
# special conflict handler.
|
||||||
@ -44,13 +43,15 @@ class _ArgumentContainerMixIn(object):
|
|||||||
|
|
||||||
|
|
||||||
class ArgumentParser(_ArgumentContainerMixIn, argparse.ArgumentParser):
|
class ArgumentParser(_ArgumentContainerMixIn, argparse.ArgumentParser):
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _handle_conflict_ignore(container, option_string_actions,
|
def _handle_conflict_ignore(
|
||||||
new_action, conflicting_actions):
|
container,
|
||||||
|
option_string_actions,
|
||||||
|
new_action,
|
||||||
|
conflicting_actions,
|
||||||
|
):
|
||||||
# Remember the option strings the new action starts with so we can
|
# Remember the option strings the new action starts with so we can
|
||||||
# restore them as part of error reporting if we need to.
|
# restore them as part of error reporting if we need to.
|
||||||
original_option_strings = new_action.option_strings
|
original_option_strings = new_action.option_strings
|
||||||
@ -58,13 +59,14 @@ def _handle_conflict_ignore(container, option_string_actions,
|
|||||||
# Remove all of the conflicting option strings from the new action
|
# Remove all of the conflicting option strings from the new action
|
||||||
# and report an error if none are left at the end.
|
# and report an error if none are left at the end.
|
||||||
for option_string, action in conflicting_actions:
|
for option_string, action in conflicting_actions:
|
||||||
|
|
||||||
# remove the conflicting option from the new action
|
# remove the conflicting option from the new action
|
||||||
new_action.option_strings.remove(option_string)
|
new_action.option_strings.remove(option_string)
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
('Ignoring option string {} for new action '
|
(
|
||||||
'because it conflicts with an existing option.').format(
|
'Ignoring option string {} for new action '
|
||||||
option_string))
|
'because it conflicts with an existing option.'
|
||||||
|
).format(option_string)
|
||||||
|
)
|
||||||
|
|
||||||
# if the option now has no option string, remove it from the
|
# if the option now has no option string, remove it from the
|
||||||
# container holding it
|
# container holding it
|
||||||
@ -72,8 +74,10 @@ def _handle_conflict_ignore(container, option_string_actions,
|
|||||||
new_action.option_strings = original_option_strings
|
new_action.option_strings = original_option_strings
|
||||||
raise argparse.ArgumentError(
|
raise argparse.ArgumentError(
|
||||||
new_action,
|
new_action,
|
||||||
('Cannot resolve conflicting option string, '
|
(
|
||||||
'all names conflict.'),
|
'Cannot resolve conflicting option string, '
|
||||||
|
'all names conflict.'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -81,8 +85,9 @@ class _ArgumentGroup(_ArgumentContainerMixIn, orig_argparse._ArgumentGroup):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class _MutuallyExclusiveGroup(_ArgumentContainerMixIn,
|
class _MutuallyExclusiveGroup(
|
||||||
orig_argparse._MutuallyExclusiveGroup):
|
_ArgumentContainerMixIn, orig_argparse._MutuallyExclusiveGroup
|
||||||
|
):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
99
cliff/app.py
99
cliff/app.py
@ -63,17 +63,24 @@ class App(object):
|
|||||||
LOG = logging.getLogger(NAME)
|
LOG = logging.getLogger(NAME)
|
||||||
|
|
||||||
CONSOLE_MESSAGE_FORMAT = '%(message)s'
|
CONSOLE_MESSAGE_FORMAT = '%(message)s'
|
||||||
LOG_FILE_MESSAGE_FORMAT = \
|
LOG_FILE_MESSAGE_FORMAT = (
|
||||||
'[%(asctime)s] %(levelname)-8s %(name)s %(message)s'
|
'[%(asctime)s] %(levelname)-8s %(name)s %(message)s'
|
||||||
|
)
|
||||||
DEFAULT_VERBOSE_LEVEL = 1
|
DEFAULT_VERBOSE_LEVEL = 1
|
||||||
DEFAULT_OUTPUT_ENCODING = 'utf-8'
|
DEFAULT_OUTPUT_ENCODING = 'utf-8'
|
||||||
|
|
||||||
def __init__(self, description, version, command_manager,
|
def __init__(
|
||||||
stdin=None, stdout=None, stderr=None,
|
self,
|
||||||
interactive_app_factory=None,
|
description,
|
||||||
deferred_help=False):
|
version,
|
||||||
"""Initialize the application.
|
command_manager,
|
||||||
"""
|
stdin=None,
|
||||||
|
stdout=None,
|
||||||
|
stderr=None,
|
||||||
|
interactive_app_factory=None,
|
||||||
|
deferred_help=False,
|
||||||
|
):
|
||||||
|
"""Initialize the application."""
|
||||||
self.command_manager = command_manager
|
self.command_manager = command_manager
|
||||||
self.command_manager.add_command('help', help.HelpCommand)
|
self.command_manager.add_command('help', help.HelpCommand)
|
||||||
self.command_manager.add_command('complete', complete.CompleteCommand)
|
self.command_manager.add_command('complete', complete.CompleteCommand)
|
||||||
@ -120,8 +127,7 @@ class App(object):
|
|||||||
self.stdout = stdout or sys.stdout
|
self.stdout = stdout or sys.stdout
|
||||||
self.stderr = stderr or sys.stderr
|
self.stderr = stderr or sys.stderr
|
||||||
|
|
||||||
def build_option_parser(self, description, version,
|
def build_option_parser(self, description, version, argparse_kwargs=None):
|
||||||
argparse_kwargs=None):
|
|
||||||
"""Return an argparse option parser for this application.
|
"""Return an argparse option parser for this application.
|
||||||
|
|
||||||
Subclasses may override this method to extend
|
Subclasses may override this method to extend
|
||||||
@ -137,9 +143,7 @@ class App(object):
|
|||||||
"""
|
"""
|
||||||
argparse_kwargs = argparse_kwargs or {}
|
argparse_kwargs = argparse_kwargs or {}
|
||||||
parser = _argparse.ArgumentParser(
|
parser = _argparse.ArgumentParser(
|
||||||
description=description,
|
description=description, add_help=False, **argparse_kwargs
|
||||||
add_help=False,
|
|
||||||
**argparse_kwargs
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--version',
|
'--version',
|
||||||
@ -148,14 +152,16 @@ class App(object):
|
|||||||
)
|
)
|
||||||
verbose_group = parser.add_mutually_exclusive_group()
|
verbose_group = parser.add_mutually_exclusive_group()
|
||||||
verbose_group.add_argument(
|
verbose_group.add_argument(
|
||||||
'-v', '--verbose',
|
'-v',
|
||||||
|
'--verbose',
|
||||||
action='count',
|
action='count',
|
||||||
dest='verbose_level',
|
dest='verbose_level',
|
||||||
default=self.DEFAULT_VERBOSE_LEVEL,
|
default=self.DEFAULT_VERBOSE_LEVEL,
|
||||||
help='Increase verbosity of output. Can be repeated.',
|
help='Increase verbosity of output. Can be repeated.',
|
||||||
)
|
)
|
||||||
verbose_group.add_argument(
|
verbose_group.add_argument(
|
||||||
'-q', '--quiet',
|
'-q',
|
||||||
|
'--quiet',
|
||||||
action='store_const',
|
action='store_const',
|
||||||
dest='verbose_level',
|
dest='verbose_level',
|
||||||
const=0,
|
const=0,
|
||||||
@ -169,14 +175,16 @@ class App(object):
|
|||||||
)
|
)
|
||||||
if self.deferred_help:
|
if self.deferred_help:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-h', '--help',
|
'-h',
|
||||||
|
'--help',
|
||||||
dest='deferred_help',
|
dest='deferred_help',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help="Show help message and exit.",
|
help="Show help message and exit.",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-h', '--help',
|
'-h',
|
||||||
|
'--help',
|
||||||
action=help.HelpAction,
|
action=help.HelpAction,
|
||||||
nargs=0,
|
nargs=0,
|
||||||
default=self, # tricky
|
default=self, # tricky
|
||||||
@ -191,8 +199,7 @@ class App(object):
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
def configure_logging(self):
|
def configure_logging(self):
|
||||||
"""Create logging handlers for any log output.
|
"""Create logging handlers for any log output."""
|
||||||
"""
|
|
||||||
root_logger = logging.getLogger('')
|
root_logger = logging.getLogger('')
|
||||||
root_logger.setLevel(logging.DEBUG)
|
root_logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
@ -207,10 +214,11 @@ class App(object):
|
|||||||
|
|
||||||
# Always send higher-level messages to the console via stderr
|
# Always send higher-level messages to the console via stderr
|
||||||
console = logging.StreamHandler(self.stderr)
|
console = logging.StreamHandler(self.stderr)
|
||||||
console_level = {0: logging.WARNING,
|
console_level = {
|
||||||
1: logging.INFO,
|
0: logging.WARNING,
|
||||||
2: logging.DEBUG,
|
1: logging.INFO,
|
||||||
}.get(self.options.verbose_level, logging.DEBUG)
|
2: logging.DEBUG,
|
||||||
|
}.get(self.options.verbose_level, logging.DEBUG)
|
||||||
console.setLevel(console_level)
|
console.setLevel(console_level)
|
||||||
formatter = logging.Formatter(self.CONSOLE_MESSAGE_FORMAT)
|
formatter = logging.Formatter(self.CONSOLE_MESSAGE_FORMAT)
|
||||||
console.setFormatter(formatter)
|
console.setFormatter(formatter)
|
||||||
@ -320,16 +328,16 @@ class App(object):
|
|||||||
|
|
||||||
if self.interactive_app_factory is None:
|
if self.interactive_app_factory is None:
|
||||||
self.interactive_app_factory = InteractiveApp
|
self.interactive_app_factory = InteractiveApp
|
||||||
self.interpreter = self.interactive_app_factory(self,
|
self.interpreter = self.interactive_app_factory(
|
||||||
self.command_manager,
|
self,
|
||||||
self.stdin,
|
self.command_manager,
|
||||||
self.stdout,
|
self.stdin,
|
||||||
)
|
self.stdout,
|
||||||
|
)
|
||||||
return self.interpreter.cmdloop()
|
return self.interpreter.cmdloop()
|
||||||
|
|
||||||
def get_fuzzy_matches(self, cmd):
|
def get_fuzzy_matches(self, cmd):
|
||||||
"""return fuzzy matches of unknown command
|
"""return fuzzy matches of unknown command"""
|
||||||
"""
|
|
||||||
|
|
||||||
sep = '_'
|
sep = '_'
|
||||||
if self.command_manager.convert_underscores:
|
if self.command_manager.convert_underscores:
|
||||||
@ -343,8 +351,12 @@ class App(object):
|
|||||||
dist.append((0, candidate))
|
dist.append((0, candidate))
|
||||||
continue
|
continue
|
||||||
# Levenshtein distance
|
# Levenshtein distance
|
||||||
dist.append((utils.damerau_levenshtein(cmd, prefix, utils.COST)+1,
|
dist.append(
|
||||||
candidate))
|
(
|
||||||
|
utils.damerau_levenshtein(cmd, prefix, utils.COST) + 1,
|
||||||
|
candidate,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
matches = []
|
matches = []
|
||||||
match_distance = 0
|
match_distance = 0
|
||||||
@ -371,10 +383,17 @@ class App(object):
|
|||||||
article = 'a'
|
article = 'a'
|
||||||
if self.NAME[0] in 'aeiou':
|
if self.NAME[0] in 'aeiou':
|
||||||
article = 'an'
|
article = 'an'
|
||||||
self.stdout.write('%s: \'%s\' is not %s %s command. '
|
self.stdout.write(
|
||||||
'See \'%s --help\'.\n'
|
'%s: \'%s\' is not %s %s command. '
|
||||||
% (self.NAME, ' '.join(argv), article,
|
'See \'%s --help\'.\n'
|
||||||
self.NAME, self.NAME))
|
% (
|
||||||
|
self.NAME,
|
||||||
|
' '.join(argv),
|
||||||
|
article,
|
||||||
|
self.NAME,
|
||||||
|
self.NAME,
|
||||||
|
)
|
||||||
|
)
|
||||||
self.stdout.write('Did you mean one of these?\n')
|
self.stdout.write('Did you mean one of these?\n')
|
||||||
for match in fuzzy_matches:
|
for match in fuzzy_matches:
|
||||||
self.stdout.write(' %s\n' % match)
|
self.stdout.write(' %s\n' % match)
|
||||||
@ -393,10 +412,11 @@ class App(object):
|
|||||||
err = None
|
err = None
|
||||||
try:
|
try:
|
||||||
self.prepare_to_run_command(cmd)
|
self.prepare_to_run_command(cmd)
|
||||||
full_name = (cmd_name
|
full_name = (
|
||||||
if self.interactive_mode
|
cmd_name
|
||||||
else ' '.join([self.NAME, cmd_name])
|
if self.interactive_mode
|
||||||
)
|
else ' '.join([self.NAME, cmd_name])
|
||||||
|
)
|
||||||
cmd_parser = cmd.get_parser(full_name)
|
cmd_parser = cmd.get_parser(full_name)
|
||||||
try:
|
try:
|
||||||
parsed_args = cmd_parser.parse_args(sub_argv)
|
parsed_args = cmd_parser.parse_args(sub_argv)
|
||||||
@ -404,6 +424,7 @@ class App(object):
|
|||||||
if self.interactive_mode:
|
if self.interactive_mode:
|
||||||
# Defer importing cmd2 as it is a slow import
|
# Defer importing cmd2 as it is a slow import
|
||||||
import cmd2
|
import cmd2
|
||||||
|
|
||||||
raise cmd2.exceptions.Cmd2ArgparseError from ex
|
raise cmd2.exceptions.Cmd2ArgparseError from ex
|
||||||
else:
|
else:
|
||||||
raise ex
|
raise ex
|
||||||
|
@ -17,7 +17,6 @@ import abc
|
|||||||
|
|
||||||
|
|
||||||
class FormattableColumn(object, metaclass=abc.ABCMeta):
|
class FormattableColumn(object, metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self._value = value
|
self._value = value
|
||||||
|
|
||||||
@ -27,9 +26,7 @@ class FormattableColumn(object, metaclass=abc.ABCMeta):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
return (
|
return self.__class__ == other.__class__ and self._value < other._value
|
||||||
self.__class__ == other.__class__ and self._value < other._value
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.human_readable()
|
return self.human_readable()
|
||||||
|
@ -39,9 +39,7 @@ def _get_distributions_by_modules():
|
|||||||
if _dists_by_mods is None:
|
if _dists_by_mods is None:
|
||||||
# There can be multiple distribution in the case of namespace packages
|
# There can be multiple distribution in the case of namespace packages
|
||||||
# so we'll just grab the first one
|
# so we'll just grab the first one
|
||||||
_dists_by_mods = {
|
_dists_by_mods = {k: v[0] for k, v in packages_distributions().items()}
|
||||||
k: v[0] for k, v in packages_distributions().items()
|
|
||||||
}
|
|
||||||
return _dists_by_mods
|
return _dists_by_mods
|
||||||
|
|
||||||
|
|
||||||
@ -85,7 +83,7 @@ class Command(object, metaclass=abc.ABCMeta):
|
|||||||
if self.app and self.cmd_name:
|
if self.app and self.cmd_name:
|
||||||
namespace = '{}.{}'.format(
|
namespace = '{}.{}'.format(
|
||||||
self.app.command_manager.namespace,
|
self.app.command_manager.namespace,
|
||||||
self.cmd_name.replace(' ', '_')
|
self.cmd_name.replace(' ', '_'),
|
||||||
)
|
)
|
||||||
self._hooks = extension.ExtensionManager(
|
self._hooks = extension.ExtensionManager(
|
||||||
namespace=namespace,
|
namespace=namespace,
|
||||||
@ -132,21 +130,19 @@ class Command(object, metaclass=abc.ABCMeta):
|
|||||||
)
|
)
|
||||||
parts.extend(hook_epilogs)
|
parts.extend(hook_epilogs)
|
||||||
app_dist_name = getattr(
|
app_dist_name = getattr(
|
||||||
self, 'app_dist_name', _get_distribution_for_module(
|
self,
|
||||||
inspect.getmodule(self.app)
|
'app_dist_name',
|
||||||
)
|
_get_distribution_for_module(inspect.getmodule(self.app)),
|
||||||
)
|
)
|
||||||
dist_name = _get_distribution_for_module(inspect.getmodule(self))
|
dist_name = _get_distribution_for_module(inspect.getmodule(self))
|
||||||
if dist_name and dist_name != app_dist_name:
|
if dist_name and dist_name != app_dist_name:
|
||||||
parts.append(
|
parts.append(
|
||||||
'This command is provided by the %s plugin.' %
|
'This command is provided by the %s plugin.' % (dist_name,)
|
||||||
(dist_name,)
|
|
||||||
)
|
)
|
||||||
return '\n\n'.join(parts)
|
return '\n\n'.join(parts)
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
"""Return an :class:`argparse.ArgumentParser`.
|
"""Return an :class:`argparse.ArgumentParser`."""
|
||||||
"""
|
|
||||||
parser = _argparse.ArgumentParser(
|
parser = _argparse.ArgumentParser(
|
||||||
description=self.get_description(),
|
description=self.get_description(),
|
||||||
epilog=self.get_epilog(),
|
epilog=self.get_epilog(),
|
||||||
|
@ -35,8 +35,7 @@ def _get_commands_by_partial_name(args, commands):
|
|||||||
|
|
||||||
|
|
||||||
class EntryPointWrapper(object):
|
class EntryPointWrapper(object):
|
||||||
"""Wrap up a command class already imported to make it look like a plugin.
|
"""Wrap up a command class already imported to make it look like a plugin."""
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, name, command_class):
|
def __init__(self, name, command_class):
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -54,6 +53,7 @@ class CommandManager(object):
|
|||||||
:param convert_underscores: Whether cliff should convert underscores to
|
:param convert_underscores: Whether cliff should convert underscores to
|
||||||
spaces in entry_point commands.
|
spaces in entry_point commands.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, namespace, convert_underscores=True):
|
def __init__(self, namespace, convert_underscores=True):
|
||||||
self.commands = {}
|
self.commands = {}
|
||||||
self._legacy = {}
|
self._legacy = {}
|
||||||
@ -72,9 +72,11 @@ class CommandManager(object):
|
|||||||
self.group_list.append(namespace)
|
self.group_list.append(namespace)
|
||||||
for ep in stevedore.ExtensionManager(namespace):
|
for ep in stevedore.ExtensionManager(namespace):
|
||||||
LOG.debug('found command %r', ep.name)
|
LOG.debug('found command %r', ep.name)
|
||||||
cmd_name = (ep.name.replace('_', ' ')
|
cmd_name = (
|
||||||
if self.convert_underscores
|
ep.name.replace('_', ' ')
|
||||||
else ep.name)
|
if self.convert_underscores
|
||||||
|
else ep.name
|
||||||
|
)
|
||||||
self.commands[cmd_name] = ep.entry_point
|
self.commands[cmd_name] = ep.entry_point
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -114,7 +116,8 @@ class CommandManager(object):
|
|||||||
found = name
|
found = name
|
||||||
else:
|
else:
|
||||||
candidates = _get_commands_by_partial_name(
|
candidates = _get_commands_by_partial_name(
|
||||||
argv[:i], self.commands)
|
argv[:i], self.commands
|
||||||
|
)
|
||||||
if len(candidates) == 1:
|
if len(candidates) == 1:
|
||||||
found = candidates[0]
|
found = candidates[0]
|
||||||
if found:
|
if found:
|
||||||
@ -131,8 +134,7 @@ class CommandManager(object):
|
|||||||
cmd_factory = cmd_ep.load()
|
cmd_factory = cmd_ep.load()
|
||||||
return (cmd_factory, return_name, search_args)
|
return (cmd_factory, return_name, search_args)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown command %r' %
|
raise ValueError('Unknown command %r' % (argv,))
|
||||||
(argv,))
|
|
||||||
|
|
||||||
def _get_last_possible_command_index(self, argv):
|
def _get_last_possible_command_index(self, argv):
|
||||||
"""Returns the index after the last argument
|
"""Returns the index after the last argument
|
||||||
|
@ -21,15 +21,15 @@ from cliff import command
|
|||||||
|
|
||||||
|
|
||||||
class CompleteDictionary:
|
class CompleteDictionary:
|
||||||
"""dictionary for bash completion
|
"""dictionary for bash completion"""
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._dictionary = {}
|
self._dictionary = {}
|
||||||
|
|
||||||
def add_command(self, command, actions):
|
def add_command(self, command, actions):
|
||||||
optstr = ' '.join(opt for action in actions
|
optstr = ' '.join(
|
||||||
for opt in action.option_strings)
|
opt for action in actions for opt in action.option_strings
|
||||||
|
)
|
||||||
dicto = self._dictionary
|
dicto = self._dictionary
|
||||||
last_cmd = command[-1]
|
last_cmd = command[-1]
|
||||||
for subcmd in command[:-1]:
|
for subcmd in command[:-1]:
|
||||||
@ -69,8 +69,8 @@ class CompleteDictionary:
|
|||||||
|
|
||||||
|
|
||||||
class CompleteShellBase(object):
|
class CompleteShellBase(object):
|
||||||
"""base class for bash completion generation
|
"""base class for bash completion generation"""
|
||||||
"""
|
|
||||||
def __init__(self, name, output):
|
def __init__(self, name, output):
|
||||||
self.name = str(name)
|
self.name = str(name)
|
||||||
self.output = output
|
self.output = output
|
||||||
@ -89,8 +89,8 @@ class CompleteShellBase(object):
|
|||||||
|
|
||||||
|
|
||||||
class CompleteNoCode(CompleteShellBase):
|
class CompleteNoCode(CompleteShellBase):
|
||||||
"""completion with no code
|
"""completion with no code"""
|
||||||
"""
|
|
||||||
def __init__(self, name, output):
|
def __init__(self, name, output):
|
||||||
super(CompleteNoCode, self).__init__(name, output)
|
super(CompleteNoCode, self).__init__(name, output)
|
||||||
|
|
||||||
@ -102,23 +102,28 @@ class CompleteNoCode(CompleteShellBase):
|
|||||||
|
|
||||||
|
|
||||||
class CompleteBash(CompleteShellBase):
|
class CompleteBash(CompleteShellBase):
|
||||||
"""completion for bash
|
"""completion for bash"""
|
||||||
"""
|
|
||||||
def __init__(self, name, output):
|
def __init__(self, name, output):
|
||||||
super(CompleteBash, self).__init__(name, output)
|
super(CompleteBash, self).__init__(name, output)
|
||||||
|
|
||||||
def get_header(self):
|
def get_header(self):
|
||||||
return ('_' + self.escaped_name + """()
|
return (
|
||||||
|
'_'
|
||||||
|
+ self.escaped_name
|
||||||
|
+ """()
|
||||||
{
|
{
|
||||||
local cur prev words
|
local cur prev words
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
_get_comp_words_by_ref -n : cur prev words
|
_get_comp_words_by_ref -n : cur prev words
|
||||||
|
|
||||||
# Command data:
|
# Command data:
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
def get_trailer(self):
|
def get_trailer(self):
|
||||||
return ("""
|
return (
|
||||||
|
"""
|
||||||
dash=-
|
dash=-
|
||||||
underscore=_
|
underscore=_
|
||||||
cmd=""
|
cmd=""
|
||||||
@ -157,12 +162,16 @@ class CompleteBash(CompleteShellBase):
|
|||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
complete -F _""" + self.escaped_name + ' ' + self.name + '\n')
|
complete -F _"""
|
||||||
|
+ self.escaped_name
|
||||||
|
+ ' '
|
||||||
|
+ self.name
|
||||||
|
+ '\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CompleteCommand(command.Command):
|
class CompleteCommand(command.Command):
|
||||||
"""print bash completion command
|
"""print bash completion command"""
|
||||||
"""
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__ + '.CompleteCommand')
|
log = logging.getLogger(__name__ + '.CompleteCommand')
|
||||||
|
|
||||||
@ -178,14 +187,14 @@ class CompleteCommand(command.Command):
|
|||||||
"--name",
|
"--name",
|
||||||
default=None,
|
default=None,
|
||||||
metavar='<command_name>',
|
metavar='<command_name>',
|
||||||
help="Command name to support with command completion"
|
help="Command name to support with command completion",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--shell",
|
"--shell",
|
||||||
default='bash',
|
default='bash',
|
||||||
metavar='<shell>',
|
metavar='<shell>',
|
||||||
choices=sorted(self._formatters.names()),
|
choices=sorted(self._formatters.names()),
|
||||||
help="Shell being used. Use none for data only (default: bash)"
|
help="Shell being used. Use none for data only (default: bash)",
|
||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -194,9 +203,9 @@ class CompleteCommand(command.Command):
|
|||||||
cmd_factory, cmd_name, search_args = the_cmd
|
cmd_factory, cmd_name, search_args = the_cmd
|
||||||
cmd = cmd_factory(self.app, search_args)
|
cmd = cmd_factory(self.app, search_args)
|
||||||
if self.app.interactive_mode:
|
if self.app.interactive_mode:
|
||||||
full_name = (cmd_name)
|
full_name = cmd_name
|
||||||
else:
|
else:
|
||||||
full_name = (' '.join([self.app.NAME, cmd_name]))
|
full_name = ' '.join([self.app.NAME, cmd_name])
|
||||||
cmd_parser = cmd.get_parser(full_name)
|
cmd_parser = cmd.get_parser(full_name)
|
||||||
return cmd_parser._get_optional_actions()
|
return cmd_parser._get_optional_actions()
|
||||||
|
|
||||||
|
@ -21,12 +21,12 @@ from . import command
|
|||||||
|
|
||||||
|
|
||||||
class DisplayCommandBase(command.Command, metaclass=abc.ABCMeta):
|
class DisplayCommandBase(command.Command, metaclass=abc.ABCMeta):
|
||||||
"""Command base class for displaying data about a single object.
|
"""Command base class for displaying data about a single object."""
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, app, app_args, cmd_name=None):
|
def __init__(self, app, app_args, cmd_name=None):
|
||||||
super(DisplayCommandBase, self).__init__(app, app_args,
|
super(DisplayCommandBase, self).__init__(
|
||||||
cmd_name=cmd_name)
|
app, app_args, cmd_name=cmd_name
|
||||||
|
)
|
||||||
self._formatter_plugins = self._load_formatter_plugins()
|
self._formatter_plugins = self._load_formatter_plugins()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -58,7 +58,8 @@ class DisplayCommandBase(command.Command, metaclass=abc.ABCMeta):
|
|||||||
if formatter_default not in formatter_choices:
|
if formatter_default not in formatter_choices:
|
||||||
formatter_default = formatter_choices[0]
|
formatter_default = formatter_choices[0]
|
||||||
formatter_group.add_argument(
|
formatter_group.add_argument(
|
||||||
'-f', '--format',
|
'-f',
|
||||||
|
'--format',
|
||||||
dest='formatter',
|
dest='formatter',
|
||||||
action='store',
|
action='store',
|
||||||
choices=formatter_choices,
|
choices=formatter_choices,
|
||||||
@ -66,13 +67,14 @@ class DisplayCommandBase(command.Command, metaclass=abc.ABCMeta):
|
|||||||
help='the output format, defaults to %s' % formatter_default,
|
help='the output format, defaults to %s' % formatter_default,
|
||||||
)
|
)
|
||||||
formatter_group.add_argument(
|
formatter_group.add_argument(
|
||||||
'-c', '--column',
|
'-c',
|
||||||
|
'--column',
|
||||||
action='append',
|
action='append',
|
||||||
default=[],
|
default=[],
|
||||||
dest='columns',
|
dest='columns',
|
||||||
metavar='COLUMN',
|
metavar='COLUMN',
|
||||||
help='specify the column(s) to include, can be '
|
help='specify the column(s) to include, can be '
|
||||||
'repeated to show multiple columns',
|
'repeated to show multiple columns',
|
||||||
)
|
)
|
||||||
for formatter in self._formatter_plugins:
|
for formatter in self._formatter_plugins:
|
||||||
formatter.obj.add_argument_group(parser)
|
formatter.obj.add_argument_group(parser)
|
||||||
@ -99,24 +101,27 @@ class DisplayCommandBase(command.Command, metaclass=abc.ABCMeta):
|
|||||||
columns_to_include = column_names
|
columns_to_include = column_names
|
||||||
selector = None
|
selector = None
|
||||||
else:
|
else:
|
||||||
columns_to_include = [c for c in column_names
|
columns_to_include = [
|
||||||
if c in parsed_args.columns]
|
c for c in column_names if c in parsed_args.columns
|
||||||
|
]
|
||||||
if not columns_to_include:
|
if not columns_to_include:
|
||||||
raise ValueError('No recognized column names in %s. '
|
raise ValueError(
|
||||||
'Recognized columns are %s.' %
|
'No recognized column names in %s. '
|
||||||
(str(parsed_args.columns), str(column_names)))
|
'Recognized columns are %s.'
|
||||||
|
% (str(parsed_args.columns), str(column_names))
|
||||||
|
)
|
||||||
|
|
||||||
# Set up argument to compress()
|
# Set up argument to compress()
|
||||||
selector = [(c in columns_to_include)
|
selector = [(c in columns_to_include) for c in column_names]
|
||||||
for c in column_names]
|
|
||||||
return columns_to_include, selector
|
return columns_to_include, selector
|
||||||
|
|
||||||
def run(self, parsed_args):
|
def run(self, parsed_args):
|
||||||
parsed_args = self._run_before_hooks(parsed_args)
|
parsed_args = self._run_before_hooks(parsed_args)
|
||||||
self.formatter = self._formatter_plugins[parsed_args.formatter].obj
|
self.formatter = self._formatter_plugins[parsed_args.formatter].obj
|
||||||
column_names, data = self.take_action(parsed_args)
|
column_names, data = self.take_action(parsed_args)
|
||||||
column_names, data = self._run_after_hooks(parsed_args,
|
column_names, data = self._run_after_hooks(
|
||||||
(column_names, data))
|
parsed_args, (column_names, data)
|
||||||
|
)
|
||||||
self.produce_output(parsed_args, column_names, data)
|
self.produce_output(parsed_args, column_names, data)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import abc
|
|||||||
|
|
||||||
|
|
||||||
class Formatter(object, metaclass=abc.ABCMeta):
|
class Formatter(object, metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def add_argument_group(self, parser):
|
def add_argument_group(self, parser):
|
||||||
"""Add any options to the argument parser.
|
"""Add any options to the argument parser.
|
||||||
@ -27,8 +26,7 @@ class Formatter(object, metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
|
|
||||||
class ListFormatter(Formatter, metaclass=abc.ABCMeta):
|
class ListFormatter(Formatter, metaclass=abc.ABCMeta):
|
||||||
"""Base class for formatters that know how to deal with multiple objects.
|
"""Base class for formatters that know how to deal with multiple objects."""
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def emit_list(self, column_names, data, stdout, parsed_args):
|
def emit_list(self, column_names, data, stdout, parsed_args):
|
||||||
@ -50,8 +48,7 @@ class ListFormatter(Formatter, metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
|
|
||||||
class SingleFormatter(Formatter, metaclass=abc.ABCMeta):
|
class SingleFormatter(Formatter, metaclass=abc.ABCMeta):
|
||||||
"""Base class for formatters that work with single objects.
|
"""Base class for formatters that work with single objects."""
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def emit_one(self, column_names, data, stdout, parsed_args):
|
def emit_one(self, column_names, data, stdout, parsed_args):
|
||||||
|
@ -21,7 +21,6 @@ from cliff import columns
|
|||||||
|
|
||||||
|
|
||||||
class CSVLister(ListFormatter):
|
class CSVLister(ListFormatter):
|
||||||
|
|
||||||
QUOTE_MODES = {
|
QUOTE_MODES = {
|
||||||
'all': csv.QUOTE_ALL,
|
'all': csv.QUOTE_ALL,
|
||||||
'minimal': csv.QUOTE_MINIMAL,
|
'minimal': csv.QUOTE_MINIMAL,
|
||||||
@ -50,9 +49,13 @@ class CSVLister(ListFormatter):
|
|||||||
writer.writerow(column_names)
|
writer.writerow(column_names)
|
||||||
for row in data:
|
for row in data:
|
||||||
writer.writerow(
|
writer.writerow(
|
||||||
[(str(c.machine_readable())
|
[
|
||||||
if isinstance(c, columns.FormattableColumn)
|
(
|
||||||
else c)
|
str(c.machine_readable())
|
||||||
for c in row]
|
if isinstance(c, columns.FormattableColumn)
|
||||||
|
else c
|
||||||
|
)
|
||||||
|
for c in row
|
||||||
|
]
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -20,24 +20,27 @@ from cliff import columns
|
|||||||
|
|
||||||
|
|
||||||
class JSONFormatter(base.ListFormatter, base.SingleFormatter):
|
class JSONFormatter(base.ListFormatter, base.SingleFormatter):
|
||||||
|
|
||||||
def add_argument_group(self, parser):
|
def add_argument_group(self, parser):
|
||||||
group = parser.add_argument_group(title='json formatter')
|
group = parser.add_argument_group(title='json formatter')
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
'--noindent',
|
'--noindent',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
dest='noindent',
|
dest='noindent',
|
||||||
help='whether to disable indenting the JSON'
|
help='whether to disable indenting the JSON',
|
||||||
)
|
)
|
||||||
|
|
||||||
def emit_list(self, column_names, data, stdout, parsed_args):
|
def emit_list(self, column_names, data, stdout, parsed_args):
|
||||||
items = []
|
items = []
|
||||||
for item in data:
|
for item in data:
|
||||||
items.append(
|
items.append(
|
||||||
{n: (i.machine_readable()
|
{
|
||||||
if isinstance(i, columns.FormattableColumn)
|
n: (
|
||||||
else i)
|
i.machine_readable()
|
||||||
for n, i in zip(column_names, item)}
|
if isinstance(i, columns.FormattableColumn)
|
||||||
|
else i
|
||||||
|
)
|
||||||
|
for n, i in zip(column_names, item)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
indent = None if parsed_args.noindent else 2
|
indent = None if parsed_args.noindent else 2
|
||||||
json.dump(items, stdout, indent=indent)
|
json.dump(items, stdout, indent=indent)
|
||||||
@ -45,9 +48,11 @@ class JSONFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
|
|
||||||
def emit_one(self, column_names, data, stdout, parsed_args):
|
def emit_one(self, column_names, data, stdout, parsed_args):
|
||||||
one = {
|
one = {
|
||||||
n: (i.machine_readable()
|
n: (
|
||||||
|
i.machine_readable()
|
||||||
if isinstance(i, columns.FormattableColumn)
|
if isinstance(i, columns.FormattableColumn)
|
||||||
else i)
|
else i
|
||||||
|
)
|
||||||
for n, i in zip(column_names, data)
|
for n, i in zip(column_names, data)
|
||||||
}
|
}
|
||||||
indent = None if parsed_args.noindent else 2
|
indent = None if parsed_args.noindent else 2
|
||||||
|
@ -20,7 +20,6 @@ import argparse
|
|||||||
|
|
||||||
|
|
||||||
class ShellFormatter(base.SingleFormatter):
|
class ShellFormatter(base.SingleFormatter):
|
||||||
|
|
||||||
def add_argument_group(self, parser):
|
def add_argument_group(self, parser):
|
||||||
group = parser.add_argument_group(
|
group = parser.add_argument_group(
|
||||||
title='shell formatter',
|
title='shell formatter',
|
||||||
@ -43,15 +42,15 @@ class ShellFormatter(base.SingleFormatter):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def emit_one(self, column_names, data, stdout, parsed_args):
|
def emit_one(self, column_names, data, stdout, parsed_args):
|
||||||
variable_names = [c.lower().replace(' ', '_')
|
variable_names = [c.lower().replace(' ', '_') for c in column_names]
|
||||||
for c in column_names
|
|
||||||
]
|
|
||||||
desired_columns = parsed_args.variables
|
desired_columns = parsed_args.variables
|
||||||
for name, value in zip(variable_names, data):
|
for name, value in zip(variable_names, data):
|
||||||
if name in desired_columns or not desired_columns:
|
if name in desired_columns or not desired_columns:
|
||||||
value = (str(value.machine_readable())
|
value = (
|
||||||
if isinstance(value, columns.FormattableColumn)
|
str(value.machine_readable())
|
||||||
else value)
|
if isinstance(value, columns.FormattableColumn)
|
||||||
|
else value
|
||||||
|
)
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
value = value.replace('"', '\\"')
|
value = value.replace('"', '\\"')
|
||||||
if isinstance(name, str):
|
if isinstance(name, str):
|
||||||
|
@ -42,7 +42,6 @@ def _do_fit(fit_width):
|
|||||||
|
|
||||||
|
|
||||||
class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
||||||
|
|
||||||
ALIGNMENTS = {
|
ALIGNMENTS = {
|
||||||
int: 'r',
|
int: 'r',
|
||||||
str: 'l',
|
str: 'l',
|
||||||
@ -56,18 +55,22 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
metavar='<integer>',
|
metavar='<integer>',
|
||||||
default=int(os.environ.get('CLIFF_MAX_TERM_WIDTH', 0)),
|
default=int(os.environ.get('CLIFF_MAX_TERM_WIDTH', 0)),
|
||||||
type=int,
|
type=int,
|
||||||
help=('Maximum display width, <1 to disable. You can also '
|
help=(
|
||||||
'use the CLIFF_MAX_TERM_WIDTH environment variable, '
|
'Maximum display width, <1 to disable. You can also '
|
||||||
'but the parameter takes precedence.'),
|
'use the CLIFF_MAX_TERM_WIDTH environment variable, '
|
||||||
|
'but the parameter takes precedence.'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
'--fit-width',
|
'--fit-width',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
default=bool(int(os.environ.get('CLIFF_FIT_WIDTH', 0))),
|
default=bool(int(os.environ.get('CLIFF_FIT_WIDTH', 0))),
|
||||||
help=('Fit the table to the display width. '
|
help=(
|
||||||
'Implied if --max-width greater than 0. '
|
'Fit the table to the display width. '
|
||||||
'Set the environment variable CLIFF_FIT_WIDTH=1 '
|
'Implied if --max-width greater than 0. '
|
||||||
'to always enable'),
|
'Set the environment variable CLIFF_FIT_WIDTH=1 '
|
||||||
|
'to always enable'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
'--print-empty',
|
'--print-empty',
|
||||||
@ -109,8 +112,8 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
# preference to wrapping columns smaller than 8 characters.
|
# preference to wrapping columns smaller than 8 characters.
|
||||||
min_width = 8
|
min_width = 8
|
||||||
self._assign_max_widths(
|
self._assign_max_widths(
|
||||||
x, int(parsed_args.max_width), min_width,
|
x, int(parsed_args.max_width), min_width, parsed_args.fit_width
|
||||||
parsed_args.fit_width)
|
)
|
||||||
|
|
||||||
formatted = x.get_string()
|
formatted = x.get_string()
|
||||||
stdout.write(formatted)
|
stdout.write(formatted)
|
||||||
@ -118,8 +121,9 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def emit_one(self, column_names, data, stdout, parsed_args):
|
def emit_one(self, column_names, data, stdout, parsed_args):
|
||||||
x = prettytable.PrettyTable(field_names=('Field', 'Value'),
|
x = prettytable.PrettyTable(
|
||||||
print_empty=False)
|
field_names=('Field', 'Value'), print_empty=False
|
||||||
|
)
|
||||||
x.padding_width = 1
|
x.padding_width = 1
|
||||||
# Align all columns left because the values are
|
# Align all columns left because the values are
|
||||||
# not all the same type.
|
# not all the same type.
|
||||||
@ -134,8 +138,8 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
# the Field column readable.
|
# the Field column readable.
|
||||||
min_width = 16
|
min_width = 16
|
||||||
self._assign_max_widths(
|
self._assign_max_widths(
|
||||||
x, int(parsed_args.max_width), min_width,
|
x, int(parsed_args.max_width), min_width, parsed_args.fit_width
|
||||||
parsed_args.fit_width)
|
)
|
||||||
|
|
||||||
formatted = x.get_string()
|
formatted = x.get_string()
|
||||||
stdout.write(formatted)
|
stdout.write(formatted)
|
||||||
@ -144,7 +148,6 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _field_widths(field_names, first_line):
|
def _field_widths(field_names, first_line):
|
||||||
|
|
||||||
# use the first line +----+-------+ to infer column widths
|
# use the first line +----+-------+ to infer column widths
|
||||||
# accounting for padding and dividers
|
# accounting for padding and dividers
|
||||||
widths = [max(0, len(i) - 2) for i in first_line.split('+')[1:-1]]
|
widths = [max(0, len(i) - 2) for i in first_line.split('+')[1:-1]]
|
||||||
@ -164,8 +167,9 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
return usable_total_width, optimal_width
|
return usable_total_width, optimal_width
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _build_shrink_fields(usable_total_width, optimal_width,
|
def _build_shrink_fields(
|
||||||
field_widths, field_names):
|
usable_total_width, optimal_width, field_widths, field_names
|
||||||
|
):
|
||||||
shrink_fields = []
|
shrink_fields = []
|
||||||
shrink_remaining = usable_total_width
|
shrink_remaining = usable_total_width
|
||||||
for field in field_names:
|
for field in field_names:
|
||||||
@ -204,12 +208,14 @@ class TableFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
return
|
return
|
||||||
|
|
||||||
usable_total_width, optimal_width = TableFormatter._width_info(
|
usable_total_width, optimal_width = TableFormatter._width_info(
|
||||||
term_width, field_count)
|
term_width, field_count
|
||||||
|
)
|
||||||
|
|
||||||
field_widths = TableFormatter._field_widths(x.field_names, first_line)
|
field_widths = TableFormatter._field_widths(x.field_names, first_line)
|
||||||
|
|
||||||
shrink_fields, shrink_remaining = TableFormatter._build_shrink_fields(
|
shrink_fields, shrink_remaining = TableFormatter._build_shrink_fields(
|
||||||
usable_total_width, optimal_width, field_widths, x.field_names)
|
usable_total_width, optimal_width, field_widths, x.field_names
|
||||||
|
)
|
||||||
|
|
||||||
shrink_to = shrink_remaining // len(shrink_fields)
|
shrink_to = shrink_remaining // len(shrink_fields)
|
||||||
# make all shrinkable fields size shrink_to apart from the last one
|
# make all shrinkable fields size shrink_to apart from the last one
|
||||||
|
@ -18,7 +18,6 @@ from cliff import columns
|
|||||||
|
|
||||||
|
|
||||||
class ValueFormatter(base.ListFormatter, base.SingleFormatter):
|
class ValueFormatter(base.ListFormatter, base.SingleFormatter):
|
||||||
|
|
||||||
def add_argument_group(self, parser):
|
def add_argument_group(self, parser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -26,17 +25,25 @@ class ValueFormatter(base.ListFormatter, base.SingleFormatter):
|
|||||||
for row in data:
|
for row in data:
|
||||||
stdout.write(
|
stdout.write(
|
||||||
' '.join(
|
' '.join(
|
||||||
str(c.machine_readable()
|
str(
|
||||||
|
c.machine_readable()
|
||||||
if isinstance(c, columns.FormattableColumn)
|
if isinstance(c, columns.FormattableColumn)
|
||||||
else c)
|
else c
|
||||||
for c in row) + '\n')
|
)
|
||||||
|
for c in row
|
||||||
|
)
|
||||||
|
+ '\n'
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
def emit_one(self, column_names, data, stdout, parsed_args):
|
def emit_one(self, column_names, data, stdout, parsed_args):
|
||||||
for value in data:
|
for value in data:
|
||||||
stdout.write('%s\n' % str(
|
stdout.write(
|
||||||
value.machine_readable()
|
'%s\n'
|
||||||
if isinstance(value, columns.FormattableColumn)
|
% str(
|
||||||
else value)
|
value.machine_readable()
|
||||||
|
if isinstance(value, columns.FormattableColumn)
|
||||||
|
else value
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -29,7 +29,6 @@ def _yaml_friendly(value):
|
|||||||
|
|
||||||
|
|
||||||
class YAMLFormatter(base.ListFormatter, base.SingleFormatter):
|
class YAMLFormatter(base.ListFormatter, base.SingleFormatter):
|
||||||
|
|
||||||
def add_argument_group(self, parser):
|
def add_argument_group(self, parser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -30,13 +30,13 @@ class HelpExit(SystemExit):
|
|||||||
|
|
||||||
|
|
||||||
class HelpAction(argparse.Action):
|
class HelpAction(argparse.Action):
|
||||||
|
|
||||||
"""Provide a custom action so the -h and --help options
|
"""Provide a custom action so the -h and --help options
|
||||||
to the main app will print a list of the commands.
|
to the main app will print a list of the commands.
|
||||||
|
|
||||||
The commands are determined by checking the CommandManager
|
The commands are determined by checking the CommandManager
|
||||||
instance, passed in as the "default" value for the action.
|
instance, passed in as the "default" value for the action.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
app = self.default
|
app = self.default
|
||||||
pager = autopage.argparse.help_pager(app.stdout)
|
pager = autopage.argparse.help_pager(app.stdout)
|
||||||
@ -90,15 +90,15 @@ class HelpAction(argparse.Action):
|
|||||||
|
|
||||||
|
|
||||||
class HelpCommand(command.Command):
|
class HelpCommand(command.Command):
|
||||||
"""print detailed help for another command
|
"""print detailed help for another command"""
|
||||||
"""
|
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(HelpCommand, self).get_parser(prog_name)
|
parser = super(HelpCommand, self).get_parser(prog_name)
|
||||||
parser.add_argument('cmd',
|
parser.add_argument(
|
||||||
nargs='*',
|
'cmd',
|
||||||
help='name of the command',
|
nargs='*',
|
||||||
)
|
help='name of the command',
|
||||||
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
@ -111,9 +111,11 @@ class HelpCommand(command.Command):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
# Did not find an exact match
|
# Did not find an exact match
|
||||||
cmd = parsed_args.cmd[0]
|
cmd = parsed_args.cmd[0]
|
||||||
fuzzy_matches = [k[0] for k in self.app.command_manager
|
fuzzy_matches = [
|
||||||
if k[0].startswith(cmd)
|
k[0]
|
||||||
]
|
for k in self.app.command_manager
|
||||||
|
if k[0].startswith(cmd)
|
||||||
|
]
|
||||||
if not fuzzy_matches:
|
if not fuzzy_matches:
|
||||||
raise
|
raise
|
||||||
self.app.stdout.write('Command "%s" matches:\n' % cmd)
|
self.app.stdout.write('Command "%s" matches:\n' % cmd)
|
||||||
@ -125,15 +127,17 @@ class HelpCommand(command.Command):
|
|||||||
if 'cmd_name' in inspect.getfullargspec(cmd_factory.__init__).args:
|
if 'cmd_name' in inspect.getfullargspec(cmd_factory.__init__).args:
|
||||||
kwargs['cmd_name'] = cmd_name
|
kwargs['cmd_name'] = cmd_name
|
||||||
cmd = cmd_factory(self.app, self.app_args, **kwargs)
|
cmd = cmd_factory(self.app, self.app_args, **kwargs)
|
||||||
full_name = (cmd_name
|
full_name = (
|
||||||
if self.app.interactive_mode
|
cmd_name
|
||||||
else ' '.join([self.app.NAME, cmd_name])
|
if self.app.interactive_mode
|
||||||
)
|
else ' '.join([self.app.NAME, cmd_name])
|
||||||
|
)
|
||||||
cmd_parser = cmd.get_parser(full_name)
|
cmd_parser = cmd.get_parser(full_name)
|
||||||
pager = autopage.argparse.help_pager(self.app.stdout)
|
pager = autopage.argparse.help_pager(self.app.stdout)
|
||||||
with pager as out:
|
with pager as out:
|
||||||
autopage.argparse.use_color_for_parser(cmd_parser,
|
autopage.argparse.use_color_for_parser(
|
||||||
pager.to_terminal())
|
cmd_parser, pager.to_terminal()
|
||||||
|
)
|
||||||
cmd_parser.print_help(out)
|
cmd_parser.print_help(out)
|
||||||
else:
|
else:
|
||||||
action = HelpAction(None, None, default=self.app)
|
action = HelpAction(None, None, default=self.app)
|
||||||
|
@ -42,8 +42,9 @@ class InteractiveApp(cmd2.Cmd):
|
|||||||
doc_header = "Shell commands (type help <topic>):"
|
doc_header = "Shell commands (type help <topic>):"
|
||||||
app_cmd_header = "Application commands (type help <topic>):"
|
app_cmd_header = "Application commands (type help <topic>):"
|
||||||
|
|
||||||
def __init__(self, parent_app, command_manager, stdin, stdout,
|
def __init__(
|
||||||
errexit=False):
|
self, parent_app, command_manager, stdin, stdout, errexit=False
|
||||||
|
):
|
||||||
self.parent_app = parent_app
|
self.parent_app = parent_app
|
||||||
if not hasattr(sys.stdin, 'isatty') or sys.stdin.isatty():
|
if not hasattr(sys.stdin, 'isatty') or sys.stdin.isatty():
|
||||||
self.prompt = '(%s) ' % parent_app.NAME
|
self.prompt = '(%s) ' % parent_app.NAME
|
||||||
@ -117,8 +118,9 @@ class InteractiveApp(cmd2.Cmd):
|
|||||||
method_name = '_'.join(
|
method_name = '_'.join(
|
||||||
itertools.chain(
|
itertools.chain(
|
||||||
['do'],
|
['do'],
|
||||||
itertools.takewhile(lambda x: not x.startswith('-'),
|
itertools.takewhile(
|
||||||
arg_parts)
|
lambda x: not x.startswith('-'), arg_parts
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# Have the command manager version of the help
|
# Have the command manager version of the help
|
||||||
@ -160,10 +162,9 @@ class InteractiveApp(cmd2.Cmd):
|
|||||||
# Override the base class version to filter out
|
# Override the base class version to filter out
|
||||||
# things that look like they should be hidden
|
# things that look like they should be hidden
|
||||||
# from the user.
|
# from the user.
|
||||||
return [n
|
return [
|
||||||
for n in cmd2.Cmd.get_names(self)
|
n for n in cmd2.Cmd.get_names(self) if not n.startswith('do__')
|
||||||
if not n.startswith('do__')
|
]
|
||||||
]
|
|
||||||
|
|
||||||
def precmd(self, statement):
|
def precmd(self, statement):
|
||||||
"""Hook method executed just before the command is executed by
|
"""Hook method executed just before the command is executed by
|
||||||
|
@ -83,7 +83,8 @@ class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
|
|||||||
def produce_output(self, parsed_args, column_names, data):
|
def produce_output(self, parsed_args, column_names, data):
|
||||||
if parsed_args.sort_columns and self.need_sort_by_cliff:
|
if parsed_args.sort_columns and self.need_sort_by_cliff:
|
||||||
indexes = [
|
indexes = [
|
||||||
column_names.index(c) for c in parsed_args.sort_columns
|
column_names.index(c)
|
||||||
|
for c in parsed_args.sort_columns
|
||||||
if c in column_names
|
if c in column_names
|
||||||
]
|
]
|
||||||
reverse = parsed_args.sort_direction == 'desc'
|
reverse = parsed_args.sort_direction == 'desc'
|
||||||
@ -97,7 +98,8 @@ class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
|
|||||||
# returns from the 'is None' check on the two values are
|
# returns from the 'is None' check on the two values are
|
||||||
# the same, i.e. both None or both not-None
|
# the same, i.e. both None or both not-None
|
||||||
data = sorted(
|
data = sorted(
|
||||||
data, key=lambda k: (k[index] is None, k[index]),
|
data,
|
||||||
|
key=lambda k: (k[index] is None, k[index]),
|
||||||
reverse=reverse,
|
reverse=reverse,
|
||||||
)
|
)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
@ -108,7 +110,8 @@ class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
|
|||||||
)
|
)
|
||||||
|
|
||||||
columns_to_include, selector = self._generate_columns_and_selector(
|
columns_to_include, selector = self._generate_columns_and_selector(
|
||||||
parsed_args, column_names,
|
parsed_args,
|
||||||
|
column_names,
|
||||||
)
|
)
|
||||||
if selector:
|
if selector:
|
||||||
# Generator expression to only return the parts of a row
|
# Generator expression to only return the parts of a row
|
||||||
@ -120,7 +123,10 @@ class Lister(display.DisplayCommandBase, metaclass=abc.ABCMeta):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.formatter.emit_list(
|
self.formatter.emit_list(
|
||||||
columns_to_include, data, self.app.stdout, parsed_args,
|
columns_to_include,
|
||||||
|
data,
|
||||||
|
self.app.stdout,
|
||||||
|
parsed_args,
|
||||||
)
|
)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
@ -18,8 +18,7 @@ from . import display
|
|||||||
|
|
||||||
|
|
||||||
class ShowOne(display.DisplayCommandBase, metaclass=abc.ABCMeta):
|
class ShowOne(display.DisplayCommandBase, metaclass=abc.ABCMeta):
|
||||||
"""Command base class for displaying data about a single object.
|
"""Command base class for displaying data about a single object."""
|
||||||
"""
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def formatter_namespace(self):
|
def formatter_namespace(self):
|
||||||
@ -37,13 +36,13 @@ class ShowOne(display.DisplayCommandBase, metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
def produce_output(self, parsed_args, column_names, data):
|
def produce_output(self, parsed_args, column_names, data):
|
||||||
(columns_to_include, selector) = self._generate_columns_and_selector(
|
(columns_to_include, selector) = self._generate_columns_and_selector(
|
||||||
parsed_args, column_names)
|
parsed_args, column_names
|
||||||
|
)
|
||||||
if selector:
|
if selector:
|
||||||
data = list(self._compress_iterable(data, selector))
|
data = list(self._compress_iterable(data, selector))
|
||||||
self.formatter.emit_one(columns_to_include,
|
self.formatter.emit_one(
|
||||||
data,
|
columns_to_include, data, self.app.stdout, parsed_args
|
||||||
self.app.stdout,
|
)
|
||||||
parsed_args)
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def dict2columns(self, data):
|
def dict2columns(self, data):
|
||||||
|
@ -46,7 +46,8 @@ def _format_description(parser):
|
|||||||
information in their help messages if they so choose.
|
information in their help messages if they so choose.
|
||||||
"""
|
"""
|
||||||
for line in statemachine.string2lines(
|
for line in statemachine.string2lines(
|
||||||
parser.description, tab_width=4, convert_whitespace=True):
|
parser.description, tab_width=4, convert_whitespace=True
|
||||||
|
):
|
||||||
yield line
|
yield line
|
||||||
|
|
||||||
|
|
||||||
@ -64,12 +65,15 @@ def _format_usage(parser):
|
|||||||
# becomes ['--format <FORMAT>'] and not ['--format', '<FORMAT>'].
|
# becomes ['--format <FORMAT>'] and not ['--format', '<FORMAT>'].
|
||||||
# Yes, they really do use regexes to break apart and rewrap their help
|
# Yes, they really do use regexes to break apart and rewrap their help
|
||||||
# string. Don't ask me why.
|
# string. Don't ask me why.
|
||||||
part_regexp = re.compile(r"""
|
part_regexp = re.compile(
|
||||||
|
r"""
|
||||||
\(.*?\)+ |
|
\(.*?\)+ |
|
||||||
\[.*?\]+ |
|
\[.*?\]+ |
|
||||||
(?:(?:-\w|--\w+(?:-\w+)*)(?:\s+<?\w[\w-]*>?)?) |
|
(?:(?:-\w|--\w+(?:-\w+)*)(?:\s+<?\w[\w-]*>?)?) |
|
||||||
\S+
|
\S+
|
||||||
""", re.VERBOSE)
|
""",
|
||||||
|
re.VERBOSE,
|
||||||
|
)
|
||||||
|
|
||||||
opt_usage = fmt._format_actions_usage(optionals, groups)
|
opt_usage = fmt._format_actions_usage(optionals, groups)
|
||||||
pos_usage = fmt._format_actions_usage(positionals, groups)
|
pos_usage = fmt._format_actions_usage(positionals, groups)
|
||||||
@ -91,7 +95,8 @@ def _format_epilog(parser):
|
|||||||
information in their help messages if they so choose.
|
information in their help messages if they so choose.
|
||||||
"""
|
"""
|
||||||
for line in statemachine.string2lines(
|
for line in statemachine.string2lines(
|
||||||
parser.epilog, tab_width=4, convert_whitespace=True):
|
parser.epilog, tab_width=4, convert_whitespace=True
|
||||||
|
):
|
||||||
yield line
|
yield line
|
||||||
|
|
||||||
|
|
||||||
@ -104,11 +109,13 @@ def _format_positional_action(action):
|
|||||||
# the 'option' directive dictates that only option argument names should be
|
# the 'option' directive dictates that only option argument names should be
|
||||||
# surrounded by angle brackets
|
# surrounded by angle brackets
|
||||||
yield '.. option:: {}'.format(
|
yield '.. option:: {}'.format(
|
||||||
(action.metavar or action.dest).strip('<>[]() '))
|
(action.metavar or action.dest).strip('<>[]() ')
|
||||||
|
)
|
||||||
if action.help:
|
if action.help:
|
||||||
yield ''
|
yield ''
|
||||||
for line in statemachine.string2lines(
|
for line in statemachine.string2lines(
|
||||||
action.help, tab_width=4, convert_whitespace=True):
|
action.help, tab_width=4, convert_whitespace=True
|
||||||
|
):
|
||||||
yield _indent(line)
|
yield _indent(line)
|
||||||
|
|
||||||
|
|
||||||
@ -123,15 +130,17 @@ def _format_optional_action(action):
|
|||||||
# TODO(stephenfin): At some point, we may wish to provide more
|
# TODO(stephenfin): At some point, we may wish to provide more
|
||||||
# information about the options themselves, for example, if nargs is
|
# information about the options themselves, for example, if nargs is
|
||||||
# specified
|
# specified
|
||||||
option_strings = [' '.join(
|
option_strings = [
|
||||||
[x, action.metavar or '<{}>'.format(action.dest.upper())])
|
' '.join([x, action.metavar or '<{}>'.format(action.dest.upper())])
|
||||||
for x in action.option_strings]
|
for x in action.option_strings
|
||||||
|
]
|
||||||
yield '.. option:: {}'.format(', '.join(option_strings))
|
yield '.. option:: {}'.format(', '.join(option_strings))
|
||||||
|
|
||||||
if action.help:
|
if action.help:
|
||||||
yield ''
|
yield ''
|
||||||
for line in statemachine.string2lines(
|
for line in statemachine.string2lines(
|
||||||
action.help, tab_width=4, convert_whitespace=True):
|
action.help, tab_width=4, convert_whitespace=True
|
||||||
|
):
|
||||||
yield _indent(line)
|
yield _indent(line)
|
||||||
|
|
||||||
|
|
||||||
@ -220,8 +229,9 @@ class AutoprogramCliffDirective(rst.Directive):
|
|||||||
def _get_ignored_opts(self):
|
def _get_ignored_opts(self):
|
||||||
global_ignored = self.env.config.autoprogram_cliff_ignored
|
global_ignored = self.env.config.autoprogram_cliff_ignored
|
||||||
local_ignored = self.options.get('ignored', '')
|
local_ignored = self.options.get('ignored', '')
|
||||||
local_ignored = [x.strip() for x in local_ignored.split(',')
|
local_ignored = [
|
||||||
if x.strip()]
|
x.strip() for x in local_ignored.split(',') if x.strip()
|
||||||
|
]
|
||||||
return list(set(global_ignored + local_ignored))
|
return list(set(global_ignored + local_ignored))
|
||||||
|
|
||||||
def _drop_ignored_options(self, parser, ignored_opts):
|
def _drop_ignored_options(self, parser, ignored_opts):
|
||||||
@ -256,9 +266,10 @@ class AutoprogramCliffDirective(rst.Directive):
|
|||||||
# find_command expects the value of argv so split to emulate that
|
# find_command expects the value of argv so split to emulate that
|
||||||
return manager.find_command(command_name.split())[0]
|
return manager.find_command(command_name.split())[0]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise self.error('"{}" is not a valid command in the "{}" '
|
raise self.error(
|
||||||
'namespace'.format(
|
'"{}" is not a valid command in the "{}" '
|
||||||
command_name, manager.namespace))
|
'namespace'.format(command_name, manager.namespace)
|
||||||
|
)
|
||||||
|
|
||||||
def _load_commands(self):
|
def _load_commands(self):
|
||||||
# TODO(sfinucan): We should probably add this wildcarding functionality
|
# TODO(sfinucan): We should probably add this wildcarding functionality
|
||||||
@ -267,8 +278,11 @@ class AutoprogramCliffDirective(rst.Directive):
|
|||||||
command_pattern = self.options.get('command')
|
command_pattern = self.options.get('command')
|
||||||
manager = commandmanager.CommandManager(self.arguments[0])
|
manager = commandmanager.CommandManager(self.arguments[0])
|
||||||
if command_pattern:
|
if command_pattern:
|
||||||
commands = [x for x in manager.commands
|
commands = [
|
||||||
if fnmatch.fnmatch(x, command_pattern)]
|
x
|
||||||
|
for x in manager.commands
|
||||||
|
if fnmatch.fnmatch(x, command_pattern)
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
commands = manager.commands.keys()
|
commands = manager.commands.keys()
|
||||||
|
|
||||||
@ -276,12 +290,15 @@ class AutoprogramCliffDirective(rst.Directive):
|
|||||||
msg = 'No commands found in the "{}" namespace'
|
msg = 'No commands found in the "{}" namespace'
|
||||||
if command_pattern:
|
if command_pattern:
|
||||||
msg += ' using the "{}" command name/pattern'
|
msg += ' using the "{}" command name/pattern'
|
||||||
msg += ('. Are you sure this is correct and the application being '
|
msg += (
|
||||||
'documented is installed?')
|
'. Are you sure this is correct and the application being '
|
||||||
|
'documented is installed?'
|
||||||
|
)
|
||||||
raise self.warning(msg.format(self.arguments[0], command_pattern))
|
raise self.warning(msg.format(self.arguments[0], command_pattern))
|
||||||
|
|
||||||
return dict((name, self._load_command(manager, name))
|
return dict(
|
||||||
for name in commands)
|
(name, self._load_command(manager, name)) for name in commands
|
||||||
|
)
|
||||||
|
|
||||||
def _generate_app_node(self, app, application_name):
|
def _generate_app_node(self, app, application_name):
|
||||||
ignored_opts = self._get_ignored_opts()
|
ignored_opts = self._get_ignored_opts()
|
||||||
@ -303,8 +320,9 @@ class AutoprogramCliffDirective(rst.Directive):
|
|||||||
# return [section.children]
|
# return [section.children]
|
||||||
return section.children
|
return section.children
|
||||||
|
|
||||||
def _generate_nodes_per_command(self, title, command_name, command_class,
|
def _generate_nodes_per_command(
|
||||||
ignored_opts):
|
self, title, command_name, command_class, ignored_opts
|
||||||
|
):
|
||||||
"""Generate the relevant Sphinx nodes.
|
"""Generate the relevant Sphinx nodes.
|
||||||
|
|
||||||
This doesn't bother using raw docutils nodes as they simply don't offer
|
This doesn't bother using raw docutils nodes as they simply don't offer
|
||||||
@ -324,7 +342,8 @@ class AutoprogramCliffDirective(rst.Directive):
|
|||||||
command = command_class(None, None)
|
command = command_class(None, None)
|
||||||
if not getattr(command, 'app_dist_name', None):
|
if not getattr(command, 'app_dist_name', None):
|
||||||
command.app_dist_name = (
|
command.app_dist_name = (
|
||||||
self.env.config.autoprogram_cliff_app_dist_name)
|
self.env.config.autoprogram_cliff_app_dist_name
|
||||||
|
)
|
||||||
parser = command.get_parser(command_name)
|
parser = command.get_parser(command_name)
|
||||||
ignored_opts = ignored_opts or []
|
ignored_opts = ignored_opts or []
|
||||||
|
|
||||||
@ -334,7 +353,8 @@ class AutoprogramCliffDirective(rst.Directive):
|
|||||||
'',
|
'',
|
||||||
nodes.title(text=title),
|
nodes.title(text=title),
|
||||||
ids=[nodes.make_id(title)],
|
ids=[nodes.make_id(title)],
|
||||||
names=[nodes.fully_normalize_name(title)])
|
names=[nodes.fully_normalize_name(title)],
|
||||||
|
)
|
||||||
|
|
||||||
source_name = '<{}>'.format(command.__class__.__name__)
|
source_name = '<{}>'.format(command.__class__.__name__)
|
||||||
result = statemachine.ViewList()
|
result = statemachine.ViewList()
|
||||||
@ -355,16 +375,21 @@ class AutoprogramCliffDirective(rst.Directive):
|
|||||||
if application_name:
|
if application_name:
|
||||||
command_name = ' '.join([application_name, command_name])
|
command_name = ' '.join([application_name, command_name])
|
||||||
|
|
||||||
output.extend(self._generate_nodes_per_command(
|
output.extend(
|
||||||
title, command_name, command_class, ignored_opts))
|
self._generate_nodes_per_command(
|
||||||
|
title, command_name, command_class, ignored_opts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.env = self.state.document.settings.env
|
self.env = self.state.document.settings.env
|
||||||
|
|
||||||
application_name = (self.options.get('application')
|
application_name = (
|
||||||
or self.env.config.autoprogram_cliff_application)
|
self.options.get('application')
|
||||||
|
or self.env.config.autoprogram_cliff_application
|
||||||
|
)
|
||||||
|
|
||||||
app = self._load_app()
|
app = self._load_app()
|
||||||
if app:
|
if app:
|
||||||
|
@ -18,7 +18,6 @@ import fixtures
|
|||||||
|
|
||||||
|
|
||||||
class TestBase(testtools.TestCase):
|
class TestBase(testtools.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestBase, self).setUp()
|
super(TestBase, self).setUp()
|
||||||
self._stdout_fixture = fixtures.StringStream('stdout')
|
self._stdout_fixture = fixtures.StringStream('stdout')
|
||||||
|
@ -19,7 +19,6 @@ from cliff import _argparse
|
|||||||
|
|
||||||
|
|
||||||
class TestArgparse(unittest.TestCase):
|
class TestArgparse(unittest.TestCase):
|
||||||
|
|
||||||
def test_argument_parser(self):
|
def test_argument_parser(self):
|
||||||
_argparse.ArgumentParser(conflict_handler='ignore')
|
_argparse.ArgumentParser(conflict_handler='ignore')
|
||||||
|
|
||||||
|
@ -48,32 +48,28 @@ def make_app(**kwargs):
|
|||||||
# Register a command that is interrrupted
|
# Register a command that is interrrupted
|
||||||
interrupt_command = mock.Mock(name='interrupt_command', spec=c_cmd.Command)
|
interrupt_command = mock.Mock(name='interrupt_command', spec=c_cmd.Command)
|
||||||
interrupt_command_inst = mock.Mock(spec=c_cmd.Command)
|
interrupt_command_inst = mock.Mock(spec=c_cmd.Command)
|
||||||
interrupt_command_inst.run = mock.Mock(
|
interrupt_command_inst.run = mock.Mock(side_effect=KeyboardInterrupt)
|
||||||
side_effect=KeyboardInterrupt
|
|
||||||
)
|
|
||||||
interrupt_command.return_value = interrupt_command_inst
|
interrupt_command.return_value = interrupt_command_inst
|
||||||
cmd_mgr.add_command('interrupt', interrupt_command)
|
cmd_mgr.add_command('interrupt', interrupt_command)
|
||||||
|
|
||||||
# Register a command that is interrrupted by a broken pipe
|
# Register a command that is interrrupted by a broken pipe
|
||||||
pipeclose_command = mock.Mock(name='pipeclose_command', spec=c_cmd.Command)
|
pipeclose_command = mock.Mock(name='pipeclose_command', spec=c_cmd.Command)
|
||||||
pipeclose_command_inst = mock.Mock(spec=c_cmd.Command)
|
pipeclose_command_inst = mock.Mock(spec=c_cmd.Command)
|
||||||
pipeclose_command_inst.run = mock.Mock(
|
pipeclose_command_inst.run = mock.Mock(side_effect=BrokenPipeError)
|
||||||
side_effect=BrokenPipeError
|
|
||||||
)
|
|
||||||
pipeclose_command.return_value = pipeclose_command_inst
|
pipeclose_command.return_value = pipeclose_command_inst
|
||||||
cmd_mgr.add_command('pipe-close', pipeclose_command)
|
cmd_mgr.add_command('pipe-close', pipeclose_command)
|
||||||
|
|
||||||
app = application.App('testing interactive mode',
|
app = application.App(
|
||||||
'1',
|
'testing interactive mode',
|
||||||
cmd_mgr,
|
'1',
|
||||||
stderr=mock.Mock(), # suppress warning messages
|
cmd_mgr,
|
||||||
**kwargs
|
stderr=mock.Mock(), # suppress warning messages
|
||||||
)
|
**kwargs
|
||||||
|
)
|
||||||
return app, command
|
return app, command
|
||||||
|
|
||||||
|
|
||||||
class TestInteractiveMode(base.TestBase):
|
class TestInteractiveMode(base.TestBase):
|
||||||
|
|
||||||
def test_no_args_triggers_interactive_mode(self):
|
def test_no_args_triggers_interactive_mode(self):
|
||||||
app, command = make_app()
|
app, command = make_app()
|
||||||
app.interact = mock.MagicMock(name='inspect')
|
app.interact = mock.MagicMock(name='inspect')
|
||||||
@ -110,7 +106,6 @@ class TestInteractiveMode(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestInitAndCleanup(base.TestBase):
|
class TestInitAndCleanup(base.TestBase):
|
||||||
|
|
||||||
def test_initialize_app(self):
|
def test_initialize_app(self):
|
||||||
app, command = make_app()
|
app, command = make_app()
|
||||||
app.initialize_app = mock.MagicMock(name='initialize_app')
|
app.initialize_app = mock.MagicMock(name='initialize_app')
|
||||||
@ -266,7 +261,6 @@ class TestInitAndCleanup(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestOptionParser(base.TestBase):
|
class TestOptionParser(base.TestBase):
|
||||||
|
|
||||||
def test_conflicting_option_should_throw(self):
|
def test_conflicting_option_should_throw(self):
|
||||||
class MyApp(application.App):
|
class MyApp(application.App):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -277,10 +271,12 @@ class TestOptionParser(base.TestBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def build_option_parser(self, description, version):
|
def build_option_parser(self, description, version):
|
||||||
parser = super(MyApp, self).build_option_parser(description,
|
parser = super(MyApp, self).build_option_parser(
|
||||||
version)
|
description, version
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-h', '--help',
|
'-h',
|
||||||
|
'--help',
|
||||||
default=self, # tricky
|
default=self, # tricky
|
||||||
help="Show help message and exit.",
|
help="Show help message and exit.",
|
||||||
)
|
)
|
||||||
@ -302,11 +298,11 @@ class TestOptionParser(base.TestBase):
|
|||||||
def build_option_parser(self, description, version):
|
def build_option_parser(self, description, version):
|
||||||
argparse_kwargs = {'conflict_handler': 'resolve'}
|
argparse_kwargs = {'conflict_handler': 'resolve'}
|
||||||
parser = super(MyApp, self).build_option_parser(
|
parser = super(MyApp, self).build_option_parser(
|
||||||
description,
|
description, version, argparse_kwargs=argparse_kwargs
|
||||||
version,
|
)
|
||||||
argparse_kwargs=argparse_kwargs)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-h', '--help',
|
'-h',
|
||||||
|
'--help',
|
||||||
default=self, # tricky
|
default=self, # tricky
|
||||||
help="Show help message and exit.",
|
help="Show help message and exit.",
|
||||||
)
|
)
|
||||||
@ -339,7 +335,8 @@ class TestOptionParser(base.TestBase):
|
|||||||
parser = super(MyApp, self).build_option_parser(
|
parser = super(MyApp, self).build_option_parser(
|
||||||
description,
|
description,
|
||||||
version,
|
version,
|
||||||
argparse_kwargs={'allow_abbrev': False})
|
argparse_kwargs={'allow_abbrev': False},
|
||||||
|
)
|
||||||
parser.add_argument('--endpoint')
|
parser.add_argument('--endpoint')
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -350,12 +347,12 @@ class TestOptionParser(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestHelpHandling(base.TestBase):
|
class TestHelpHandling(base.TestBase):
|
||||||
|
|
||||||
def _test_help(self, deferred_help):
|
def _test_help(self, deferred_help):
|
||||||
app, _ = make_app(deferred_help=deferred_help)
|
app, _ = make_app(deferred_help=deferred_help)
|
||||||
with mock.patch.object(app, 'initialize_app') as init:
|
with mock.patch.object(app, 'initialize_app') as init:
|
||||||
with mock.patch('cliff.help.HelpAction.__call__',
|
with mock.patch(
|
||||||
side_effect=SystemExit(0)) as helper:
|
'cliff.help.HelpAction.__call__', side_effect=SystemExit(0)
|
||||||
|
) as helper:
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
SystemExit,
|
SystemExit,
|
||||||
app.run,
|
app.run,
|
||||||
@ -372,8 +369,9 @@ class TestHelpHandling(base.TestBase):
|
|||||||
|
|
||||||
def _test_interrupted_help(self, deferred_help):
|
def _test_interrupted_help(self, deferred_help):
|
||||||
app, _ = make_app(deferred_help=deferred_help)
|
app, _ = make_app(deferred_help=deferred_help)
|
||||||
with mock.patch('cliff.help.HelpAction.__call__',
|
with mock.patch(
|
||||||
side_effect=KeyboardInterrupt):
|
'cliff.help.HelpAction.__call__', side_effect=KeyboardInterrupt
|
||||||
|
):
|
||||||
result = app.run(['--help'])
|
result = app.run(['--help'])
|
||||||
self.assertEqual(result, 130)
|
self.assertEqual(result, 130)
|
||||||
|
|
||||||
@ -385,8 +383,9 @@ class TestHelpHandling(base.TestBase):
|
|||||||
|
|
||||||
def _test_pipeclose_help(self, deferred_help):
|
def _test_pipeclose_help(self, deferred_help):
|
||||||
app, _ = make_app(deferred_help=deferred_help)
|
app, _ = make_app(deferred_help=deferred_help)
|
||||||
with mock.patch('cliff.help.HelpAction.__call__',
|
with mock.patch(
|
||||||
side_effect=BrokenPipeError):
|
'cliff.help.HelpAction.__call__', side_effect=BrokenPipeError
|
||||||
|
):
|
||||||
app.run(['--help'])
|
app.run(['--help'])
|
||||||
|
|
||||||
def test_pipeclose_help(self):
|
def test_pipeclose_help(self):
|
||||||
@ -415,7 +414,6 @@ class TestHelpHandling(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestCommandLookup(base.TestBase):
|
class TestCommandLookup(base.TestBase):
|
||||||
|
|
||||||
def test_unknown_cmd(self):
|
def test_unknown_cmd(self):
|
||||||
app, command = make_app()
|
app, command = make_app()
|
||||||
self.assertEqual(2, app.run(['hell']))
|
self.assertEqual(2, app.run(['hell']))
|
||||||
@ -429,18 +427,21 @@ class TestCommandLookup(base.TestBase):
|
|||||||
|
|
||||||
def test_list_matching_commands(self):
|
def test_list_matching_commands(self):
|
||||||
stdout = io.StringIO()
|
stdout = io.StringIO()
|
||||||
app = application.App('testing', '1',
|
app = application.App(
|
||||||
test_utils.TestCommandManager(
|
'testing',
|
||||||
test_utils.TEST_NAMESPACE),
|
'1',
|
||||||
stdout=stdout)
|
test_utils.TestCommandManager(test_utils.TEST_NAMESPACE),
|
||||||
|
stdout=stdout,
|
||||||
|
)
|
||||||
app.NAME = 'test'
|
app.NAME = 'test'
|
||||||
try:
|
try:
|
||||||
self.assertEqual(2, app.run(['t']))
|
self.assertEqual(2, app.run(['t']))
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
pass
|
pass
|
||||||
output = stdout.getvalue()
|
output = stdout.getvalue()
|
||||||
self.assertIn("test: 't' is not a test command. See 'test --help'.",
|
self.assertIn(
|
||||||
output)
|
"test: 't' is not a test command. See 'test --help'.", output
|
||||||
|
)
|
||||||
self.assertIn('Did you mean one of these?', output)
|
self.assertIn('Did you mean one of these?', output)
|
||||||
self.assertIn('three word command\n two words\n', output)
|
self.assertIn('three word command\n two words\n', output)
|
||||||
|
|
||||||
@ -484,7 +485,6 @@ class TestCommandLookup(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestVerboseMode(base.TestBase):
|
class TestVerboseMode(base.TestBase):
|
||||||
|
|
||||||
def test_verbose(self):
|
def test_verbose(self):
|
||||||
app, command = make_app()
|
app, command = make_app()
|
||||||
app.clean_up = mock.MagicMock(name='clean_up')
|
app.clean_up = mock.MagicMock(name='clean_up')
|
||||||
@ -501,7 +501,6 @@ class TestVerboseMode(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestIO(base.TestBase):
|
class TestIO(base.TestBase):
|
||||||
|
|
||||||
def test_io_streams(self):
|
def test_io_streams(self):
|
||||||
cmd_mgr = commandmanager.CommandManager('cliff.tests')
|
cmd_mgr = commandmanager.CommandManager('cliff.tests')
|
||||||
io = mock.Mock()
|
io = mock.Mock()
|
||||||
@ -516,14 +515,12 @@ class TestIO(base.TestBase):
|
|||||||
self.assertIs(sys.stdout, app.stdout)
|
self.assertIs(sys.stdout, app.stdout)
|
||||||
self.assertIs(sys.stderr, app.stderr)
|
self.assertIs(sys.stderr, app.stderr)
|
||||||
|
|
||||||
app = application.App('with stdout io stream', 1, cmd_mgr,
|
app = application.App('with stdout io stream', 1, cmd_mgr, stdout=io)
|
||||||
stdout=io)
|
|
||||||
self.assertIs(sys.stdin, app.stdin)
|
self.assertIs(sys.stdin, app.stdin)
|
||||||
self.assertIs(io, app.stdout)
|
self.assertIs(io, app.stdout)
|
||||||
self.assertIs(sys.stderr, app.stderr)
|
self.assertIs(sys.stderr, app.stderr)
|
||||||
|
|
||||||
app = application.App('with stderr io stream', 1, cmd_mgr,
|
app = application.App('with stderr io stream', 1, cmd_mgr, stderr=io)
|
||||||
stderr=io)
|
|
||||||
self.assertIs(sys.stdin, app.stdin)
|
self.assertIs(sys.stdin, app.stdin)
|
||||||
self.assertIs(sys.stdout, app.stdout)
|
self.assertIs(sys.stdout, app.stdout)
|
||||||
self.assertIs(io, app.stderr)
|
self.assertIs(io, app.stderr)
|
||||||
|
@ -16,13 +16,11 @@ from cliff import columns
|
|||||||
|
|
||||||
|
|
||||||
class FauxColumn(columns.FormattableColumn):
|
class FauxColumn(columns.FormattableColumn):
|
||||||
|
|
||||||
def human_readable(self):
|
def human_readable(self):
|
||||||
return 'I made this string myself: {}'.format(self._value)
|
return 'I made this string myself: {}'.format(self._value)
|
||||||
|
|
||||||
|
|
||||||
class TestColumns(unittest.TestCase):
|
class TestColumns(unittest.TestCase):
|
||||||
|
|
||||||
def test_machine_readable(self):
|
def test_machine_readable(self):
|
||||||
c = FauxColumn(['list', 'of', 'values'])
|
c = FauxColumn(['list', 'of', 'values'])
|
||||||
self.assertEqual(['list', 'of', 'values'], c.machine_readable())
|
self.assertEqual(['list', 'of', 'values'], c.machine_readable())
|
||||||
|
@ -18,30 +18,28 @@ from cliff.tests import base
|
|||||||
|
|
||||||
|
|
||||||
class TestCommand(command.Command):
|
class TestCommand(command.Command):
|
||||||
"""Description of command.
|
"""Description of command."""
|
||||||
"""
|
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(TestCommand, self).get_parser(prog_name)
|
parser = super(TestCommand, self).get_parser(prog_name)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'long_help_argument',
|
'long_help_argument',
|
||||||
help="Create a NIC on the server.\n"
|
help="Create a NIC on the server.\n"
|
||||||
"Specify option multiple times to create multiple NICs. "
|
"Specify option multiple times to create multiple NICs. "
|
||||||
"Either net-id or port-id must be provided, but not both.\n"
|
"Either net-id or port-id must be provided, but not both.\n"
|
||||||
"net-id: attach NIC to network with this UUID\n"
|
"net-id: attach NIC to network with this UUID\n"
|
||||||
"port-id: attach NIC to port with this UUID\n"
|
"port-id: attach NIC to port with this UUID\n"
|
||||||
"v4-fixed-ip: IPv4 fixed address for NIC (optional)\n"
|
"v4-fixed-ip: IPv4 fixed address for NIC (optional)\n"
|
||||||
"v6-fixed-ip: IPv6 fixed address for NIC (optional)\n"
|
"v6-fixed-ip: IPv6 fixed address for NIC (optional)\n"
|
||||||
"none: (v2.37+) no network is attached\n"
|
"none: (v2.37+) no network is attached\n"
|
||||||
"auto: (v2.37+) the compute service will automatically "
|
"auto: (v2.37+) the compute service will automatically "
|
||||||
"allocate a network.\n"
|
"allocate a network.\n"
|
||||||
"Specifying a --nic of auto or none "
|
"Specifying a --nic of auto or none "
|
||||||
"cannot be used with any other --nic value.",
|
"cannot be used with any other --nic value.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'regular_help_argument',
|
'regular_help_argument',
|
||||||
help="The quick brown fox jumps "
|
help="The quick brown fox jumps " "over the lazy dog.",
|
||||||
"over the lazy dog.",
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-z',
|
'-z',
|
||||||
@ -56,17 +54,15 @@ class TestCommand(command.Command):
|
|||||||
|
|
||||||
|
|
||||||
class TestCommandNoDocstring(command.Command):
|
class TestCommandNoDocstring(command.Command):
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
|
|
||||||
class TestDescription(base.TestBase):
|
class TestDescription(base.TestBase):
|
||||||
|
|
||||||
def test_get_description_docstring(self):
|
def test_get_description_docstring(self):
|
||||||
cmd = TestCommand(None, None)
|
cmd = TestCommand(None, None)
|
||||||
desc = cmd.get_description()
|
desc = cmd.get_description()
|
||||||
assert desc == "Description of command.\n "
|
assert desc == "Description of command."
|
||||||
|
|
||||||
def test_get_description_attribute(self):
|
def test_get_description_attribute(self):
|
||||||
cmd = TestCommand(None, None)
|
cmd = TestCommand(None, None)
|
||||||
@ -83,7 +79,6 @@ class TestDescription(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestBasicValues(base.TestBase):
|
class TestBasicValues(base.TestBase):
|
||||||
|
|
||||||
def test_get_parser(self):
|
def test_get_parser(self):
|
||||||
cmd = TestCommand(None, None)
|
cmd = TestCommand(None, None)
|
||||||
parser = cmd.get_parser('NAME')
|
parser = cmd.get_parser('NAME')
|
||||||
@ -118,7 +113,6 @@ expected_help_message = """
|
|||||||
|
|
||||||
|
|
||||||
class TestHelp(base.TestBase):
|
class TestHelp(base.TestBase):
|
||||||
|
|
||||||
def test_smart_help_formatter(self):
|
def test_smart_help_formatter(self):
|
||||||
cmd = TestCommand(None, None)
|
cmd = TestCommand(None, None)
|
||||||
parser = cmd.get_parser('NAME')
|
parser = cmd.get_parser('NAME')
|
||||||
@ -138,7 +132,6 @@ class TestHelp(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestArgumentParser(base.TestBase):
|
class TestArgumentParser(base.TestBase):
|
||||||
|
|
||||||
def test_option_name_collision(self):
|
def test_option_name_collision(self):
|
||||||
cmd = TestCommand(None, None)
|
cmd = TestCommand(None, None)
|
||||||
parser = cmd.get_parser('NAME')
|
parser = cmd.get_parser('NAME')
|
||||||
@ -165,7 +158,8 @@ class TestArgumentParser(base.TestBase):
|
|||||||
cmd = TestCommand(None, None)
|
cmd = TestCommand(None, None)
|
||||||
parser = cmd.get_parser('NAME')
|
parser = cmd.get_parser('NAME')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-z', '--zero',
|
'-z',
|
||||||
|
'--zero',
|
||||||
dest='zero',
|
dest='zero',
|
||||||
default='zero-default',
|
default='zero-default',
|
||||||
)
|
)
|
||||||
@ -183,7 +177,8 @@ class TestArgumentParser(base.TestBase):
|
|||||||
cmd = TestCommand(None, None)
|
cmd = TestCommand(None, None)
|
||||||
parser = cmd.get_parser('NAME')
|
parser = cmd.get_parser('NAME')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-f', '--foo',
|
'-f',
|
||||||
|
'--foo',
|
||||||
dest='foo',
|
dest='foo',
|
||||||
default='foo',
|
default='foo',
|
||||||
)
|
)
|
||||||
@ -198,12 +193,14 @@ class TestArgumentParser(base.TestBase):
|
|||||||
cmd.conflict_handler = 'resolve'
|
cmd.conflict_handler = 'resolve'
|
||||||
parser = cmd.get_parser('NAME')
|
parser = cmd.get_parser('NAME')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-f', '--foo',
|
'-f',
|
||||||
|
'--foo',
|
||||||
dest='foo',
|
dest='foo',
|
||||||
default='foo',
|
default='foo',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-f', '--foo',
|
'-f',
|
||||||
|
'--foo',
|
||||||
dest='foo',
|
dest='foo',
|
||||||
default='bar',
|
default='bar',
|
||||||
)
|
)
|
||||||
|
@ -41,18 +41,18 @@ def make_app(**kwargs):
|
|||||||
err_command.return_value = err_command_inst
|
err_command.return_value = err_command_inst
|
||||||
cmd_mgr.add_command('error', err_command)
|
cmd_mgr.add_command('error', err_command)
|
||||||
|
|
||||||
app = application.App('testing command hooks',
|
app = application.App(
|
||||||
'1',
|
'testing command hooks',
|
||||||
cmd_mgr,
|
'1',
|
||||||
stderr=mock.Mock(), # suppress warning messages
|
cmd_mgr,
|
||||||
**kwargs
|
stderr=mock.Mock(), # suppress warning messages
|
||||||
)
|
**kwargs
|
||||||
|
)
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
class TestCommand(command.Command):
|
class TestCommand(command.Command):
|
||||||
"""Description of command.
|
"""Description of command."""
|
||||||
"""
|
|
||||||
|
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super(TestCommand, self).get_parser(prog_name)
|
parser = super(TestCommand, self).get_parser(prog_name)
|
||||||
@ -63,23 +63,20 @@ class TestCommand(command.Command):
|
|||||||
|
|
||||||
|
|
||||||
class TestShowCommand(show.ShowOne):
|
class TestShowCommand(show.ShowOne):
|
||||||
"""Description of command.
|
"""Description of command."""
|
||||||
"""
|
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
return (('Name',), ('value',))
|
return (('Name',), ('value',))
|
||||||
|
|
||||||
|
|
||||||
class TestListerCommand(lister.Lister):
|
class TestListerCommand(lister.Lister):
|
||||||
"""Description of command.
|
"""Description of command."""
|
||||||
"""
|
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
return (('Name',), [('value',)])
|
return (('Name',), [('value',)])
|
||||||
|
|
||||||
|
|
||||||
class TestHook(hooks.CommandHook):
|
class TestHook(hooks.CommandHook):
|
||||||
|
|
||||||
_before_called = False
|
_before_called = False
|
||||||
_after_called = False
|
_after_called = False
|
||||||
|
|
||||||
@ -98,7 +95,6 @@ class TestHook(hooks.CommandHook):
|
|||||||
|
|
||||||
|
|
||||||
class TestChangeHook(hooks.CommandHook):
|
class TestChangeHook(hooks.CommandHook):
|
||||||
|
|
||||||
_before_called = False
|
_before_called = False
|
||||||
_after_called = False
|
_after_called = False
|
||||||
|
|
||||||
@ -121,7 +117,6 @@ class TestChangeHook(hooks.CommandHook):
|
|||||||
|
|
||||||
|
|
||||||
class TestDisplayChangeHook(hooks.CommandHook):
|
class TestDisplayChangeHook(hooks.CommandHook):
|
||||||
|
|
||||||
_before_called = False
|
_before_called = False
|
||||||
_after_called = False
|
_after_called = False
|
||||||
|
|
||||||
@ -144,7 +139,6 @@ class TestDisplayChangeHook(hooks.CommandHook):
|
|||||||
|
|
||||||
|
|
||||||
class TestListerChangeHook(hooks.CommandHook):
|
class TestListerChangeHook(hooks.CommandHook):
|
||||||
|
|
||||||
_before_called = False
|
_before_called = False
|
||||||
_after_called = False
|
_after_called = False
|
||||||
|
|
||||||
@ -167,7 +161,6 @@ class TestListerChangeHook(hooks.CommandHook):
|
|||||||
|
|
||||||
|
|
||||||
class TestCommandLoadHooks(base.TestBase):
|
class TestCommandLoadHooks(base.TestBase):
|
||||||
|
|
||||||
def test_no_app_or_name(self):
|
def test_no_app_or_name(self):
|
||||||
cmd = TestCommand(None, None)
|
cmd = TestCommand(None, None)
|
||||||
self.assertEqual([], cmd._hooks)
|
self.assertEqual([], cmd._hooks)
|
||||||
@ -183,18 +176,13 @@ class TestCommandLoadHooks(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestHooks(base.TestBase):
|
class TestHooks(base.TestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestHooks, self).setUp()
|
super(TestHooks, self).setUp()
|
||||||
self.app = make_app()
|
self.app = make_app()
|
||||||
self.cmd = TestCommand(self.app, None, cmd_name='test')
|
self.cmd = TestCommand(self.app, None, cmd_name='test')
|
||||||
self.hook = TestHook(self.cmd)
|
self.hook = TestHook(self.cmd)
|
||||||
self.mgr = extension.ExtensionManager.make_test_instance(
|
self.mgr = extension.ExtensionManager.make_test_instance(
|
||||||
[extension.Extension(
|
[extension.Extension('parser-hook', None, None, self.hook)],
|
||||||
'parser-hook',
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
self.hook)],
|
|
||||||
)
|
)
|
||||||
# Replace the auto-loaded hooks with our explicitly created
|
# Replace the auto-loaded hooks with our explicitly created
|
||||||
# manager.
|
# manager.
|
||||||
@ -222,18 +210,13 @@ class TestHooks(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestChangeHooks(base.TestBase):
|
class TestChangeHooks(base.TestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestChangeHooks, self).setUp()
|
super(TestChangeHooks, self).setUp()
|
||||||
self.app = make_app()
|
self.app = make_app()
|
||||||
self.cmd = TestCommand(self.app, None, cmd_name='test')
|
self.cmd = TestCommand(self.app, None, cmd_name='test')
|
||||||
self.hook = TestChangeHook(self.cmd)
|
self.hook = TestChangeHook(self.cmd)
|
||||||
self.mgr = extension.ExtensionManager.make_test_instance(
|
self.mgr = extension.ExtensionManager.make_test_instance(
|
||||||
[extension.Extension(
|
[extension.Extension('parser-hook', None, None, self.hook)],
|
||||||
'parser-hook',
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
self.hook)],
|
|
||||||
)
|
)
|
||||||
# Replace the auto-loaded hooks with our explicitly created
|
# Replace the auto-loaded hooks with our explicitly created
|
||||||
# manager.
|
# manager.
|
||||||
@ -267,18 +250,13 @@ class TestChangeHooks(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestShowOneHooks(base.TestBase):
|
class TestShowOneHooks(base.TestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestShowOneHooks, self).setUp()
|
super(TestShowOneHooks, self).setUp()
|
||||||
self.app = make_app()
|
self.app = make_app()
|
||||||
self.cmd = TestShowCommand(self.app, None, cmd_name='test')
|
self.cmd = TestShowCommand(self.app, None, cmd_name='test')
|
||||||
self.hook = TestHook(self.cmd)
|
self.hook = TestHook(self.cmd)
|
||||||
self.mgr = extension.ExtensionManager.make_test_instance(
|
self.mgr = extension.ExtensionManager.make_test_instance(
|
||||||
[extension.Extension(
|
[extension.Extension('parser-hook', None, None, self.hook)],
|
||||||
'parser-hook',
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
self.hook)],
|
|
||||||
)
|
)
|
||||||
# Replace the auto-loaded hooks with our explicitly created
|
# Replace the auto-loaded hooks with our explicitly created
|
||||||
# manager.
|
# manager.
|
||||||
@ -309,18 +287,13 @@ class TestShowOneHooks(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestShowOneChangeHooks(base.TestBase):
|
class TestShowOneChangeHooks(base.TestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestShowOneChangeHooks, self).setUp()
|
super(TestShowOneChangeHooks, self).setUp()
|
||||||
self.app = make_app()
|
self.app = make_app()
|
||||||
self.cmd = TestShowCommand(self.app, None, cmd_name='test')
|
self.cmd = TestShowCommand(self.app, None, cmd_name='test')
|
||||||
self.hook = TestDisplayChangeHook(self.cmd)
|
self.hook = TestDisplayChangeHook(self.cmd)
|
||||||
self.mgr = extension.ExtensionManager.make_test_instance(
|
self.mgr = extension.ExtensionManager.make_test_instance(
|
||||||
[extension.Extension(
|
[extension.Extension('parser-hook', None, None, self.hook)],
|
||||||
'parser-hook',
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
self.hook)],
|
|
||||||
)
|
)
|
||||||
# Replace the auto-loaded hooks with our explicitly created
|
# Replace the auto-loaded hooks with our explicitly created
|
||||||
# manager.
|
# manager.
|
||||||
@ -354,18 +327,13 @@ class TestShowOneChangeHooks(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestListerHooks(base.TestBase):
|
class TestListerHooks(base.TestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestListerHooks, self).setUp()
|
super(TestListerHooks, self).setUp()
|
||||||
self.app = make_app()
|
self.app = make_app()
|
||||||
self.cmd = TestListerCommand(self.app, None, cmd_name='test')
|
self.cmd = TestListerCommand(self.app, None, cmd_name='test')
|
||||||
self.hook = TestHook(self.cmd)
|
self.hook = TestHook(self.cmd)
|
||||||
self.mgr = extension.ExtensionManager.make_test_instance(
|
self.mgr = extension.ExtensionManager.make_test_instance(
|
||||||
[extension.Extension(
|
[extension.Extension('parser-hook', None, None, self.hook)],
|
||||||
'parser-hook',
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
self.hook)],
|
|
||||||
)
|
)
|
||||||
# Replace the auto-loaded hooks with our explicitly created
|
# Replace the auto-loaded hooks with our explicitly created
|
||||||
# manager.
|
# manager.
|
||||||
@ -396,18 +364,13 @@ class TestListerHooks(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestListerChangeHooks(base.TestBase):
|
class TestListerChangeHooks(base.TestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestListerChangeHooks, self).setUp()
|
super(TestListerChangeHooks, self).setUp()
|
||||||
self.app = make_app()
|
self.app = make_app()
|
||||||
self.cmd = TestListerCommand(self.app, None, cmd_name='test')
|
self.cmd = TestListerCommand(self.app, None, cmd_name='test')
|
||||||
self.hook = TestListerChangeHook(self.cmd)
|
self.hook = TestListerChangeHook(self.cmd)
|
||||||
self.mgr = extension.ExtensionManager.make_test_instance(
|
self.mgr = extension.ExtensionManager.make_test_instance(
|
||||||
[extension.Extension(
|
[extension.Extension('parser-hook', None, None, self.hook)],
|
||||||
'parser-hook',
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
self.hook)],
|
|
||||||
)
|
)
|
||||||
# Replace the auto-loaded hooks with our explicitly created
|
# Replace the auto-loaded hooks with our explicitly created
|
||||||
# manager.
|
# manager.
|
||||||
|
@ -23,7 +23,6 @@ load_tests = testscenarios.load_tests_apply_scenarios
|
|||||||
|
|
||||||
|
|
||||||
class TestLookupAndFind(base.TestBase):
|
class TestLookupAndFind(base.TestBase):
|
||||||
|
|
||||||
scenarios = [
|
scenarios = [
|
||||||
('one-word', {'argv': ['one']}),
|
('one-word', {'argv': ['one']}),
|
||||||
('two-words', {'argv': ['two', 'words']}),
|
('two-words', {'argv': ['two', 'words']}),
|
||||||
@ -39,7 +38,6 @@ class TestLookupAndFind(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestLookupWithRemainder(base.TestBase):
|
class TestLookupWithRemainder(base.TestBase):
|
||||||
|
|
||||||
scenarios = [
|
scenarios = [
|
||||||
('one', {'argv': ['one', '--opt']}),
|
('one', {'argv': ['one', '--opt']}),
|
||||||
('two', {'argv': ['two', 'words', '--opt']}),
|
('two', {'argv': ['two', 'words', '--opt']}),
|
||||||
@ -54,7 +52,6 @@ class TestLookupWithRemainder(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestFindInvalidCommand(base.TestBase):
|
class TestFindInvalidCommand(base.TestBase):
|
||||||
|
|
||||||
scenarios = [
|
scenarios = [
|
||||||
('no-such-command', {'argv': ['a', '-b']}),
|
('no-such-command', {'argv': ['a', '-b']}),
|
||||||
('no-command-given', {'argv': ['-b']}),
|
('no-command-given', {'argv': ['-b']}),
|
||||||
@ -73,7 +70,6 @@ class TestFindInvalidCommand(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestFindUnknownCommand(base.TestBase):
|
class TestFindUnknownCommand(base.TestBase):
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
|
mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
|
||||||
try:
|
try:
|
||||||
@ -85,7 +81,6 @@ class TestFindUnknownCommand(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestDynamicCommands(base.TestBase):
|
class TestDynamicCommands(base.TestBase):
|
||||||
|
|
||||||
def test_add(self):
|
def test_add(self):
|
||||||
mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
|
mgr = utils.TestCommandManager(utils.TEST_NAMESPACE)
|
||||||
mock_cmd = mock.Mock()
|
mock_cmd = mock.Mock()
|
||||||
@ -112,13 +107,13 @@ class TestDynamicCommands(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestLoad(base.TestBase):
|
class TestLoad(base.TestBase):
|
||||||
|
|
||||||
def test_load_commands(self):
|
def test_load_commands(self):
|
||||||
testcmd = mock.Mock(name='testcmd')
|
testcmd = mock.Mock(name='testcmd')
|
||||||
testcmd.name.replace.return_value = 'test'
|
testcmd.name.replace.return_value = 'test'
|
||||||
mock_get_group_all = mock.Mock(return_value=[testcmd])
|
mock_get_group_all = mock.Mock(return_value=[testcmd])
|
||||||
with mock.patch('stevedore.ExtensionManager',
|
with mock.patch(
|
||||||
mock_get_group_all) as mock_manager:
|
'stevedore.ExtensionManager', mock_get_group_all
|
||||||
|
) as mock_manager:
|
||||||
mgr = commandmanager.CommandManager('test')
|
mgr = commandmanager.CommandManager('test')
|
||||||
mock_manager.assert_called_once_with('test')
|
mock_manager.assert_called_once_with('test')
|
||||||
names = [n for n, v in mgr]
|
names = [n for n, v in mgr]
|
||||||
@ -128,8 +123,9 @@ class TestLoad(base.TestBase):
|
|||||||
testcmd = mock.Mock()
|
testcmd = mock.Mock()
|
||||||
testcmd.name = 'test_cmd'
|
testcmd.name = 'test_cmd'
|
||||||
mock_get_group_all = mock.Mock(return_value=[testcmd])
|
mock_get_group_all = mock.Mock(return_value=[testcmd])
|
||||||
with mock.patch('stevedore.ExtensionManager',
|
with mock.patch(
|
||||||
mock_get_group_all) as mock_manager:
|
'stevedore.ExtensionManager', mock_get_group_all
|
||||||
|
) as mock_manager:
|
||||||
mgr = commandmanager.CommandManager(
|
mgr = commandmanager.CommandManager(
|
||||||
'test',
|
'test',
|
||||||
convert_underscores=False,
|
convert_underscores=False,
|
||||||
@ -142,8 +138,9 @@ class TestLoad(base.TestBase):
|
|||||||
testcmd = mock.Mock()
|
testcmd = mock.Mock()
|
||||||
testcmd.name = 'test_cmd'
|
testcmd.name = 'test_cmd'
|
||||||
mock_get_group_all = mock.Mock(return_value=[testcmd])
|
mock_get_group_all = mock.Mock(return_value=[testcmd])
|
||||||
with mock.patch('stevedore.ExtensionManager',
|
with mock.patch(
|
||||||
mock_get_group_all) as mock_manager:
|
'stevedore.ExtensionManager', mock_get_group_all
|
||||||
|
) as mock_manager:
|
||||||
mgr = commandmanager.CommandManager(
|
mgr = commandmanager.CommandManager(
|
||||||
'test',
|
'test',
|
||||||
convert_underscores=True,
|
convert_underscores=True,
|
||||||
@ -154,7 +151,6 @@ class TestLoad(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class FauxCommand(command.Command):
|
class FauxCommand(command.Command):
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -164,7 +160,6 @@ class FauxCommand2(FauxCommand):
|
|||||||
|
|
||||||
|
|
||||||
class TestLegacyCommand(base.TestBase):
|
class TestLegacyCommand(base.TestBase):
|
||||||
|
|
||||||
def test_find_legacy(self):
|
def test_find_legacy(self):
|
||||||
mgr = utils.TestCommandManager(None)
|
mgr = utils.TestCommandManager(None)
|
||||||
mgr.add_command('new name', FauxCommand)
|
mgr.add_command('new name', FauxCommand)
|
||||||
@ -202,7 +197,6 @@ class TestLegacyCommand(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestLookupAndFindPartialName(base.TestBase):
|
class TestLookupAndFindPartialName(base.TestBase):
|
||||||
|
|
||||||
scenarios = [
|
scenarios = [
|
||||||
('one-word', {'argv': ['o']}),
|
('one-word', {'argv': ['o']}),
|
||||||
('two-words', {'argv': ['t', 'w']}),
|
('two-words', {'argv': ['t', 'w']}),
|
||||||
@ -218,45 +212,61 @@ class TestLookupAndFindPartialName(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestGetByPartialName(base.TestBase):
|
class TestGetByPartialName(base.TestBase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestGetByPartialName, self).setUp()
|
super(TestGetByPartialName, self).setUp()
|
||||||
self.commands = {
|
self.commands = {
|
||||||
'resource provider list': 1,
|
'resource provider list': 1,
|
||||||
'resource class list': 2,
|
'resource class list': 2,
|
||||||
'server list': 3,
|
'server list': 3,
|
||||||
'service list': 4}
|
'service list': 4,
|
||||||
|
}
|
||||||
|
|
||||||
def test_no_candidates(self):
|
def test_no_candidates(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[], commandmanager._get_commands_by_partial_name(
|
[],
|
||||||
['r', 'p'], self.commands))
|
commandmanager._get_commands_by_partial_name(
|
||||||
|
['r', 'p'], self.commands
|
||||||
|
),
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[], commandmanager._get_commands_by_partial_name(
|
[],
|
||||||
['r', 'p', 'c'], self.commands))
|
commandmanager._get_commands_by_partial_name(
|
||||||
|
['r', 'p', 'c'], self.commands
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_multiple_candidates(self):
|
def test_multiple_candidates(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
2, len(commandmanager._get_commands_by_partial_name(
|
2,
|
||||||
['se', 'li'], self.commands)))
|
len(
|
||||||
|
commandmanager._get_commands_by_partial_name(
|
||||||
|
['se', 'li'], self.commands
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_one_candidate(self):
|
def test_one_candidate(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['resource provider list'],
|
['resource provider list'],
|
||||||
commandmanager._get_commands_by_partial_name(
|
commandmanager._get_commands_by_partial_name(
|
||||||
['r', 'p', 'l'], self.commands))
|
['r', 'p', 'l'], self.commands
|
||||||
|
),
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['resource provider list'],
|
['resource provider list'],
|
||||||
commandmanager._get_commands_by_partial_name(
|
commandmanager._get_commands_by_partial_name(
|
||||||
['resource', 'provider', 'list'], self.commands))
|
['resource', 'provider', 'list'], self.commands
|
||||||
|
),
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['server list'],
|
['server list'],
|
||||||
commandmanager._get_commands_by_partial_name(
|
commandmanager._get_commands_by_partial_name(
|
||||||
['serve', 'l'], self.commands))
|
['serve', 'l'], self.commands
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FakeCommand(object):
|
class FakeCommand(object):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
return cls
|
return cls
|
||||||
@ -286,7 +296,6 @@ class FakeCommandManager(commandmanager.CommandManager):
|
|||||||
|
|
||||||
|
|
||||||
class TestCommandManagerGroups(base.TestBase):
|
class TestCommandManagerGroups(base.TestBase):
|
||||||
|
|
||||||
def test_add_command_group(self):
|
def test_add_command_group(self):
|
||||||
mgr = FakeCommandManager('test')
|
mgr = FakeCommandManager('test')
|
||||||
|
|
||||||
|
@ -22,19 +22,23 @@ from cliff.tests import base
|
|||||||
|
|
||||||
|
|
||||||
class TestCompletion(base.TestBase):
|
class TestCompletion(base.TestBase):
|
||||||
|
|
||||||
def test_dictionary(self):
|
def test_dictionary(self):
|
||||||
sot = complete.CompleteDictionary()
|
sot = complete.CompleteDictionary()
|
||||||
sot.add_command("image delete".split(),
|
sot.add_command(
|
||||||
[mock.Mock(option_strings=["1"])])
|
"image delete".split(), [mock.Mock(option_strings=["1"])]
|
||||||
sot.add_command("image list".split(),
|
)
|
||||||
[mock.Mock(option_strings=["2"])])
|
sot.add_command(
|
||||||
sot.add_command("image create".split(),
|
"image list".split(), [mock.Mock(option_strings=["2"])]
|
||||||
[mock.Mock(option_strings=["3"])])
|
)
|
||||||
sot.add_command("volume type create".split(),
|
sot.add_command(
|
||||||
[mock.Mock(option_strings=["4"])])
|
"image create".split(), [mock.Mock(option_strings=["3"])]
|
||||||
sot.add_command("volume type delete".split(),
|
)
|
||||||
[mock.Mock(option_strings=["5"])])
|
sot.add_command(
|
||||||
|
"volume type create".split(), [mock.Mock(option_strings=["4"])]
|
||||||
|
)
|
||||||
|
sot.add_command(
|
||||||
|
"volume type delete".split(), [mock.Mock(option_strings=["5"])]
|
||||||
|
)
|
||||||
self.assertEqual("image volume", sot.get_commands())
|
self.assertEqual("image volume", sot.get_commands())
|
||||||
result = sot.get_data()
|
result = sot.get_data()
|
||||||
self.assertEqual("image", result[0][0])
|
self.assertEqual("image", result[0][0])
|
||||||
@ -48,12 +52,15 @@ class TestCompletion(base.TestBase):
|
|||||||
|
|
||||||
def test_complete_dictionary_subcmd(self):
|
def test_complete_dictionary_subcmd(self):
|
||||||
sot = complete.CompleteDictionary()
|
sot = complete.CompleteDictionary()
|
||||||
sot.add_command("image delete".split(),
|
sot.add_command(
|
||||||
[mock.Mock(option_strings=["1"])])
|
"image delete".split(), [mock.Mock(option_strings=["1"])]
|
||||||
sot.add_command("image list".split(),
|
)
|
||||||
[mock.Mock(option_strings=["2"])])
|
sot.add_command(
|
||||||
sot.add_command("image list better".split(),
|
"image list".split(), [mock.Mock(option_strings=["2"])]
|
||||||
[mock.Mock(option_strings=["3"])])
|
)
|
||||||
|
sot.add_command(
|
||||||
|
"image list better".split(), [mock.Mock(option_strings=["3"])]
|
||||||
|
)
|
||||||
self.assertEqual("image", sot.get_commands())
|
self.assertEqual("image", sot.get_commands())
|
||||||
result = sot.get_data()
|
result = sot.get_data()
|
||||||
self.assertEqual("image", result[0][0])
|
self.assertEqual("image", result[0][0])
|
||||||
@ -81,14 +88,15 @@ class FakeStdout:
|
|||||||
|
|
||||||
|
|
||||||
class TestCompletionAlternatives(base.TestBase):
|
class TestCompletionAlternatives(base.TestBase):
|
||||||
|
|
||||||
def given_cmdo_data(self):
|
def given_cmdo_data(self):
|
||||||
cmdo = "image server"
|
cmdo = "image server"
|
||||||
data = [("image", "create"),
|
data = [
|
||||||
("image_create", "--eolus"),
|
("image", "create"),
|
||||||
("server", "meta ssh"),
|
("image_create", "--eolus"),
|
||||||
("server_meta_delete", "--wilson"),
|
("server", "meta ssh"),
|
||||||
("server_ssh", "--sunlight")]
|
("server_meta_delete", "--wilson"),
|
||||||
|
("server_ssh", "--sunlight"),
|
||||||
|
]
|
||||||
return cmdo, data
|
return cmdo, data
|
||||||
|
|
||||||
def then_data(self, content):
|
def then_data(self, content):
|
||||||
@ -117,12 +125,10 @@ class TestCompletionAlternatives(base.TestBase):
|
|||||||
sot = complete.CompleteCommand(mock.Mock(), mock.Mock())
|
sot = complete.CompleteCommand(mock.Mock(), mock.Mock())
|
||||||
parser = sot.get_parser('nothing')
|
parser = sot.get_parser('nothing')
|
||||||
self.assertEqual("nothing", parser.prog)
|
self.assertEqual("nothing", parser.prog)
|
||||||
self.assertEqual("print bash completion command\n ",
|
self.assertEqual("print bash completion command", parser.description)
|
||||||
parser.description)
|
|
||||||
|
|
||||||
|
|
||||||
class TestCompletionAction(base.TestBase):
|
class TestCompletionAction(base.TestBase):
|
||||||
|
|
||||||
def given_complete_command(self):
|
def given_complete_command(self):
|
||||||
cmd_mgr = commandmanager.CommandManager('cliff.tests')
|
cmd_mgr = commandmanager.CommandManager('cliff.tests')
|
||||||
app = application.App('testing', '1', cmd_mgr, stdout=FakeStdout())
|
app = application.App('testing', '1', cmd_mgr, stdout=FakeStdout())
|
||||||
@ -131,8 +137,9 @@ class TestCompletionAction(base.TestBase):
|
|||||||
return sot, app, cmd_mgr
|
return sot, app, cmd_mgr
|
||||||
|
|
||||||
def then_actions_equal(self, actions):
|
def then_actions_equal(self, actions):
|
||||||
optstr = ' '.join(opt for action in actions
|
optstr = ' '.join(
|
||||||
for opt in action.option_strings)
|
opt for action in actions for opt in action.option_strings
|
||||||
|
)
|
||||||
self.assertEqual('-h --help --name --shell', optstr)
|
self.assertEqual('-h --help --name --shell', optstr)
|
||||||
|
|
||||||
def test_complete_command_get_actions(self):
|
def test_complete_command_get_actions(self):
|
||||||
|
@ -23,7 +23,6 @@ from cliff.tests import test_columns
|
|||||||
|
|
||||||
|
|
||||||
class TestCSVFormatter(unittest.TestCase):
|
class TestCSVFormatter(unittest.TestCase):
|
||||||
|
|
||||||
def test_commaseparated_list_formatter(self):
|
def test_commaseparated_list_formatter(self):
|
||||||
sf = commaseparated.CSVLister()
|
sf = commaseparated.CSVLister()
|
||||||
c = ('a', 'b', 'c')
|
c = ('a', 'b', 'c')
|
||||||
|
@ -22,17 +22,11 @@ from cliff.tests import test_columns
|
|||||||
|
|
||||||
|
|
||||||
class TestJSONFormatter(base.TestBase):
|
class TestJSONFormatter(base.TestBase):
|
||||||
|
|
||||||
def test_one(self):
|
def test_one(self):
|
||||||
sf = json_format.JSONFormatter()
|
sf = json_format.JSONFormatter()
|
||||||
c = ('a', 'b', 'c', 'd')
|
c = ('a', 'b', 'c', 'd')
|
||||||
d = ('A', 'B', 'C', '"escape me"')
|
d = ('A', 'B', 'C', '"escape me"')
|
||||||
expected = {
|
expected = {'a': 'A', 'b': 'B', 'c': 'C', 'd': '"escape me"'}
|
||||||
'a': 'A',
|
|
||||||
'b': 'B',
|
|
||||||
'c': 'C',
|
|
||||||
'd': '"escape me"'
|
|
||||||
}
|
|
||||||
args = mock.Mock()
|
args = mock.Mock()
|
||||||
sf.add_argument_group(args)
|
sf.add_argument_group(args)
|
||||||
|
|
||||||
@ -78,15 +72,11 @@ class TestJSONFormatter(base.TestBase):
|
|||||||
def test_list(self):
|
def test_list(self):
|
||||||
sf = json_format.JSONFormatter()
|
sf = json_format.JSONFormatter()
|
||||||
c = ('a', 'b', 'c')
|
c = ('a', 'b', 'c')
|
||||||
d = (
|
d = (('A1', 'B1', 'C1'), ('A2', 'B2', 'C2'), ('A3', 'B3', 'C3'))
|
||||||
('A1', 'B1', 'C1'),
|
|
||||||
('A2', 'B2', 'C2'),
|
|
||||||
('A3', 'B3', 'C3')
|
|
||||||
)
|
|
||||||
expected = [
|
expected = [
|
||||||
{'a': 'A1', 'b': 'B1', 'c': 'C1'},
|
{'a': 'A1', 'b': 'B1', 'c': 'C1'},
|
||||||
{'a': 'A2', 'b': 'B2', 'c': 'C2'},
|
{'a': 'A2', 'b': 'B2', 'c': 'C2'},
|
||||||
{'a': 'A3', 'b': 'B3', 'c': 'C3'}
|
{'a': 'A3', 'b': 'B3', 'c': 'C3'},
|
||||||
]
|
]
|
||||||
args = mock.Mock()
|
args = mock.Mock()
|
||||||
sf.add_argument_group(args)
|
sf.add_argument_group(args)
|
||||||
@ -110,9 +100,7 @@ class TestJSONFormatter(base.TestBase):
|
|||||||
def test_formattablecolumn_list(self):
|
def test_formattablecolumn_list(self):
|
||||||
sf = json_format.JSONFormatter()
|
sf = json_format.JSONFormatter()
|
||||||
c = ('a', 'b', 'c')
|
c = ('a', 'b', 'c')
|
||||||
d = (
|
d = (('A1', 'B1', test_columns.FauxColumn(['the', 'value'])),)
|
||||||
('A1', 'B1', test_columns.FauxColumn(['the', 'value'])),
|
|
||||||
)
|
|
||||||
expected = [
|
expected = [
|
||||||
{'a': 'A1', 'b': 'B1', 'c': ['the', 'value']},
|
{'a': 'A1', 'b': 'B1', 'c': ['the', 'value']},
|
||||||
]
|
]
|
||||||
|
@ -22,7 +22,6 @@ from cliff.tests import test_columns
|
|||||||
|
|
||||||
|
|
||||||
class TestShellFormatter(base.TestBase):
|
class TestShellFormatter(base.TestBase):
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
sf = shell.ShellFormatter()
|
sf = shell.ShellFormatter()
|
||||||
c = ('a', 'b', 'c', 'd')
|
c = ('a', 'b', 'c', 'd')
|
||||||
@ -54,11 +53,13 @@ class TestShellFormatter(base.TestBase):
|
|||||||
sf = shell.ShellFormatter()
|
sf = shell.ShellFormatter()
|
||||||
c = ('a', 'b', 'c')
|
c = ('a', 'b', 'c')
|
||||||
d = ('A', 'B', test_columns.FauxColumn(['the', 'value']))
|
d = ('A', 'B', test_columns.FauxColumn(['the', 'value']))
|
||||||
expected = '\n'.join([
|
expected = '\n'.join(
|
||||||
'a="A"',
|
[
|
||||||
'b="B"',
|
'a="A"',
|
||||||
'c="[\'the\', \'value\']"\n',
|
'b="B"',
|
||||||
])
|
'c="[\'the\', \'value\']"\n',
|
||||||
|
]
|
||||||
|
)
|
||||||
output = io.StringIO()
|
output = io.StringIO()
|
||||||
args = mock.Mock()
|
args = mock.Mock()
|
||||||
args.variables = ['a', 'b', 'c']
|
args.variables = ['a', 'b', 'c']
|
||||||
@ -71,8 +72,9 @@ class TestShellFormatter(base.TestBase):
|
|||||||
sf = shell.ShellFormatter()
|
sf = shell.ShellFormatter()
|
||||||
c = ('a', 'b', 'c', 'd', 'e')
|
c = ('a', 'b', 'c', 'd', 'e')
|
||||||
d = (True, False, 100, '"esc"', str('"esc"'))
|
d = (True, False, 100, '"esc"', str('"esc"'))
|
||||||
expected = ('a="True"\nb="False"\nc="100"\n'
|
expected = (
|
||||||
'd="\\"esc\\""\ne="\\"esc\\""\n')
|
'a="True"\nb="False"\nc="100"\n' 'd="\\"esc\\""\ne="\\"esc\\""\n'
|
||||||
|
)
|
||||||
output = io.StringIO()
|
output = io.StringIO()
|
||||||
args = mock.Mock()
|
args = mock.Mock()
|
||||||
args.variables = ['a', 'b', 'c', 'd', 'e']
|
args.variables = ['a', 'b', 'c', 'd', 'e']
|
||||||
|
@ -66,13 +66,13 @@ def _table_tester_helper(tags, data, extra_args=None):
|
|||||||
|
|
||||||
|
|
||||||
class TestTableFormatter(base.TestBase):
|
class TestTableFormatter(base.TestBase):
|
||||||
|
|
||||||
@mock.patch('cliff.utils.terminal_width')
|
@mock.patch('cliff.utils.terminal_width')
|
||||||
def test(self, tw):
|
def test(self, tw):
|
||||||
tw.return_value = 80
|
tw.return_value = 80
|
||||||
c = ('a', 'b', 'c', 'd')
|
c = ('a', 'b', 'c', 'd')
|
||||||
d = ('A', 'B', 'C', 'test\rcarriage\r\nreturn')
|
d = ('A', 'B', 'C', 'test\rcarriage\r\nreturn')
|
||||||
expected = textwrap.dedent('''\
|
expected = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+-------+---------------+
|
+-------+---------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+-------+---------------+
|
+-------+---------------+
|
||||||
@ -82,14 +82,15 @@ class TestTableFormatter(base.TestBase):
|
|||||||
| d | test carriage |
|
| d | test carriage |
|
||||||
| | return |
|
| | return |
|
||||||
+-------+---------------+
|
+-------+---------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
self.assertEqual(expected, _table_tester_helper(c, d))
|
self.assertEqual(expected, _table_tester_helper(c, d))
|
||||||
|
|
||||||
|
|
||||||
class TestTerminalWidth(base.TestBase):
|
class TestTerminalWidth(base.TestBase):
|
||||||
|
|
||||||
# Multi-line output when width is restricted to 42 columns
|
# Multi-line output when width is restricted to 42 columns
|
||||||
expected_ml_val = textwrap.dedent('''\
|
expected_ml_val = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+-------+--------------------------------+
|
+-------+--------------------------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+-------+--------------------------------+
|
+-------+--------------------------------+
|
||||||
@ -100,10 +101,12 @@ class TestTerminalWidth(base.TestBase):
|
|||||||
| | dddddddddddddddddddddddddddddd |
|
| | dddddddddddddddddddddddddddddd |
|
||||||
| | ddddddddddddddddd |
|
| | ddddddddddddddddd |
|
||||||
+-------+--------------------------------+
|
+-------+--------------------------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
# Multi-line output when width is restricted to 80 columns
|
# Multi-line output when width is restricted to 80 columns
|
||||||
expected_ml_80_val = textwrap.dedent('''\
|
expected_ml_80_val = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+-------+----------------------------------------------------------------------+
|
+-------+----------------------------------------------------------------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+-------+----------------------------------------------------------------------+
|
+-------+----------------------------------------------------------------------+
|
||||||
@ -113,10 +116,12 @@ class TestTerminalWidth(base.TestBase):
|
|||||||
| d | dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd |
|
| d | dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd |
|
||||||
| | ddddddddd |
|
| | ddddddddd |
|
||||||
+-------+----------------------------------------------------------------------+
|
+-------+----------------------------------------------------------------------+
|
||||||
''') # noqa
|
'''
|
||||||
|
) # noqa
|
||||||
|
|
||||||
# Single-line output, for when no line length restriction apply
|
# Single-line output, for when no line length restriction apply
|
||||||
expected_sl_val = textwrap.dedent('''\
|
expected_sl_val = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+-------+-------------------------------------------------------------------------------+
|
+-------+-------------------------------------------------------------------------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+-------+-------------------------------------------------------------------------------+
|
+-------+-------------------------------------------------------------------------------+
|
||||||
@ -125,7 +130,8 @@ class TestTerminalWidth(base.TestBase):
|
|||||||
| c | C |
|
| c | C |
|
||||||
| d | ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd |
|
| d | ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd |
|
||||||
+-------+-------------------------------------------------------------------------------+
|
+-------+-------------------------------------------------------------------------------+
|
||||||
''') # noqa
|
'''
|
||||||
|
) # noqa
|
||||||
|
|
||||||
@mock.patch('cliff.utils.terminal_width')
|
@mock.patch('cliff.utils.terminal_width')
|
||||||
def test_table_formatter_no_cli_param(self, tw):
|
def test_table_formatter_no_cli_param(self, tw):
|
||||||
@ -192,15 +198,16 @@ class TestTerminalWidth(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestMaxWidth(base.TestBase):
|
class TestMaxWidth(base.TestBase):
|
||||||
|
expected_80 = textwrap.dedent(
|
||||||
expected_80 = textwrap.dedent('''\
|
'''\
|
||||||
+--------------------------+---------------------------------------------+
|
+--------------------------+---------------------------------------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+--------------------------+---------------------------------------------+
|
+--------------------------+---------------------------------------------+
|
||||||
| field_name | the value |
|
| field_name | the value |
|
||||||
| a_really_long_field_name | a value significantly longer than the field |
|
| a_really_long_field_name | a value significantly longer than the field |
|
||||||
+--------------------------+---------------------------------------------+
|
+--------------------------+---------------------------------------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
@mock.patch('cliff.utils.terminal_width')
|
@mock.patch('cliff.utils.terminal_width')
|
||||||
def test_80(self, tw):
|
def test_80(self, tw):
|
||||||
@ -215,7 +222,8 @@ class TestMaxWidth(base.TestBase):
|
|||||||
tw.return_value = 70
|
tw.return_value = 70
|
||||||
c = ('field_name', 'a_really_long_field_name')
|
c = ('field_name', 'a_really_long_field_name')
|
||||||
d = ('the value', 'a value significantly longer than the field')
|
d = ('the value', 'a value significantly longer than the field')
|
||||||
expected = textwrap.dedent('''\
|
expected = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+--------------------------+-----------------------------------------+
|
+--------------------------+-----------------------------------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+--------------------------+-----------------------------------------+
|
+--------------------------+-----------------------------------------+
|
||||||
@ -223,7 +231,8 @@ class TestMaxWidth(base.TestBase):
|
|||||||
| a_really_long_field_name | a value significantly longer than the |
|
| a_really_long_field_name | a value significantly longer than the |
|
||||||
| | field |
|
| | field |
|
||||||
+--------------------------+-----------------------------------------+
|
+--------------------------+-----------------------------------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected,
|
expected,
|
||||||
_table_tester_helper(c, d, extra_args=['--fit-width']),
|
_table_tester_helper(c, d, extra_args=['--fit-width']),
|
||||||
@ -235,7 +244,8 @@ class TestMaxWidth(base.TestBase):
|
|||||||
tw.return_value = 50
|
tw.return_value = 50
|
||||||
c = ('field_name', 'a_really_long_field_name')
|
c = ('field_name', 'a_really_long_field_name')
|
||||||
d = ('the value', 'a value significantly longer than the field')
|
d = ('the value', 'a value significantly longer than the field')
|
||||||
expected = textwrap.dedent('''\
|
expected = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+-----------------------+------------------------+
|
+-----------------------+------------------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+-----------------------+------------------------+
|
+-----------------------+------------------------+
|
||||||
@ -243,7 +253,8 @@ class TestMaxWidth(base.TestBase):
|
|||||||
| a_really_long_field_n | a value significantly |
|
| a_really_long_field_n | a value significantly |
|
||||||
| ame | longer than the field |
|
| ame | longer than the field |
|
||||||
+-----------------------+------------------------+
|
+-----------------------+------------------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected,
|
expected,
|
||||||
_table_tester_helper(c, d, extra_args=['--fit-width']),
|
_table_tester_helper(c, d, extra_args=['--fit-width']),
|
||||||
@ -255,7 +266,8 @@ class TestMaxWidth(base.TestBase):
|
|||||||
tw.return_value = 10
|
tw.return_value = 10
|
||||||
c = ('field_name', 'a_really_long_field_name')
|
c = ('field_name', 'a_really_long_field_name')
|
||||||
d = ('the value', 'a value significantly longer than the field')
|
d = ('the value', 'a value significantly longer than the field')
|
||||||
expected = textwrap.dedent('''\
|
expected = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+------------------+------------------+
|
+------------------+------------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+------------------+------------------+
|
+------------------+------------------+
|
||||||
@ -265,7 +277,8 @@ class TestMaxWidth(base.TestBase):
|
|||||||
| | longer than the |
|
| | longer than the |
|
||||||
| | field |
|
| | field |
|
||||||
+------------------+------------------+
|
+------------------+------------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected,
|
expected,
|
||||||
_table_tester_helper(c, d, extra_args=['--fit-width']),
|
_table_tester_helper(c, d, extra_args=['--fit-width']),
|
||||||
@ -273,50 +286,51 @@ class TestMaxWidth(base.TestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestListFormatter(base.TestBase):
|
class TestListFormatter(base.TestBase):
|
||||||
|
|
||||||
_col_names = ('one', 'two', 'three')
|
_col_names = ('one', 'two', 'three')
|
||||||
_col_data = [(
|
_col_data = [('one one one one one', 'two two two two', 'three three')]
|
||||||
'one one one one one',
|
|
||||||
'two two two two',
|
|
||||||
'three three')]
|
|
||||||
|
|
||||||
_expected_mv = {
|
_expected_mv = {
|
||||||
80: textwrap.dedent('''\
|
80: textwrap.dedent(
|
||||||
|
'''\
|
||||||
+---------------------+-----------------+-------------+
|
+---------------------+-----------------+-------------+
|
||||||
| one | two | three |
|
| one | two | three |
|
||||||
+---------------------+-----------------+-------------+
|
+---------------------+-----------------+-------------+
|
||||||
| one one one one one | two two two two | three three |
|
| one one one one one | two two two two | three three |
|
||||||
+---------------------+-----------------+-------------+
|
+---------------------+-----------------+-------------+
|
||||||
'''),
|
'''
|
||||||
|
),
|
||||||
50: textwrap.dedent('''\
|
50: textwrap.dedent(
|
||||||
|
'''\
|
||||||
+----------------+-----------------+-------------+
|
+----------------+-----------------+-------------+
|
||||||
| one | two | three |
|
| one | two | three |
|
||||||
+----------------+-----------------+-------------+
|
+----------------+-----------------+-------------+
|
||||||
| one one one | two two two two | three three |
|
| one one one | two two two two | three three |
|
||||||
| one one | | |
|
| one one | | |
|
||||||
+----------------+-----------------+-------------+
|
+----------------+-----------------+-------------+
|
||||||
'''),
|
'''
|
||||||
|
),
|
||||||
47: textwrap.dedent('''\
|
47: textwrap.dedent(
|
||||||
|
'''\
|
||||||
+---------------+---------------+-------------+
|
+---------------+---------------+-------------+
|
||||||
| one | two | three |
|
| one | two | three |
|
||||||
+---------------+---------------+-------------+
|
+---------------+---------------+-------------+
|
||||||
| one one one | two two two | three three |
|
| one one one | two two two | three three |
|
||||||
| one one | two | |
|
| one one | two | |
|
||||||
+---------------+---------------+-------------+
|
+---------------+---------------+-------------+
|
||||||
'''),
|
'''
|
||||||
|
),
|
||||||
45: textwrap.dedent('''\
|
45: textwrap.dedent(
|
||||||
|
'''\
|
||||||
+--------------+--------------+-------------+
|
+--------------+--------------+-------------+
|
||||||
| one | two | three |
|
| one | two | three |
|
||||||
+--------------+--------------+-------------+
|
+--------------+--------------+-------------+
|
||||||
| one one one | two two two | three three |
|
| one one one | two two two | three three |
|
||||||
| one one | two | |
|
| one one | two | |
|
||||||
+--------------+--------------+-------------+
|
+--------------+--------------+-------------+
|
||||||
'''),
|
'''
|
||||||
|
),
|
||||||
40: textwrap.dedent('''\
|
40: textwrap.dedent(
|
||||||
|
'''\
|
||||||
+------------+------------+------------+
|
+------------+------------+------------+
|
||||||
| one | two | three |
|
| one | two | three |
|
||||||
+------------+------------+------------+
|
+------------+------------+------------+
|
||||||
@ -324,9 +338,10 @@ class TestListFormatter(base.TestBase):
|
|||||||
| one one | two two | three |
|
| one one | two two | three |
|
||||||
| one | | |
|
| one | | |
|
||||||
+------------+------------+------------+
|
+------------+------------+------------+
|
||||||
'''),
|
'''
|
||||||
|
),
|
||||||
10: textwrap.dedent('''\
|
10: textwrap.dedent(
|
||||||
|
'''\
|
||||||
+----------+----------+----------+
|
+----------+----------+----------+
|
||||||
| one | two | three |
|
| one | two | three |
|
||||||
+----------+----------+----------+
|
+----------+----------+----------+
|
||||||
@ -334,7 +349,8 @@ class TestListFormatter(base.TestBase):
|
|||||||
| one one | two two | three |
|
| one one | two two | three |
|
||||||
| one | | |
|
| one | | |
|
||||||
+----------+----------+----------+
|
+----------+----------+----------+
|
||||||
'''),
|
'''
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@mock.patch('cliff.utils.terminal_width')
|
@mock.patch('cliff.utils.terminal_width')
|
||||||
@ -344,7 +360,8 @@ class TestListFormatter(base.TestBase):
|
|||||||
d1 = ('A', 'B', 'C')
|
d1 = ('A', 'B', 'C')
|
||||||
d2 = ('D', 'E', 'test\rcarriage\r\nreturn')
|
d2 = ('D', 'E', 'test\rcarriage\r\nreturn')
|
||||||
data = [d1, d2]
|
data = [d1, d2]
|
||||||
expected = textwrap.dedent('''\
|
expected = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+---+---+---------------+
|
+---+---+---------------+
|
||||||
| a | b | c |
|
| a | b | c |
|
||||||
+---+---+---------------+
|
+---+---+---------------+
|
||||||
@ -352,7 +369,8 @@ class TestListFormatter(base.TestBase):
|
|||||||
| D | E | test carriage |
|
| D | E | test carriage |
|
||||||
| | | return |
|
| | | return |
|
||||||
+---+---+---------------+
|
+---+---+---------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
self.assertEqual(expected, _table_tester_helper(c, data))
|
self.assertEqual(expected, _table_tester_helper(c, data))
|
||||||
|
|
||||||
@mock.patch('cliff.utils.terminal_width')
|
@mock.patch('cliff.utils.terminal_width')
|
||||||
@ -360,7 +378,8 @@ class TestListFormatter(base.TestBase):
|
|||||||
tw.return_value = 0
|
tw.return_value = 0
|
||||||
c = ('a', 'b', 'c', 'd')
|
c = ('a', 'b', 'c', 'd')
|
||||||
d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value']))
|
d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value']))
|
||||||
expected = textwrap.dedent('''\
|
expected = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+-------+---------------------------------------------+
|
+-------+---------------------------------------------+
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
+-------+---------------------------------------------+
|
+-------+---------------------------------------------+
|
||||||
@ -369,7 +388,8 @@ class TestListFormatter(base.TestBase):
|
|||||||
| c | C |
|
| c | C |
|
||||||
| d | I made this string myself: ['the', 'value'] |
|
| d | I made this string myself: ['the', 'value'] |
|
||||||
+-------+---------------------------------------------+
|
+-------+---------------------------------------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
self.assertEqual(expected, _table_tester_helper(c, d))
|
self.assertEqual(expected, _table_tester_helper(c, d))
|
||||||
|
|
||||||
@mock.patch('cliff.utils.terminal_width')
|
@mock.patch('cliff.utils.terminal_width')
|
||||||
@ -378,13 +398,15 @@ class TestListFormatter(base.TestBase):
|
|||||||
c = ('a', 'b', 'c')
|
c = ('a', 'b', 'c')
|
||||||
d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value']))
|
d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value']))
|
||||||
data = [d1]
|
data = [d1]
|
||||||
expected = textwrap.dedent('''\
|
expected = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+---+---+---------------------------------------------+
|
+---+---+---------------------------------------------+
|
||||||
| a | b | c |
|
| a | b | c |
|
||||||
+---+---+---------------------------------------------+
|
+---+---+---------------------------------------------+
|
||||||
| A | B | I made this string myself: ['the', 'value'] |
|
| A | B | I made this string myself: ['the', 'value'] |
|
||||||
+---+---+---------------------------------------------+
|
+---+---+---------------------------------------------+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
self.assertEqual(expected, _table_tester_helper(c, data))
|
self.assertEqual(expected, _table_tester_helper(c, data))
|
||||||
|
|
||||||
@mock.patch('cliff.utils.terminal_width')
|
@mock.patch('cliff.utils.terminal_width')
|
||||||
@ -400,8 +422,9 @@ class TestListFormatter(base.TestBase):
|
|||||||
def test_max_width_50(self, tw):
|
def test_max_width_50(self, tw):
|
||||||
# resize 1 column
|
# resize 1 column
|
||||||
width = tw.return_value = 50
|
width = tw.return_value = 50
|
||||||
actual = _table_tester_helper(self._col_names, self._col_data,
|
actual = _table_tester_helper(
|
||||||
extra_args=['--fit-width'])
|
self._col_names, self._col_data, extra_args=['--fit-width']
|
||||||
|
)
|
||||||
self.assertEqual(self._expected_mv[width], actual)
|
self.assertEqual(self._expected_mv[width], actual)
|
||||||
self.assertEqual(width, len(actual.splitlines()[0]))
|
self.assertEqual(width, len(actual.splitlines()[0]))
|
||||||
|
|
||||||
@ -409,8 +432,9 @@ class TestListFormatter(base.TestBase):
|
|||||||
def test_max_width_45(self, tw):
|
def test_max_width_45(self, tw):
|
||||||
# resize 2 columns
|
# resize 2 columns
|
||||||
width = tw.return_value = 45
|
width = tw.return_value = 45
|
||||||
actual = _table_tester_helper(self._col_names, self._col_data,
|
actual = _table_tester_helper(
|
||||||
extra_args=['--fit-width'])
|
self._col_names, self._col_data, extra_args=['--fit-width']
|
||||||
|
)
|
||||||
self.assertEqual(self._expected_mv[width], actual)
|
self.assertEqual(self._expected_mv[width], actual)
|
||||||
self.assertEqual(width, len(actual.splitlines()[0]))
|
self.assertEqual(width, len(actual.splitlines()[0]))
|
||||||
|
|
||||||
@ -418,8 +442,9 @@ class TestListFormatter(base.TestBase):
|
|||||||
def test_max_width_40(self, tw):
|
def test_max_width_40(self, tw):
|
||||||
# resize all columns
|
# resize all columns
|
||||||
width = tw.return_value = 40
|
width = tw.return_value = 40
|
||||||
actual = _table_tester_helper(self._col_names, self._col_data,
|
actual = _table_tester_helper(
|
||||||
extra_args=['--fit-width'])
|
self._col_names, self._col_data, extra_args=['--fit-width']
|
||||||
|
)
|
||||||
self.assertEqual(self._expected_mv[width], actual)
|
self.assertEqual(self._expected_mv[width], actual)
|
||||||
self.assertEqual(width, len(actual.splitlines()[0]))
|
self.assertEqual(width, len(actual.splitlines()[0]))
|
||||||
|
|
||||||
@ -427,8 +452,9 @@ class TestListFormatter(base.TestBase):
|
|||||||
def test_max_width_10(self, tw):
|
def test_max_width_10(self, tw):
|
||||||
# resize all columns limited by min_width=8
|
# resize all columns limited by min_width=8
|
||||||
width = tw.return_value = 10
|
width = tw.return_value = 10
|
||||||
actual = _table_tester_helper(self._col_names, self._col_data,
|
actual = _table_tester_helper(
|
||||||
extra_args=['--fit-width'])
|
self._col_names, self._col_data, extra_args=['--fit-width']
|
||||||
|
)
|
||||||
self.assertEqual(self._expected_mv[width], actual)
|
self.assertEqual(self._expected_mv[width], actual)
|
||||||
# 3 columns each 8 wide, plus table spacing and borders
|
# 3 columns each 8 wide, plus table spacing and borders
|
||||||
expected_width = 11 * 3 + 1
|
expected_width = 11 * 3 + 1
|
||||||
@ -550,16 +576,18 @@ class TestListFormatter(base.TestBase):
|
|||||||
def test_env_maxwidth_args_big(self):
|
def test_env_maxwidth_args_big(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self._expected_mv[80],
|
self._expected_mv[80],
|
||||||
_table_tester_helper(self._col_names, self._col_data,
|
_table_tester_helper(
|
||||||
extra_args=args(666)),
|
self._col_names, self._col_data, extra_args=args(666)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '42'})
|
@mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '42'})
|
||||||
def test_env_maxwidth_args_tiny(self):
|
def test_env_maxwidth_args_tiny(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self._expected_mv[40],
|
self._expected_mv[40],
|
||||||
_table_tester_helper(self._col_names, self._col_data,
|
_table_tester_helper(
|
||||||
extra_args=args(40)),
|
self._col_names, self._col_data, extra_args=args(40)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch('cliff.utils.terminal_width')
|
@mock.patch('cliff.utils.terminal_width')
|
||||||
@ -575,46 +603,35 @@ class TestListFormatter(base.TestBase):
|
|||||||
tw.return_value = 80
|
tw.return_value = 80
|
||||||
c = ('a', 'b', 'c')
|
c = ('a', 'b', 'c')
|
||||||
data = []
|
data = []
|
||||||
expected = textwrap.dedent('''\
|
expected = textwrap.dedent(
|
||||||
|
'''\
|
||||||
+---+---+---+
|
+---+---+---+
|
||||||
| a | b | c |
|
| a | b | c |
|
||||||
+---+---+---+
|
+---+---+---+
|
||||||
+---+---+---+
|
+---+---+---+
|
||||||
''')
|
'''
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected,
|
expected,
|
||||||
_table_tester_helper(c, data,
|
_table_tester_helper(c, data, extra_args=['--print-empty']),
|
||||||
extra_args=['--print-empty']),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestFieldWidths(base.TestBase):
|
class TestFieldWidths(base.TestBase):
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
tf = table.TableFormatter
|
tf = table.TableFormatter
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{
|
{'a': 1, 'b': 2, 'c': 3, 'd': 10},
|
||||||
'a': 1,
|
|
||||||
'b': 2,
|
|
||||||
'c': 3,
|
|
||||||
'd': 10
|
|
||||||
},
|
|
||||||
tf._field_widths(
|
tf._field_widths(
|
||||||
('a', 'b', 'c', 'd'),
|
('a', 'b', 'c', 'd'), '+---+----+-----+------------+'
|
||||||
'+---+----+-----+------------+'),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_zero(self):
|
def test_zero(self):
|
||||||
tf = table.TableFormatter
|
tf = table.TableFormatter
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{
|
{'a': 0, 'b': 0, 'c': 0},
|
||||||
'a': 0,
|
tf._field_widths(('a', 'b', 'c'), '+--+-++'),
|
||||||
'b': 0,
|
|
||||||
'c': 0
|
|
||||||
},
|
|
||||||
tf._field_widths(
|
|
||||||
('a', 'b', 'c'),
|
|
||||||
'+--+-++'),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_info(self):
|
def test_info(self):
|
||||||
|
@ -20,7 +20,6 @@ from cliff.tests import test_columns
|
|||||||
|
|
||||||
|
|
||||||
class TestValueFormatter(base.TestBase):
|
class TestValueFormatter(base.TestBase):
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
sf = value.ValueFormatter()
|
sf = value.ValueFormatter()
|
||||||
c = ('a', 'b', 'c', 'd')
|
c = ('a', 'b', 'c', 'd')
|
||||||
|
@ -23,7 +23,6 @@ from cliff.tests import test_columns
|
|||||||
|
|
||||||
|
|
||||||
class _toDict:
|
class _toDict:
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self._data = kwargs
|
self._data = kwargs
|
||||||
|
|
||||||
@ -40,17 +39,11 @@ class _to_Dict:
|
|||||||
|
|
||||||
|
|
||||||
class TestYAMLFormatter(base.TestBase):
|
class TestYAMLFormatter(base.TestBase):
|
||||||
|
|
||||||
def test_format_one(self):
|
def test_format_one(self):
|
||||||
sf = yaml_format.YAMLFormatter()
|
sf = yaml_format.YAMLFormatter()
|
||||||
c = ('a', 'b', 'c', 'd')
|
c = ('a', 'b', 'c', 'd')
|
||||||
d = ('A', 'B', 'C', '"escape me"')
|
d = ('A', 'B', 'C', '"escape me"')
|
||||||
expected = {
|
expected = {'a': 'A', 'b': 'B', 'c': 'C', 'd': '"escape me"'}
|
||||||
'a': 'A',
|
|
||||||
'b': 'B',
|
|
||||||
'c': 'C',
|
|
||||||
'd': '"escape me"'
|
|
||||||
}
|
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
args = mock.Mock()
|
args = mock.Mock()
|
||||||
sf.emit_one(c, d, output, args)
|
sf.emit_one(c, d, output, args)
|
||||||
@ -81,15 +74,11 @@ class TestYAMLFormatter(base.TestBase):
|
|||||||
def test_list(self):
|
def test_list(self):
|
||||||
sf = yaml_format.YAMLFormatter()
|
sf = yaml_format.YAMLFormatter()
|
||||||
c = ('a', 'b', 'c')
|
c = ('a', 'b', 'c')
|
||||||
d = (
|
d = (('A1', 'B1', 'C1'), ('A2', 'B2', 'C2'), ('A3', 'B3', 'C3'))
|
||||||
('A1', 'B1', 'C1'),
|
|
||||||
('A2', 'B2', 'C2'),
|
|
||||||
('A3', 'B3', 'C3')
|
|
||||||
)
|
|
||||||
expected = [
|
expected = [
|
||||||
{'a': 'A1', 'b': 'B1', 'c': 'C1'},
|
{'a': 'A1', 'b': 'B1', 'c': 'C1'},
|
||||||
{'a': 'A2', 'b': 'B2', 'c': 'C2'},
|
{'a': 'A2', 'b': 'B2', 'c': 'C2'},
|
||||||
{'a': 'A3', 'b': 'B3', 'c': 'C3'}
|
{'a': 'A3', 'b': 'B3', 'c': 'C3'},
|
||||||
]
|
]
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
args = mock.Mock()
|
args = mock.Mock()
|
||||||
@ -101,9 +90,7 @@ class TestYAMLFormatter(base.TestBase):
|
|||||||
def test_formattablecolumn_list(self):
|
def test_formattablecolumn_list(self):
|
||||||
sf = yaml_format.YAMLFormatter()
|
sf = yaml_format.YAMLFormatter()
|
||||||
c = ('a', 'b', 'c')
|
c = ('a', 'b', 'c')
|
||||||
d = (
|
d = (('A1', 'B1', test_columns.FauxColumn(['the', 'value'])),)
|
||||||
('A1', 'B1', test_columns.FauxColumn(['the', 'value'])),
|
|
||||||
)
|
|
||||||
expected = [
|
expected = [
|
||||||
{'a': 'A1', 'b': 'B1', 'c': ['the', 'value']},
|
{'a': 'A1', 'b': 'B1', 'c': ['the', 'value']},
|
||||||
]
|
]
|
||||||
@ -124,7 +111,7 @@ class TestYAMLFormatter(base.TestBase):
|
|||||||
'a': 'A',
|
'a': 'A',
|
||||||
'b': 'B',
|
'b': 'B',
|
||||||
'toDict': {"spam": "ham"},
|
'toDict': {"spam": "ham"},
|
||||||
'to_dict': {"ham": "eggs"}
|
'to_dict': {"ham": "eggs"},
|
||||||
}
|
}
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
args = mock.Mock()
|
args = mock.Mock()
|
||||||
@ -138,12 +125,12 @@ class TestYAMLFormatter(base.TestBase):
|
|||||||
d = (
|
d = (
|
||||||
('A1', _toDict(B=1), _to_Dict(C=1)),
|
('A1', _toDict(B=1), _to_Dict(C=1)),
|
||||||
('A2', _toDict(B=2), _to_Dict(C=2)),
|
('A2', _toDict(B=2), _to_Dict(C=2)),
|
||||||
('A3', _toDict(B=3), _to_Dict(C=3))
|
('A3', _toDict(B=3), _to_Dict(C=3)),
|
||||||
)
|
)
|
||||||
expected = [
|
expected = [
|
||||||
{'a': 'A1', 'toDict': {'B': 1}, 'to_dict': {'C': 1}},
|
{'a': 'A1', 'toDict': {'B': 1}, 'to_dict': {'C': 1}},
|
||||||
{'a': 'A2', 'toDict': {'B': 2}, 'to_dict': {'C': 2}},
|
{'a': 'A2', 'toDict': {'B': 2}, 'to_dict': {'C': 2}},
|
||||||
{'a': 'A3', 'toDict': {'B': 3}, 'to_dict': {'C': 3}}
|
{'a': 'A3', 'toDict': {'B': 3}, 'to_dict': {'C': 3}},
|
||||||
]
|
]
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
args = mock.Mock()
|
args = mock.Mock()
|
||||||
|
@ -24,15 +24,17 @@ from cliff.tests import utils
|
|||||||
|
|
||||||
|
|
||||||
class TestHelp(base.TestBase):
|
class TestHelp(base.TestBase):
|
||||||
|
|
||||||
def test_show_help_for_command(self):
|
def test_show_help_for_command(self):
|
||||||
# FIXME(dhellmann): Are commands tied too closely to the app? Or
|
# FIXME(dhellmann): Are commands tied too closely to the app? Or
|
||||||
# do commands know too much about apps by using them to get to the
|
# do commands know too much about apps by using them to get to the
|
||||||
# command manager?
|
# command manager?
|
||||||
stdout = io.StringIO()
|
stdout = io.StringIO()
|
||||||
app = application.App('testing', '1',
|
app = application.App(
|
||||||
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
'testing',
|
||||||
stdout=stdout)
|
'1',
|
||||||
|
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
||||||
|
stdout=stdout,
|
||||||
|
)
|
||||||
app.NAME = 'test'
|
app.NAME = 'test'
|
||||||
help_cmd = help.HelpCommand(app, mock.Mock())
|
help_cmd = help.HelpCommand(app, mock.Mock())
|
||||||
parser = help_cmd.get_parser('test')
|
parser = help_cmd.get_parser('test')
|
||||||
@ -48,9 +50,12 @@ class TestHelp(base.TestBase):
|
|||||||
# do commands know too much about apps by using them to get to the
|
# do commands know too much about apps by using them to get to the
|
||||||
# command manager?
|
# command manager?
|
||||||
stdout = io.StringIO()
|
stdout = io.StringIO()
|
||||||
app = application.App('testing', '1',
|
app = application.App(
|
||||||
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
'testing',
|
||||||
stdout=stdout)
|
'1',
|
||||||
|
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
||||||
|
stdout=stdout,
|
||||||
|
)
|
||||||
app.NAME = 'test'
|
app.NAME = 'test'
|
||||||
help_cmd = help.HelpCommand(app, mock.Mock())
|
help_cmd = help.HelpCommand(app, mock.Mock())
|
||||||
parser = help_cmd.get_parser('test')
|
parser = help_cmd.get_parser('test')
|
||||||
@ -68,9 +73,12 @@ class TestHelp(base.TestBase):
|
|||||||
# do commands know too much about apps by using them to get to the
|
# do commands know too much about apps by using them to get to the
|
||||||
# command manager?
|
# command manager?
|
||||||
stdout = io.StringIO()
|
stdout = io.StringIO()
|
||||||
app = application.App('testing', '1',
|
app = application.App(
|
||||||
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
'testing',
|
||||||
stdout=stdout)
|
'1',
|
||||||
|
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
||||||
|
stdout=stdout,
|
||||||
|
)
|
||||||
app.NAME = 'test'
|
app.NAME = 'test'
|
||||||
help_cmd = help.HelpCommand(app, mock.Mock())
|
help_cmd = help.HelpCommand(app, mock.Mock())
|
||||||
parser = help_cmd.get_parser('test')
|
parser = help_cmd.get_parser('test')
|
||||||
@ -86,9 +94,12 @@ class TestHelp(base.TestBase):
|
|||||||
# do commands know too much about apps by using them to get to the
|
# do commands know too much about apps by using them to get to the
|
||||||
# command manager?
|
# command manager?
|
||||||
stdout = io.StringIO()
|
stdout = io.StringIO()
|
||||||
app = application.App('testing', '1',
|
app = application.App(
|
||||||
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
'testing',
|
||||||
stdout=stdout)
|
'1',
|
||||||
|
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
||||||
|
stdout=stdout,
|
||||||
|
)
|
||||||
app.NAME = 'test'
|
app.NAME = 'test'
|
||||||
app.options = mock.Mock()
|
app.options = mock.Mock()
|
||||||
help_cmd = help.HelpCommand(app, mock.Mock())
|
help_cmd = help.HelpCommand(app, mock.Mock())
|
||||||
@ -113,9 +124,12 @@ class TestHelp(base.TestBase):
|
|||||||
# do commands know too much about apps by using them to get to the
|
# do commands know too much about apps by using them to get to the
|
||||||
# command manager?
|
# command manager?
|
||||||
stdout = io.StringIO()
|
stdout = io.StringIO()
|
||||||
app = application.App('testing', '1',
|
app = application.App(
|
||||||
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
'testing',
|
||||||
stdout=stdout)
|
'1',
|
||||||
|
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
||||||
|
stdout=stdout,
|
||||||
|
)
|
||||||
app.NAME = 'test'
|
app.NAME = 'test'
|
||||||
try:
|
try:
|
||||||
app.run(['--help'])
|
app.run(['--help'])
|
||||||
@ -126,13 +140,19 @@ class TestHelp(base.TestBase):
|
|||||||
self.assertIn('three word command', help_output)
|
self.assertIn('three word command', help_output)
|
||||||
self.assertNotIn('old cmd', help_output)
|
self.assertNotIn('old cmd', help_output)
|
||||||
|
|
||||||
@mock.patch.object(commandmanager.EntryPointWrapper, 'load',
|
@mock.patch.object(
|
||||||
side_effect=Exception('Could not load EntryPoint'))
|
commandmanager.EntryPointWrapper,
|
||||||
|
'load',
|
||||||
|
side_effect=Exception('Could not load EntryPoint'),
|
||||||
|
)
|
||||||
def test_show_help_with_ep_load_fail(self, mock_load):
|
def test_show_help_with_ep_load_fail(self, mock_load):
|
||||||
stdout = io.StringIO()
|
stdout = io.StringIO()
|
||||||
app = application.App('testing', '1',
|
app = application.App(
|
||||||
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
'testing',
|
||||||
stdout=stdout)
|
'1',
|
||||||
|
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
||||||
|
stdout=stdout,
|
||||||
|
)
|
||||||
app.NAME = 'test'
|
app.NAME = 'test'
|
||||||
app.options = mock.Mock()
|
app.options = mock.Mock()
|
||||||
app.options.debug = False
|
app.options.debug = False
|
||||||
@ -148,13 +168,19 @@ class TestHelp(base.TestBase):
|
|||||||
self.assertIn('Could not load', help_output)
|
self.assertIn('Could not load', help_output)
|
||||||
self.assertNotIn('Exception: Could not load EntryPoint', help_output)
|
self.assertNotIn('Exception: Could not load EntryPoint', help_output)
|
||||||
|
|
||||||
@mock.patch.object(commandmanager.EntryPointWrapper, 'load',
|
@mock.patch.object(
|
||||||
side_effect=Exception('Could not load EntryPoint'))
|
commandmanager.EntryPointWrapper,
|
||||||
|
'load',
|
||||||
|
side_effect=Exception('Could not load EntryPoint'),
|
||||||
|
)
|
||||||
def test_show_help_print_exc_with_ep_load_fail(self, mock_load):
|
def test_show_help_print_exc_with_ep_load_fail(self, mock_load):
|
||||||
stdout = io.StringIO()
|
stdout = io.StringIO()
|
||||||
app = application.App('testing', '1',
|
app = application.App(
|
||||||
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
'testing',
|
||||||
stdout=stdout)
|
'1',
|
||||||
|
utils.TestCommandManager(utils.TEST_NAMESPACE),
|
||||||
|
stdout=stdout,
|
||||||
|
)
|
||||||
app.NAME = 'test'
|
app.NAME = 'test'
|
||||||
app.options = mock.Mock()
|
app.options = mock.Mock()
|
||||||
app.options.debug = True
|
app.options.debug = True
|
||||||
|
@ -23,16 +23,21 @@ class FakeApp(object):
|
|||||||
|
|
||||||
|
|
||||||
class TestInteractive(base.TestBase):
|
class TestInteractive(base.TestBase):
|
||||||
|
|
||||||
def make_interactive_app(self, errexit, *command_names):
|
def make_interactive_app(self, errexit, *command_names):
|
||||||
fake_command_manager = [(x, None) for x in command_names]
|
fake_command_manager = [(x, None) for x in command_names]
|
||||||
return InteractiveApp(FakeApp, fake_command_manager,
|
return InteractiveApp(
|
||||||
stdin=None, stdout=None, errexit=errexit)
|
FakeApp,
|
||||||
|
fake_command_manager,
|
||||||
|
stdin=None,
|
||||||
|
stdout=None,
|
||||||
|
errexit=errexit,
|
||||||
|
)
|
||||||
|
|
||||||
def _test_completenames(self, expecteds, prefix):
|
def _test_completenames(self, expecteds, prefix):
|
||||||
app = self.make_interactive_app(False, 'hips', 'hippo', 'nonmatching')
|
app = self.make_interactive_app(False, 'hips', 'hippo', 'nonmatching')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set(app.completenames(prefix, '', 0, 1)), set(expecteds))
|
set(app.completenames(prefix, '', 0, 1)), set(expecteds)
|
||||||
|
)
|
||||||
|
|
||||||
def test_cmd2_completenames(self):
|
def test_cmd2_completenames(self):
|
||||||
# cmd2.Cmd define do_help method
|
# cmd2.Cmd define do_help method
|
||||||
@ -56,8 +61,9 @@ class TestInteractive(base.TestBase):
|
|||||||
self._test_completenames(['history', 'hips', 'hippo'], 'hi')
|
self._test_completenames(['history', 'hips', 'hippo'], 'hi')
|
||||||
|
|
||||||
def _test_completedefault(self, expecteds, line, begidx):
|
def _test_completedefault(self, expecteds, line, begidx):
|
||||||
command_names = set(['show file', 'show folder', 'show long',
|
command_names = set(
|
||||||
'list all'])
|
['show file', 'show folder', 'show long', 'list all']
|
||||||
|
)
|
||||||
app = self.make_interactive_app(False, *command_names)
|
app = self.make_interactive_app(False, *command_names)
|
||||||
observeds = app.completedefault(None, line, begidx, None)
|
observeds = app.completedefault(None, line, begidx, None)
|
||||||
self.assertEqual(set(expecteds), set(observeds))
|
self.assertEqual(set(expecteds), set(observeds))
|
||||||
|
@ -21,7 +21,6 @@ from cliff.tests import base
|
|||||||
|
|
||||||
|
|
||||||
class FauxFormatter(object):
|
class FauxFormatter(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.args = []
|
self.args = []
|
||||||
self.obj = weakref.proxy(self)
|
self.obj = weakref.proxy(self)
|
||||||
@ -31,7 +30,6 @@ class FauxFormatter(object):
|
|||||||
|
|
||||||
|
|
||||||
class ExerciseLister(lister.Lister):
|
class ExerciseLister(lister.Lister):
|
||||||
|
|
||||||
data = [('a', 'A'), ('b', 'B'), ('c', 'A')]
|
data = [('a', 'A'), ('b', 'B'), ('c', 'A')]
|
||||||
|
|
||||||
def _load_formatter_plugins(self):
|
def _load_formatter_plugins(self):
|
||||||
@ -44,22 +42,18 @@ class ExerciseLister(lister.Lister):
|
|||||||
|
|
||||||
|
|
||||||
class ExerciseListerCustomSort(ExerciseLister):
|
class ExerciseListerCustomSort(ExerciseLister):
|
||||||
|
|
||||||
need_sort_by_cliff = False
|
need_sort_by_cliff = False
|
||||||
|
|
||||||
|
|
||||||
class ExerciseListerNullValues(ExerciseLister):
|
class ExerciseListerNullValues(ExerciseLister):
|
||||||
|
|
||||||
data = ExerciseLister.data + [(None, None)]
|
data = ExerciseLister.data + [(None, None)]
|
||||||
|
|
||||||
|
|
||||||
class ExerciseListerDifferentTypes(ExerciseLister):
|
class ExerciseListerDifferentTypes(ExerciseLister):
|
||||||
|
|
||||||
data = ExerciseLister.data + [(1, 0)]
|
data = ExerciseLister.data + [(1, 0)]
|
||||||
|
|
||||||
|
|
||||||
class TestLister(base.TestBase):
|
class TestLister(base.TestBase):
|
||||||
|
|
||||||
def test_formatter_args(self):
|
def test_formatter_args(self):
|
||||||
app = mock.Mock()
|
app = mock.Mock()
|
||||||
test_lister = ExerciseLister(app, [])
|
test_lister = ExerciseLister(app, [])
|
||||||
@ -148,7 +142,8 @@ class TestLister(base.TestBase):
|
|||||||
args = f.args[0]
|
args = f.args[0]
|
||||||
data = list(args[1])
|
data = list(args[1])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[['a', 'A'], ['c', 'A'], ['b', 'B'], [None, None]], data)
|
[['a', 'A'], ['c', 'A'], ['b', 'B'], [None, None]], data
|
||||||
|
)
|
||||||
|
|
||||||
def test_sort_by_column_with_different_types(self):
|
def test_sort_by_column_with_different_types(self):
|
||||||
test_lister = ExerciseListerDifferentTypes(mock.Mock(), [])
|
test_lister = ExerciseListerDifferentTypes(mock.Mock(), [])
|
||||||
@ -164,13 +159,16 @@ class TestLister(base.TestBase):
|
|||||||
args = f.args[0]
|
args = f.args[0]
|
||||||
data = list(args[1])
|
data = list(args[1])
|
||||||
# The output should be unchanged
|
# The output should be unchanged
|
||||||
self.assertEqual(
|
self.assertEqual([['a', 'A'], ['b', 'B'], ['c', 'A'], [1, 0]], data)
|
||||||
[['a', 'A'], ['b', 'B'], ['c', 'A'], [1, 0]], data)
|
|
||||||
# but we should have logged a warning
|
# but we should have logged a warning
|
||||||
mock_log.warning.assert_has_calls([
|
mock_log.warning.assert_has_calls(
|
||||||
mock.call("Could not sort on field '%s'; unsortable types", col)
|
[
|
||||||
for col in parsed_args.sort_columns
|
mock.call(
|
||||||
])
|
"Could not sort on field '%s'; unsortable types", col
|
||||||
|
)
|
||||||
|
for col in parsed_args.sort_columns
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def test_sort_by_non_displayed_column(self):
|
def test_sort_by_non_displayed_column(self):
|
||||||
test_lister = ExerciseLister(mock.Mock(), [])
|
test_lister = ExerciseLister(mock.Mock(), [])
|
||||||
@ -181,7 +179,8 @@ class TestLister(base.TestBase):
|
|||||||
|
|
||||||
with mock.patch.object(test_lister, 'take_action') as mock_take_action:
|
with mock.patch.object(test_lister, 'take_action') as mock_take_action:
|
||||||
mock_take_action.return_value = (
|
mock_take_action.return_value = (
|
||||||
('Col1', 'Col2'), [['a', 'A'], ['b', 'B'], ['c', 'A']]
|
('Col1', 'Col2'),
|
||||||
|
[['a', 'A'], ['b', 'B'], ['c', 'A']],
|
||||||
)
|
)
|
||||||
test_lister.run(parsed_args)
|
test_lister.run(parsed_args)
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ from cliff.tests import base
|
|||||||
|
|
||||||
|
|
||||||
class FauxFormatter(object):
|
class FauxFormatter(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.args = []
|
self.args = []
|
||||||
self.obj = weakref.proxy(self)
|
self.obj = weakref.proxy(self)
|
||||||
@ -31,7 +30,6 @@ class FauxFormatter(object):
|
|||||||
|
|
||||||
|
|
||||||
class ExerciseShowOne(show.ShowOne):
|
class ExerciseShowOne(show.ShowOne):
|
||||||
|
|
||||||
def _load_formatter_plugins(self):
|
def _load_formatter_plugins(self):
|
||||||
return {
|
return {
|
||||||
'test': FauxFormatter(),
|
'test': FauxFormatter(),
|
||||||
@ -45,7 +43,6 @@ class ExerciseShowOne(show.ShowOne):
|
|||||||
|
|
||||||
|
|
||||||
class TestShow(base.TestBase):
|
class TestShow(base.TestBase):
|
||||||
|
|
||||||
def test_formatter_args(self):
|
def test_formatter_args(self):
|
||||||
app = mock.Mock()
|
app = mock.Mock()
|
||||||
test_show = ExerciseShowOne(app, [])
|
test_show = ExerciseShowOne(app, [])
|
||||||
|
@ -20,7 +20,6 @@ from cliff.tests import base
|
|||||||
|
|
||||||
|
|
||||||
class TestSphinxExtension(base.TestBase):
|
class TestSphinxExtension(base.TestBase):
|
||||||
|
|
||||||
def test_empty_help(self):
|
def test_empty_help(self):
|
||||||
"""Handle positional and optional actions without help messages."""
|
"""Handle positional and optional actions without help messages."""
|
||||||
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
||||||
@ -28,7 +27,9 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
parser.add_argument('--language', dest='lang')
|
parser.add_argument('--language', dest='lang')
|
||||||
|
|
||||||
output = '\n'.join(sphinxext._format_parser(parser))
|
output = '\n'.join(sphinxext._format_parser(parser))
|
||||||
self.assertEqual(textwrap.dedent("""
|
self.assertEqual(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
.. program:: hello-world
|
.. program:: hello-world
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -37,17 +38,23 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
.. option:: --language <LANG>
|
.. option:: --language <LANG>
|
||||||
|
|
||||||
.. option:: name
|
.. option:: name
|
||||||
""").lstrip(), output)
|
"""
|
||||||
|
).lstrip(),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
def test_nonempty_help(self):
|
def test_nonempty_help(self):
|
||||||
"""Handle positional and optional actions with help messages."""
|
"""Handle positional and optional actions with help messages."""
|
||||||
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
||||||
parser.add_argument('name', help='user name')
|
parser.add_argument('name', help='user name')
|
||||||
parser.add_argument('--language', dest='lang',
|
parser.add_argument(
|
||||||
help='greeting language')
|
'--language', dest='lang', help='greeting language'
|
||||||
|
)
|
||||||
|
|
||||||
output = '\n'.join(sphinxext._format_parser(parser))
|
output = '\n'.join(sphinxext._format_parser(parser))
|
||||||
self.assertEqual(textwrap.dedent("""
|
self.assertEqual(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
.. program:: hello-world
|
.. program:: hello-world
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -60,18 +67,26 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
.. option:: name
|
.. option:: name
|
||||||
|
|
||||||
user name
|
user name
|
||||||
""").lstrip(), output)
|
"""
|
||||||
|
).lstrip(),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
def test_description_epilog(self):
|
def test_description_epilog(self):
|
||||||
"""Handle a parser description, epilog."""
|
"""Handle a parser description, epilog."""
|
||||||
parser = argparse.ArgumentParser(prog='hello-world', add_help=False,
|
parser = argparse.ArgumentParser(
|
||||||
description='A "Hello, World" app.',
|
prog='hello-world',
|
||||||
epilog='What am I doing down here?')
|
add_help=False,
|
||||||
|
description='A "Hello, World" app.',
|
||||||
|
epilog='What am I doing down here?',
|
||||||
|
)
|
||||||
parser.add_argument('name', action='store')
|
parser.add_argument('name', action='store')
|
||||||
parser.add_argument('--language', dest='lang')
|
parser.add_argument('--language', dest='lang')
|
||||||
|
|
||||||
output = '\n'.join(sphinxext._format_parser(parser))
|
output = '\n'.join(sphinxext._format_parser(parser))
|
||||||
self.assertEqual(textwrap.dedent("""
|
self.assertEqual(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
A "Hello, World" app.
|
A "Hello, World" app.
|
||||||
|
|
||||||
.. program:: hello-world
|
.. program:: hello-world
|
||||||
@ -84,17 +99,25 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
.. option:: name
|
.. option:: name
|
||||||
|
|
||||||
What am I doing down here?
|
What am I doing down here?
|
||||||
""").lstrip(), output)
|
"""
|
||||||
|
).lstrip(),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
def test_flag(self):
|
def test_flag(self):
|
||||||
"""Handle a boolean argparse action."""
|
"""Handle a boolean argparse action."""
|
||||||
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
||||||
parser.add_argument('name', help='user name')
|
parser.add_argument('name', help='user name')
|
||||||
parser.add_argument('--translate', action='store_true',
|
parser.add_argument(
|
||||||
help='translate to local language')
|
'--translate',
|
||||||
|
action='store_true',
|
||||||
|
help='translate to local language',
|
||||||
|
)
|
||||||
|
|
||||||
output = '\n'.join(sphinxext._format_parser(parser))
|
output = '\n'.join(sphinxext._format_parser(parser))
|
||||||
self.assertEqual(textwrap.dedent("""
|
self.assertEqual(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
.. program:: hello-world
|
.. program:: hello-world
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -107,7 +130,10 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
.. option:: name
|
.. option:: name
|
||||||
|
|
||||||
user name
|
user name
|
||||||
""").lstrip(), output)
|
"""
|
||||||
|
).lstrip(),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
def test_supressed(self):
|
def test_supressed(self):
|
||||||
"""Handle a supressed action."""
|
"""Handle a supressed action."""
|
||||||
@ -116,7 +142,9 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
parser.add_argument('--variable', help=argparse.SUPPRESS)
|
parser.add_argument('--variable', help=argparse.SUPPRESS)
|
||||||
|
|
||||||
output = '\n'.join(sphinxext._format_parser(parser))
|
output = '\n'.join(sphinxext._format_parser(parser))
|
||||||
self.assertEqual(textwrap.dedent("""
|
self.assertEqual(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
.. program:: hello-world
|
.. program:: hello-world
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -126,16 +154,22 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
.. option:: name
|
.. option:: name
|
||||||
|
|
||||||
user name
|
user name
|
||||||
""").lstrip(), output)
|
"""
|
||||||
|
).lstrip(),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
def test_metavar(self):
|
def test_metavar(self):
|
||||||
"""Handle an option with a metavar."""
|
"""Handle an option with a metavar."""
|
||||||
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
||||||
parser.add_argument('names', metavar='<NAME>', nargs='+',
|
parser.add_argument(
|
||||||
help='a user name')
|
'names', metavar='<NAME>', nargs='+', help='a user name'
|
||||||
|
)
|
||||||
|
|
||||||
output = '\n'.join(sphinxext._format_parser(parser))
|
output = '\n'.join(sphinxext._format_parser(parser))
|
||||||
self.assertEqual(textwrap.dedent("""
|
self.assertEqual(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
.. program:: hello-world
|
.. program:: hello-world
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -144,29 +178,46 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
.. option:: NAME
|
.. option:: NAME
|
||||||
|
|
||||||
a user name
|
a user name
|
||||||
""").lstrip(), output)
|
"""
|
||||||
|
).lstrip(),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
def test_multiple_opts(self):
|
def test_multiple_opts(self):
|
||||||
"""Correctly output multiple opts on separate lines."""
|
"""Correctly output multiple opts on separate lines."""
|
||||||
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
||||||
parser.add_argument('name', help='user name')
|
parser.add_argument('name', help='user name')
|
||||||
parser.add_argument('--language', dest='lang',
|
parser.add_argument(
|
||||||
help='greeting language')
|
'--language', dest='lang', help='greeting language'
|
||||||
parser.add_argument('--translate', action='store_true',
|
)
|
||||||
help='translate to local language')
|
parser.add_argument(
|
||||||
parser.add_argument('--write-to-var-log-something-or-other',
|
'--translate',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='a long opt to force wrapping')
|
help='translate to local language',
|
||||||
parser.add_argument('--required-arg', dest='stuff', required=True,
|
)
|
||||||
help='a required argument')
|
parser.add_argument(
|
||||||
|
'--write-to-var-log-something-or-other',
|
||||||
|
action='store_true',
|
||||||
|
help='a long opt to force wrapping',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--required-arg',
|
||||||
|
dest='stuff',
|
||||||
|
required=True,
|
||||||
|
help='a required argument',
|
||||||
|
)
|
||||||
style_group = parser.add_mutually_exclusive_group(required=True)
|
style_group = parser.add_mutually_exclusive_group(required=True)
|
||||||
style_group.add_argument('--polite', action='store_true',
|
style_group.add_argument(
|
||||||
help='use a polite greeting')
|
'--polite', action='store_true', help='use a polite greeting'
|
||||||
style_group.add_argument('--profane', action='store_true',
|
)
|
||||||
help='use a less polite greeting')
|
style_group.add_argument(
|
||||||
|
'--profane', action='store_true', help='use a less polite greeting'
|
||||||
|
)
|
||||||
|
|
||||||
output = '\n'.join(sphinxext._format_parser(parser))
|
output = '\n'.join(sphinxext._format_parser(parser))
|
||||||
self.assertEqual(textwrap.dedent("""
|
self.assertEqual(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
.. program:: hello-world
|
.. program:: hello-world
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -205,26 +256,36 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
.. option:: name
|
.. option:: name
|
||||||
|
|
||||||
user name
|
user name
|
||||||
""").lstrip(), output)
|
"""
|
||||||
|
).lstrip(),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
def test_various_option_names_with_hyphen(self):
|
def test_various_option_names_with_hyphen(self):
|
||||||
"""Handle options whose name and/or metavar contain hyphen(s)"""
|
"""Handle options whose name and/or metavar contain hyphen(s)"""
|
||||||
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
parser = argparse.ArgumentParser(prog='hello-world', add_help=False)
|
||||||
parser.add_argument('--foo-bar', metavar='<foo-bar>',
|
parser.add_argument(
|
||||||
help='foo bar', required=True)
|
'--foo-bar', metavar='<foo-bar>', help='foo bar', required=True
|
||||||
parser.add_argument('--foo-bar-baz', metavar='<foo-bar-baz>',
|
)
|
||||||
help='foo bar baz', required=True)
|
parser.add_argument(
|
||||||
parser.add_argument('--foo', metavar='<foo>',
|
'--foo-bar-baz',
|
||||||
help='foo', required=True)
|
metavar='<foo-bar-baz>',
|
||||||
parser.add_argument('--alpha', metavar='<A>',
|
help='foo bar baz',
|
||||||
help='alpha')
|
required=True,
|
||||||
parser.add_argument('--alpha-beta', metavar='<A-B>',
|
)
|
||||||
help='alpha beta')
|
parser.add_argument(
|
||||||
parser.add_argument('--alpha-beta-gamma', metavar='<A-B-C>',
|
'--foo', metavar='<foo>', help='foo', required=True
|
||||||
help='alpha beta gamma')
|
)
|
||||||
|
parser.add_argument('--alpha', metavar='<A>', help='alpha')
|
||||||
|
parser.add_argument('--alpha-beta', metavar='<A-B>', help='alpha beta')
|
||||||
|
parser.add_argument(
|
||||||
|
'--alpha-beta-gamma', metavar='<A-B-C>', help='alpha beta gamma'
|
||||||
|
)
|
||||||
|
|
||||||
output = '\n'.join(sphinxext._format_parser(parser))
|
output = '\n'.join(sphinxext._format_parser(parser))
|
||||||
self.assertEqual(textwrap.dedent("""
|
self.assertEqual(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
.. program:: hello-world
|
.. program:: hello-world
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -259,4 +320,7 @@ class TestSphinxExtension(base.TestBase):
|
|||||||
.. option:: --alpha-beta-gamma <A-B-C>
|
.. option:: --alpha-beta-gamma <A-B-C>
|
||||||
|
|
||||||
alpha beta gamma
|
alpha beta gamma
|
||||||
""").lstrip(), output)
|
"""
|
||||||
|
).lstrip(),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
@ -20,7 +20,6 @@ from cliff import utils
|
|||||||
|
|
||||||
|
|
||||||
class TestTerminalWidth(base.TestBase):
|
class TestTerminalWidth(base.TestBase):
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
width = utils.terminal_width()
|
width = utils.terminal_width()
|
||||||
# Results are specific to the execution environment, so only assert
|
# Results are specific to the execution environment, so only assert
|
||||||
|
@ -17,7 +17,6 @@ TEST_NAMESPACE = 'cliff.test'
|
|||||||
|
|
||||||
|
|
||||||
class TestParser(object):
|
class TestParser(object):
|
||||||
|
|
||||||
def print_help(self, stdout):
|
def print_help(self, stdout):
|
||||||
stdout.write('TestParser')
|
stdout.write('TestParser')
|
||||||
|
|
||||||
@ -35,12 +34,10 @@ class TestCommand(Command):
|
|||||||
|
|
||||||
|
|
||||||
class TestDeprecatedCommand(TestCommand):
|
class TestDeprecatedCommand(TestCommand):
|
||||||
|
|
||||||
deprecated = True
|
deprecated = True
|
||||||
|
|
||||||
|
|
||||||
class TestCommandManager(CommandManager):
|
class TestCommandManager(CommandManager):
|
||||||
|
|
||||||
def load_commands(self, namespace):
|
def load_commands(self, namespace):
|
||||||
if namespace == TEST_NAMESPACE:
|
if namespace == TEST_NAMESPACE:
|
||||||
for key in ('one', 'two words', 'three word command'):
|
for key in ('one', 'two words', 'three word command'):
|
||||||
|
@ -59,7 +59,6 @@ def damerau_levenshtein(s1, s2, cost):
|
|||||||
row2[0] = (i + 1) * cost['d']
|
row2[0] = (i + 1) * cost['d']
|
||||||
|
|
||||||
for j in range(len2):
|
for j in range(len2):
|
||||||
|
|
||||||
# substitution
|
# substitution
|
||||||
sub_cost = row1[j] + (s1[i] != s2[j]) * cost['s']
|
sub_cost = row1[j] + (s1[i] != s2[j]) * cost['s']
|
||||||
|
|
||||||
@ -70,11 +69,12 @@ def damerau_levenshtein(s1, s2, cost):
|
|||||||
del_cost = row1[j + 1] + cost['d']
|
del_cost = row1[j + 1] + cost['d']
|
||||||
|
|
||||||
# swap
|
# swap
|
||||||
swp_condition = ((i > 0) and
|
swp_condition = (
|
||||||
(j > 0) and
|
(i > 0)
|
||||||
(s1[i - 1] == s2[j]) and
|
and (j > 0)
|
||||||
(s1[i] == s2[j - 1])
|
and (s1[i - 1] == s2[j])
|
||||||
)
|
and (s1[i] == s2[j - 1])
|
||||||
|
)
|
||||||
|
|
||||||
# min cost
|
# min cost
|
||||||
if swp_condition:
|
if swp_condition:
|
||||||
|
@ -6,8 +6,7 @@ from cliff.lister import Lister
|
|||||||
|
|
||||||
|
|
||||||
class Encoding(Lister):
|
class Encoding(Lister):
|
||||||
"""Show some unicode text
|
"""Show some unicode text"""
|
||||||
"""
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -18,6 +17,5 @@ class Encoding(Lister):
|
|||||||
]
|
]
|
||||||
return (
|
return (
|
||||||
('UTF-8', 'Unicode'),
|
('UTF-8', 'Unicode'),
|
||||||
[(repr(t.encode('utf-8')), t)
|
[(repr(t.encode('utf-8')), t) for t in messages],
|
||||||
for t in messages],
|
|
||||||
)
|
)
|
||||||
|
@ -13,6 +13,7 @@ class Files(Lister):
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
return (('Name', 'Size'),
|
return (
|
||||||
((n, os.stat(n).st_size) for n in os.listdir('.'))
|
('Name', 'Size'),
|
||||||
)
|
((n, os.stat(n).st_size) for n in os.listdir('.')),
|
||||||
|
)
|
||||||
|
@ -5,14 +5,13 @@ from cliff.commandmanager import CommandManager
|
|||||||
|
|
||||||
|
|
||||||
class DemoApp(App):
|
class DemoApp(App):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(DemoApp, self).__init__(
|
super(DemoApp, self).__init__(
|
||||||
description='cliff demo app',
|
description='cliff demo app',
|
||||||
version='0.1',
|
version='0.1',
|
||||||
command_manager=CommandManager('cliff.demo'),
|
command_manager=CommandManager('cliff.demo'),
|
||||||
deferred_help=True,
|
deferred_help=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def initialize_app(self, argv):
|
def initialize_app(self, argv):
|
||||||
self.LOG.debug('initialize_app')
|
self.LOG.debug('initialize_app')
|
||||||
|
@ -16,16 +16,18 @@ class File(ShowOne):
|
|||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
stat_data = os.stat(parsed_args.filename)
|
stat_data = os.stat(parsed_args.filename)
|
||||||
columns = ('Name',
|
columns = (
|
||||||
'Size',
|
'Name',
|
||||||
'UID',
|
'Size',
|
||||||
'GID',
|
'UID',
|
||||||
'Modified Time',
|
'GID',
|
||||||
)
|
'Modified Time',
|
||||||
data = (parsed_args.filename,
|
)
|
||||||
stat_data.st_size,
|
data = (
|
||||||
stat_data.st_uid,
|
parsed_args.filename,
|
||||||
stat_data.st_gid,
|
stat_data.st_size,
|
||||||
stat_data.st_mtime,
|
stat_data.st_uid,
|
||||||
)
|
stat_data.st_gid,
|
||||||
|
stat_data.st_mtime,
|
||||||
|
)
|
||||||
return (columns, data)
|
return (columns, data)
|
||||||
|
@ -16,16 +16,12 @@ except IOError:
|
|||||||
setup(
|
setup(
|
||||||
name=PROJECT,
|
name=PROJECT,
|
||||||
version=VERSION,
|
version=VERSION,
|
||||||
|
|
||||||
description='Demo app for cliff',
|
description='Demo app for cliff',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
|
|
||||||
author='Doug Hellmann',
|
author='Doug Hellmann',
|
||||||
author_email='doug.hellmann@gmail.com',
|
author_email='doug.hellmann@gmail.com',
|
||||||
|
|
||||||
url='https://github.com/openstack/cliff',
|
url='https://github.com/openstack/cliff',
|
||||||
download_url='https://github.com/openstack/cliff/tarball/master',
|
download_url='https://github.com/openstack/cliff/tarball/master',
|
||||||
|
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 3 - Alpha',
|
'Development Status :: 3 - Alpha',
|
||||||
'License :: OSI Approved :: Apache Software License',
|
'License :: OSI Approved :: Apache Software License',
|
||||||
@ -35,22 +31,15 @@ setup(
|
|||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'Environment :: Console',
|
'Environment :: Console',
|
||||||
],
|
],
|
||||||
|
|
||||||
platforms=['Any'],
|
platforms=['Any'],
|
||||||
|
|
||||||
scripts=[],
|
scripts=[],
|
||||||
|
|
||||||
provides=[],
|
provides=[],
|
||||||
install_requires=['cliff'],
|
install_requires=['cliff'],
|
||||||
|
|
||||||
namespace_packages=[],
|
namespace_packages=[],
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
|
|
||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': [
|
'console_scripts': ['cliffdemo = cliffdemo.main:main'],
|
||||||
'cliffdemo = cliffdemo.main:main'
|
|
||||||
],
|
|
||||||
'cliff.demo': [
|
'cliff.demo': [
|
||||||
'simple = cliffdemo.simple:Simple',
|
'simple = cliffdemo.simple:Simple',
|
||||||
'two_part = cliffdemo.simple:Simple',
|
'two_part = cliffdemo.simple:Simple',
|
||||||
@ -66,6 +55,5 @@ setup(
|
|||||||
'sample-hook = cliffdemo.hook:Hook',
|
'sample-hook = cliffdemo.hook:Hook',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
)
|
)
|
||||||
|
@ -197,10 +197,8 @@ htmlhelp_basename = 'cliffdoc'
|
|||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
# 'papersize': 'letterpaper',
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
# 'pointsize': '10pt',
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
# 'preamble': '',
|
# 'preamble': '',
|
||||||
}
|
}
|
||||||
@ -209,8 +207,7 @@ latex_elements = {
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# documentclass [howto/manual]).
|
# documentclass [howto/manual]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', 'cliff.tex', 'cliff Documentation',
|
('index', 'cliff.tex', 'cliff Documentation', 'Doug Hellmann', 'manual'),
|
||||||
'Doug Hellmann', 'manual'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
@ -238,10 +235,7 @@ latex_documents = [
|
|||||||
|
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [('index', 'cliff', 'cliff Documentation', ['Doug Hellmann'], 1)]
|
||||||
('index', 'cliff', 'cliff Documentation',
|
|
||||||
['Doug Hellmann'], 1)
|
|
||||||
]
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
# man_show_urls = False
|
# man_show_urls = False
|
||||||
@ -253,9 +247,15 @@ man_pages = [
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'cliff', 'cliff Documentation',
|
(
|
||||||
'Doug Hellmann', 'cliff', 'One line description of project.',
|
'index',
|
||||||
'Miscellaneous'),
|
'cliff',
|
||||||
|
'cliff Documentation',
|
||||||
|
'Doug Hellmann',
|
||||||
|
'cliff',
|
||||||
|
'One line description of project.',
|
||||||
|
'Miscellaneous',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
|
@ -57,4 +57,3 @@ cliff.demo =
|
|||||||
hooked = cliffdemo.hook:Hooked
|
hooked = cliffdemo.hook:Hooked
|
||||||
cliff.demo.hooked =
|
cliff.demo.hooked =
|
||||||
sample-hook = cliffdemo.hook:Hook
|
sample-hook = cliffdemo.hook:Hook
|
||||||
|
|
||||||
|
4
setup.py
4
setup.py
@ -13,10 +13,10 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
setup_requires=['pbr>=2.0.0'],
|
setup_requires=['pbr>=2.0.0'],
|
||||||
install_requires=['setuptools'],
|
install_requires=['setuptools'],
|
||||||
pbr=True)
|
pbr=True,
|
||||||
|
)
|
||||||
|
12
tox.ini
12
tox.ini
@ -59,3 +59,15 @@ commands =
|
|||||||
coverage combine
|
coverage combine
|
||||||
coverage html -d cover
|
coverage html -d cover
|
||||||
coverage xml -o cover/coverage.xml
|
coverage xml -o cover/coverage.xml
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
application-import-names = cliff
|
||||||
|
# E203 Black will put spaces after colons in list comprehensions
|
||||||
|
# E501 Black takes care of line length for us
|
||||||
|
# W503 Is supposed to be off by default but in the latest pycodestyle isn't.
|
||||||
|
# Also, both openstacksdk and Donald Knuth disagree with the rule. Line
|
||||||
|
# breaks should occur before the binary operator for readability.
|
||||||
|
ignore = E203, E501, W503
|
||||||
|
import-order-style = pep8
|
||||||
|
show-source = true
|
||||||
|
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
||||||
|
Loading…
x
Reference in New Issue
Block a user