diff --git a/ChangeLog.md b/ChangeLog.md index ad2409bd3fb..c2e1de3901c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -9,6 +9,10 @@ Modelerfour version: 4.15.400 - Updated minimum `azure-core` version to 1.8.0 #747 - Updated minimum `msrest` version to 0.6.18 #747 +**Bug fixes** + +- Fix "multi" in Swagger (will generate correctly multiple query param now) + ### 2020-08-07 - 5.1.0-preview.7 Autorest Core version: 3.0.6302 Modelerfour version: 4.15.400 diff --git a/autorest/codegen/models/operation.py b/autorest/codegen/models/operation.py index 652e69ef423..bf753f76b42 100644 --- a/autorest/codegen/models/operation.py +++ b/autorest/codegen/models/operation.py @@ -15,6 +15,7 @@ from .schema_request import SchemaRequest from .object_schema import ObjectSchema from .constant_schema import ConstantSchema +from .list_schema import ListSchema _LOGGER = logging.getLogger(__name__) @@ -197,7 +198,7 @@ def build_serialize_data_call(parameter: Parameter, function_name: str) -> str: if parameter.skip_url_encoding: optional_parameters.append("skip_quote=True") - if parameter.style: + if parameter.style and not parameter.explode: if parameter.style in [ParameterStyle.simple, ParameterStyle.form]: div_char = "," elif parameter.style in [ParameterStyle.spaceDelimited]: @@ -210,17 +211,32 @@ def build_serialize_data_call(parameter: Parameter, function_name: str) -> str: raise ValueError(f"Do not support {parameter.style} yet") optional_parameters.append(f"div='{div_char}'") - serialization_constraints = parameter.schema.serialization_constraints - optional_parameters += serialization_constraints if serialization_constraints else "" + if parameter.explode: + if not isinstance(parameter.schema, ListSchema): + raise ValueError("Got a explode boolean on a non-array schema") + serialization_schema = parameter.schema.element_type + else: + serialization_schema = parameter.schema - optional_parameters_string = "" if not optional_parameters else ", " + ", ".join(optional_parameters) + serialization_constraints = serialization_schema.serialization_constraints + if serialization_constraints: + optional_parameters += serialization_constraints origin_name = parameter.full_serialized_name - return ( - f"""self._serialize.{function_name}("{origin_name.lstrip('_')}", {origin_name}, """ - + f"""'{parameter.schema.serialization_type}'{optional_parameters_string})""" - ) + parameters = [ + f'"{origin_name.lstrip("_")}"', + "q" if parameter.explode else origin_name, + f"'{serialization_schema.serialization_type}'", + *optional_parameters + ] + parameters_line = ', '.join(parameters) + + serialize_line = f'self._serialize.{function_name}({parameters_line})' + + if parameter.explode: + return f"[{serialize_line} if q is not None else '' for q in {origin_name}]" + return serialize_line @property def serialization_context(self) -> str: diff --git a/autorest/codegen/models/parameter.py b/autorest/codegen/models/parameter.py index 81cc6c9b8d9..85ce9e6d86f 100644 --- a/autorest/codegen/models/parameter.py +++ b/autorest/codegen/models/parameter.py @@ -54,6 +54,7 @@ def __init__( constraints: List[Any], target_property_name: Optional[Union[int, str]] = None, # first uses id as placeholder style: Optional[ParameterStyle] = None, + explode: Optional[bool] = False, *, flattened: bool = False, grouped_by: Optional["Parameter"] = None, @@ -72,6 +73,7 @@ def __init__( self.constraints = constraints self.target_property_name = target_property_name self.style = style + self.explode = explode self.flattened = flattened self.grouped_by = grouped_by self.original_parameter = original_parameter @@ -194,6 +196,7 @@ def from_yaml(cls, yaml_data: Dict[str, Any]) -> "Parameter": constraints=[], # FIXME constraints target_property_name=id(yaml_data["targetProperty"]) if yaml_data.get("targetProperty") else None, style=ParameterStyle(http_protocol["style"]) if "style" in http_protocol else None, + explode=http_protocol.get("explode", False), grouped_by=yaml_data.get("groupedBy", None), original_parameter=yaml_data.get("originalParameter", None), flattened=yaml_data.get("flattened", False), diff --git a/test/vanilla/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/operations_async/_queries_operations_async.py b/test/vanilla/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/operations_async/_queries_operations_async.py index 52ba17b0b0b..d1c2645b6ff 100644 --- a/test/vanilla/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/operations_async/_queries_operations_async.py +++ b/test/vanilla/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/operations_async/_queries_operations_async.py @@ -65,7 +65,7 @@ async def array_string_multi_null( # Construct parameters query_parameters = {} # type: Dict[str, Any] if array_query is not None: - query_parameters['arrayQuery'] = self._serialize.query("array_query", array_query, '[str]', div=',') + query_parameters['arrayQuery'] = [self._serialize.query("array_query", q, 'str') if q is not None else '' for q in array_query] # Construct headers header_parameters = {} # type: Dict[str, Any] @@ -92,6 +92,8 @@ async def array_string_multi_empty( ) -> None: """Get an empty array [] of string using the multi-array format. + No query parameter should be sent, since the array is empty. + :param array_query: an empty array [] of string using the multi-array format. :type array_query: list[str] :keyword callable cls: A custom type or function that will be passed the direct response @@ -109,7 +111,7 @@ async def array_string_multi_empty( # Construct parameters query_parameters = {} # type: Dict[str, Any] if array_query is not None: - query_parameters['arrayQuery'] = self._serialize.query("array_query", array_query, '[str]', div=',') + query_parameters['arrayQuery'] = [self._serialize.query("array_query", q, 'str') if q is not None else '' for q in array_query] # Construct headers header_parameters = {} # type: Dict[str, Any] @@ -134,11 +136,13 @@ async def array_string_multi_valid( array_query: Optional[List[str]] = None, **kwargs ) -> None: - """Get an array of string ['ArrayQuery1', 'begin!*'();:@ &=+$,/?#[]end' , null, ''] using the - mult-array format. + """Get an array of string using the multi-array format. + + Parameter is ['ArrayQuery1', 'begin!*'();:@ &=+$,/?#[]end' , null, '']. null is sent as empty + string. :param array_query: an array of string ['ArrayQuery1', 'begin!*'();:@ &=+$,/?#[]end' , null, - ''] using the mult-array format. + ''] using the multi-array format. :type array_query: list[str] :keyword callable cls: A custom type or function that will be passed the direct response :return: None, or the result of cls(response) @@ -155,7 +159,7 @@ async def array_string_multi_valid( # Construct parameters query_parameters = {} # type: Dict[str, Any] if array_query is not None: - query_parameters['arrayQuery'] = self._serialize.query("array_query", array_query, '[str]', div=',') + query_parameters['arrayQuery'] = [self._serialize.query("array_query", q, 'str') if q is not None else '' for q in array_query] # Construct headers header_parameters = {} # type: Dict[str, Any] diff --git a/test/vanilla/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/operations/_queries_operations.py b/test/vanilla/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/operations/_queries_operations.py index 78e9b705cfe..e68accf5139 100644 --- a/test/vanilla/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/operations/_queries_operations.py +++ b/test/vanilla/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/operations/_queries_operations.py @@ -70,7 +70,7 @@ def array_string_multi_null( # Construct parameters query_parameters = {} # type: Dict[str, Any] if array_query is not None: - query_parameters['arrayQuery'] = self._serialize.query("array_query", array_query, '[str]', div=',') + query_parameters['arrayQuery'] = [self._serialize.query("array_query", q, 'str') if q is not None else '' for q in array_query] # Construct headers header_parameters = {} # type: Dict[str, Any] @@ -98,6 +98,8 @@ def array_string_multi_empty( # type: (...) -> None """Get an empty array [] of string using the multi-array format. + No query parameter should be sent, since the array is empty. + :param array_query: an empty array [] of string using the multi-array format. :type array_query: list[str] :keyword callable cls: A custom type or function that will be passed the direct response @@ -115,7 +117,7 @@ def array_string_multi_empty( # Construct parameters query_parameters = {} # type: Dict[str, Any] if array_query is not None: - query_parameters['arrayQuery'] = self._serialize.query("array_query", array_query, '[str]', div=',') + query_parameters['arrayQuery'] = [self._serialize.query("array_query", q, 'str') if q is not None else '' for q in array_query] # Construct headers header_parameters = {} # type: Dict[str, Any] @@ -141,11 +143,13 @@ def array_string_multi_valid( **kwargs # type: Any ): # type: (...) -> None - """Get an array of string ['ArrayQuery1', 'begin!*'();:@ &=+$,/?#[]end' , null, ''] using the - mult-array format. + """Get an array of string using the multi-array format. + + Parameter is ['ArrayQuery1', 'begin!*'();:@ &=+$,/?#[]end' , null, '']. null is sent as empty + string. :param array_query: an array of string ['ArrayQuery1', 'begin!*'();:@ &=+$,/?#[]end' , null, - ''] using the mult-array format. + ''] using the multi-array format. :type array_query: list[str] :keyword callable cls: A custom type or function that will be passed the direct response :return: None, or the result of cls(response) @@ -162,7 +166,7 @@ def array_string_multi_valid( # Construct parameters query_parameters = {} # type: Dict[str, Any] if array_query is not None: - query_parameters['arrayQuery'] = self._serialize.query("array_query", array_query, '[str]', div=',') + query_parameters['arrayQuery'] = [self._serialize.query("array_query", q, 'str') if q is not None else '' for q in array_query] # Construct headers header_parameters = {} # type: Dict[str, Any]