def test_help_with_param_specified(self, _): app = Application(Configuration([])) def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 --arg foo -h'.split()) s = """ Command az n1 Arguments --arg -a -b Global Arguments --help -h: Show this help message and exit. """ self.assertEqual(s, io.getvalue())
def test_register_simple_commands(self): def test_handler1(): pass def test_handler2(): pass command = CliCommand('command the-name', test_handler1) command2 = CliCommand('sub-command the-second-name', test_handler2) cmd_table = { 'command the-name': command, 'sub-command the-second-name': command2 } parser = AzCliCommandParser() parser.load_command_table(cmd_table) args = parser.parse_args('command the-name'.split()) self.assertIs(args.func, test_handler1) args = parser.parse_args('sub-command the-second-name'.split()) self.assertIs(args.func, test_handler2) AzCliCommandParser.error = VerifyError(self, ) parser.parse_args('sub-command'.split()) self.assertTrue(AzCliCommandParser.error.called)
def test_help_group_children(self): app = Application(Configuration([])) def test_handler(): pass def test_handler2(): pass command = CliCommand('group1 group3 n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command2 = CliCommand('group1 group2 n1', test_handler2) command2.add_argument('foobar', '--foobar', '-fb', required=False) command2.add_argument('foobar2', '--foobar2', '-fb2', required=True) cmd_table = {'group1 group3 n1': command, 'group1 group2 n1': command2} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('group1 -h'.split()) s = '\nGroup\n az group1\n\nSubgroups:\n group2\n group3\n\n' self.assertEqual(s, io.getvalue())
def test_help_params_documentations(self, _): app = Application(Configuration([])) def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command.add_argument('foobar3', '--foobar3', '-fb3', required=False, help='the foobar3') command.help = """ parameters: - name: --foobar -fb type: string required: false short-summary: one line partial sentence long-summary: text, markdown, etc. populator-commands: - az vm list - default - name: --foobar2 -fb2 type: string required: true short-summary: one line partial sentence long-summary: paragraph(s) """ cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) s = """ Command az n1 Arguments --foobar2 -fb2 [Required]: One line partial sentence. Paragraph(s). --foobar -fb : One line partial sentence. Text, markdown, etc. Values from: az vm list, default. --foobar3 -fb3 : The foobar3. Global Arguments --help -h : Show this help message and exit. """ self.assertEqual(s, io.getvalue())
def test_help_plain_short_description(self): def test_handler(): pass command = CliCommand('n1', test_handler, description='the description') command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, 'n1: The description.' in io.getvalue())
def test_nargs_parameter(self): def test_handler(): pass command = CliCommand('test command', test_handler) command.add_argument('req', '--req', required=True, nargs=2) cmd_table = {'test command': command} parser = AzCliCommandParser() parser.load_command_table(cmd_table) args = parser.parse_args('test command --req yep nope'.split()) self.assertIs(args.func, test_handler) AzCliCommandParser.error = VerifyError(self) parser.parse_args('test command -req yep'.split()) self.assertTrue(AzCliCommandParser.error.called)
def test_required_parameter(self): def test_handler(args): # pylint: disable=unused-argument pass command = CliCommand('test command', test_handler) command.add_argument('req', '--req', required=True) cmd_table = {'test command': command} parser = AzCliCommandParser() parser.load_command_table(cmd_table) args = parser.parse_args('test command --req yep'.split()) self.assertIs(args.func, test_handler) AzCliCommandParser.error = VerifyError(self) parser.parse_args('test command'.split()) self.assertTrue(AzCliCommandParser.error.called)
def test_help_param(self): def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application() app.initialize(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) with self.assertRaises(SystemExit): app.execute('n1 --help'.split())
def test_list_value_parameter(self): hellos = [] def handler(args): hellos.append(args) command = CliCommand('test command', handler) command.add_argument('hello', '--hello', nargs='+', action=IterateAction) command.add_argument('something', '--something') cmd_table = {'test command': command} argv = 'az test command --hello world sir --something else'.split() config = Configuration(argv) config.get_command_table = lambda: cmd_table application = Application(config) application.execute(argv[1:]) self.assertEqual(2, len(hellos)) self.assertEqual(hellos[0]['hello'], 'world') self.assertEqual(hellos[0]['something'], 'else') self.assertEqual(hellos[1]['hello'], 'sir') self.assertEqual(hellos[1]['something'], 'else')
def test_help_extra_missing_params(self): app = Application(Configuration([])) def test_handler(foobar2, foobar=None): # pylint: disable=unused-argument pass command = CliCommand('n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) # work around an argparse behavior where output is not printed and SystemExit # is not raised on Python 2.7.9 if sys.version_info < (2, 7, 10): try: app.execute('n1 -fb a --foobar value'.split()) except SystemExit: pass try: app.execute('n1 -fb a --foobar2 value --foobar3 extra'.split()) except SystemExit: pass else: with self.assertRaises(SystemExit): app.execute('n1 -fb a --foobar value'.split()) with self.assertRaises(SystemExit): app.execute('n1 -fb a --foobar2 value --foobar3 extra'.split()) self.assertTrue('required' in io.getvalue() and '--foobar/-fb' not in io.getvalue() and '--foobar2/-fb2' in io.getvalue() and 'unrecognized arguments: --foobar3 extra' in io.getvalue())
def test_help_global_params(self, mock_register_extensions, _): def register_globals(global_group): global_group.add_argument( '--query2', dest='_jmespath_query', metavar='JMESPATH', help='JMESPath query string. See http://jmespath.org/ ' 'for more information and examples.') mock_register_extensions.return_value = None mock_register_extensions.side_effect = lambda app: \ app._event_handlers[app.GLOBAL_PARSER_CREATED].append(register_globals) # pylint: disable=protected-access def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = """ long-summary: | line1 line2 """ cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) s = """ Command az n1 Line1 line2. Arguments --arg -a -b Global Arguments --help -h: Show this help message and exit. --query2 : JMESPath query string. See http://jmespath.org/ for more information and examples. """ self.assertEqual(s, io.getvalue())
def test_help_plain_long_description(self): def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = 'long description' cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, io.getvalue().startswith('\nCommand\n az n1\n Long description.')) # pylint: disable=line-too-long
def test_help_docstring_description_overrides_short_description(self): def test_handler(): pass command = CliCommand('n1', test_handler, description='short description') command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = 'short-summary: docstring summary' cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, 'n1: Docstring summary.' in io.getvalue())
def test_help_long_description_and_short_description(self): def test_handler(): pass command = CliCommand('n1', test_handler, description='short description') command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = 'long description' cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, io.getvalue().startswith('\nCommand\n az n1: Short description.\n Long description.')) # pylint: disable=line-too-long
def test_help_global_params(self, mock_register_extensions, _): def register_globals(global_group): global_group.add_argument('--query2', dest='_jmespath_query', metavar='JMESPATH', help='JMESPath query string. See http://jmespath.org/ ' 'for more information and examples.') mock_register_extensions.return_value = None mock_register_extensions.side_effect = lambda app: \ app._event_handlers[app.GLOBAL_PARSER_CREATED].append(register_globals) # pylint: disable=protected-access def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = """ long-summary: | line1 line2 """ cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) s = """ Command az n1 Line1 line2. Arguments --arg -a -b Global Arguments --help -h: Show this help message and exit. --query2 : JMESPath query string. See http://jmespath.org/ for more information and examples. """ self.assertEqual(s, io.getvalue())
def test_help_long_description_multi_line(self): def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = """ long-summary: | line1 line2 """ cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, io.getvalue().startswith('\nCommand\n az n1\n Line1\n line2.')) # pylint: disable=line-too-long
def test_help_extra_missing_params(self): app = Application(Configuration([])) def test_handler(foobar2, foobar=None): # pylint: disable=unused-argument pass command = CliCommand('n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) # work around an argparse behavior where output is not printed and SystemExit # is not raised on Python 2.7.9 if sys.version_info < (2, 7, 10): try: app.execute('n1 -fb a --foobar value'.split()) except SystemExit: pass try: app.execute('n1 -fb a --foobar2 value --foobar3 extra'.split()) except SystemExit: pass else: with self.assertRaises(SystemExit): app.execute('n1 -fb a --foobar value'.split()) with self.assertRaises(SystemExit): app.execute('n1 -fb a --foobar2 value --foobar3 extra'.split()) self.assertTrue( 'required' in io.getvalue() and '--foobar/-fb' not in io.getvalue() and '--foobar2/-fb2' in io.getvalue() and 'unrecognized arguments: --foobar3 extra' in io.getvalue())
def register_generic_update(name, getter, setter, factory=None, setter_arg_name='parameters', #pylint:disable=too-many-arguments simple_output_query=None): get_arguments = dict(extract_args_from_signature(getter)) set_arguments = dict(extract_args_from_signature(setter)) def handler(args): ordered_arguments = args.pop('ordered_arguments') try: client = factory() if factory else None except TypeError: client = factory(None) if factory else None getterargs = {key: val for key, val in args.items() if key in get_arguments} instance = getter(client, **getterargs) if client else getter(**getterargs) # Update properties for arg in ordered_arguments: arg_type, expressions = arg if arg_type == '--set': try: for expression in expressions: set_properties(instance, expression) except ValueError: raise CLIError('--set should be of the form:' ' --set property.property=<value>' ' property2.property=<value>') elif arg_type == '--add': try: add_properties(instance, expressions) except ValueError: raise CLIError('--add should be of the form:' ' --add property.list key1=value1 key2=value2') elif arg_type == '--remove': try: remove_properties(instance, expressions) except ValueError: raise CLIError('--remove should be of the form: --remove' ' property.propertyToRemove or' ' --remove property.list <indexToRemove>') else: raise ValueError('Unsupported arg type {}'.format(arg_type)) # Done... update the instance! getterargs[setter_arg_name] = instance opres = setter(client, **getterargs) if client else setter(**getterargs) return opres.result() if isinstance(opres, AzureOperationPoller) else opres class OrderedArgsAction(argparse.Action): #pylint:disable=too-few-public-methods def __call__(self, parser, namespace, values, option_string=None): if not getattr(namespace, 'ordered_arguments', None): setattr(namespace, 'ordered_arguments', []) namespace.ordered_arguments.append((option_string, values)) def one_required(namespace): if not getattr(namespace, 'ordered_arguments', None): raise ValueError('At least one must be specified: --add, --set, --remove') cmd = CliCommand(name, handler, simple_output_query=simple_output_query) cmd.arguments.update(set_arguments) cmd.arguments.update(get_arguments) cmd.arguments.pop(setter_arg_name, None) cmd.add_argument('properties_to_set', '--set', nargs='+', action=OrderedArgsAction, default=[], help='Update an object by specifying a property path and value to set.' ' Example: --set property1.property2=value', metavar='KEY=VALUE') cmd.add_argument('properties_to_add', '--add', nargs='+', action=OrderedArgsAction, default=[], help='Add an object to a list of objects by specifying a path and key' ' value pairs. Example: --add property.list key=<value>', metavar='LIST KEY=VALUE') cmd.add_argument('properties_to_remove', '--remove', nargs='+', action=OrderedArgsAction, default=[], help='Remove a property or an element from a list. Example: ' '--remove property.list <index>', metavar='LIST INDEX', validator=one_required) main_command_table[name] = cmd
def test_help_full_documentations(self, _): app = Application(Configuration([])) def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command.help = """ short-summary: this module does xyz one-line or so long-summary: | this module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2 parameters: - name: --foobar -fb type: string required: false short-summary: one line partial sentence long-summary: text, markdown, etc. populator-commands: - az vm list - default - name: --foobar2 -fb2 type: string required: true short-summary: one line partial sentence long-summary: paragraph(s) examples: - name: foo example text: example details """ cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) s = """ Command az n1: This module does xyz one-line or so. This module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2. Arguments --foobar2 -fb2 [Required]: One line partial sentence. Paragraph(s). --foobar -fb : One line partial sentence. Text, markdown, etc. Values from: az vm list, default. Global Arguments --help -h : Show this help message and exit. Examples foo example example details """ self.assertEqual(s, io.getvalue())
def test_help_group_help(self): app = Application(Configuration([])) def test_handler(): pass azure.cli.help_files.helps['test_group1 test_group2'] = """ type: group short-summary: this module does xyz one-line or so long-summary: | this module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2 examples: - name: foo example text: example details """ command = CliCommand('test_group1 test_group2 n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command.help = """ short-summary: this module does xyz one-line or so long-summary: | this module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2 parameters: - name: --foobar -fb type: string required: false short-summary: one line partial sentence long-summary: text, markdown, etc. populator-commands: - az vm list - default - name: --foobar2 -fb2 type: string required: true short-summary: one line partial sentence long-summary: paragraph(s) examples: - name: foo example text: example details """ cmd_table = {'test_group1 test_group2 n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('test_group1 test_group2 --help'.split()) s = """ Group az test_group1 test_group2: This module does xyz one-line or so. This module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2. Commands: n1: This module does xyz one-line or so. Examples foo example example details """ self.assertEqual(s, io.getvalue()) del azure.cli.help_files.helps['test_group1 test_group2']
def test_help_group_help(self): app = Application(Configuration([])) def test_handler(): pass azure.cli.help_files.helps['test_group1 test_group2'] = """ type: group short-summary: this module does xyz one-line or so long-summary: | this module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2 examples: - name: foo example text: example details """ command = CliCommand('test_group1 test_group2 n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command.help = """ short-summary: this module does xyz one-line or so long-summary: | this module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2 parameters: - name: --foobar -fb type: string required: false short-summary: one line partial sentence long-summary: text, markdown, etc. populator-commands: - az vm list - default - name: --foobar2 -fb2 type: string required: true short-summary: one line partial sentence long-summary: paragraph(s) examples: - name: foo example text: example details """ cmd_table = {'test_group1 test_group2 n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('test_group1 test_group2 --help'.split()) s = """ Group az test_group1 test_group2: This module does xyz one-line or so. This module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2. Commands: n1: This module does xyz one-line or so. Examples foo example example details """ self.assertEqual(s, io.getvalue())
def register_generic_update(name, getter, setter, factory=None, setter_arg_name='parameters'): get_arguments = dict(extract_args_from_signature(getter)) set_arguments = dict(extract_args_from_signature(setter)) def handler(args): ordered_arguments = args.pop('ordered_arguments') try: client = factory() if factory else None except TypeError: client = factory(None) if factory else None getterargs = { key: val for key, val in args.items() if key in get_arguments } instance = getter(client, **getterargs) if client else getter( **getterargs) # Update properties for arg in ordered_arguments: arg_type, expressions = arg if arg_type == '--set': try: for expression in expressions: set_properties(instance, expression) except ValueError: raise CLIError('--set should be of the form:' ' --set property.property=<value>' ' property2.property=<value>') elif arg_type == '--add': try: add_properties(instance, expressions) except ValueError: raise CLIError( '--add should be of the form:' ' --add property.list key1=value1 key2=value2') elif arg_type == '--remove': try: remove_properties(instance, expressions) except ValueError: raise CLIError('--remove should be of the form: --remove' ' property.propertyToRemove or' ' --remove property.list <indexToRemove>') else: raise ValueError('Unsupported arg type {}'.format(arg_type)) # Done... update the instance! getterargs[setter_arg_name] = instance opres = setter(client, **getterargs) if client else setter( **getterargs) return opres.result() if isinstance(opres, AzureOperationPoller) else opres class OrderedArgsAction(argparse.Action): #pylint:disable=too-few-public-methods def __call__(self, parser, namespace, values, option_string=None): if not getattr(namespace, 'ordered_arguments', None): setattr(namespace, 'ordered_arguments', []) namespace.ordered_arguments.append((option_string, values)) def one_required(namespace): if not getattr(namespace, 'ordered_arguments', None): raise ValueError( 'At least one must be specified: --add, --set, --remove') cmd = CliCommand(name, handler) cmd.arguments.update(set_arguments) cmd.arguments.update(get_arguments) cmd.arguments.pop(setter_arg_name, None) cmd.add_argument( 'properties_to_set', '--set', nargs='+', action=OrderedArgsAction, default=[], help='Update an object by specifying a property path and value to set.' ' Example: --set property1.property2=value', metavar='KEY=VALUE') cmd.add_argument( 'properties_to_add', '--add', nargs='+', action=OrderedArgsAction, default=[], help='Add an object to a list of objects by specifying a path and key' ' value pairs. Example: --add property.list key=<value>', metavar='LIST KEY=VALUE') cmd.add_argument( 'properties_to_remove', '--remove', nargs='+', action=OrderedArgsAction, default=[], help='Remove a property or an element from a list. Example: ' '--remove property.list <index>', metavar='LIST INDEX', validator=one_required) main_command_table[name] = cmd