Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Declare kwargs reserved #525

Merged
merged 21 commits into from
Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
18 changes: 13 additions & 5 deletions autorest/codegen/models/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ def _non_binary_schema_media_types(media_types: List[str]) -> List[str]:
response_media_types.append(xml_media_types[0])
return response_media_types

def _remove_multiple_content_type_parameters(parameters: List[Parameter]) -> List[Parameter]:
content_type_params = [p for p in parameters if p.serialized_name == "content_type"]
remaining_params = [p for p in parameters if p.serialized_name != "content_type"]
json_content_type_param = [p for p in content_type_params if p.yaml_data["schema"]["type"] == "constant"]
if json_content_type_param:
remaining_params.append(json_content_type_param[0])
else:
remaining_params.append(content_type_params[0])
return remaining_params

class Operation(BaseModel): # pylint: disable=too-many-public-methods, too-many-instance-attributes
"""Represent an operation.
"""
Expand Down Expand Up @@ -262,12 +272,7 @@ def from_yaml(cls, yaml_data: Dict[str, Any]) -> "Operation":
for request in yaml_data["requests"]:
for yaml in request.get("parameters", []):
parameter = Parameter.from_yaml(yaml)

if yaml["language"]["python"]["name"] == "content_type":
if yaml["schema"]["type"] == "sealed-choice":
# for requests with multiple media types
# we get one that's a constant, one that's an enum
continue
parameter.is_kwarg = True
parameters.append(parameter)
elif multiple_requests:
Expand All @@ -276,6 +281,9 @@ def from_yaml(cls, yaml_data: Dict[str, Any]) -> "Operation":
parameters.append(parameter)

if multiple_requests:
parameters = _remove_multiple_content_type_parameters(parameters)
chosen_parameter = multiple_media_type_parameters[0]

# binary body parameters are required, while object
# ones are not. We default to optional in this case.
optional_parameters = [p for p in multiple_media_type_parameters if not p.required]
Expand Down
22 changes: 2 additions & 20 deletions autorest/namer/name_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,7 @@
# --------------------------------------------------------------------------
import re
from typing import cast, Any, Dict, List, Match, Optional
from enum import Enum
from .python_mappings import basic_latin_chars, reserved_words


class PadType(Enum):
Model = "Model"
Method = "Method"
Parameter = "Parameter"
Enum = "Enum"
Property = "Property"
from .python_mappings import basic_latin_chars, reserved_words, PadType


class NameConverter:
Expand Down Expand Up @@ -198,17 +189,8 @@ def _get_escaped_reserved_name(name: str, pad_string: Optional[PadType] = None)
try:
# check to see if name is reserved for the type of name we are converting
pad_string = cast(PadType, pad_string)
if name.lower() in reserved_words["always_reserved"]:
if pad_string and name.lower() in reserved_words[pad_string]:
name += pad_string.value
elif pad_string in [PadType.Method, PadType.Parameter]:
if name.lower() in reserved_words["reserved_for_operations"]:
name += pad_string.value
elif pad_string in [PadType.Model, PadType.Property]:
if name.lower() in reserved_words["reserved_for_models"]:
name += pad_string.value
elif pad_string == PadType.Enum:
if name.lower() in reserved_words["reserved_for_enums"]:
name += pad_string.value
return name
except AttributeError:
raise ValueError(f"The name {name} is a reserved word and you have not specified a pad string for it.")
Expand Down
156 changes: 117 additions & 39 deletions autorest/namer/python_mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
from enum import Enum

basic_latin_chars = {
" ": "Space",
Expand Down Expand Up @@ -49,48 +50,125 @@
"~": "Tilde",
}

class PadType(Enum):
Model = "Model"
Method = "Method"
Parameter = "Parameter"
Enum = "Enum"
Property = "Property"

_always_reserved = [
"and",
"as",
"assert",
"break",
"class",
"continue",
"def",
"del",
"elif",
"else",
"except",
"exec",
"finally",
"for",
"from",
"global",
"if",
"import",
"in",
"is",
"lambda",
"not",
"or",
"pass",
"raise",
"return",
"try",
"while",
"with",
"yield",
"async",
"await"
]

