Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ef44eab
add invoke to client
iscai-msft Jan 26, 2021
d6fe76b
make macro for path format arguments
iscai-msft Jan 26, 2021
25640c1
add type hints to invoke
iscai-msft Jan 26, 2021
5715bd5
allow users to set stream
iscai-msft Jan 26, 2021
f24931c
revert import moving to client function
iscai-msft Jan 26, 2021
8366535
avoid import duplication
iscai-msft Jan 26, 2021
c50cec1
set stream in invoke
iscai-msft Jan 26, 2021
3585701
add vanilla invoke tests
iscai-msft Jan 26, 2021
2511e2e
add path format args test
iscai-msft Jan 26, 2021
ba73f8c
invoke returns http response
iscai-msft Jan 27, 2021
2c5493f
allow users to pass in partial urls to invoke
iscai-msft Jan 27, 2021
eda0cd9
use json.dumps and msrest serialize
iscai-msft Jan 27, 2021
77d6f28
remove stream download
iscai-msft Jan 27, 2021
20f9b02
add docstring to invoke
iscai-msft Jan 28, 2021
a917bed
add back stream test, json navigation of get request
iscai-msft Jan 28, 2021
7566532
add set json body to test
iscai-msft Jan 28, 2021
0d26405
Merge branch 'autorestv3' of https://github.com/Azure/autorest.python…
iscai-msft Feb 2, 2021
71ede58
invoke -> _request
iscai-msft Feb 3, 2021
fef8bc5
generate with stream defaulting to true
iscai-msft Feb 4, 2021
2a28d50
use json.load
iscai-msft Feb 8, 2021
33cd210
fix stream download iteration
iscai-msft Feb 9, 2021
c7ff9e6
Merge branch 'autorestv3' of https://github.com/Azure/autorest.python…
iscai-msft Feb 9, 2021
22258b1
add put stream test
iscai-msft Feb 9, 2021
465ad5a
decode bytes to string
iscai-msft Feb 9, 2021
056d85a
regen with _send
iscai-msft Feb 10, 2021
6b8a7f0
make tests use send
iscai-msft Feb 10, 2021
b667f1b
Merge branch 'autorestv3' of https://github.com/Azure/autorest.python…
iscai-msft Feb 10, 2021
436d6b5
_send -> _send_request
iscai-msft Feb 10, 2021
b36fd01
httpresponse -> asynchttpresponse for async
iscai-msft Feb 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion autorest/codegen/models/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,17 @@ def imports(code_model, async_mode: bool) -> FileImport:
file_import.add_from_import("msrest", "Serializer", ImportType.AZURECORE)
file_import.add_from_import("msrest", "Deserializer", ImportType.AZURECORE)
file_import.add_from_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)

if async_mode:
file_import.add_from_import(
"azure.core.pipeline.transport", "AsyncHttpResponse", ImportType.AZURECORE, TypingSection.CONDITIONAL
)
else:
file_import.add_from_import(
"azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE, TypingSection.CONDITIONAL
)
file_import.add_from_import(
"azure.core.pipeline.transport", "HttpRequest", ImportType.AZURECORE, TypingSection.CONDITIONAL
)
any_optional_gp = any(not gp.required for gp in code_model.global_parameters)

if any_optional_gp or code_model.base_url:
Expand Down
52 changes: 1 addition & 51 deletions autorest/codegen/models/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
from .base_model import BaseModel
from .imports import FileImport, ImportType, TypingSection
from .schema_response import SchemaResponse
from .parameter import Parameter, ParameterStyle
from .parameter import Parameter
from .parameter_list import ParameterList
from .base_schema import BaseSchema
from .schema_request import SchemaRequest
from .object_schema import ObjectSchema
from .constant_schema import ConstantSchema
from .list_schema import ListSchema


_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -148,55 +147,6 @@ def has_optional_return_type(self) -> bool:
len(self.success_status_code) != len(status_codes_for_responses_with_bodies)
)


@staticmethod
def build_serialize_data_call(parameter: Parameter, function_name: str) -> str:

optional_parameters = []

if parameter.skip_url_encoding:
optional_parameters.append("skip_quote=True")

if parameter.style and not parameter.explode:
if parameter.style in [ParameterStyle.simple, ParameterStyle.form]:
div_char = ","
elif parameter.style in [ParameterStyle.spaceDelimited]:
div_char = " "
elif parameter.style in [ParameterStyle.pipeDelimited]:
div_char = "|"
elif parameter.style in [ParameterStyle.tabDelimited]:
div_char = "\t"
else:
raise ValueError(f"Do not support {parameter.style} yet")
optional_parameters.append(f"div='{div_char}'")

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

