diff --git a/sprockets/clients/dynamodb/__init__.py b/sprockets/clients/dynamodb/__init__.py index 30a10bd..c53b607 100644 --- a/sprockets/clients/dynamodb/__init__.py +++ b/sprockets/clients/dynamodb/__init__.py @@ -4,7 +4,7 @@ except ImportError as error: def DynamoDB(*args, **kwargs): raise error -version_info = (0, 2, 1) +version_info = (0, 2, 2) __version__ = '.'.join(str(v) for v in version_info) # Response constants diff --git a/sprockets/clients/dynamodb/connector.py b/sprockets/clients/dynamodb/connector.py index 5a0882b..d3acf8b 100644 --- a/sprockets/clients/dynamodb/connector.py +++ b/sprockets/clients/dynamodb/connector.py @@ -1,6 +1,7 @@ import json import logging import os +import socket from tornado import concurrent, httpclient, ioloop import tornado_aws @@ -9,6 +10,13 @@ from tornado_aws import exceptions as aws_exceptions from . import utils from . import exceptions +# Stub ConnectionError for Python 2.7 that doesn't support it +try: + ConnectionError +except NameError: + class ConnectionError(Exception): + pass + LOGGER = logging.getLogger(__name__) @@ -126,6 +134,8 @@ class DynamoDB(object): future.set_exception(exceptions.NoCredentialsError(str(error))) except aws_exceptions.NoProfileError as error: future.set_exception(exceptions.NoProfileError(str(error))) + except (socket.gaierror, ConnectionError) as req_err: + future.set_exception(exceptions.RequestException(req_err)) except httpclient.HTTPError as err: if err.code == 599: future.set_exception(exceptions.TimeoutException()) diff --git a/sprockets/clients/dynamodb/exceptions.py b/sprockets/clients/dynamodb/exceptions.py index 976cf3f..7b8c1bb 100644 --- a/sprockets/clients/dynamodb/exceptions.py +++ b/sprockets/clients/dynamodb/exceptions.py @@ -17,6 +17,14 @@ class DynamoDBException(Exception): super(DynamoDBException, self).__init__(*args, **kwargs) +class RequestException(DynamoDBException): + """Raised when the HTTP request failed due to a network or DNS related + issue. + + """ + pass + + class ConditionalCheckFailedException(DynamoDBException): """A condition specified in the operation could not be evaluated.""" pass diff --git a/tests/api_tests.py b/tests/api_tests.py index d585aa7..1a90c8f 100644 --- a/tests/api_tests.py +++ b/tests/api_tests.py @@ -1,6 +1,9 @@ import datetime import os +import socket +import sys import uuid +import unittest import mock @@ -10,7 +13,7 @@ from tornado import testing from tornado_aws import exceptions as aws_exceptions from sprockets.clients import dynamodb -from sprockets.clients.dynamodb import exceptions +from sprockets.clients.dynamodb import connector, exceptions class AsyncTestCase(testing.AsyncTestCase): @@ -103,6 +106,22 @@ class AWSClientTests(AsyncTestCase): with self.assertRaises(exceptions.DynamoDBException): yield self.client.create_table(self.generic_table_definition()) + @testing.gen_test + def test_gaierror_raises_request_exception(self): + with mock.patch('tornado_aws.client.AsyncAWSClient.fetch') as fetch: + fetch.side_effect = socket.gaierror + with self.assertRaises(exceptions.RequestException): + yield self.client.create_table(self.generic_table_definition()) + + @unittest.skipIf(sys.version_info.major < 3, + 'ConnectionError is Python3 only') + @testing.gen_test + def test_connection_error_request_exception(self): + with mock.patch('tornado_aws.client.AsyncAWSClient.fetch') as fetch: + fetch.side_effect = ConnectionError + with self.assertRaises(exceptions.RequestException): + yield self.client.create_table(self.generic_table_definition()) + class CreateTableTests(AsyncTestCase):