reserved_words = {
"always_reserved": [
"and",
"as",
"assert",
"break",
"class",
"continue",
"def",
"del",
"elif",
"else",
"except",
"exec",
"finally",
"for",
"from",
"global",
"if",
"import",
"in",
"is",
"lambda",
"not",
"or",
"pass",
"raise",
"return",
"try",
"while",
"with",
"yield",
"async",
"await"
PadType.Method: [
"self",
*_always_reserved
],
PadType.Parameter: [
# these are kwargs we've reserved for our autorest generated operations
"content_type",
"cls",
"polling",
# these are transport kwargs
# https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md#transport
"connection_timeout",
"connection_verify",
"connection_cert",
"connection_data_block_size",
"use_env_settings",
# the following aren't in the readme, but Xiang said these are also transport kwargs
"read_timeout",
"proxies",
"cookies",
# these are policy kwargs
# https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/core/azure-core/CLIENT_LIBRARY_DEVELOPER.md#available-policies
"base_headers",
"headers",
"request_id",
"auto_request_id",
"base_user_agent",
"user_agent",
"user_agent_overwrite",
"user_agent_use_env",
"user_agent",
"sdk_moniker",
"logging_enable",
"logger",
"response_encoding",
"proxies",
"raw_request_hook",
"raw_response_hook",
"network_span_namer",
"tracing_attributes",
"permit_redirects",
"redirect_max",
"redirect_remove_headers",
"redirect_on_status_codes",
"permit_redirects",
"redirect_max",
"redirect_remove_headers",
"redirect_on_status_codes",
"retry_total",
"retry_connect",
"retry_read",
"retry_status",
"retry_backoff_factor",
"retry_backoff_max",
"retry_mode",
"retry_on_status_codes",
"retry_total",
"retry_connect",
"retry_read",
"retry_status",
"retry_backoff_factor",
"retry_backoff_max",
"retry_mode",
"retry_on_status_codes",
*_always_reserved
],
"reserved_for_operations": [
"self"
PadType.Model: [
"self",
*_always_reserved
],
"reserved_for_models": [
"self"
PadType.Property: [
"self",
*_always_reserved
],
"reserved_for_enums": [
"mro"
PadType.Enum: [
"mro",
*_always_reserved
]
}
14 changes: 12 additions & 2 deletions test/unittests/test_name_converter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from autorest.namer.name_converter import NameConverter, PadType
from autorest.namer.name_converter import NameConverter
from autorest.namer.python_mappings import PadType

def test_escaped_reserved_words():
expected_conversion_model = {
Expand All @@ -11,11 +12,20 @@ def test_escaped_reserved_words():

expected_conversion_method = {
"self": "self_method",
"and": "and_method"
"and": "and_method",
"content_type": "content_type"
}
for name in expected_conversion_method:
assert NameConverter._to_valid_python_name(name, pad_string=PadType.Method) == expected_conversion_method[name]

expected_conversion_parameter = {
"content_type": "content_type_parameter",
"request_id": "request_id_parameter",
"elif": "elif_parameter"
}
for name in expected_conversion_parameter:
assert NameConverter._to_valid_python_name(name, pad_string=PadType.Parameter) == expected_conversion_parameter[name]

expected_conversion_enum = {
"self": "self",
"mro": "mro_enum"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ def __init__(self, client, config, serializer, deserializer) -> None:
@distributed_trace_async
async def param_existing_key(
self,
user_agent: str,
user_agent_parameter: str,
**kwargs
) -> None:
"""Send a post request with header value "User-Agent": "overwrite".

:param user_agent: Send a post request with header value "User-Agent": "overwrite".
:type user_agent: str
:param user_agent_parameter: Send a post request with header value "User-Agent": "overwrite".
:type user_agent_parameter: str
:keyword callable cls: A custom type or function that will be passed the direct response
:return: None or the result of cls(response)
:rtype: None
Expand All @@ -67,7 +67,7 @@ async def param_existing_key(

# Construct headers
header_parameters = {} # type: Dict[str, Any]
header_parameters['User-Agent'] = self._serialize.header("user_agent", user_agent, 'str')
header_parameters['User-Agent'] = self._serialize.header("user_agent_parameter", user_agent_parameter, 'str')

# Construct and send request
request = self._client.post(url, query_parameters, header_parameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ def __init__(self, client, config, serializer, deserializer):
@distributed_trace
def param_existing_key(
self,
user_agent, # type: str
user_agent_parameter, # type: str
**kwargs # type: Any
):
# type: (...) -> None
"""Send a post request with header value "User-Agent": "overwrite".

:param user_agent: Send a post request with header value "User-Agent": "overwrite".
:type user_agent: str
:param user_agent_parameter: Send a post request with header value "User-Agent": "overwrite".
:type user_agent_parameter: str
:keyword callable cls: A custom type or function that will be passed the direct response
:return: None or the result of cls(response)
:rtype: None
Expand All @@ -68,7 +68,7 @@ def param_existing_key(

# Construct headers
header_parameters = {} # type: Dict[str, Any]
header_parameters['User-Agent'] = self._serialize.header("user_agent", user_agent, 'str')
header_parameters['User-Agent'] = self._serialize.header("user_agent_parameter", user_agent_parameter, 'str')

# Construct and send request
request = self._client.post(url, query_parameters, header_parameters)
Expand Down