def _GenerateResourceArg(self): """Gets the flags to add to the parser that appear in the method path. Returns: {str, calliope.base.Argument}, A map of field name to argument. """ args = [] field_names = (self.method.request_collection.detailed_params if self.method.request_collection else None) if not field_names: return args field_helps = arg_utils.FieldHelpDocs(self.method.GetRequestType()) default_help = 'For substitution into: ' + self.method.detailed_path # Make a dedicated positional in addition to the flags for each part of # the URI path. arg = base.Argument(AutoArgumentGenerator.FLAT_RESOURCE_ARG_NAME, nargs='?', help='The GRI for the resource being operated on.') args.append(arg) for field in field_names: arg = base.Argument( '--' + field, metavar=resource_property.ConvertToAngrySnakeCase(field), category='RESOURCE', help=field_helps.get(field, default_help)) args.append(arg) return args
def _FlagForMessageField(self, name, field, field_helps): """Gets a flag for a single field in a message. Args: name: The name of the field. field: The apitools field object. field_helps: {str: str}, A mapping of field name to help text. Returns: {str: str}, A mapping of field name to help text. """ help_text = field_helps.get(field.name, None) if self._IsOutputField(help_text): return None variant = field.variant t = ArgumentGenerator.TYPES.get(variant, None) choices = None if variant == messages.Variant.ENUM: choices = field.type.names() return base.Argument( # TODO(b/38000796): Consider not using camel case for flags. '--' + name, metavar=resource_property.ConvertToAngrySnakeCase(field.name), category='MESSAGE', action='store', type=t, choices=choices, help=help_text, )
def _GenerateResourceArg(self): """Generates the flags to add to the parser that appear in the method path. Returns: {str, calliope.base.Argument}, A map of field name to argument. """ resource_args = self.resource_arg_info if not resource_args: return {} args = {} anchor_field = resource_args[-1].api_field for attributes in resource_args: # Don't generate any placeholder arguments for ignored fields. if not attributes.generate: continue is_anchor = attributes.api_field == anchor_field is_positional = is_anchor and not self.method.IsList() arg_name = attributes.arg_name arg = base.Argument( arg_name if is_positional else '--' + arg_name, metavar=resource_property.ConvertToAngrySnakeCase( attributes.arg_name), completer=attributes.completer, help=attributes.help_text) if is_anchor and not is_positional: arg.kwargs['required'] = True args[arg.name] = arg return args
def GenerateFlag(field, attributes, fix_bools=True, category=None): """Generates a flag for a single field in a message. Args: field: The apitools field object. attributes: yaml_command_schema.Argument, The attributes to use to generate the arg. fix_bools: True to generate boolean flags as switches that take a value or False to just generate them as regular string flags. category: The help category to put the flag in. Returns: calliope.base.Argument, The generated argument. """ variant = field.variant if field else None t = attributes.type or TYPES.get(variant, None) choices = None if attributes.choices is not None: choices = sorted(attributes.choices.keys()) elif variant == messages.Variant.ENUM: choices = [ EnumNameToChoice(name) for name in sorted(field.type.names()) ] action = attributes.action if fix_bools and not action and variant == messages.Variant.BOOL: action = 'store_true' # Note that a field will never be a message at this point, always a scalar. # pylint: disable=g-explicit-bool-comparison, only an explicit False should # override this, None just means to do the default. if (field and field.repeated) and attributes.repeated != False: t = arg_parsers.ArgList(element_type=t, choices=choices) name = attributes.arg_name arg = base.Argument( # TODO(b/38000796): Consider not using camel case for flags. name if attributes.is_positional else '--' + name, category=category if not attributes.is_positional else None, action=action, completer=attributes.completer, help=attributes.help_text, hidden=attributes.hidden, ) if attributes.default is not None: arg.kwargs['default'] = attributes.default if action != 'store_true': # For this special action type, it won't accept a bunch of the common # kwargs, so we can only add them if not generating a boolean flag. metavar = attributes.metavar or name arg.kwargs['metavar'] = resource_property.ConvertToAngrySnakeCase( metavar.replace('-', '_')) arg.kwargs['type'] = t arg.kwargs['choices'] = choices if not attributes.is_positional: arg.kwargs['required'] = attributes.required return arg
def _GenerateResourceArg(self): """Gets the flags to add to the parser that appear in the method path. Returns: {str, calliope.base.Argument}, A map of field name to argument. """ field_names = self.method.ResourceFieldNames() if not field_names: return {} message = self.method.GetRequestType() field_helps = _FieldHelpDocs(message) default_help = 'For substitution into: ' + self.method.detailed_path args = {} if not self.clean_surface: # Make a dedicated positional in addition to the flags for each part of # the URI path. args[ArgumentGenerator.FLAT_RESOURCE_ARG_NAME] = base.Argument( ArgumentGenerator.FLAT_RESOURCE_ARG_NAME, nargs='?', help='The GRI for the resource being operated on.') anchor_arg_name = self._GetArgAttributes(field_names[-1], required=True).arg_name for field in field_names: attributes = self._GetArgAttributes(field, field_helps, default_help, required=True) param = attributes.arg_name # If the request params match, this means this method takes the same # params as the get method and so the last item should be positional. # If it doesn't (like for a list command) then we are omitting the last # arg so all other should be flags and none should be made positional. is_positional = (self.clean_surface and param == anchor_arg_name and self.method.request_params_match_resource) args[param] = base.Argument( param if is_positional else '--' + param, metavar=resource_property.ConvertToAngrySnakeCase(param), # TODO(b/64147277): Usage a proper arg group to make the positional # and flags for the resource argument show up together. # category=(None if param == self.anchor_arg_name and # self.is_positional else 'RESOURCE'), type=attributes.type or str, completer=attributes.completer, help=attributes.help_text) if (self.clean_surface and param == anchor_arg_name and not is_positional): args[param].kwargs['required'] = True return args
def ResourceFlags(self): """Get the arguments to add to the parser that appear in the method path. Returns: {str, calliope.base.Argument}, A map of field name to argument. """ message = self.method.GetRequestType() field_helps = self._FieldHelpDocs(message) default_help = 'For substitution into: ' + self.method.detailed_path args = {} for param in set(self.method.ResourceFieldNames()): args[param] = base.Argument( # TODO(b/38000796): Consider not using camel case for flags. '--' + param, metavar=resource_property.ConvertToAngrySnakeCase(param), category='RESOURCE', type=str, help=field_helps.get(param, default_help)) return args
def _GenerateMessageFieldFlag(self, attributes, prefix, field): """Gets a flag for a single field in a message. Args: attributes: yaml_command_schema.Argument, The attributes to use to generate the arg. prefix: str, The flag prefix for the sub-message being generated. field: The apitools field object. Returns: calliope.base.Argument, The generated argument. """ if _IsOutputField(attributes.help_text): return None variant = field.variant choices = None if variant == messages.Variant.ENUM: choices = field.type.names() t = attributes.type or _TYPES.get(variant, None) # Note that a field will never be a message at this point, always a scalar. if field.repeated: t = arg_parsers.ArgList(element_type=t, choices=choices) name = attributes.arg_name arg = base.Argument( # TODO(b/38000796): Consider not using camel case for flags. name if attributes.is_positional else '--' + name, metavar=resource_property.ConvertToAngrySnakeCase( name[len(prefix):]), category=None if attributes.is_positional else 'MESSAGE', action=attributes.action, type=t, default=attributes.default, choices=choices, completer=attributes.completer, help=attributes.help_text, hidden=attributes.hidden, ) if not attributes.is_positional: arg.kwargs['required'] = attributes.required return arg
def _GenerateResourceArg(self): """Generates the flags to add to the parser that appear in the method path. Returns: {str, calliope.base.Argument}, A map of field name to argument. """ resource_args = self.resource_arg_info if not resource_args: return {} args = {} anchor_field = resource_args[-1].api_field for attributes in resource_args: # Don't generate any placeholder arguments for ignored fields. if not attributes.generate: continue is_anchor = attributes.api_field == anchor_field # pylint: disable=g-explicit-bool-comparison, only an explicit False # should, None just means to do the default. # The anchor arg is positional unless explicitly overridden by the # attributes or for list commands (where everything should be a flag since # the parent resource collection is being used). is_positional = (is_anchor and not (attributes.is_positional == False or self.method.IsList())) arg_name = attributes.arg_name arg = base.Argument( arg_name if is_positional else '--' + arg_name, metavar=resource_property.ConvertToAngrySnakeCase( attributes.arg_name), completer=attributes.completer, help=attributes.help_text, hidden=attributes.hidden) if is_anchor and not is_positional and not attributes.fallback: arg.kwargs['required'] = True args[arg.name] = arg return args
def GenerateFlag(field, attributes, fix_bools=True, category=None): """Generates a flag for a single field in a message. Args: field: The apitools field object. attributes: yaml_command_schema.Argument, The attributes to use to generate the arg. fix_bools: True to generate boolean flags as switches that take a value or False to just generate them as regular string flags. category: The help category to put the flag in. Raises: ArgumentGenerationError: When an argument could not be generated from the API field. Returns: calliope.base.Argument, The generated argument. """ variant = field.variant if field else None t = attributes.type or TYPES.get(variant, None) choices = None if attributes.choices is not None: choice_map = {c.arg_value: c.help_text for c in attributes.choices} # If help text is provided, give a choice map. Otherwise, just use the # choice values. choices = (choice_map if any(choice_map.values()) else sorted(choice_map.keys())) elif variant == messages.Variant.ENUM: choices = [ EnumNameToChoice(name) for name in sorted(field.type.names()) ] action = attributes.action if t == bool and fix_bools and not action: # For boolean flags, we want to create a flag with action 'store_true' # rather than a flag that takes a value and converts it to a boolean. Only # do this if not using a custom action. action = 'store_true' # Default action is store if one was not provided. action = action or 'store' # pylint: disable=g-explicit-bool-comparison, only an explicit False should # override this, None just means to do the default. repeated = (field and field.repeated) and attributes.repeated != False if repeated: if action != 'store': raise ArgumentGenerationError( field.name, 'The field is repeated but is but is using a custom action. You might' ' want to set repeated: False in your arg spec.') if t: # A special ArgDict wrapper type was given, bind it to the message so it # can generate the message from the key/value pairs. if isinstance(t, RepeatedMessageBindableType): action = t.Action() t = t.GenerateType(field.type) # If a simple type was provided, just use a list of that type (even if it # is a message). The type function will be responsible for converting to # the correct value. If type is an ArgList or ArgDict, don't try to wrap # it. elif not isinstance(t, arg_parsers.ArgList): t = arg_parsers.ArgList(element_type=t, choices=choices) # Don't register the choices on the argparse arg because it is validated # by the ArgList. choices = None elif isinstance(t, RepeatedMessageBindableType): raise ArgumentGenerationError( field.name, 'The given type can only be used on repeated fields.') if field and not t and action == 'store' and not attributes.processor: # The type is unknown and there is no custom action or processor, we don't # know what to do with this. raise ArgumentGenerationError( field.name, 'The field is of an unknown type. You can specify a type ' 'function or a processor to manually handle this argument.') name = attributes.arg_name arg = base.Argument( name if attributes.is_positional else '--' + name, category=category if not attributes.is_positional else None, action=action, completer=attributes.completer, help=attributes.help_text, hidden=attributes.hidden, ) if attributes.default is not None: arg.kwargs['default'] = attributes.default if action != 'store_true': # For this special action type, it won't accept a bunch of the common # kwargs, so we can only add them if not generating a boolean flag. metavar = attributes.metavar or name arg.kwargs['metavar'] = resource_property.ConvertToAngrySnakeCase( metavar.replace('-', '_')) arg.kwargs['type'] = t arg.kwargs['choices'] = choices if not attributes.is_positional: arg.kwargs['required'] = attributes.required return arg
def _GenerateMessageFieldFlag(self, attributes, prefix, field): """Gets a flag for a single field in a message. Args: attributes: yaml_command_schema.Argument, The attributes to use to generate the arg. prefix: str, The flag prefix for the sub-message being generated. field: The apitools field object. Returns: calliope.base.Argument, The generated argument. """ if _IsOutputField(attributes.help_text): return None variant = field.variant choices = None if attributes.choices is not None: choices = attributes.choices.keys() elif variant == messages.Variant.ENUM: choices = [_EnumNameToChoice(name) for name in field.type.names()] t = attributes.type or _TYPES.get(variant, None) action = attributes.action if not action: if variant == messages.Variant.BOOL and self.clean_surface: # Create proper boolean flags for declarative surfaces action = 'store_true' else: action = 'store' # Note that a field will never be a message at this point, always a scalar. if field.repeated: t = arg_parsers.ArgList(element_type=t, choices=choices) name = attributes.arg_name metavar = name if metavar.startswith(prefix): metavar = metavar[len(prefix):] category = None if self.arg_info is None and not attributes.is_positional: category = 'MESSAGE' arg = base.Argument( # TODO(b/38000796): Consider not using camel case for flags. name if attributes.is_positional else '--' + name, category=category, action=action, completer=attributes.completer, help=attributes.help_text, hidden=attributes.hidden, ) if attributes.default is not None: arg.kwargs['default'] = attributes.default if action != 'store_true': # For this special action type, it won't accept a bunch of the common # kwargs, so we can only add them if not generating a boolean flag. arg.kwargs['metavar'] = resource_property.ConvertToAngrySnakeCase( metavar.replace('-', '_')) arg.kwargs['type'] = t arg.kwargs['choices'] = choices if not attributes.is_positional: arg.kwargs['required'] = attributes.required return arg