Skip to content

Commit

Permalink
fix and add test for data bodies (#1061)
Browse files Browse the repository at this point in the history
  • Loading branch information
iscai-msft authored Oct 16, 2021
1 parent 5ec5ab4 commit b58b108
Show file tree
Hide file tree
Showing 85 changed files with 2,423 additions and 155 deletions.
14 changes: 14 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Change Log

### 2021-10-15 - 5.9.3

| Library | Min Version
| --------------- | -------
|`@autorest/core` | `3.6.2`
|`@autorest/modelerfour` | `4.19.1`
|`azure-core` dep of generated code | `1.19.0`
|`msrest` dep of generated code | `0.6.21`
|`azure-mgmt-core` dep of generated code (If generating mgmt plane code) | `1.3.0`

**Bug Fixes**

- Fix generation of form-data inputs #1061

### 2021-10-05 - 5.9.2

| Library | Min Version
Expand Down
2 changes: 1 addition & 1 deletion autorest/codegen/models/base_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,6 @@ def get_json_template_representation(self, **kwargs: Any) -> Any:
...

@abstractmethod
def get_files_template_representation(self, **kwargs: Any) -> Any:
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
"""Template of what this schema would look like as files input"""
...
4 changes: 2 additions & 2 deletions autorest/codegen/models/constant_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ def get_json_template_representation(self, **kwargs: Any) -> Any:
kwargs['default_value_declaration'] = self.schema.get_declaration(self.value)
return self.schema.get_json_template_representation(**kwargs)

def get_files_template_representation(self, **kwargs: Any) -> Any:
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
kwargs['default_value_declaration'] = self.schema.get_declaration(self.value)
return self.schema.get_files_template_representation(**kwargs)
return self.schema.get_files_and_data_template_representation(**kwargs)

def imports(self) -> FileImport:
file_import = FileImport()
Expand Down
2 changes: 1 addition & 1 deletion autorest/codegen/models/credential_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def serialization_type(self) -> str:
def get_json_template_representation(self, **kwargs: Any) -> Any:
raise TypeError("You should not try to get a JSON template representation of a CredentialSchema")

def get_files_template_representation(self, **kwargs: Any) -> Any:
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
raise TypeError("You should not try to get a files template representation of a CredentialSchema")


Expand Down
4 changes: 2 additions & 2 deletions autorest/codegen/models/dictionary_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ def get_json_template_representation(self, **kwargs: Any) -> Any:
f'"{"str"}"' : self.element_type.get_json_template_representation(**kwargs)
}

def get_files_template_representation(self, **kwargs: Any) -> Any:
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
return {
f'"{"str"}"' : self.element_type.get_files_template_representation(**kwargs)
f'"{"str"}"' : self.element_type.get_files_and_data_template_representation(**kwargs)
}

@classmethod
Expand Down
4 changes: 2 additions & 2 deletions autorest/codegen/models/enum_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ def get_json_template_representation(self, **kwargs: Any) -> Any:
# for better display effect, use the only value instead of var type
return self.enum_type.get_json_template_representation(**self._template_kwargs(**kwargs))

def get_files_template_representation(self, **kwargs: Any) -> Any:
return self.enum_type.get_files_template_representation(**self._template_kwargs(**kwargs))
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
return self.enum_type.get_files_and_data_template_representation(**self._template_kwargs(**kwargs))

@classmethod
def from_yaml(cls, namespace: str, yaml_data: Dict[str, Any], **kwargs: Any) -> "EnumSchema":
Expand Down
4 changes: 2 additions & 2 deletions autorest/codegen/models/list_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ def has_xml_serialization_ctxt(self) -> bool:
def get_json_template_representation(self, **kwargs: Any) -> Any:
return [self.element_type.get_json_template_representation(**kwargs)]

def get_files_template_representation(self, **kwargs: Any) -> Any:
return [self.element_type.get_files_template_representation(**kwargs)]
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
return [self.element_type.get_files_and_data_template_representation(**kwargs)]

