def _ParseArguments(self, namespace, prefix, message): """Recursively generates the request message and any sub-messages. Args: namespace: The argparse namespace containing the all the parsed arguments. prefix: str, The flag prefix for the sub-message being generated. message: The apitools class for the message. Returns: The instantiated apitools Message with all fields filled in from flags. """ kwargs = {} for field in message.all_fields(): arg_name = self._GetArgName(field.name) if not arg_name: continue arg_name = prefix + arg_name # Field is a sub-message, recursively generate it. if field.variant == messages.Variant.MESSAGE: sub_kwargs = self._ParseArguments(namespace, arg_name + '.', field.type) if sub_kwargs: # Only construct the sub-message if we have something to put in it. value = field.type(**sub_kwargs) # TODO(b/38000796): Handle repeated fields correctly. kwargs[field.name] = value if not field.repeated else [ value ] # Field is a scalar, just get the value. else: value = arg_utils.GetFromNamespace(namespace, arg_name) if value is not None: kwargs[field.name] = arg_utils.ConvertValue(field, value) return kwargs
def CreateRequest(self, namespace, static_fields=None, resource_method_params=None): """Generates the request object for the method call from the parsed args. Args: namespace: The argparse namespace. static_fields: {str, value}, A mapping of API field name to value to insert into the message. This is a convenient way to insert extra data while the request is being constructed for fields that don't have corresponding arguments. resource_method_params: {str: str}, A mapping of API method parameter name to resource ref attribute name when the API method uses non-standard names. Returns: The apitools message to be send to the method. """ static_fields = static_fields or {} resource_method_params = resource_method_params or {} message_type = self.method.GetRequestType() message = message_type() # Insert static fields into message. for field_path, value in static_fields.iteritems(): field = arg_utils.GetFieldFromMessage(message_type, field_path) arg_utils.SetFieldInMessage(message, field_path, arg_utils.ConvertValue(field, value)) # Parse api Fields into message. self._ParseArguments(message, namespace) ref = self._ParseResourceArg(namespace) if not ref: return message # This only happens for non-list methods where the API method params don't # match the resource parameters (basically only create methods). In this # case, we re-parse the resource as its parent collection (to fill in the # API parameters, and we insert the name of the resource itself into the # correct position in the body of the request method. if (self.method.resource_argument_collection.detailed_params != self.method.request_collection.detailed_params): # Sets the name of the resource in the message object body. arg_utils.SetFieldInMessage(message, self.resource_arg_info[-1].api_field, ref.Name()) # Create a reference for the parent resource to put in the API params. ref = ref.Parent( parent_collection=self.method.request_collection.full_name) # For each method path field, get the value from the resource reference. relative_name = ref.RelativeName() for p in self.method.params: value = getattr(ref, resource_method_params.get(p, p), relative_name) arg_utils.SetFieldInMessage(message, p, value) return message
def Parse(arg_value): """Inner method that argparse actually calls.""" result = arg_dict(arg_value) messages = [] for k, v in sorted(six.iteritems(result)): message_instance = message() arg_utils.SetFieldInMessage( message_instance, self.key_spec.api_field, arg_utils.ConvertValue(key_field, k, choices=self.key_spec.ChoiceMap())) arg_utils.SetFieldInMessage( message_instance, self.value_spec.api_field, arg_utils.ConvertValue( value_field, v, choices=self.value_spec.ChoiceMap())) messages.append(message_instance) return messages
def testConvertValueEnum(self): choices = [ yaml_command_schema_util.Choice({'arg_value': 'a', 'enum_value': 'thing-one'}), yaml_command_schema_util.Choice({'arg_value': 'c', 'enum_value': 'thing-two'})] choices = yaml_command_schema_util.Choice.ToChoiceMap(choices) # Non-repeated. self.assertEqual( fm.FakeMessage.FakeEnum.THING_ONE, arg_utils.ConvertValue(fm.FakeMessage.enum1, 'a', choices=choices)) self.assertEqual( fm.FakeMessage.FakeEnum.THING_TWO, arg_utils.ConvertValue(fm.FakeMessage.enum1, 'c', choices=choices)) self.assertEqual( fm.FakeMessage.FakeEnum.THING_ONE, arg_utils.ConvertValue(fm.FakeMessage.enum1, 'thing-one', choices=choices)) self.assertEqual( fm.FakeMessage.FakeEnum.THING_TWO, arg_utils.ConvertValue(fm.FakeMessage.enum1, 'thing-two', choices=choices)) # Repeated. self.assertEqual( [fm.FakeMessage.FakeEnum.THING_ONE, fm.FakeMessage.FakeEnum.THING_TWO], arg_utils.ConvertValue(fm.FakeMessage.enum2, ['a', 'c'], choices=choices)) # Repeated field, but forced singular arg. self.assertEqual( [fm.FakeMessage.FakeEnum.THING_ONE], arg_utils.ConvertValue( fm.FakeMessage.enum2, 'a', repeated=False, choices=choices)) self.assertEqual( [fm.FakeMessage.FakeEnum.THING_TWO], arg_utils.ConvertValue( fm.FakeMessage.enum2, 'c', repeated=False, choices=choices)) self.assertEqual( [fm.FakeMessage.FakeEnum.THING_ONE], arg_utils.ConvertValue( fm.FakeMessage.enum2, 'thing-one', repeated=False, choices=choices)) self.assertEqual( [fm.FakeMessage.FakeEnum.THING_TWO], arg_utils.ConvertValue( fm.FakeMessage.enum2, 'thing-two', repeated=False, choices=choices))
def testConvertValueWithProcessor(self): def P(value): return '!' + value def Q(value): return ['!' + v for v in value] # Non-repeated. self.assertEqual( '!a', arg_utils.ConvertValue(fm.FakeMessage.string1, 'a', processor=P)) # Repeated. self.assertEqual( ['!a', '!b'], arg_utils.ConvertValue(fm.FakeMessage.string2, ['a', 'b'], processor=Q)) # Repeated field, but forced singular arg. self.assertEqual( ['!a'], arg_utils.ConvertValue(fm.FakeMessage.string2, 'a', processor=P, repeated=False))
def ParseDynamicFieldsIntoMessage(message, parameters): """Set fields in message corresponding to a dict of usually static fields. For repeated fields interpreted as json. Args: message: The source spec. parameters: dict of fields to values. The values are by default interpreted as raw string, but values are interpreted as a nested data structure, depending on the whitelist. """ parameters = parameters or {} for field_path, value in parameters.items(): field = arg_utils.GetFieldFromMessage(message, field_path) if field.repeated and not isinstance(value, list): value = arg_utils.ConvertValue(field, value, processor=JSONProcessor) value = arg_utils.ConvertValue(field, value) arg_utils.SetFieldInMessage(message, field_path, value)
def Parse(arg_value): """Inner method that argparse actually calls.""" result = arg_dict(arg_value) message_instance = message() for f in self.fields: value = result.get(f.arg_name) api_field = arg_utils.GetFieldFromMessage(message, f.api_field) value = arg_utils.ConvertValue(api_field, value, choices=Choice.ToChoiceMap( f.choices)) arg_utils.SetFieldInMessage(message_instance, f.api_field, value) return message_instance
def _ParseArguments(self, message, namespace): """Parse all the arguments from the namespace into the message object. Args: message: A constructed apitools message object to inject the value into. namespace: The argparse namespace. """ message_type = self.method.GetRequestType() for attributes in self.arg_info: value = arg_utils.GetFromNamespace(namespace, attributes.arg_name) if value is None: continue field = arg_utils.GetFieldFromMessage(message_type, attributes.api_field) value = arg_utils.ConvertValue(field, value, attributes) arg_utils.SetFieldInMessage(message, attributes.api_field, value)
def Parse(self, message, namespace): """Sets the argument message value, if any, from the parsed args. Args: message: The API message, None for non-resource args. namespace: The parsed command line argument namespace. """ if self.api_field is None: return value = arg_utils.GetFromNamespace( namespace, self.arg_name, fallback=self.fallback) if value is None: return field = arg_utils.GetFieldFromMessage(message, self.api_field) value = arg_utils.ConvertValue(field, value, self) arg_utils.SetFieldInMessage(message, self.api_field, value)
def testConvertValueWithChoices(self): choices = [ yaml_command_schema_util.Choice({'arg_value': 'a', 'enum_value': 'b'}), yaml_command_schema_util.Choice({'arg_value': 'c', 'enum_value': 'd'})] choices = yaml_command_schema_util.Choice.ToChoiceMap(choices) # Value not provided. self.assertEqual( None, arg_utils.ConvertValue(fm.FakeMessage.string1, None, choices=choices)) # Non-repeated. self.assertEqual( 'b', arg_utils.ConvertValue(fm.FakeMessage.string1, 'a', choices=choices)) self.assertEqual( 'd', arg_utils.ConvertValue(fm.FakeMessage.string1, 'c', choices=choices)) # Make sure case insensitive works. self.assertEqual( 'b', arg_utils.ConvertValue(fm.FakeMessage.string1, 'A', choices=choices)) # Repeated. self.assertEqual( ['b', 'b', 'd', 'd'], arg_utils.ConvertValue( fm.FakeMessage.string2, ['a', 'b', 'c', 'd'], choices=choices)) # Repeated field, but forced singular arg. self.assertEqual( ['b'], arg_utils.ConvertValue( fm.FakeMessage.string2, 'a', repeated=False, choices=choices)) self.assertEqual( ['d'], arg_utils.ConvertValue( fm.FakeMessage.string2, 'c', repeated=False, choices=choices))