serialization_constraints = serialization_schema.serialization_constraints
if serialization_constraints:
optional_parameters += serialization_constraints

origin_name = parameter.full_serialized_name

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:
# FIXME Do the serialization context (XML)
Expand Down
48 changes: 48 additions & 0 deletions autorest/codegen/models/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .imports import FileImport, ImportType, TypingSection
from .base_model import BaseModel
from .base_schema import BaseSchema
from .list_schema import ListSchema
from .constant_schema import ConstantSchema


Expand Down Expand Up @@ -84,6 +85,53 @@ def __init__(
self.multiple_media_types_type_annot: Optional[str] = None
self.multiple_media_types_docstring_type: Optional[str] = None

def build_serialize_data_call(self, function_name: str) -> str:

optional_parameters = []

if self.skip_url_encoding:
optional_parameters.append("skip_quote=True")

if self.style and not self.explode:
if self.style in [ParameterStyle.simple, ParameterStyle.form]:
div_char = ","
elif self.style in [ParameterStyle.spaceDelimited]:
div_char = " "
elif self.style in [ParameterStyle.pipeDelimited]:
div_char = "|"
elif self.style in [ParameterStyle.tabDelimited]:
div_char = "\t"
else:
raise ValueError(f"Do not support {self.style} yet")
optional_parameters.append(f"div='{div_char}'")

if self.explode:
if not isinstance(self.schema, ListSchema):
raise ValueError("Got a explode boolean on a non-array schema")
serialization_schema = self.schema.element_type
else:
serialization_schema = self.schema

serialization_constraints = serialization_schema.serialization_constraints
if serialization_constraints:
optional_parameters += serialization_constraints

origin_name = self.full_serialized_name

parameters = [
f'"{origin_name.lstrip("_")}"',
"q" if self.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 self.explode:
return f"[{serialize_line} if q is not None else '' for q in {origin_name}]"
return serialize_line

@property
def constant(self) -> bool:
"""Returns whether a parameter is a constant or not.
Expand Down
6 changes: 1 addition & 5 deletions autorest/codegen/templates/lro_operation_helper.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,7 @@
{% set operation_name = "begin_"+operation.python_name %}
{% if operation.parameters.path %}
{% set path_format_arguments = ", path_format_arguments=path_format_arguments" %}
path_format_arguments = {
{% for path_parameter in operation.parameters.path %}
'{{ path_parameter.rest_api_name }}': {{ operation.build_serialize_data_call(path_parameter, "url") }},
{% endfor %}
}
{{ op_tools.path_format_arguments(operation.parameters.path)|indent }}

{% endif %}
if polling is True: polling_method = {{ operation.get_default_polling_method(async_mode, code_model.options["azure_arm"]) }}(lro_delay{{ lro_options }}{{ path_format_arguments }}, **kwargs)
Expand Down
8 changes: 2 additions & 6 deletions autorest/codegen/templates/operation.py.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,8 @@
# Construct URL
url = self.{{ operation.python_name }}.metadata['url'] # type: ignore
{% if operation.parameters.path %}
path_format_arguments = {
{% for path_parameter in operation.parameters.path %}
'{{ path_parameter.rest_api_name }}': {{ operation.build_serialize_data_call(path_parameter, "url") }},
{% endfor %}
}
url = self._client.format_url(url, **path_format_arguments)
{{ op_tools.path_format_arguments(operation.parameters.path)|indent }}
{{ op_tools.format_path_format_arguments()|indent }}
{% endif %}

{{ op_tools.query_parameters(operation, async_mode)|indent }}
Expand Down
20 changes: 16 additions & 4 deletions autorest/codegen/templates/operation_tools.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ query_parameters = {} # type: Dict[str, Any]
{% if operation.parameters.query %}
{% for query_parameter in operation.parameters.query %}
{%if query_parameter.required %}
query_parameters['{{ query_parameter.rest_api_name }}'] = {{ operation.build_serialize_data_call(query_parameter, "query") }}
query_parameters['{{ query_parameter.rest_api_name }}'] = {{ query_parameter.build_serialize_data_call("query") }}
{% else %}
if {{ query_parameter.full_serialized_name }} is not None:
query_parameters['{{ query_parameter.rest_api_name }}'] = {{ operation.build_serialize_data_call(query_parameter, "query") }}
query_parameters['{{ query_parameter.rest_api_name }}'] = {{ query_parameter.build_serialize_data_call("query") }}
{% endif %}
{% endfor %}
{% endif %}{% endmacro %}
Expand All @@ -125,13 +125,25 @@ header_parameters = {} # type: Dict[str, Any]
{% if operation.parameters.headers %}
{% for header_parameter in operation.parameters.headers %}
{%if header_parameter.required %}
header_parameters['{{ header_parameter.rest_api_name }}'] = {{ operation.build_serialize_data_call(header_parameter, "header") }}
header_parameters['{{ header_parameter.rest_api_name }}'] = {{ header_parameter.build_serialize_data_call("header") }}
{% else %}
if {{ header_parameter.full_serialized_name }} is not None:
header_parameters['{{ header_parameter.rest_api_name }}'] = {{ operation.build_serialize_data_call(header_parameter, "header") }}
header_parameters['{{ header_parameter.rest_api_name }}'] = {{ header_parameter.build_serialize_data_call("header") }}
{% endif %}
{% endfor %}
{% endif %}{% endmacro %}

{# path format arguments #}
{% macro path_format_arguments(path_parameters) %}
path_format_arguments = {
{% for path_parameter in path_parameters %}
'{{ path_parameter.rest_api_name }}': {{ path_parameter.build_serialize_data_call("url") }},
{% endfor %}
}{% endmacro %}

{% macro format_path_format_arguments(url_name="url") %}
{{ url_name }} = self._client.format_url({{ url_name }}, **path_format_arguments){% endmacro %}

{# helper for stream body params #}
{% macro stream_body_params(operation) %}body_content_kwargs['stream_content'] = {{ operation.parameters.body[0].serialized_name }}{% endmacro %}
{# helper for non-stream body params with schema #}
Expand Down
24 changes: 6 additions & 18 deletions autorest/codegen/templates/paging_operation_helper.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -23,38 +23,26 @@ cls = kwargs.pop('cls', None) # type: ClsType[{{ op_tools.return_type_annotatio
# Construct URL
url = self.{{ operation.python_name }}.metadata['url'] # type: ignore
{% if operation.parameters.path %}
path_format_arguments = {
{% for path_parameter in operation.parameters.path %}
'{{ path_parameter.rest_api_name }}': {{ operation.build_serialize_data_call(path_parameter, "url") }},
{% endfor %}
}
url = self._client.format_url(url, **path_format_arguments)
{{ op_tools.path_format_arguments(operation.parameters.path)|indent(12) }}
{{ op_tools.format_path_format_arguments()|indent(12) }}
{% endif %}
{{ op_tools.query_parameters(operation, async_mode)|indent(12) }}
{{ op_tools.body_parameters(operation)|indent(12) }}
else:
{% if operation.next_operation %}
url = '{{ operation.next_operation.url }}'
{% if operation.next_operation.parameters.path %}
path_format_arguments = {
{% for path_parameter in operation.next_operation.parameters.path %}
'{{ path_parameter.rest_api_name }}': {{ operation.next_operation.build_serialize_data_call(path_parameter, "url") }},
{% endfor %}
}
url = self._client.format_url(url, **path_format_arguments)
{{ op_tools.path_format_arguments(operation.next_operation.parameters.path)|indent(12) }}
{{ op_tools.format_path_format_arguments()|indent(12) }}
{% endif %}
{{ op_tools.query_parameters(operation.next_operation, async_mode)|indent(12) }}
{{ op_tools.body_parameters(operation.next_operation)|indent(12) }}
{% else %}
url = next_link
query_parameters = {} # type: Dict[str, Any]
{% if operation.parameters.path and not code_model.base_url%}
path_format_arguments = {
{% for path_parameter in operation.parameters.path %}
'{{ path_parameter.rest_api_name }}': {{ operation.build_serialize_data_call(path_parameter, "url") }},
{% endfor %}
}
url = self._client.format_url(url, **path_format_arguments)
{{ op_tools.path_format_arguments(operation.parameters.path)|indent(12) }}
{{ op_tools.format_path_format_arguments()|indent(12) }}
{% endif %}
{{ op_tools.body_parameters(operation, http_verb="get")|indent(12) }}
{% endif %}
Expand Down
24 changes: 24 additions & 0 deletions autorest/codegen/templates/service_client.py.jinja2
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% import 'keywords.jinja2' as keywords with context %}
{% set path_to_models = ".." if async_mode else "." %}
{% import 'operation_tools.jinja2' as op_tools %}
{% macro method_signature() %}
def __init__(
self,
Expand Down Expand Up @@ -92,6 +93,29 @@ class {{ code_model.class_name }}({{ base_class }}):
self._client, self._config, self._serialize, self._deserialize)
{% endfor %}

{% set http_response = "AsyncHttpResponse" if async_mode else "HttpResponse" %}
{{ keywords.def }} _send_request(self, http_request{{ ": HttpRequest" if async_mode }}, **kwargs{{ ": Any" if async_mode }}){{ (" -> " + http_response) if async_mode else "" }}:
{% if not async_mode %}
# type: (HttpRequest, Any) -> {{ http_response }}
{% endif %}
"""Runs the network request through the client's chained policies.

:param http_request: The network request you want to make. Required.
:type http_request: ~azure.core.pipeline.transport.HttpRequest
:keyword bool stream: Whether the response payload will be streamed. Defaults to True.
:return: The response of your network call. Does not do error handling on your response.
:rtype: ~azure.core.pipeline.transport.{{ http_response }}
"""
{% if code_model.global_parameters.path %}
{{ op_tools.path_format_arguments(code_model.global_parameters.path)|indent(8) }}
{{ op_tools.format_path_format_arguments(url_name="http_request.url")|indent(8) }}
{% else %}
http_request.url = self._client.format_url(http_request.url)
{% endif %}
stream = kwargs.pop("stream", True)
pipeline_response = {{ keywords.await }}self._client._pipeline.run(http_request, stream=stream, **kwargs)
return pipeline_response.http_response

{{ keywords.def }} close(self){{ " -> None" if async_mode else "" }}:
{% if not async_mode %}
# type: () -> None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from typing import Any, Dict, Optional

from azure.core.credentials import AzureKeyCredential
from azure.core.pipeline.transport import HttpRequest, HttpResponse

from ._configuration import AutoRestHeadTestServiceConfiguration
from .operations import HttpSuccessOperations
Expand Down Expand Up @@ -51,6 +52,21 @@ def __init__(
self.http_success = HttpSuccessOperations(
self._client, self._config, self._serialize, self._deserialize)

def _send_request(self, http_request, **kwargs):
# type: (HttpRequest, Any) -> HttpResponse
"""Runs the network request through the client's chained policies.

:param http_request: The network request you want to make. Required.
:type http_request: ~azure.core.pipeline.transport.HttpRequest
:keyword bool stream: Whether the response payload will be streamed. Defaults to True.
:return: The response of your network call. Does not do error handling on your response.
:rtype: ~azure.core.pipeline.transport.HttpResponse
"""
http_request.url = self._client.format_url(http_request.url)
stream = kwargs.pop("stream", True)
pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs)
return pipeline_response.http_response

def close(self):
# type: () -> None
self._client.close()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from azure.core import AsyncPipelineClient
from azure.core.credentials import AzureKeyCredential
from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest
from msrest import Deserializer, Serializer

if TYPE_CHECKING:
Expand Down Expand Up @@ -49,6 +50,20 @@ def __init__(
self.http_success = HttpSuccessOperations(
self._client, self._config, self._serialize, self._deserialize)

async def _send_request(self, http_request: HttpRequest, **kwargs: Any) -> AsyncHttpResponse:
"""Runs the network request through the client's chained policies.

:param http_request: The network request you want to make. Required.
:type http_request: ~azure.core.pipeline.transport.HttpRequest
:keyword bool stream: Whether the response payload will be streamed. Defaults to True.
:return: The response of your network call. Does not do error handling on your response.
:rtype: ~azure.core.pipeline.transport.AsyncHttpResponse
"""
http_request.url = self._client.format_url(http_request.url)
stream = kwargs.pop("stream", True)
pipeline_response = await self._client._pipeline.run(http_request, stream=stream, **kwargs)
return pipeline_response.http_response

async def close(self) -> None:
await self._client.close()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# pylint: disable=unused-import,ungrouped-imports
from typing import Any, Dict, Optional

from azure.core.pipeline.transport import HttpRequest, HttpResponse

from ._configuration import AutoRestHeadTestServiceConfiguration
from .operations import HttpSuccessOperations

Expand Down Expand Up @@ -46,6 +48,21 @@ def __init__(
self.http_success = HttpSuccessOperations(
self._client, self._config, self._serialize, self._deserialize)

def _send_request(self, http_request, **kwargs):
# type: (HttpRequest, Any) -> HttpResponse
"""Runs the network request through the client's chained policies.

:param http_request: The network request you want to make. Required.
:type http_request: ~azure.core.pipeline.transport.HttpRequest
:keyword bool stream: Whether the response payload will be streamed. Defaults to True.
:return: The response of your network call. Does not do error handling on your response.
:rtype: ~azure.core.pipeline.transport.HttpResponse
"""
http_request.url = self._client.format_url(http_request.url)
stream = kwargs.pop("stream", True)
pipeline_response = self._client._pipeline.run(http_request, stream=stream, **kwargs)
return pipeline_response.http_response

def close(self):
# type: () -> None
self._client.close()
Expand Down
Loading