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

Python updates #1392

Merged
merged 20 commits into from
Sep 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 9 additions & 8 deletions src/client/Python/msrest/msrest/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
_LOGGER = logging.getLogger(__name__)


def raise_with_traceback(exception, message="", *args):
def raise_with_traceback(exception, message="", *args, **kwargs):
"""Raise exception with a specified traceback.

:param Exception exception: Error type to be raised.
Expand All @@ -42,7 +42,7 @@ def raise_with_traceback(exception, message="", *args):
"""
exc_type, exc_value, exc_traceback = sys.exc_info()
exc_msg = "{}, {}: {}".format(message, exc_type.__name__, exc_value)
error = exception(exc_msg, *args)
error = exception(exc_msg, *args, **kwargs)
try:
raise error.with_traceback(exc_traceback)
except AttributeError:
Expand All @@ -53,10 +53,10 @@ def raise_with_traceback(exception, message="", *args):
class ClientException(Exception):
"""Base exception for all Client Runtime exceptions."""

def __init__(self, message, inner_exception=None, *args):
def __init__(self, message, inner_exception=None, *args, **kwargs):
self.inner_exception = inner_exception
_LOGGER.debug(message)
super(ClientException, self).__init__(message, *args)
super(ClientException, self).__init__(message, *args, **kwargs)


class SerializationError(ClientException):
Expand Down Expand Up @@ -92,14 +92,14 @@ class ValidationError(ClientException):
"required": "can not be None."
}

def __init__(self, rule, target, value, *args):
def __init__(self, rule, target, value, *args, **kwargs):
self.rule = rule
self.target = target
message = "Parameter {!r} ".format(target)
reason = self.messages.get(
rule, "failed to meet validation requirement.")
message += reason.format(value)
super(ValidationError, self).__init__(message, *args)
super(ValidationError, self).__init__(message, *args, **kwargs)


class ClientRequestError(ClientException):
Expand All @@ -126,7 +126,8 @@ class HttpOperationError(ClientException):
def __str__(self):
return str(self.message)

def __init__(self, deserialize, response, resp_type=None, *args):
def __init__(self, deserialize, response,
resp_type=None, *args, **kwargs):
self.error = None
self.message = None
self.response = response
Expand Down Expand Up @@ -157,4 +158,4 @@ def __init__(self, deserialize, response, resp_type=None, *args):
self.message = "Unknown error"