def xml_serialization_ctxt(self) -> Optional[str]:
attrs_list = []
Expand Down
4 changes: 2 additions & 2 deletions autorest/codegen/models/object_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ def get_json_template_representation(self, **kwargs: Any) -> Any:
self._created_json_template_representation = False
return representation

def get_files_template_representation(self, **kwargs: Any) -> Any:
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
object_schema_names = kwargs.get("object_schema_names", [])
object_schema_names.append(self.name) # do tis to avoid circular
kwargs["object_schema_names"] = object_schema_names
return {
"{}".format(
prop.original_swagger_name
): prop.get_files_template_representation(**kwargs)
): prop.get_files_and_data_template_representation(**kwargs)
for prop in self.properties
}

Expand Down
7 changes: 2 additions & 5 deletions autorest/codegen/models/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ def __init__(
self.has_multiple_media_types: bool = False
self.multiple_media_types_type_annot: Optional[str] = None
self.multiple_media_types_docstring_type: Optional[str] = None
self.is_partial_body = yaml_data.get("isPartialBody", False)
self._keyword_only = keyword_only
self.is_multipart = yaml_data.get("language", {}).get("python", {}).get("multipart", False)
self.is_data_input = yaml_data.get("isPartialBody", False) and not self.is_multipart

def __hash__(self) -> int:
return hash(self.serialized_name)
Expand Down Expand Up @@ -123,10 +124,6 @@ def constant(self) -> bool:
return False
return self.required

@property
def is_multipart(self) -> bool:
return self.yaml_data["language"]["python"].get("multipart", False)

@property
def constant_declaration(self) -> str:
if self.schema:
Expand Down
53 changes: 37 additions & 16 deletions autorest/codegen/models/parameter_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ def multipart(self) -> List[Parameter]:
return self.get_from_predicate(lambda parameter: parameter.is_multipart)

@property
def has_partial_body(self) -> bool:
return any(self.get_from_predicate(lambda parameter: parameter.is_partial_body))
def data_inputs(self) -> List[Parameter]:
return self.get_from_predicate(lambda parameter: parameter.is_data_input)

@property
def content_types(self) -> List[str]:
Expand Down Expand Up @@ -278,32 +278,53 @@ def call(self) -> List[str]:
def is_flattened(self) -> bool:
return cast(bool, self.get_from_predicate(lambda parameter: parameter.flattened))

def _create_files_or_data_param(
params: List[Parameter], serialized_name: str, description: str
) -> Parameter:
param = copy(params[0])
param.serialized_name = serialized_name
param.schema = DictionarySchema(
namespace="",
yaml_data={},
element_type=AnySchema(namespace="", yaml_data={}),
)
param.description = description
return param

class ParameterOnlyPathAndBodyPositionalList(ParameterList):
# use this to change the files parameter in the method
# use this to change the files and data parameter in the method

@property
def method(self) -> List[Parameter]:
method_params = super().method
files_params = [p for p in method_params if p.is_multipart]
if not files_params:
data_params = [p for p in method_params if p.is_data_input]
if not (files_params or data_params):
return method_params
files_param = copy(files_params[0])
files_param.serialized_name = "files"
files_param.schema = DictionarySchema(
namespace="",
yaml_data={},
element_type=AnySchema(namespace="", yaml_data={}),
)
files_param.description = (
"Multipart input for files. See the template in our example to find the input shape."
)
method_params = [p for p in method_params if not p.is_multipart]

# update files param
file_and_data_params = []
if files_params:
files_param = _create_files_or_data_param(
files_params,
serialized_name="files",
description="Multipart input for files. See the template in our example to find the input shape."
)
file_and_data_params.append(files_param)
if data_params:
data_param = _create_files_or_data_param(
data_params,
serialized_name="data",
description="Form-encoded input for data. See the template in our example to find the input shape."
)
file_and_data_params.append(data_param)
method_params = [p for p in method_params if not p.is_multipart and not p.is_data_input]
positional = [p for p in method_params if p.is_positional]
keyword_only = [p for p in method_params if p.is_keyword_only]
kwargs = self._filter_out_multiple_content_type(
[p for p in method_params if p.is_kwarg]
)
return positional + [files_param] + keyword_only + kwargs
return positional + file_and_data_params + keyword_only + kwargs

def get_parameter_list(code_model):
if code_model.options["only_path_and_body_params_positional"]:
Expand Down
2 changes: 1 addition & 1 deletion autorest/codegen/models/primitive_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def get_json_template_representation(self, **kwargs: Any) -> Any:
def default_template_representation_declaration(self) -> str:
return self.get_declaration(self.docstring_type)

def get_files_template_representation(self, **kwargs: Any) -> Any:
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
"""Template of what the files input should look like
"""
return self._add_optional_and_default_value_template_representation(
Expand Down
4 changes: 2 additions & 2 deletions autorest/codegen/models/property.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,9 @@ def get_json_template_representation(self, **kwargs: Any) -> Any:
kwargs["description"] = self.description
return self.schema.get_json_template_representation(**kwargs)

def get_files_template_representation(self, **kwargs: Any) -> Any:
def get_files_and_data_template_representation(self, **kwargs: Any) -> Any:
kwargs["optional"] = not self.required
return self.schema.get_files_template_representation(**kwargs)
return self.schema.get_files_and_data_template_representation(**kwargs)

def model_file_imports(self) -> FileImport:
file_import = self.schema.model_file_imports()
Expand Down
2 changes: 1 addition & 1 deletion autorest/codegen/models/request_builder_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def name_in_high_level_operation(self) -> str:
if self.is_body:
if self.is_multipart:
return "files"
if self.is_partial_body:
if self.is_data_input:
return "data"
return "json"
name = self.yaml_data["language"]["python"]["name"]
Expand Down
14 changes: 9 additions & 5 deletions autorest/codegen/models/request_builder_parameter_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ def add_body_kwargs(self, schema_requests: List[SchemaRequest]) -> None:
except StopIteration:
pass
else:
if body_method_param.constant:
# we don't add body kwargs for constant bodies
body_method_param.serialized_name = "json"
return
if body_method_param.is_multipart:
file_kwarg = copy(body_method_param)
self._change_body_param_name(file_kwarg, "files")
Expand All @@ -58,8 +54,9 @@ def add_body_kwargs(self, schema_requests: List[SchemaRequest]) -> None:
"Multipart input for files. See the template in our example to find the input shape. " +
file_kwarg.description
)
file_kwarg.is_multipart = False
body_kwargs_added.append(file_kwarg)
if body_method_param.is_partial_body:
if body_method_param.is_data_input:
data_kwarg = copy(body_method_param)
self._change_body_param_name(data_kwarg, "data")
data_kwarg.schema = DictionarySchema(
Expand All @@ -71,7 +68,12 @@ def add_body_kwargs(self, schema_requests: List[SchemaRequest]) -> None:
"Pass in dictionary that contains form data to include in the body of the request. " +
data_kwarg.description
)
data_kwarg.is_data_input = False
body_kwargs_added.append(data_kwarg)
if body_method_param.constant:
# we don't add body kwargs for constant bodies
body_method_param.serialized_name = "json"
return
if (
any(sr for sr in schema_requests if not sr.is_stream_request) and
any([ct for ct in self.content_types if "json" in ct])
Expand All @@ -93,6 +95,8 @@ def add_body_kwargs(self, schema_requests: List[SchemaRequest]) -> None:
"a byte iterator, or stream input). " +
content_kwarg.description
)
content_kwarg.is_data_input = False
content_kwarg.is_multipart = False
body_kwargs_added.append(content_kwarg)
if len(body_kwargs_added) == 1:
body_kwargs_added[0].required = body_method_param.required
Expand Down
Loading

0 comments on commit b58b108

Please sign in to comment.