super(HttpOperationError, self).__init__(
self.message, self.error, *args)
self.message, self.error, *args, **kwargs)
98 changes: 57 additions & 41 deletions src/client/Python/msrestazure/msrestazure/azure_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ class CloudError(ClientException):
:param str error: Optional error message.
"""

def __init__(self, response, error=None, *args):
deserialize = Deserializer()
def __init__(self, response, error=None, *args, **kwargs):
self.deserializer = Deserializer()
self.error = None
self.message = None
self.response = response
Expand All @@ -110,48 +110,64 @@ def __init__(self, response, error=None, *args):
self.message = error
self.error = response
else:
try:
data = response.json()
except ValueError:
data = response
else:
data = data.get('error', data)
try:
self.error = deserialize(CloudErrorData(), data)
except DeserializationError:
self.error = None
try:
self.message = self.error.message
except AttributeError:
self.message = None
self._build_error_data(response)

if not self.error or not self.message:
try:
content = response.json()
except ValueError:
server_message = "none"
else:
server_message = content.get('message', "none")
try:
response.raise_for_status()
except RequestException as err:
if not self.error:
self.error = err
if not self.message:
if server_message == "none":
server_message = str(err)
msg = "Operation failed with status: {!r}. Details: {}"
self.message = msg.format(response.reason, server_message)
else:
if not self.error:
self.error = response
if not self.message:
msg = "Operation failed with status: {!r}. Details: {}"
self.message = msg.format(
response.status_code, server_message)

super(CloudError, self).__init__(self.message, self.error, *args)
self._build_error_message(response)

super(CloudError, self).__init__(
self.message, self.error, *args, **kwargs)

def __str__(self):
"""Cloud error message"""
return str(self.message)

def _build_error_data(self, response):
try:
data = response.json()
except ValueError:
data = response
else:
data = data.get('error', data)
try:
self.error = self.deserializer(CloudErrorData(), data)
except DeserializationError:
self.error = None
else:
if self.error:
if not self.error.error or not self.error.message:
self.error = None
else:
self.message = self.error.message

def _get_state(self, content):
state = content.get("status")
if not state:
resource_content = content.get('properties', content)
state = resource_content.get("provisioningState")
return "Resource state {}".format(state) if state else "none"

def _build_error_message(self, response):
try:
data = response.json()
except ValueError:
message = "none"
else:
message = data.get("message", self._get_state(data))
try:
response.raise_for_status()
except RequestException as err:
if not self.error:
self.error = err
if not self.message:
if message == "none":
message = str(err)
msg = "Operation failed with status: {!r}. Details: {}"
self.message = msg.format(response.reason, message)
else:
if not self.error:
self.error = response
if not self.message:
msg = "Operation failed with status: {!r}. Details: {}"
self.message = msg.format(
response.status_code, message)
4 changes: 1 addition & 3 deletions src/client/Python/msrestazure/msrestazure/azure_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,7 @@ def _start(self, send_cmd, update_cmd, output_cmd):
self._exception = CloudError(self._response, str(err))

except OperationFailed:
error = "Long running operation failed with status {!r}".format(
str(self._operation.status))
self._exception = CloudError(self._response, error)
self._exception = CloudError(self._response)

except OperationFinished:
pass
Expand Down
7 changes: 3 additions & 4 deletions src/client/Python/msrestazure/test/unittest_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,17 @@ def test_cloud_error(self):

response.content = "{"
error = CloudError(response)
self.assertEqual(error.message, "Operation failed with status: 400. Details: none")
self.assertTrue("none" in error.message)

response.content = json.dumps({'message':'server error'})
error = CloudError(response)
self.assertEqual(error.message, "server error")
self.assertTrue("server error" in error.message)
self.assertEqual(error.status_code, 400)

response.content = "{"
response.raise_for_status.side_effect = RequestException("FAILED!")
error = CloudError(response)
self.assertEqual(error.message,
"Operation failed with status: 'BadRequest'. Details: FAILED!")
self.assertTrue("FAILED!" in error.message)
self.assertIsInstance(error.error, RequestException)

response.content = '{\r\n "odata.metadata":"https://account.region.batch.azure.com/$metadata#Microsoft.Azure.Batch.Protocol.Entities.Container.errors/@Element","code":"InvalidHeaderValue","message":{\r\n "lang":"en-US","value":"The value for one of the HTTP headers is not in the correct format.\\nRequestId:5f4c1f05-603a-4495-8e80-01f776310bbd\\nTime:2016-01-04T22:12:33.9245931Z"\r\n },"values":[\r\n {\r\n "key":"HeaderName","value":"Content-Type"\r\n },{\r\n "key":"HeaderValue","value":"application/json; odata=minimalmetadata; charset=utf-8"\r\n }\r\n ]\r\n}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ def setUp(self):
return super(LroTests, self).setUp()

def assertRaisesWithMessage(self, msg, func, *args, **kwargs):

try:
func(*args, **kwargs)
self.fail("CloudError wasn't raised as expected")
Expand All @@ -75,7 +74,6 @@ def assertRaisesWithMessage(self, msg, func, *args, **kwargs):
error = err.error
self.assertIsNotNone(error)
if isinstance(error, CloudErrorData):
self.assertIsNone(error.error)
self.assertIsNotNone(error.message)

def test_lro_happy_paths(self):
Expand All @@ -85,13 +83,13 @@ def test_lro_happy_paths(self):
process = self.client.lr_os.put201_creating_succeeded200(product)
self.assertEqual("Succeeded", process.result().provisioning_state)

self.assertRaisesWithMessage("Long running operation failed",
self.assertRaisesWithMessage("Operation failed with status: 200. Details: Resource state Failed",
self.client.lr_os.put201_creating_failed200(product).result)

process = self.client.lr_os.put200_updating_succeeded204(product)
self.assertEqual("Succeeded", process.result().provisioning_state)

self.assertRaisesWithMessage("Long running operation failed",
self.assertRaisesWithMessage("Operation failed with status: 200. Details: Resource state Canceled",
self.client.lr_os.put200_acceptedcanceled200(product).result)

# Testing raw
Expand Down Expand Up @@ -143,10 +141,10 @@ def test_lro_happy_paths(self):
process = self.client.lr_os.put_async_no_retry_succeeded(product)
self.assertEqual("Succeeded", process.result().provisioning_state)

self.assertRaisesWithMessage("Long running operation failed",
self.assertRaisesWithMessage("Operation failed with status: 200. Details: Resource state Failed",
self.client.lr_os.put_async_retry_failed(product).result)

self.assertRaisesWithMessage("Long running operation failed",
self.assertRaisesWithMessage("Operation failed with status: 200. Details: Resource state Canceled",
self.client.lr_os.put_async_no_retrycanceled(product).result)

self.assertIsNone(self.client.lr_os.delete204_succeeded().result())
Expand All @@ -158,10 +156,10 @@ def test_lro_happy_paths(self):

self.assertIsNone(self.client.lr_os.delete_async_no_header_in_retry().result())

self.assertRaisesWithMessage("Long running operation failed",
self.assertRaisesWithMessage("Operation failed with status: 200. Details: Resource state Canceled",
self.client.lr_os.delete_async_retrycanceled().result)

self.assertRaisesWithMessage("Long running operation failed",
self.assertRaisesWithMessage("Operation failed with status: 200. Details: Resource state Failed",
self.client.lr_os.delete_async_retry_failed().result)

self.assertIsNone(self.client.lr_os.delete_async_retry_succeeded().result())
Expand All @@ -177,10 +175,10 @@ def test_lro_happy_paths(self):

self.assertIsNone(self.client.lr_os.post202_no_retry204(product).result())

self.assertRaisesWithMessage("Long running operation failed with status 'Failed'",
self.assertRaisesWithMessage("Internal Server Error",
self.client.lr_os.post_async_retry_failed().result)

self.assertRaisesWithMessage("Long running operation failed with status 'Canceled'",
self.assertRaisesWithMessage("Operation failed with status: 200. Details: Resource state Canceled",
self.client.lr_os.post_async_retrycanceled().result)

prod = self.client.lr_os.post_async_retry_succeeded().result()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def post_required(
parameters for the operation
:type parameter_grouping_post_required_parameters:
:class:`ParameterGroupingPostRequiredParameters
<fixtures.acceptancetestsazureparametergrouping.models.ParameterGroupingPostRequiredParameters>`
<Fixtures.AcceptanceTestsAzureParameterGrouping.models.ParameterGroupingPostRequiredParameters>`
:param dict custom_headers: headers that will be added to the request
:param bool raw: returns the direct response alongside the
deserialized response
Expand Down Expand Up @@ -110,7 +110,7 @@ def post_optional(
parameters for the operation
:type parameter_grouping_post_optional_parameters:
:class:`ParameterGroupingPostOptionalParameters
<fixtures.acceptancetestsazureparametergrouping.models.ParameterGroupingPostOptionalParameters>`
<Fixtures.AcceptanceTestsAzureParameterGrouping.models.ParameterGroupingPostOptionalParameters>`
:param dict custom_headers: headers that will be added to the request
:param bool raw: returns the direct response alongside the
deserialized response
Expand Down Expand Up @@ -164,12 +164,12 @@ def post_multi_param_groups(

:param first_parameter_group: Additional parameters for the operation
:type first_parameter_group: :class:`FirstParameterGroup
<fixtures.acceptancetestsazureparametergrouping.models.FirstParameterGroup>`
<Fixtures.AcceptanceTestsAzureParameterGrouping.models.FirstParameterGroup>`
:param parameter_grouping_post_multi_param_groups_second_param_group:
Additional parameters for the operation
:type parameter_grouping_post_multi_param_groups_second_param_group:
:class:`ParameterGroupingPostMultiParamGroupsSecondParamGroup
<fixtures.acceptancetestsazureparametergrouping.models.ParameterGroupingPostMultiParamGroupsSecondParamGroup>`
<Fixtures.AcceptanceTestsAzureParameterGrouping.models.ParameterGroupingPostMultiParamGroupsSecondParamGroup>`
:param dict custom_headers: headers that will be added to the request
:param bool raw: returns the direct response alongside the
deserialized response
Expand Down Expand Up @@ -233,7 +233,7 @@ def post_shared_parameter_group_object(

:param first_parameter_group: Additional parameters for the operation
:type first_parameter_group: :class:`FirstParameterGroup
<fixtures.acceptancetestsazureparametergrouping.models.FirstParameterGroup>`
<Fixtures.AcceptanceTestsAzureParameterGrouping.models.FirstParameterGroup>`
:param dict custom_headers: headers that will be added to the request
:param bool raw: returns the direct response alongside the
deserialized response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def put_array(

:param resource_array: External Resource as an Array to put
:type resource_array: list of :class:`Resource
<fixtures.acceptancetestsazureresource.models.Resource>`
<Fixtures.AcceptanceTestsAzureResource.models.Resource>`
:param dict custom_headers: headers that will be added to the request
:param bool raw: returns the direct response alongside the
deserialized response
Expand Down Expand Up @@ -155,7 +155,7 @@ def get_array(
:param operation_config: :ref:`Operation configuration
overrides<msrest:optionsforoperations>`.
:rtype: list of :class:`FlattenedProduct
<fixtures.acceptancetestsazureresource.models.FlattenedProduct>`
<Fixtures.AcceptanceTestsAzureResource.models.FlattenedProduct>`
:rtype: :class:`ClientRawResponse<msrest.pipeline.ClientRawResponse>`
if raw=true
"""
Expand Down Expand Up @@ -296,7 +296,7 @@ def put_resource_collection(
:param resource_complex_object: External Resource as a
ResourceCollection to put
:type resource_complex_object: :class:`ResourceCollection
<fixtures.acceptancetestsazureresource.models.ResourceCollection>`
<Fixtures.AcceptanceTestsAzureResource.models.ResourceCollection>`
:param dict custom_headers: headers that will be added to the request
:param bool raw: returns the direct response alongside the
deserialized response
Expand Down Expand Up @@ -350,7 +350,7 @@ def get_resource_collection(
:param operation_config: :ref:`Operation configuration
overrides<msrest:optionsforoperations>`.
:rtype: :class:`ResourceCollection
<fixtures.acceptancetestsazureresource.models.ResourceCollection>`
<Fixtures.AcceptanceTestsAzureResource.models.ResourceCollection>`
:rtype: :class:`ClientRawResponse<msrest.pipeline.ClientRawResponse>`
if raw=true
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ class ResourceCollection(Model):

:param productresource:
:type productresource: :class:`FlattenedProduct
<fixtures.acceptancetestsazureresource.models.FlattenedProduct>`
<Fixtures.AcceptanceTestsAzureResource.models.FlattenedProduct>`
:param arrayofresources:
:type arrayofresources: list of :class:`FlattenedProduct
<fixtures.acceptancetestsazureresource.models.FlattenedProduct>`
<Fixtures.AcceptanceTestsAzureResource.models.FlattenedProduct>`
:param dictionaryofresources:
:type dictionaryofresources: dict
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def custom_named_request_id_param_grouping(
Additional parameters for the operation
:type header_custom_named_request_id_param_grouping_parameters:
:class:`HeaderCustomNamedRequestIdParamGroupingParameters
<fixtures.acceptancetestsazurespecials.models.HeaderCustomNamedRequestIdParamGroupingParameters>`
<Fixtures.AcceptanceTestsAzureSpecials.models.HeaderCustomNamedRequestIdParamGroupingParameters>`
:param dict custom_headers: headers that will be added to the request
:param bool raw: returns the direct response alongside the
deserialized response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class OperationResult(Model):
:type status: str
:param error:
:type error: :class:`OperationResultError
<fixtures.acceptancetestslro.models.OperationResultError>`
<Fixtures.AcceptanceTestsLro.models.OperationResultError>`
"""

_attribute_map = {
Expand Down
Loading