Repository: boto/botocore
Pull request #1118 (2017-01-03 20:35:39)

Test multi config loading
Added a test for some uncovered paths.

cc @dstufft @kyleknap @JordonPhillips @jamesls  


Patch:
diff --git a/.changes/1.4.93.json b/.changes/1.4.93.json
new file mode 100644
index 000000000..6a2326963
--- /dev/null
+++ b/.changes/1.4.93.json
@@ -0,0 +1,42 @@
+[
+  {
+    "category": "``rds``", 
+    "description": "Update rds client to latest version", 
+    "type": "feature"
+  }, 
+  {
+    "category": "``marketplacecommerceanalytics``", 
+    "description": "Update marketplacecommerceanalytics client to latest version", 
+    "type": "feature"
+  }, 
+  {
+    "category": "``config``", 
+    "description": "Update config client to latest version", 
+    "type": "feature"
+  }, 
+  {
+    "category": "``iam``", 
+    "description": "Update iam client to latest version", 
+    "type": "feature"
+  }, 
+  {
+    "category": "``lambda``", 
+    "description": "Update lambda client to latest version", 
+    "type": "feature"
+  }, 
+  {
+    "category": "``dynamodbstreams``", 
+    "description": "Update dynamodbstreams client to latest version", 
+    "type": "feature"
+  }, 
+  {
+    "category": "``efs``", 
+    "description": "Update efs client to latest version", 
+    "type": "feature"
+  }, 
+  {
+    "category": "``rekognition``", 
+    "description": "Update rekognition client to latest version", 
+    "type": "feature"
+  }
+]
\ No newline at end of file
diff --git a/.changes/next-release/feature-Exceptions-61268.json b/.changes/next-release/feature-Exceptions-61268.json
new file mode 100644
index 000000000..4fd8c1a55
--- /dev/null
+++ b/.changes/next-release/feature-Exceptions-61268.json
@@ -0,0 +1,5 @@
+{
+  "category": "Exceptions",
+  "description": "Add modeled exceptions on client via ``Client.exceptions`` property",
+  "type": "feature"
+}
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 3fd3ddd78..83d70f4ec 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,19 @@
 CHANGELOG
 =========
 
+1.4.93
+======
+
+* feature:``rds``: Update rds client to latest version
+* feature:``marketplacecommerceanalytics``: Update marketplacecommerceanalytics client to latest version
+* feature:``config``: Update config client to latest version
+* feature:``iam``: Update iam client to latest version
+* feature:``lambda``: Update lambda client to latest version
+* feature:``dynamodbstreams``: Update dynamodbstreams client to latest version
+* feature:``efs``: Update efs client to latest version
+* feature:``rekognition``: Update rekognition client to latest version
+
+
 1.4.92
 ======
 
diff --git a/LICENSE.txt b/LICENSE.txt
index ab7da4797..4c00dd563 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 
 Licensed under the Apache License, Version 2.0 (the "License"). You
 may not use this file except in compliance with the License. A copy of
diff --git a/botocore/__init__.py b/botocore/__init__.py
index 740faa9ec..89fe2677a 100644
--- a/botocore/__init__.py
+++ b/botocore/__init__.py
@@ -16,7 +16,7 @@ import os
 import re
 import logging
 
-__version__ = '1.4.92'
+__version__ = '1.4.93'
 
 
 class NullHandler(logging.Handler):
diff --git a/botocore/args.py b/botocore/args.py
index da6383f6a..54f4290f1 100644
--- a/botocore/args.py
+++ b/botocore/args.py
@@ -30,11 +30,12 @@ logger = logging.getLogger(__name__)
 
 class ClientArgsCreator(object):
     def __init__(self, event_emitter, user_agent, response_parser_factory,
-                 loader):
+                 loader, exceptions_factory):
         self._event_emitter = event_emitter
         self._user_agent = user_agent
         self._response_parser_factory = response_parser_factory
         self._loader = loader
+        self._exceptions_factory = exceptions_factory
 
     def get_client_args(self, service_model, region_name, is_secure,
                         endpoint_url, verify, credentials, scoped_config,
@@ -81,7 +82,8 @@ class ClientArgsCreator(object):
             'service_model': service_model,
             'loader': self._loader,
             'client_config': new_config,
-            'partition': partition
+            'partition': partition,
+            'exceptions_factory': self._exceptions_factory
         }
 
     def compute_client_args(self, service_model, client_config,
diff --git a/botocore/client.py b/botocore/client.py
index 33de501e6..592ef177d 100644
--- a/botocore/client.py
+++ b/botocore/client.py
@@ -45,7 +45,7 @@ class ClientCreator(object):
     """Creates client objects for a service."""
     def __init__(self, loader, endpoint_resolver, user_agent, event_emitter,
                  retry_handler_factory, retry_config_translator,
-                 response_parser_factory=None):
+                 response_parser_factory=None, exceptions_factory=None):
         self._loader = loader
         self._endpoint_resolver = endpoint_resolver
         self._user_agent = user_agent
@@ -53,6 +53,7 @@ class ClientCreator(object):
         self._retry_handler_factory = retry_handler_factory
         self._retry_config_translator = retry_config_translator
         self._response_parser_factory = response_parser_factory
+        self._exceptions_factory = exceptions_factory
 
     def create_client(self, service_name, region_name, is_secure=True,
                       endpoint_url=None, verify=None,
@@ -216,7 +217,8 @@ class ClientCreator(object):
                          scoped_config, client_config, endpoint_bridge):
         args_creator = ClientArgsCreator(
             self._event_emitter, self._user_agent,
-            self._response_parser_factory, self._loader)
+            self._response_parser_factory, self._loader,
+            self._exceptions_factory)
         return args_creator.get_client_args(
             service_model, region_name, is_secure, endpoint_url,
             verify, credentials, scoped_config, client_config, endpoint_bridge)
@@ -479,7 +481,7 @@ class BaseClient(object):
 
     def __init__(self, serializer, endpoint, response_parser,
                  event_emitter, request_signer, service_model, loader,
-                 client_config, partition):
+                 client_config, partition, exceptions_factory):
         self._serializer = serializer
         self._endpoint = endpoint
         self._response_parser = response_parser
@@ -490,6 +492,8 @@ class BaseClient(object):
         self.meta = ClientMeta(event_emitter, self._client_config,
                                endpoint.host, service_model,
                                self._PY_TO_OP_NAME, partition)
+        self._exceptions_factory = exceptions_factory
+        self._exceptions = None
         self._register_handlers()
 
     def _register_handlers(self):
@@ -534,7 +538,9 @@ class BaseClient(object):
         )
 
         if http.status_code >= 300:
-            raise ClientError(parsed_response, operation_name)
+            error_code = parsed_response.get("Error", {}).get("Code")
+            error_class = self.exceptions.from_code(error_code)
+            raise error_class(parsed_response, operation_name)
         else:
             return parsed_response
 
@@ -688,6 +694,16 @@ class BaseClient(object):
         # which are the keys in the dict.
         return [xform_name(name) for name in model.waiter_names]
 
+    @property
+    def exceptions(self):
+        if self._exceptions is None:
+            self._exceptions = self._load_exceptions()
+        return self._exceptions
+
+    def _load_exceptions(self):
+        return self._exceptions_factory.create_client_exceptions(
+            self._service_model)
+
 
 class ClientMeta(object):
     """Holds additional client methods.
diff --git a/botocore/data/config/2014-11-12/service-2.json b/botocore/data/config/2014-11-12/service-2.json
index 91ae8c1b7..61cd83f20 100755
--- a/botocore/data/config/2014-11-12/service-2.json
+++ b/botocore/data/config/2014-11-12/service-2.json
@@ -775,7 +775,7 @@
           "documentation":"<p>Configuration attributes that AWS Config returns for certain resource types to supplement the information returned for the <code>configuration</code> parameter.</p>"
         }
       },
-      "documentation":"<p>A list that contains detailed configurations of a specified resource.</p> <note> <p>Currently, the list does not contain information about non-AWS components (for example, applications on your Amazon EC2 instances).</p> </note>"
+      "documentation":"<p>A list that contains detailed configurations of a specified resource.</p>"
     },
     "ConfigurationItemCaptureTime":{"type":"timestamp"},
     "ConfigurationItemList":{
@@ -1677,7 +1677,8 @@
       "enum":[
         "ConfigurationItemChangeNotification",
         "ConfigurationSnapshotDeliveryCompleted",
-        "ScheduledNotification"
+        "ScheduledNotification",
+        "OversizedConfigurationItemChangeNotification"
       ]
     },
     "Name":{"type":"string"},
@@ -2018,7 +2019,7 @@
         },
         "MessageType":{
           "shape":"MessageType",
-          "documentation":"<p>The type of notification that triggers AWS Config to run an evaluation. You can specify the following notification types:</p> <p> <code>ConfigurationItemChangeNotification</code> - Triggers an evaluation when AWS Config delivers a configuration item change notification.</p> <p> <code>ScheduledNotification</code> - Triggers a periodic evaluation at the frequency specified for <code>MaximumExecutionFrequency</code>.</p> <p> <code>ConfigurationSnapshotDeliveryCompleted</code> - Triggers a periodic evaluation when AWS Config delivers a configuration snapshot.</p>"
+          "documentation":"<p>The type of notification that triggers AWS Config to run an evaluation for a rule. You can specify the following notification types:</p> <ul> <li> <p> <code>ConfigurationItemChangeNotification</code> - Triggers an evaluation when AWS Config delivers a configuration item as a result of a resource change.</p> </li> <li> <p> <code>OversizedConfigurationItemChangeNotification</code> - Triggers an evaluation when AWS Config delivers an oversized configuration item. AWS Config may generate this notification type when a resource changes and the notification exceeds the maximum size allowed by Amazon SNS.</p> </li> <li> <p> <code>ScheduledNotification</code> - Triggers a periodic evaluation at the frequency specified for <code>MaximumExecutionFrequency</code>.</p> </li> <li> <p> <code>ConfigurationSnapshotDeliveryCompleted</code> - Triggers a periodic evaluation when AWS Config delivers a configuration snapshot.</p> </li> </ul> <p>If you want your custom rule to be triggered by configuration changes, specify both <code>ConfigurationItemChangeNotification</code> and <code>OversizedConfigurationItemChangeNotification</code>. </p>"
         },
         "MaximumExecutionFrequency":{
           "shape":"MaximumExecutionFrequency",
diff --git a/botocore/data/dynamodbstreams/2012-08-10/service-2.json b/botocore/data/dynamodbstreams/2012-08-10/service-2.json
index 6d7a1dc98..dd99b801c 100644
--- a/botocore/data/dynamodbstreams/2012-08-10/service-2.json
+++ b/botocore/data/dynamodbstreams/2012-08-10/service-2.json
@@ -1,7 +1,6 @@
 {
   "version":"2.0",
   "metadata":{
-    "uid":"streams-dynamodb-2012-08-10",
     "apiVersion":"2012-08-10",
     "endpointPrefix":"streams.dynamodb",
     "jsonVersion":"1.0",
@@ -9,7 +8,8 @@
     "serviceFullName":"Amazon DynamoDB Streams",
     "signatureVersion":"v4",
     "signingName":"dynamodb",
-    "targetPrefix":"DynamoDBStreams_20120810"
+    "targetPrefix":"DynamoDBStreams_20120810",
+    "uid":"streams-dynamodb-2012-08-10"
   },
   "operations":{
     "DescribeStream":{
diff --git a/botocore/data/efs/2015-02-01/service-2.json b/botocore/data/efs/2015-02-01/service-2.json
index ebc68fa99..6b13e1ba7 100644
--- a/botocore/data/efs/2015-02-01/service-2.json
+++ b/botocore/data/efs/2015-02-01/service-2.json
@@ -1,13 +1,13 @@
 {
   "version":"2.0",
   "metadata":{
-    "uid":"elasticfilesystem-2015-02-01",
     "apiVersion":"2015-02-01",
     "endpointPrefix":"elasticfilesystem",
     "protocol":"rest-json",
     "serviceAbbreviation":"EFS",
     "serviceFullName":"Amazon Elastic File System",
-    "signatureVersion":"v4"
+    "signatureVersion":"v4",
+    "uid":"elasticfilesystem-2015-02-01"
   },
   "operations":{
     "CreateFileSystem":{
@@ -50,7 +50,7 @@
         {"shape":"SecurityGroupNotFound"},
         {"shape":"UnsupportedAvailabilityZone"}
       ],
-      "documentation":"<p>Creates a mount target for a file system. You can then mount the file system on EC2 instances via the mount target.</p> <p>You can create one mount target in each Availability Zone in your VPC. All EC2 instances in a VPC within a given Availability Zone share a single mount target for a given file system. If you have multiple subnets in an Availability Zone, you create a mount target in one of the subnets. EC2 instances do not need to be in the same subnet as the mount target in order to access their file system. For more information, see <a href=\"http://docs.aws.amazon.com/efs/latest/ug/how-it-works.html\">Amazon EFS: How it Works</a>. </p> <p>In the request, you also specify a file system ID for which you are creating the mount target and the file system's lifecycle state must be <code>available</code>. For more information, see <a>DescribeFileSystems</a>.</p> <p>In the request, you also provide a subnet ID, which determines the following:</p> <ul> <li> <p>VPC in which Amazon EFS creates the mount target</p> </li> <li> <p>Availability Zone in which Amazon EFS creates the mount target</p> </li> <li> <p>IP address range from which Amazon EFS selects the IP address of the mount target (if you don't specify an IP address in the request)</p> </li> </ul> <p>After creating the mount target, Amazon EFS returns a response that includes, a <code>MountTargetId</code> and an <code>IpAddress</code>. You use this IP address when mounting the file system in an EC2 instance. You can also use the mount target's DNS name when mounting the file system. The EC2 instance on which you mount the file system via the mount target can resolve the mount target's DNS name to its IP address. For more information, see <a href=\"http://docs.aws.amazon.com/efs/latest/ug/how-it-works.html#how-it-works-implementation\">How it Works: Implementation Overview</a>. </p> <p>Note that you can create mount targets for a file system in only one VPC, and there can be only one mount target per Availability Zone. That is, if the file system already has one or more mount targets created for it, the subnet specified in the request to add another mount target must meet the following requirements:</p> <ul> <li> <p>Must belong to the same VPC as the subnets of the existing mount targets</p> </li> <li> <p>Must not be in the same Availability Zone as any of the subnets of the existing mount targets</p> </li> </ul> <p>If the request satisfies the requirements, Amazon EFS does the following:</p> <ul> <li> <p>Creates a new mount target in the specified subnet.</p> </li> <li> <p>Also creates a new network interface in the subnet as follows:</p> <ul> <li> <p>If the request provides an <code>IpAddress</code>, Amazon EFS assigns that IP address to the network interface. Otherwise, Amazon EFS assigns a free address in the subnet (in the same way that the Amazon EC2 <code>CreateNetworkInterface</code> call does when a request does not specify a primary private IP address).</p> </li> <li> <p>If the request provides <code>SecurityGroups</code>, this network interface is associated with those security groups. Otherwise, it belongs to the default security group for the subnet's VPC.</p> </li> <li> <p>Assigns the description <code>Mount target <i>fsmt-id</i> for file system <i>fs-id</i> </code> where <code> <i>fsmt-id</i> </code> is the mount target ID, and <code> <i>fs-id</i> </code> is the <code>FileSystemId</code>.</p> </li> <li> <p>Sets the <code>requesterManaged</code> property of the network interface to <code>true</code>, and the <code>requesterId</code> value to <code>EFS</code>.</p> </li> </ul> <p>Each Amazon EFS mount target has one corresponding requestor-managed EC2 network interface. After the network interface is created, Amazon EFS sets the <code>NetworkInterfaceId</code> field in the mount target's description to the network interface ID, and the <code>IpAddress</code> field to its address. If network interface creation fails, the entire <code>CreateMountTarget</code> operation fails.</p> </li> </ul> <note> <p>The <code>CreateMountTarget</code> call returns only after creating the network interface, but while the mount target state is still <code>creating</code>. You can check the mount target creation status by calling the <a>DescribeFileSystems</a> operation, which among other things returns the mount target state.</p> </note> <p>We recommend you create a mount target in each of the Availability Zones. There are cost considerations for using a file system in an Availability Zone through a mount target created in another Availability Zone. For more information, see <a href=\"http://aws.amazon.com/efs/\">Amazon EFS</a>. In addition, by always using a mount target local to the instance's Availability Zone, you eliminate a partial failure scenario. If the Availability Zone in which your mount target is created goes down, then you won't be able to access your file system through that mount target. </p> <p>This operation requires permissions for the following action on the file system:</p> <ul> <li> <p> <code>elasticfilesystem:CreateMountTarget</code> </p> </li> </ul> <p>This operation also requires permissions for the following Amazon EC2 actions:</p> <ul> <li> <p> <code>ec2:DescribeSubnets</code> </p> </li> <li> <p> <code>ec2:DescribeNetworkInterfaces</code> </p> </li> <li> <p> <code>ec2:CreateNetworkInterface</code> </p> </li> </ul>"
+      "documentation":"<p>Creates a mount target for a file system. You can then mount the file system on EC2 instances via the mount target.</p> <p>You can create one mount target in each Availability Zone in your VPC. All EC2 instances in a VPC within a given Availability Zone share a single mount target for a given file system. If you have multiple subnets in an Availability Zone, you create a mount target in one of the subnets. EC2 instances do not need to be in the same subnet as the mount target in order to access their file system. For more information, see <a href=\"http://docs.aws.amazon.com/efs/latest/ug/how-it-works.html\">Amazon EFS: How it Works</a>. </p> <p>In the request, you also specify a file system ID for which you are creating the mount target and the file system's lifecycle state must be <code>available</code>. For more information, see <a>DescribeFileSystems</a>.</p> <p>In the request, you also provide a subnet ID, which determines the following:</p> <ul> <li> <p>VPC in which Amazon EFS creates the mount target</p> </li> <li> <p>Availability Zone in which Amazon EFS creates the mount target</p> </li> <li> <p>IP address range from which Amazon EFS selects the IP address of the mount target (if you don't specify an IP address in the request)</p> </li> </ul> <p>After creating the mount target, Amazon EFS returns a response that includes, a <code>MountTargetId</code> and an <code>IpAddress</code>. You use this IP address when mounting the file system in an EC2 instance. You can also use the mount target's DNS name when mounting the file system. The EC2 instance on which you mount the file system via the mount target can resolve the mount target's DNS name to its IP address. For more information, see <a href=\"http://docs.aws.amazon.com/efs/latest/ug/how-it-works.html#how-it-works-implementation\">How it Works: Implementation Overview</a>. </p> <p>Note that you can create mount targets for a file system in only one VPC, and there can be only one mount target per Availability Zone. That is, if the file system already has one or more mount targets created for it, the subnet specified in the request to add another mount target must meet the following requirements:</p> <ul> <li> <p>Must belong to the same VPC as the subnets of the existing mount targets</p> </li> <li> <p>Must not be in the same Availability Zone as any of the subnets of the existing mount targets</p> </li> </ul> <p>If the request satisfies the requirements, Amazon EFS does the following:</p> <ul> <li> <p>Creates a new mount target in the specified subnet.</p> </li> <li> <p>Also creates a new network interface in the subnet as follows:</p> <ul> <li> <p>If the request provides an <code>IpAddress</code>, Amazon EFS assigns that IP address to the network interface. Otherwise, Amazon EFS assigns a free address in the subnet (in the same way that the Amazon EC2 <code>CreateNetworkInterface</code> call does when a request does not specify a primary private IP address).</p> </li> <li> <p>If the request provides <code>SecurityGroups</code>, this network interface is associated with those security groups. Otherwise, it belongs to the default security group for the subnet's VPC.</p> </li> <li> <p>Assigns the description <code>Mount target <i>fsmt-id</i> for file system <i>fs-id</i> </code> where <code> <i>fsmt-id</i> </code> is the mount target ID, and <code> <i>fs-id</i> </code> is the <code>FileSystemId</code>.</p> </li> <li> <p>Sets the <code>requesterManaged</code> property of the network interface to <code>true</code>, and the <code>requesterId</code> value to <code>EFS</code>.</p> </li> </ul> <p>Each Amazon EFS mount target has one corresponding requester-managed EC2 network interface. After the network interface is created, Amazon EFS sets the <code>NetworkInterfaceId</code> field in the mount target's description to the network interface ID, and the <code>IpAddress</code> field to its address. If network interface creation fails, the entire <code>CreateMountTarget</code> operation fails.</p> </li> </ul> <note> <p>The <code>CreateMountTarget</code> call returns only after creating the network interface, but while the mount target state is still <code>creating</code>, you can check the mount target creation status by calling the <a>DescribeMountTargets</a> operation, which among other things returns the mount target state.</p> </note> <p>We recommend you create a mount target in each of the Availability Zones. There are cost considerations for using a file system in an Availability Zone through a mount target created in another Availability Zone. For more information, see <a href=\"http://aws.amazon.com/efs/\">Amazon EFS</a>. In addition, by always using a mount target local to the instance's Availability Zone, you eliminate a partial failure scenario. If the Availability Zone in which your mount target is created goes down, then you won't be able to access your file system through that mount target. </p> <p>This operation requires permissions for the following action on the file system:</p> <ul> <li> <p> <code>elasticfilesystem:CreateMountTarget</code> </p> </li> </ul> <p>This operation also requires permissions for the following Amazon EC2 actions:</p> <ul> <li> <p> <code>ec2:DescribeSubnets</code> </p> </li> <li> <p> <code>ec2:DescribeNetworkInterfaces</code> </p> </li> <li> <p> <code>ec2:CreateNetworkInterface</code> </p> </li> </ul>"
     },
     "CreateTags":{
       "name":"CreateTags",
@@ -885,6 +885,7 @@
         "ErrorCode":{"shape":"ErrorCode"},
         "Message":{"shape":"ErrorMessage"}
       },
+      "documentation":"<p></p>",
       "error":{"httpStatusCode":400},
       "exception":true
     }
diff --git a/botocore/data/iam/2010-05-08/service-2.json b/botocore/data/iam/2010-05-08/service-2.json
index a591fb67b..c8e508d98 100644
--- a/botocore/data/iam/2010-05-08/service-2.json
+++ b/botocore/data/iam/2010-05-08/service-2.json
@@ -2136,7 +2136,7 @@
         },
         "NewPassword":{
           "shape":"passwordType",
-          "documentation":"<p>The new password. The new password must conform to the AWS account's password policy, if one exists.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of almost any printable ASCII character from the space (\\u0020) through the end of the ASCII character range (\\u00FF). You can also include the tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D) characters. Although any of these characters are valid in a password, note that many tools, such as the AWS Management Console, might restrict the ability to enter certain characters because they have special meaning within that tool.</p>"
+          "documentation":"<p>The new password. The new password must conform to the AWS account's password policy, if one exists.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of almost any printable ASCII character from the space (\\u0020) through the end of the ASCII character range (\\u00FF). You can also include the tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D) characters. Although any of these characters are valid in a password, note that many tools, such as the AWS Management Console, might restrict the ability to enter certain characters because they have special meaning within that tool.</p>"
         }
       }
     },
@@ -2287,7 +2287,7 @@
         },
         "Password":{
           "shape":"passwordType",
-          "documentation":"<p>The new password for the user.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of almost any printable ASCII character from the space (\\u0020) through the end of the ASCII character range (\\u00FF). You can also include the tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D) characters. Although any of these characters are valid in a password, note that many tools, such as the AWS Management Console, might restrict the ability to enter certain characters because they have special meaning within that tool.</p>"
+          "documentation":"<p>The new password for the user.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of almost any printable ASCII character from the space (\\u0020) through the end of the ASCII character range (\\u00FF). You can also include the tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D) characters. Although any of these characters are valid in a password, note that many tools, such as the AWS Management Console, might restrict the ability to enter certain characters because they have special meaning within that tool.</p>"
         },
         "PasswordResetRequired":{
           "shape":"booleanType",
@@ -2354,7 +2354,7 @@
         },
         "PolicyDocument":{
           "shape":"policyDocumentType",
-          "documentation":"<p>The JSON policy document that you want to use as the content for the new policy.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The JSON policy document that you want to use as the content for the new policy.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         },
         "Description":{
           "shape":"policyDescriptionType",
@@ -2385,7 +2385,7 @@
         },
         "PolicyDocument":{
           "shape":"policyDocumentType",
-          "documentation":"<p>The JSON policy document that you want to use as the content for this new version of the policy.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The JSON policy document that you want to use as the content for this new version of the policy.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         },
         "SetAsDefault":{
           "shape":"booleanType",
@@ -2420,7 +2420,7 @@
         },
         "AssumeRolePolicyDocument":{
           "shape":"policyDocumentType",
-          "documentation":"<p>The trust relationship policy document that grants an entity permission to assume the role.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The trust relationship policy document that grants an entity permission to assume the role.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -3147,7 +3147,7 @@
       "members":{
         "PolicyInputList":{
           "shape":"SimulationPolicyListType",
-          "documentation":"<p>A list of policies for which you want the list of context keys referenced in those policies. Each document is specified as a string containing the complete, valid JSON text of an IAM policy.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>A list of policies for which you want the list of context keys referenced in those policies. Each document is specified as a string containing the complete, valid JSON text of an IAM policy.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -3171,7 +3171,7 @@
         },
         "PolicyInputList":{
           "shape":"SimulationPolicyListType",
-          "documentation":"<p>An optional list of additional policies for which you want the list of context keys that are referenced.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>An optional list of additional policies for which you want the list of context keys that are referenced.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -5083,7 +5083,7 @@
         },
         "PolicyDocument":{
           "shape":"policyDocumentType",
-          "documentation":"<p>The policy document.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The policy document.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -5105,7 +5105,7 @@
         },
         "PolicyDocument":{
           "shape":"policyDocumentType",
-          "documentation":"<p>The policy document.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The policy document.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -5127,7 +5127,7 @@
         },
         "PolicyDocument":{
           "shape":"policyDocumentType",
-          "documentation":"<p>The policy document.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The policy document.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -5698,7 +5698,7 @@
       "members":{
         "PolicyInputList":{
           "shape":"SimulationPolicyListType",
-          "documentation":"<p>A list of policy documents to include in the simulation. Each document is specified as a string containing the complete, valid JSON text of an IAM policy. Do not include any resource-based policies in this parameter. Any resource-based policy must be submitted with the <code>ResourcePolicy</code> parameter. The policies cannot be \"scope-down\" policies, such as you could include in a call to <a href=\"http://docs.aws.amazon.com/IAM/latest/APIReference/API_GetFederationToken.html\">GetFederationToken</a> or one of the <a href=\"http://docs.aws.amazon.com/IAM/latest/APIReference/API_AssumeRole.html\">AssumeRole</a> APIs to restrict what a user can do while using the temporary credentials.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>A list of policy documents to include in the simulation. Each document is specified as a string containing the complete, valid JSON text of an IAM policy. Do not include any resource-based policies in this parameter. Any resource-based policy must be submitted with the <code>ResourcePolicy</code> parameter. The policies cannot be \"scope-down\" policies, such as you could include in a call to <a href=\"http://docs.aws.amazon.com/IAM/latest/APIReference/API_GetFederationToken.html\">GetFederationToken</a> or one of the <a href=\"http://docs.aws.amazon.com/IAM/latest/APIReference/API_AssumeRole.html\">AssumeRole</a> APIs to restrict what a user can do while using the temporary credentials.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         },
         "ActionNames":{
           "shape":"ActionNameListType",
@@ -5710,7 +5710,7 @@
         },
         "ResourcePolicy":{
           "shape":"policyDocumentType",
-          "documentation":"<p>A resource-based policy to include in the simulation provided as a string. Each resource in the simulation is treated as if it had this policy attached. You can include only one resource-based policy in a simulation.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>A resource-based policy to include in the simulation provided as a string. Each resource in the simulation is treated as if it had this policy attached. You can include only one resource-based policy in a simulation.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         },
         "ResourceOwner":{
           "shape":"ResourceNameType",
@@ -5769,7 +5769,7 @@
         },
         "PolicyInputList":{
           "shape":"SimulationPolicyListType",
-          "documentation":"<p>An optional list of additional policy documents to include in the simulation. Each document is specified as a string containing the complete, valid JSON text of an IAM policy.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>An optional list of additional policy documents to include in the simulation. Each document is specified as a string containing the complete, valid JSON text of an IAM policy.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         },
         "ActionNames":{
           "shape":"ActionNameListType",
@@ -5781,7 +5781,7 @@
         },
         "ResourcePolicy":{
           "shape":"policyDocumentType",
-          "documentation":"<p>A resource-based policy to include in the simulation provided as a string. Each resource in the simulation is treated as if it had this policy attached. You can include only one resource-based policy in a simulation.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>A resource-based policy to include in the simulation provided as a string. Each resource in the simulation is treated as if it had this policy attached. You can include only one resource-based policy in a simulation.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         },
         "ResourceOwner":{
           "shape":"ResourceNameType",
@@ -5927,7 +5927,7 @@
         },
         "PolicyDocument":{
           "shape":"policyDocumentType",
-          "documentation":"<p>The policy that grants an entity permission to assume the role.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The policy that grants an entity permission to assume the role.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -5959,7 +5959,7 @@
         },
         "Password":{
           "shape":"passwordType",
-          "documentation":"<p>The new password for the specified IAM user.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D). However, the format can be further restricted by the account administrator by setting a password policy on the AWS account. For more information, see <a>UpdateAccountPasswordPolicy</a>.</p>"
+          "documentation":"<p>The new password for the specified IAM user.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D). However, the format can be further restricted by the account administrator by setting a password policy on the AWS account. For more information, see <a>UpdateAccountPasswordPolicy</a>.</p>"
         },
         "PasswordResetRequired":{
           "shape":"booleanObjectType",
@@ -6124,7 +6124,7 @@
         },
         "SSHPublicKeyBody":{
           "shape":"publicKeyMaterialType",
-          "documentation":"<p>The SSH public key. The public key must be encoded in ssh-rsa format or PEM format.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The SSH public key. The public key must be encoded in ssh-rsa format or PEM format.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -6156,15 +6156,15 @@
         },
         "CertificateBody":{
           "shape":"certificateBodyType",
-          "documentation":"<p>The contents of the public key certificate in PEM-encoded format.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The contents of the public key certificate in PEM-encoded format.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         },
         "PrivateKey":{
           "shape":"privateKeyType",
-          "documentation":"<p>The contents of the private key in PEM-encoded format.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The contents of the private key in PEM-encoded format.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         },
         "CertificateChain":{
           "shape":"certificateChainType",
-          "documentation":"<p>The contents of the certificate chain. This is typically a concatenation of the PEM-encoded public key certificates of the chain.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The contents of the certificate chain. This is typically a concatenation of the PEM-encoded public key certificates of the chain.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -6188,7 +6188,7 @@
         },
         "CertificateBody":{
           "shape":"certificateBodyType",
-          "documentation":"<p>The contents of the signing certificate.</p> <p>This parameter allows (per its <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a>) a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range (\\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
+          "documentation":"<p>The contents of the signing certificate.</p> <p>The <a href=\"http://wikipedia.org/wiki/regex\">regex pattern</a> used to validate this parameter is a string of characters consisting of any printable ASCII character ranging from the space character (\\u0020) through end of the ASCII character range as well as the printable characters in the Basic Latin and Latin-1 Supplement character set (through \\u00FF). It also includes the special characters tab (\\u0009), line feed (\\u000A), and carriage return (\\u000D).</p>"
         }
       }
     },
@@ -6285,7 +6285,7 @@
         },
         "Base32StringSeed":{
           "shape":"BootstrapDatum",
-          "documentation":"<p> The Base32 seed defined as specified in <a href=\"http://www.ietf.org/rfc/rfc3548.txt\">RFC3548</a>. The <code>Base32StringSeed</code> is Base64-encoded. </p>"
+          "documentation":"<p> The Base32 seed defined as specified in <a href=\"https://tools.ietf.org/html/rfc3548.txt\">RFC3548</a>. The <code>Base32StringSeed</code> is Base64-encoded. </p>"
         },
         "QRCodePNG":{
           "shape":"BootstrapDatum",
diff --git a/botocore/data/lambda/2015-03-31/service-2.json b/botocore/data/lambda/2015-03-31/service-2.json
index 123567497..49ac83ed2 100644
--- a/botocore/data/lambda/2015-03-31/service-2.json
+++ b/botocore/data/lambda/2015-03-31/service-2.json
@@ -62,7 +62,7 @@
         {"shape":"TooManyRequestsException"},
         {"shape":"ResourceNotFoundException"}
       ],
-      "documentation":"<p>Identifies a stream as an event source for a Lambda function. It can be either an Amazon Kinesis stream or an Amazon DynamoDB stream. AWS Lambda invokes the specified function when records are posted to the stream.</p> <p>This association between a stream source and a Lambda function is called the event source mapping.</p> <important><p>This event source mapping is relevant only in the AWS Lambda pull model, where AWS Lambda invokes the function. For more information, go to <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/lambda-introduction.html\">AWS Lambda: How it Works</a> in the <i>AWS Lambda Developer Guide</i>.</p> </important> <p>You provide mapping information (for example, which stream to read from and which Lambda function to invoke) in the request body.</p> <p>Each event source, such as an Amazon Kinesis or a DynamoDB stream, can be associated with multiple AWS Lambda function. A given Lambda function can be associated with multiple AWS event sources.</p> <p>If you are using versioning, you can specify a specific function version or an alias via the function name parameter. For more information about versioning, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/versioning-aliases.html\">AWS Lambda Function Versioning and Aliases</a>. </p> <p>This operation requires permission for the <code>lambda:CreateEventSourceMapping</code> action.</p>"
+      "documentation":"<p>Identifies a stream as an event source for a Lambda function. It can be either an Amazon Kinesis stream or an Amazon DynamoDB stream. AWS Lambda invokes the specified function when records are posted to the stream.</p> <p>This association between a stream source and a Lambda function is called the event source mapping.</p> <important><p>This event source mapping is relevant only in the AWS Lambda pull model, where AWS Lambda invokes the function. For more information, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/lambda-introduction.html\">AWS Lambda: How it Works</a> in the <i>AWS Lambda Developer Guide</i>.</p> </important> <p>You provide mapping information (for example, which stream to read from and which Lambda function to invoke) in the request body.</p> <p>Each event source, such as an Amazon Kinesis or a DynamoDB stream, can be associated with multiple AWS Lambda function. A given Lambda function can be associated with multiple AWS event sources.</p> <p>If you are using versioning, you can specify a specific function version or an alias via the function name parameter. For more information about versioning, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/versioning-aliases.html\">AWS Lambda Function Versioning and Aliases</a>. </p> <p>This operation requires permission for the <code>lambda:CreateEventSourceMapping</code> action.</p>"
     },
     "CreateFunction":{
       "name":"CreateFunction",
@@ -145,7 +145,7 @@
         {"shape":"TooManyRequestsException"},
         {"shape":"ServiceException"}
       ],
-      "documentation":"<p>Returns a customer's account settings.</p> <p>You can use this operation to retrieve Lambda limit information such as code size and concurrency limits. For more information on limits, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/limits.html\">AWS Lambda Limits</a>. You can also retrieve resource usage statistics such as code storage usage and function count.</p>"
+      "documentation":"<p>Returns a customer's account settings.</p> <p>You can use this operation to retrieve Lambda limits information, such as code size and concurrency limits. For more information about limits, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/limits.html\">AWS Lambda Limits</a>. You can also retrieve resource usage statistics, such as code storage usage and function count.</p>"
     },
     "GetAlias":{
       "name":"GetAlias",
@@ -465,7 +465,7 @@
         },
         "CodeSizeZipped":{
           "shape":"Long",
-          "documentation":"<p>Size, in bytes, of a single zipped code/dependencies package you can upload for your Lambda function(.zip/.jar file). Try using AWS S3 for uploading larger files. Default limit is 50 MB.</p>"
+          "documentation":"<p>Size, in bytes, of a single zipped code/dependencies package you can upload for your Lambda function(.zip/.jar file). Try using Amazon S3 for uploading larger files. Default limit is 50 MB.</p>"
         },
         "ConcurrentExecutions":{
           "shape":"Integer",
@@ -479,7 +479,7 @@
       "members":{
         "TotalCodeSize":{
           "shape":"Long",
-          "documentation":"<p>Total size, in megabytes, of the account's deployment packages per region.</p>"
+          "documentation":"<p>Total size, in bytes, of the account's deployment packages per region.</p>"
         },
         "FunctionCount":{
           "shape":"Long",
@@ -667,7 +667,7 @@
         },
         "StartingPosition":{
           "shape":"EventSourcePosition",
-          "documentation":"<p>The position in the stream where AWS Lambda should start reading. Valid only for Kinesis streams. For more information, go to <a href=\"http://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#Kinesis-GetShardIterator-request-ShardIteratorType\">ShardIteratorType</a> in the <i>Amazon Kinesis API Reference</i>. </p>"
+          "documentation":"<p>The position in the stream where AWS Lambda should start reading. Valid only for Kinesis streams. For more information, see <a href=\"http://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html#Kinesis-GetShardIterator-request-ShardIteratorType\">ShardIteratorType</a> in the <i>Amazon Kinesis API Reference</i>. </p>"
         },
         "StartingPositionTimestamp":{
           "shape":"Date",
@@ -688,11 +688,11 @@
       "members":{
         "FunctionName":{
           "shape":"FunctionName",
-          "documentation":"<p>The name you want to assign to the function you are uploading. The function names appear in the console and are returned in the <a>ListFunctions</a> API. Function names are used to specify functions to other AWS Lambda APIs, such as <a>Invoke</a>. </p>"
+          "documentation":"<p>The name you want to assign to the function you are uploading. The function names appear in the console and are returned in the <a>ListFunctions</a> API. Function names are used to specify functions to other AWS Lambda API operations, such as <a>Invoke</a>. </p>"
         },
         "Runtime":{
           "shape":"Runtime",
-          "documentation":"<p>The runtime environment for the Lambda function you are uploading.</p> <p>To use the Node.js runtime v4.3, set the value to \"nodejs4.3\". To use earlier runtime (v0.10.42), set the value to \"nodejs\".</p> <note> <p>You can no longer create functions using the v0.10.42 runtime version as of November, 2016. Existing functions will be supported until early 2017 but we recommend you migrate them to nodejs4.3 runtime version as soon as possible.</p> </note>"
+          "documentation":"<p>The runtime environment for the Lambda function you are uploading.</p> <p>To use the Node.js runtime v4.3, set the value to \"nodejs4.3\". To use earlier runtime (v0.10.42), set the value to \"nodejs\".</p> <note> <p>You can no longer create functions using the v0.10.42 runtime version as of November, 2016. Existing functions will be supported until early 2017, but we recommend you migrate them to nodejs4.3 runtime version as soon as possible.</p> </note>"
         },
         "Role":{
           "shape":"RoleArn",
@@ -728,7 +728,7 @@
         },
         "DeadLetterConfig":{
           "shape":"DeadLetterConfig",
-          "documentation":"<p>The parent object that contains the target ARN (Amazon Resource Name) of an Amazon SQS queue or Amazon SNS topic. </p>"
+          "documentation":"<p>The parent object that contains the target Amazon Resource Name (ARN) of an Amazon SQS queue or Amazon SNS topic. </p>"
         },
         "Environment":{"shape":"Environment"},
         "KMSKeyArn":{
@@ -744,10 +744,10 @@
       "members":{
         "TargetArn":{
           "shape":"ResourceArn",
-          "documentation":"<p>The ARN (Amazon Resource Value) of an Amazon SQS queue or Amazon SNS topic you specify as your Dead Letter Queue (DLQ).</p>"
+          "documentation":"<p>The Amazon Resource Name (ARN) of an Amazon SQS queue or Amazon SNS topic you specify as your Dead Letter Queue (DLQ).</p>"
         }
       },
-      "documentation":"<p>The parent object that contains the target ARN (Amazon Resource Name) of an Amazon SQS queue or Amazon SNS topic.</p>"
+      "documentation":"<p>The parent object that contains the target Amazon Resource Name (ARN) of an Amazon SQS queue or Amazon SNS topic.</p>"
     },
     "DeleteAliasRequest":{
       "type":"structure",
@@ -964,7 +964,7 @@
       "members":{
         "ZipFile":{
           "shape":"Blob",
-          "documentation":"<p>The contents of your zip file containing your deployment package. If you are using the web API directly, the contents of the zip file must be base64-encoded. If you are using the AWS SDKs or the AWS CLI, the SDKs or CLI will do the encoding for you. For more information about creating a .zip file, go to <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role.html\">Execution Permissions</a> in the <i>AWS Lambda Developer Guide</i>. </p>"
+          "documentation":"<p>The contents of your zip file containing your deployment package. If you are using the web API directly, the contents of the zip file must be base64-encoded. If you are using the AWS SDKs or the AWS CLI, the SDKs or CLI will do the encoding for you. For more information about creating a .zip file, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role.html\">Execution Permissions</a> in the <i>AWS Lambda Developer Guide</i>. </p>"
         },
         "S3Bucket":{
           "shape":"S3Bucket",
@@ -1052,7 +1052,7 @@
         },
         "DeadLetterConfig":{
           "shape":"DeadLetterConfig",
-          "documentation":"<p>The parent object that contains the target ARN (Amazon Resource Name) of an Amazon SQS queue or Amazon SNS topic.</p>"
+          "documentation":"<p>The parent object that contains the target Amazon Resource Name (ARN) of an Amazon SQS queue or Amazon SNS topic.</p>"
         },
         "Environment":{
           "shape":"EnvironmentResponse",
@@ -1383,7 +1383,7 @@
         "Type":{"shape":"String"},
         "Message":{"shape":"String"}
       },
-      "documentation":"<p>Lambda was unable to decrypt the environment variables because KMS access was denied. Please check the Lambda function's KMS permissions.</p>",
+      "documentation":"<p>Lambda was unable to decrypt the environment variables because KMS access was denied. Check the Lambda function's KMS permissions.</p>",
       "error":{"httpStatusCode":502},
       "exception":true
     },
@@ -1393,7 +1393,7 @@
         "Type":{"shape":"String"},
         "Message":{"shape":"String"}
       },
-      "documentation":"<p>Lambda was unable to decrypt the environment variables because the KMS key used is disabled. Please check the Lambda function's KMS key settings.</p>",
+      "documentation":"<p>Lambda was unable to decrypt the environment variables because the KMS key used is disabled. Check the Lambda function's KMS key settings.</p>",
       "error":{"httpStatusCode":502},
       "exception":true
     },
@@ -1403,7 +1403,7 @@
         "Type":{"shape":"String"},
         "Message":{"shape":"String"}
       },
-      "documentation":"<p>Lambda was unable to decrypt the environment variables because the KMS key used is in an invalid state for Decrypt. Please check the function's KMS key settings.</p>",
+      "documentation":"<p>Lambda was unable to decrypt the environment variables because the KMS key used is in an invalid state for Decrypt. Check the function's KMS key settings.</p>",
       "error":{"httpStatusCode":502},
       "exception":true
     },
@@ -1417,7 +1417,7 @@
         "Type":{"shape":"String"},
         "Message":{"shape":"String"}
       },
-      "documentation":"<p>Lambda was unable to decrypt the environment variables because the KMS key was not found. Please check the function's KMS key settings. </p>",
+      "documentation":"<p>Lambda was unable to decrypt the environment variables because the KMS key was not found. Check the function's KMS key settings. </p>",
       "error":{"httpStatusCode":502},
       "exception":true
     },
@@ -1890,11 +1890,11 @@
         },
         "ZipFile":{
           "shape":"Blob",
-          "documentation":"<p>The contents of your zip file containing your deployment package. If you are using the web API directly, the contents of the zip file must be base64-encoded. If you are using the AWS SDKs or the AWS CLI, the SDKs or CLI will do the encoding for you. For more information about creating a .zip file, go to <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role.html\">Execution Permissions</a> in the <i>AWS Lambda Developer Guide</i>. </p>"
+          "documentation":"<p>The contents of your zip file containing your deployment package. If you are using the web API directly, the contents of the zip file must be base64-encoded. If you are using the AWS SDKs or the AWS CLI, the SDKs or CLI will do the encoding for you. For more information about creating a .zip file, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role.html\">Execution Permissions</a> in the <i>AWS Lambda Developer Guide</i>. </p>"
         },
         "S3Bucket":{
           "shape":"S3Bucket",
-          "documentation":"<p>Amazon S3 bucket name where the .zip file containing your deployment package is stored. This bucket must reside in the same AWS region where you are creating the Lambda function.</p>"
+          "documentation":"<p>Amazon S3 bucket name where the .zip file containing your deployment package is stored. This bucket must reside in the same AWS Region where you are creating the Lambda function.</p>"
         },
         "S3Key":{
           "shape":"S3Key",
@@ -1952,7 +1952,7 @@
         },
         "DeadLetterConfig":{
           "shape":"DeadLetterConfig",
-          "documentation":"<p>The parent object that contains the target ARN (Amazon Resource Name) of an Amazon SQS queue or Amazon SNS topic.</p>"
+          "documentation":"<p>The parent object that contains the target Amazon Resource Name (ARN) of an Amazon SQS queue or Amazon SNS topic.</p>"
         },
         "KMSKeyArn":{
           "shape":"KMSKeyArn",
@@ -2001,5 +2001,5 @@
     },
     "VpcId":{"type":"string"}
   },
-  "documentation":"<fullname>AWS Lambda</fullname> <p> <b>Overview</b> </p> <p>This is the <i>AWS Lambda API Reference</i>. The AWS Lambda Developer Guide provides additional information. For the service overview, go to <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/welcome.html\">What is AWS Lambda</a>, and for information about how the service works, go to <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/lambda-introduction.html\">AWS Lambda: How it Works</a> in the <i>AWS Lambda Developer Guide</i>.</p>"
+  "documentation":"<fullname>AWS Lambda</fullname> <p> <b>Overview</b> </p> <p>This is the <i>AWS Lambda API Reference</i>. The AWS Lambda Developer Guide provides additional information. For the service overview, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/welcome.html\">What is AWS Lambda</a>, and for information about how the service works, see <a href=\"http://docs.aws.amazon.com/lambda/latest/dg/lambda-introduction.html\">AWS Lambda: How it Works</a> in the <i>AWS Lambda Developer Guide</i>.</p>"
 }
diff --git a/botocore/data/marketplacecommerceanalytics/2015-07-01/service-2.json b/botocore/data/marketplacecommerceanalytics/2015-07-01/service-2.json
index 96f3b8e5b..f247a660d 100644
--- a/botocore/data/marketplacecommerceanalytics/2015-07-01/service-2.json
+++ b/botocore/data/marketplacecommerceanalytics/2015-07-01/service-2.json
@@ -64,6 +64,7 @@
         "monthly_revenue_annual_subscriptions",
         "disbursed_amount_by_product",
         "disbursed_amount_by_product_with_uncollected_funds",
+        "disbursed_amount_by_instance_hours",
         "disbursed_amount_by_customer_geo",
         "disbursed_amount_by_age_of_uncollected_funds",
         "disbursed_amount_by_age_of_disbursed_funds",
@@ -94,7 +95,7 @@
       "members":{
         "dataSetType":{
           "shape":"DataSetType",
-          "documentation":"<p>The desired data set type.</p> <p> <ul> <li><i>customer_subscriber_hourly_monthly_subscriptions</i> - Available daily by 5:00 PM Pacific Time since 2014-07-21.</li> <li><i>customer_subscriber_annual_subscriptions</i> - Available daily by 5:00 PM Pacific Time since 2014-07-21.</li> <li><i>daily_business_usage_by_instance_type</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_fees</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_free_trial_conversions</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_new_instances</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_new_product_subscribers</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_canceled_product_subscribers</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>monthly_revenue_billing_and_revenue_data</i> - Available monthly on the 4th day of the month by 5:00 PM Pacific Time since 2015-02.</li> <li><i>monthly_revenue_annual_subscriptions</i> - Available monthly on the 4th day of the month by 5:00 PM Pacific Time since 2015-02.</li> <li><i>disbursed_amount_by_product</i> - Available every 30 days by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>disbursed_amount_by_product_with_uncollected_funds</i> -This data set is only available from 2012-04-19 until 2015-01-25. After 2015-01-25, this data set was split into three data sets: disbursed_amount_by_product, disbursed_amount_by_age_of_uncollected_funds, and disbursed_amount_by_age_of_disbursed_funds. </li> <li><i>disbursed_amount_by_customer_geo</i> - Available every 30 days by 5:00 PM Pacific Time since 2012-04-19.</li> <li><i>disbursed_amount_by_age_of_uncollected_funds</i> - Available every 30 days by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>disbursed_amount_by_age_of_disbursed_funds</i> - Available every 30 days by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>customer_profile_by_industry</i> - Available daily by 5:00 PM Pacific Time since 2015-10-01.</li> <li><i>customer_profile_by_revenue</i> - Available daily by 5:00 PM Pacific Time since 2015-10-01.</li> <li><i>customer_profile_by_geography</i> - Available daily by 5:00 PM Pacific Time since 2015-10-01.</li> <li><i>sales_compensation_billed_revenue</i> - Available monthly on the 4th day of the month by 5:00 PM Pacific Time since 2016-12.</li> </ul> </p>"
+          "documentation":"<p>The desired data set type.</p> <p> <ul> <li><i>customer_subscriber_hourly_monthly_subscriptions</i> - Available daily by 5:00 PM Pacific Time since 2014-07-21.</li> <li><i>customer_subscriber_annual_subscriptions</i> - Available daily by 5:00 PM Pacific Time since 2014-07-21.</li> <li><i>daily_business_usage_by_instance_type</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_fees</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_free_trial_conversions</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_new_instances</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_new_product_subscribers</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>daily_business_canceled_product_subscribers</i> - Available daily by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>monthly_revenue_billing_and_revenue_data</i> - Available monthly on the 4th day of the month by 5:00 PM Pacific Time since 2015-02.</li> <li><i>monthly_revenue_annual_subscriptions</i> - Available monthly on the 4th day of the month by 5:00 PM Pacific Time since 2015-02.</li> <li><i>disbursed_amount_by_product</i> - Available every 30 days by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>disbursed_amount_by_product_with_uncollected_funds</i> -This data set is only available from 2012-04-19 until 2015-01-25. After 2015-01-25, this data set was split into three data sets: disbursed_amount_by_product, disbursed_amount_by_age_of_uncollected_funds, and disbursed_amount_by_age_of_disbursed_funds. </li> <li><i>disbursed_amount_by_instance_hours</i> - Available every 30 days by 5:00 PM Pacific Time since 2012-09-04.</li> <li><i>disbursed_amount_by_customer_geo</i> - Available every 30 days by 5:00 PM Pacific Time since 2012-04-19.</li> <li><i>disbursed_amount_by_age_of_uncollected_funds</i> - Available every 30 days by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>disbursed_amount_by_age_of_disbursed_funds</i> - Available every 30 days by 5:00 PM Pacific Time since 2015-01-26.</li> <li><i>customer_profile_by_industry</i> - Available daily by 5:00 PM Pacific Time since 2015-10-01.</li> <li><i>customer_profile_by_revenue</i> - Available daily by 5:00 PM Pacific Time since 2015-10-01.</li> <li><i>customer_profile_by_geography</i> - Available daily by 5:00 PM Pacific Time since 2015-10-01.</li> <li><i>sales_compensation_billed_revenue</i> - Available monthly on the 4th day of the month by 5:00 PM Pacific Time since 2016-12.</li> </ul> </p>"
         },
         "dataSetPublicationDate":{
           "shape":"DataSetPublicationDate",
diff --git a/botocore/data/rds/2014-10-31/service-2.json b/botocore/data/rds/2014-10-31/service-2.json
index b1635262a..4d96031c3 100755
--- a/botocore/data/rds/2014-10-31/service-2.json
+++ b/botocore/data/rds/2014-10-31/service-2.json
@@ -167,7 +167,7 @@
         {"shape":"SnapshotQuotaExceededFault"},
         {"shape":"KMSKeyNotAccessibleFault"}
       ],
-      "documentation":"<p>Copies the specified DB snapshot. The source DB snapshot must be in the \"available\" state.</p> <p>To copy a DB snapshot from a shared manual DB snapshot, <code>SourceDBSnapshotIdentifier</code> must be the Amazon Resource Name (ARN) of the shared DB snapshot.</p> <p>You can not copy an encrypted DB snapshot from another AWS region.</p> <p>You can copy an encrypted DB snapshot from another AWS region. In that case, the region where you call the <code>CopyDBSnapshot</code> action is the destination region for the encrypted DB snapshot to be copied to. To copy an encrypted DB snapshot from another region, you must provide the following values:</p> <ul> <li> <p> <code>KmsKeyId</code> - the AWS Key Management System (KMS) key identifier for the key to use to encrypt the copy of the DB snapshot in the destination region.</p> </li> <li> <p> <code>PreSignedUrl</code> - a URL that contains a Signature Version 4 signed request for the <code>CopyDBSnapshot</code> action to be called in the source region where the DB snapshot will be copied from. The pre-signed URL must be a valid request for the <code>CopyDBSnapshot</code> API action that can be executed in the source region that contains the encrypted DB snapshot to be copied.</p> <p>The pre-signed URL request must contain the following parameter values:</p> <ul> <li> <p> <code>KmsKeyId</code> - The KMS key identifier for the key to use to encrypt the copy of the DB snapshot in the destination region. This is the same identifier for both the <code>CopyDBSnapshot</code> action that is called in the destination region, and the action contained in the pre-signed URL.</p> </li> <li> <p> <code>SourceDBSnapshotIdentifier</code> - the DB snapshot identifier for the encrypted snapshot to be copied. This identifier must be in the Amazon Resource Name (ARN) format for the source region. For example, if you are copying an encrypted DB snapshot from the us-west-2 region, then your <code>SourceDBSnapshotIdentifier</code> would look like Example: <code>arn:aws:rds:us-west-2:123456789012:snapshot:mysql-instance1-snapshot-20161115</code>.</p> </li> </ul> <p>To learn how to generate a Signature Version 4 signed request, see <a href=\"http://docs.aws.amazon.com/http:/docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html\"> Authenticating Requests: Using Query Parameters (AWS Signature Version 4)</a> and <a href=\"http://docs.aws.amazon.com/http:/docs.aws.amazon.com/general/latest/gr/signature-version-4.html\"> Signature Version 4 Signing Process</a>.</p> </li> <li> <p> <code>TargetDBSnapshotIdentifier</code> - the identifier for the new copy of the DB snapshot in the destination region.</p> </li> <li> <p> <code>SourceDBSnapshotIdentifier</code> - the DB snapshot identifier for the encrypted snapshot to be copied. This identifier must be in the ARN format for the source region and is the same value as the <code>SourceDBSnapshotIdentifier</code> in the pre-signed URL. </p> </li> </ul> <p>For more information on copying encrypted snapshots from one region to another, see <a href=\"http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_CopySnapshot.html#USER_CopySnapshot.Encrypted.CrossRegion\"> Copying an Encrypted DB Snapshot to Another Region in the Amazon RDS User Guide.</a> </p>"
+      "documentation":"<p>Copies the specified DB snapshot. The source DB snapshot must be in the \"available\" state.</p> <p>To copy a DB snapshot from a shared manual DB snapshot, <code>SourceDBSnapshotIdentifier</code> must be the Amazon Resource Name (ARN) of the shared DB snapshot.</p> <p>You can copy an encrypted DB snapshot from another AWS Region. In that case, the region where you call the <code>CopyDBSnapshot</code> action is the destination region for the encrypted DB snapshot to be copied to. To copy an encrypted DB snapshot from another region, you must provide the following values:</p> <ul> <li> <p> <code>KmsKeyId</code> - The AWS Key Management System (KMS) key identifier for the key to use to encrypt the copy of the DB snapshot in the destination region.</p> </li> <li> <p> <code>PreSignedUrl</code> - A URL that contains a Signature Version 4 signed request for the <code>CopyDBSnapshot</code> action to be called in the source region where the DB snapshot will be copied from. The presigned URL must be a valid request for the <code>CopyDBSnapshot</code> API action that can be executed in the source region that contains the encrypted DB snapshot to be copied.</p> <p>The presigned URL request must contain the following parameter values:</p> <ul> <li> <p> <code>DestinationRegion</code> - The AWS Region that the encrypted DB snapshot will be copied to. This region is the same one where the <code>CopyDBSnapshot</code> action is called that contains this presigned URL. </p> <p>For example, if you copy an encrypted DB snapshot from the us-west-2 region to the us-east-1 region, then you will call the <code>CopyDBSnapshot</code> action in the us-east-1 region and provide a presigned URL that contains a call to the <code>CopyDBSnapshot</code> action in the us-west-2 region. For this example, the <code>DestinationRegion</code> in the presigned URL must be set to the us-east-1 region.</p> </li> <li> <p> <code>KmsKeyId</code> - The KMS key identifier for the key to use to encrypt the copy of the DB snapshot in the destination region. This identifier is the same for both the <code>CopyDBSnapshot</code> action that is called in the destination region, and the action contained in the presigned URL.</p> </li> <li> <p> <code>SourceDBSnapshotIdentifier</code> - The DB snapshot identifier for the encrypted snapshot to be copied. This identifier must be in the Amazon Resource Name (ARN) format for the source region. For example, if you copy an encrypted DB snapshot from the us-west-2 region, then your <code>SourceDBSnapshotIdentifier</code> looks like this example: <code>arn:aws:rds:us-west-2:123456789012:snapshot:mysql-instance1-snapshot-20161115</code>.</p> </li> </ul> <p>To learn how to generate a Signature Version 4 signed request, see <a href=\"http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html\"> Authenticating Requests: Using Query Parameters (AWS Signature Version 4)</a> and <a href=\"http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html\"> Signature Version 4 Signing Process</a>.</p> </li> <li> <p> <code>TargetDBSnapshotIdentifier</code> - The identifier for the new copy of the DB snapshot in the destination region.</p> </li> <li> <p> <code>SourceDBSnapshotIdentifier</code> - The DB snapshot identifier for the encrypted snapshot to be copied. This identifier must be in the ARN format for the source region and is the same value as the <code>SourceDBSnapshotIdentifier</code> in the presigned URL. </p> </li> </ul> <p>For more information on copying encrypted snapshots from one region to another, see <a href=\"http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_CopySnapshot.html#USER_CopySnapshot.Encrypted.CrossRegion\"> Copying an Encrypted DB Snapshot to Another Region</a> in the Amazon RDS User Guide.</p>"
     },
     "CopyOptionGroup":{
       "name":"CopyOptionGroup",
@@ -1996,7 +1996,7 @@
         },
         "PreSignedUrl":{
           "shape":"String",
-          "documentation":"<p>The URL that contains a Signature Version 4 signed request for the <code>CopyDBSnapshot</code> API action in the AWS region that contains the source DB snapshot to copy. The <code>PreSignedUrl</code> parameter must be used when copying an encrypted DB snapshot from another AWS region.</p> <p>The pre-signed URL must be a valid request for the <code>CopyDBSnapshot</code> API action that can be executed in the source region that contains the encrypted DB snapshot to be copied. The pre-signed URL request must contain the following parameter values:</p> <ul> <li> <p> <code>KmsKeyId</code> - The KMS key identifier for the key to use to encrypt the copy of the DB snapshot in the destination region. This is the same identifier for both the <code>CopyDBSnapshot</code> action that is called in the destination region, and the action contained in the pre-signed URL.</p> </li> <li> <p> <code>SourceDBSnapshotIdentifier</code> - the DB snapshot identifier for the encrypted snapshot to be copied. This identifier must be in the Amazon Resource Name (ARN) format for the source region. For example, if you are copying an encrypted DB snapshot from the us-west-2 region, then your <code>SourceDBSnapshotIdentifier</code> would look like Example: <code>arn:aws:rds:us-west-2:123456789012:snapshot:mysql-instance1-snapshot-20161115</code>.</p> </li> </ul> <p>To learn how to generate a Signature Version 4 signed request, see <a href=\"http://docs.aws.amazon.com/http:/docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html\"> Authenticating Requests: Using Query Parameters (AWS Signature Version 4)</a> and <a href=\"http://docs.aws.amazon.com/http:/docs.aws.amazon.com/general/latest/gr/signature-version-4.html\"> Signature Version 4 Signing Process</a>.</p>"
+          "documentation":"<p>The URL that contains a Signature Version 4 signed request for the <code>CopyDBSnapshot</code> API action in the AWS region that contains the source DB snapshot to copy. The <code>PreSignedUrl</code> parameter must be used when copying an encrypted DB snapshot from another AWS region.</p> <p>The presigned URL must be a valid request for the <code>CopyDBSnapshot</code> API action that can be executed in the source region that contains the encrypted DB snapshot to be copied. The presigned URL request must contain the following parameter values:</p> <ul> <li> <p> <code>DestinationRegion</code> - The AWS Region that the encrypted DB snapshot will be copied to. This region is the same one where the <code>CopyDBSnapshot</code> action is called that contains this presigned URL. </p> <p>For example, if you copy an encrypted DB snapshot from the us-west-2 region to the us-east-1 region, then you will call the <code>CopyDBSnapshot</code> action in the us-east-1 region and provide a presigned URL that contains a call to the <code>CopyDBSnapshot</code> action in the us-west-2 region. For this example, the <code>DestinationRegion</code> in the presigned URL must be set to the us-east-1 region.</p> </li> <li> <p> <code>KmsKeyId</code> - The KMS key identifier for the key to use to encrypt the copy of the DB snapshot in the destination region. This is the same identifier for both the <code>CopyDBSnapshot</code> action that is called in the destination region, and the action contained in the presigned URL.</p> </li> <li> <p> <code>SourceDBSnapshotIdentifier</code> - The DB snapshot identifier for the encrypted snapshot to be copied. This identifier must be in the Amazon Resource Name (ARN) format for the source region. For example, if you are copying an encrypted DB snapshot from the us-west-2 region, then your <code>SourceDBSnapshotIdentifier</code> would look like Example: <code>arn:aws:rds:us-west-2:123456789012:snapshot:mysql-instance1-snapshot-20161115</code>.</p> </li> </ul> <p>To learn how to generate a Signature Version 4 signed request, see <a href=\"http://docs.aws.amazon.com/http:/docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html\"> Authenticating Requests: Using Query Parameters (AWS Signature Version 4)</a> and <a href=\"http://docs.aws.amazon.com/http:/docs.aws.amazon.com/general/latest/gr/signature-version-4.html\"> Signature Version 4 Signing Process</a>.</p>"
         }
       },
       "documentation":"<p/>"
@@ -4442,7 +4442,7 @@
         },
         "Filters":{
           "shape":"FilterList",
-          "documentation":"<p>A filter that specifies one or more DB instances to describe.</p> <p>Supported filters:</p> <ul> <li> <p> <code>db-instance-id</code> - Accepts DB instance identifiers and DB instance Amazon Resource Names (ARNs). The results list will only include information about the DB instances identified by these ARNs.</p> </li> </ul>"
+          "documentation":"<p>A filter that specifies one or more DB instances to describe.</p> <p>Supported filters:</p> <ul> <li> <p> <code>db-cluster-id</code> - Accepts DB cluster identifiers and DB cluster Amazon Resource Names (ARNs). The results list will only include information about the DB instances associated with the DB Clusters identified by these ARNs.</p> </li> <li> <p> <code>db-instance-id</code> - Accepts DB instance identifiers and DB instance Amazon Resource Names (ARNs). The results list will only include information about the DB instances identified by these ARNs.</p> </li> </ul>"
         },
         "MaxRecords":{
           "shape":"IntegerOptional",
@@ -7506,7 +7506,7 @@
         },
         "Engine":{
           "shape":"String",
-          "documentation":"<p>The database engine to use for the new instance.</p> <p>Default: The same as source</p> <p>Constraint: Must be compatible with the engine of the source</p> <p> Valid Values: <code>MySQL</code> | <code>mariadb</code> | <code>oracle-se1</code> | <code>oracle-se</code> | <code>oracle-ee</code> | <code>sqlserver-ee</code> | <code>sqlserver-se</code> | <code>sqlserver-ex</code> | <code>sqlserver-web</code> | <code>postgres</code> | <code>aurora</code> </p>"
+          "documentation":"<p>The database engine to use for the new instance.</p> <p>Default: The same as source</p> <p>Constraint: Must be compatible with the engine of the source. You can restore a MariaDB 10.1 DB instance from a MySQL 5.6 snapshot.</p> <p> Valid Values: <code>MySQL</code> | <code>mariadb</code> | <code>oracle-se1</code> | <code>oracle-se</code> | <code>oracle-ee</code> | <code>sqlserver-ee</code> | <code>sqlserver-se</code> | <code>sqlserver-ex</code> | <code>sqlserver-web</code> | <code>postgres</code> | <code>aurora</code> </p>"
         },
         "Iops":{
           "shape":"IntegerOptional",
diff --git a/botocore/data/rekognition/2016-06-27/service-2.json b/botocore/data/rekognition/2016-06-27/service-2.json
index 137ec9999..bbccdb833 100644
--- a/botocore/data/rekognition/2016-06-27/service-2.json
+++ b/botocore/data/rekognition/2016-06-27/service-2.json
@@ -47,7 +47,7 @@
         {"shape":"ProvisionedThroughputExceededException"},
         {"shape":"ResourceAlreadyExistsException"}
       ],
-      "documentation":"<p>Creates a collection in an AWS region. You can add faces to the collection using the operation. </p> <p>For example, you might create collections, one for each of your application users. A user can then index faces using the <code>IndexFaces</code> operation and persist results in a specific collection. Then, a user can search the collection for faces in the user-specific container. </p> <p>For an example, see <a>example1</a>. </p> <p>This operation requires permissions to perform the <code>rekognition:CreateCollection</code> action.</p>"
+      "documentation":"<p>Creates a collection in an AWS Region. You can add faces to the collection using the operation. </p> <p>For example, you might create collections, one for each of your application users. A user can then index faces using the <code>IndexFaces</code> operation and persist results in a specific collection. Then, a user can search the collection for faces in the user-specific container. </p> <p>For an example, see <a>example1</a>. </p> <p>This operation requires permissions to perform the <code>rekognition:CreateCollection</code> action.</p>"
     },
     "DeleteCollection":{
       "name":"DeleteCollection",
@@ -123,7 +123,7 @@
         {"shape":"ProvisionedThroughputExceededException"},
         {"shape":"InvalidImageFormatException"}
       ],
-      "documentation":"<p>Detects instances of real-world labels within an image (JPEG or PNG) provided as input. This includes objects like flower, tree, and table; events like wedding, graduation, and birthday party; and concepts like landscape, evening, and nature. For an example, see <a>get-started-exercise-detect-labels</a>.</p> <p> For each object, scene, and concept the API returns one or more labels. Each label provides the object name, and the level of confidence that the image contains the object. For example, suppose the input image has a lighthouse, the sea, and a rock. The response will include all three labels, one for each object. </p> <p> <code>{Name: lighthouse, Confidence: 98.4629}</code> </p> <p> <code>{Name: rock,Confidence: 79.2097}</code> </p> <p> <code> {Name: sea,Confidence: 75.061}</code> </p> <p> In the preceding example, the operation returns one label for each of the three objects. The operation can also return multiple labels for the same object in the image. For example, if the input image shows a flower (for example, a tulip), the operation might return the following three labels. </p> <p> <code>{Name: flower,Confidence: 99.0562}</code> </p> <p> <code>{Name: plant,Confidence: 99.0562}</code> </p> <p> <code>{Name: tulip,Confidence: 99.0562}</code> </p> <p>In this example, the detection algorithm more precisely identifies the flower as a tulip.</p> <p> You can provide the input image as an S3 object or as base64-encoded bytes. In response, the API returns an array of labels. In addition, the response also includes the orientation correction. Optionally, you can specify <code>MinConfidence</code> to control the confidence threshold for the labels returned. The default is 50%. You can also add the <code>MaxLabels</code> parameter to limit the number of labels returned. </p> <note> <p>If the object detected is a person, the operation doesn't provide the same facial details that the <a>DetectFaces</a> operation provides.</p> </note> <p>This is a stateless API operation. That is, the operation does not persist any data.</p> <p>This operation requires permissions to perform the <code>rekognition:DetectLabels</code> action. </p>"
+      "documentation":"<p>Detects instances of real-world labels within an image (JPEG or PNG) provided as input. This includes objects like flower, tree, and table; events like wedding, graduation, and birthday party; and concepts like landscape, evening, and nature. For an example, see <a>get-started-exercise-detect-labels</a>.</p> <p> For each object, scene, and concept the API returns one or more labels. Each label provides the object name, and the level of confidence that the image contains the object. For example, suppose the input image has a lighthouse, the sea, and a rock. The response will include all three labels, one for each object. </p> <p> <code>{Name: lighthouse, Confidence: 98.4629}</code> </p> <p> <code>{Name: rock,Confidence: 79.2097}</code> </p> <p> <code> {Name: sea,Confidence: 75.061}</code> </p> <p> In the preceding example, the operation returns one label for each of the three objects. The operation can also return multiple labels for the same object in the image. For example, if the input image shows a flower (for example, a tulip), the operation might return the following three labels. </p> <p> <code>{Name: flower,Confidence: 99.0562}</code> </p> <p> <code>{Name: plant,Confidence: 99.0562}</code> </p> <p> <code>{Name: tulip,Confidence: 99.0562}</code> </p> <p>In this example, the detection algorithm more precisely identifies the flower as a tulip.</p> <p>You can provide the input image as an S3 object or as base64-encoded bytes. In response, the API returns an array of labels. In addition, the response also includes the orientation correction. Optionally, you can specify <code>MinConfidence</code> to control the confidence threshold for the labels returned. The default is 50%. You can also add the <code>MaxLabels</code> parameter to limit the number of labels returned. </p> <note> <p>If the object detected is a person, the operation doesn't provide the same facial details that the <a>DetectFaces</a> operation provides.</p> </note> <p>This is a stateless API operation. That is, the operation does not persist any data.</p> <p>This operation requires permissions to perform the <code>rekognition:DetectLabels</code> action. </p>"
     },
     "IndexFaces":{
       "name":"IndexFaces",
@@ -144,7 +144,7 @@
         {"shape":"ResourceNotFoundException"},
         {"shape":"InvalidImageFormatException"}
       ],
-      "documentation":"<p>Detects faces in the input image and adds them to the specified collection. </p> <p> Amazon Rekognition does not save the actual faces detected. Instead, the underlying detection algorithm first detects the faces in the input image, and for each face extracts facial features into a feature vector, and stores it in the back-end database. Amazon Rekognition uses feature vectors when performing face match and search operations using the and operations. </p> <p>If you provide the optional <code>externalImageID</code> for the input image you provided, Amazon Rekognition associates this ID with all faces that it detects. When you call the operation, the response returns the external ID. You can use this external image ID to create a client-side index to associate the faces with each image. You can then use the index to find all faces in an image. </p> <p>In response, the operation returns an array of metadata for all detected faces. This includes, the bounding box of the detected face, confidence value (indicating the bounding box contains a face), a face ID assigned by the service for each face that is detected and stored, and an image ID assigned by the service for the input image If you request all facial attributes (using the <code>detectionAttributes</code> parameter, Rekognition returns detailed facial attributes such as facial landmarks (for example, location of eye and mount) and other facial attributes such gender. If you provide the same image, specify the same collection, and use the same external ID in the <code>IndexFaces</code> operation, Rekognition doesn't save duplicate face metadata. </p> <p>For an example, see <a>example2</a>.</p> <p>This operation requires permissions to perform the <code>rekognition:IndexFaces</code> action.</p>"
+      "documentation":"<p>Detects faces in the input image and adds them to the specified collection. </p> <p> Amazon Rekognition does not save the actual faces detected. Instead, the underlying detection algorithm first detects the faces in the input image, and for each face extracts facial features into a feature vector, and stores it in the back-end database. Amazon Rekognition uses feature vectors when performing face match and search operations using the and operations. </p> <p>If you provide the optional <code>externalImageID</code> for the input image you provided, Amazon Rekognition associates this ID with all faces that it detects. When you call the operation, the response returns the external ID. You can use this external image ID to create a client-side index to associate the faces with each image. You can then use the index to find all faces in an image. </p> <p>In response, the operation returns an array of metadata for all detected faces. This includes, the bounding box of the detected face, confidence value (indicating the bounding box contains a face), a face ID assigned by the service for each face that is detected and stored, and an image ID assigned by the service for the input image If you request all facial attributes (using the <code>detectionAttributes</code> parameter, Amazon Rekognition returns detailed facial attributes such as facial landmarks (for example, location of eye and mount) and other facial attributes such gender. If you provide the same image, specify the same collection, and use the same external ID in the <code>IndexFaces</code> operation, Amazon Rekognition doesn't save duplicate face metadata. </p> <p>For an example, see <a>example2</a>.</p> <p>This operation requires permissions to perform the <code>rekognition:IndexFaces</code> action.</p>"
     },
     "ListCollections":{
       "name":"ListCollections",
@@ -200,7 +200,7 @@
         {"shape":"ProvisionedThroughputExceededException"},
         {"shape":"ResourceNotFoundException"}
       ],
-      "documentation":"<p>For a given input face ID, searches the specified collection for matching faces. You get a face ID when you add a face to the collection using the <a>IndexFaces</a> operation. The operation compares the features of the input face with faces in the specified collection. </p> <note> <p>You can also search faces without indexing faces by using the <code>SearchFacesByImage</code> operation.</p> </note> <p> The operation response returns an array of faces that match, ordered by similarity score with the highest similarity first. More specifically, it is an array of metadata for each face match that is found. Along with the metadata, the response also includes a <code>confidence</code> value for each face match, indicating the confidence that the specific face matches the input face. </p> <p>For an example, see <a>example3</a>.</p> <p>This operation requires permissions to perform the <code>rekognition:SearchFaces</code> action.</p>"
+      "documentation":"<p>For a given input face ID, searches for matching faces in the collection the face belongs to. You get a face ID when you add a face to the collection using the <a>IndexFaces</a> operation. The operation compares the features of the input face with faces in the specified collection. </p> <note> <p>You can also search faces without indexing faces by using the <code>SearchFacesByImage</code> operation.</p> </note> <p> The operation response returns an array of faces that match, ordered by similarity score with the highest similarity first. More specifically, it is an array of metadata for each face match that is found. Along with the metadata, the response also includes a <code>confidence</code> value for each face match, indicating the confidence that the specific face matches the input face. </p> <p>For an example, see <a>example3</a>.</p> <p>This operation requires permissions to perform the <code>rekognition:SearchFaces</code> action.</p>"
     },
     "SearchFacesByImage":{
       "name":"SearchFacesByImage",
@@ -221,7 +221,7 @@
         {"shape":"ResourceNotFoundException"},
         {"shape":"InvalidImageFormatException"}
       ],
-      "documentation":"<p>For a given input image, first detects the largest face in the image, and then searches the specified collection for matching faces. The operation compares the features of the input face with faces in the specified collection. </p> <note> <p> To search for all faces in an input image, you might first call the API, and then use the face IDs returned in subsequent calls to the API. </p> <p> You can also call the <code>DetectFaces</code> API and use the bounding boxes in the response to make face crops, which then you can pass in to the <code>SearchFacesByImage</code> API. </p> </note> <p> The response returns an array of faces that match, ordered by similarity score with the highest similarity first. More specifically, it is an array of metadata for each face match found. Along with the metadata, the response also includes a <code>similarity</code> indicating how similar the face is to the input face. In the response, the API also returns the bounding box (and a confidence level that the bounding box contains a face) of the face that Rekognition used for the input image. </p> <p>For an example, see <a>example3</a>.</p> <p>This operation requires permissions to perform the <code>rekognition:SearchFacesByImage</code> action.</p>"
+      "documentation":"<p>For a given input image, first detects the largest face in the image, and then searches the specified collection for matching faces. The operation compares the features of the input face with faces in the specified collection. </p> <note> <p> To search for all faces in an input image, you might first call the operation, and then use the face IDs returned in subsequent calls to the operation. </p> <p> You can also call the <code>DetectFaces</code> operation and use the bounding boxes in the response to make face crops, which then you can pass in to the <code>SearchFacesByImage</code> operation. </p> </note> <p> The response returns an array of faces that match, ordered by similarity score with the highest similarity first. More specifically, it is an array of metadata for each face match found. Along with the metadata, the response also includes a <code>similarity</code> indicating how similar the face is to the input face. In the response, the operation also returns the bounding box (and a confidence level that the bounding box contains a face) of the face that Amazon Rekognition used for the input image. </p> <p>For an example, see <a>example3</a>.</p> <p>This operation requires permissions to perform the <code>rekognition:SearchFacesByImage</code> action.</p>"
     }
   },
   "shapes":{
@@ -302,7 +302,7 @@
           "documentation":"<p>Provides face metadata (bounding box and confidence that the bounding box actually contains a face).</p>"
         }
       },
-      "documentation":"<p>Provide the bounding box, confidence that the bounding box actually contains a face, and the similarity between the face in the bounding box and the face in the source image.</p>"
+      "documentation":"<p>For the provided the bounding box, confidence level that the bounding box actually contains a face, and the similarity between the face in the bounding box and the face in the source image.</p>"
     },
     "CompareFacesMatchList":{
       "type":"list",
@@ -317,11 +317,11 @@
       "members":{
         "SourceImage":{
           "shape":"Image",
-          "documentation":"<p>Source image either as bytes or an Amazon S3 object</p>"
+          "documentation":"<p>Source image either as bytes or an S3 object</p>"
         },
         "TargetImage":{
           "shape":"Image",
-          "documentation":"<p>Target image either as bytes or an Amazon S3 object</p>"
+          "documentation":"<p>Target image either as bytes or an S3 object</p>"
         },
         "SimilarityThreshold":{
           "shape":"Percent",
@@ -338,7 +338,7 @@
         },
         "FaceMatches":{
           "shape":"CompareFacesMatchList",
-          "documentation":"<p>Provides an array of <code>CompareFacesMatch </code> objects. Each object provides the bounding box, confidence that the bounding box contains a face, and the similarity between the face in the bounding box and the face in the source image.</p>"
+          "documentation":"<p>Provides an array of <code>CompareFacesMatch</code> objects. Each object provides the bounding box, confidence that the bounding box contains a face, and the similarity between the face in the bounding box and the face in the source image.</p>"
         }
       }
     },
@@ -359,7 +359,7 @@
         "BoundingBox":{"shape":"BoundingBox"},
         "Confidence":{
           "shape":"Percent",
-          "documentation":"<p>Confidence that the selected bounding box contains a face.</p>"
+          "documentation":"<p>Confidence level that the selected bounding box contains a face.</p>"
         }
       },
       "documentation":"<p>Type that describes the face Amazon Rekognition chose to compare with the faces in the target. This contains a bounding box for the selected face and confidence level that the bounding box contains a face. Note that Amazon Rekognition selects the largest face in the source image for this comparison. </p>"
@@ -447,7 +447,7 @@
         },
         "Attributes":{
           "shape":"Attributes",
-          "documentation":"<p>A list of facial attributes you would like to be returned. By default, the API returns subset of facial attributes. </p> <p>For example, you can specify the value as, [\"ALL\"] or [\"DEFAULT\"]. If you provide both, [\"ALL\", \"DEFAULT\"], the service uses a logical AND operator to determine which attributes to return (in this case, it is all attributes). If you specify all attributes, Rekognition performs additional detection. </p>"
+          "documentation":"<p>A list of facial attributes you would like to be returned. By default, the API returns subset of facial attributes. </p> <p>For example, you can specify the value as, [\"ALL\"] or [\"DEFAULT\"]. If you provide both, [\"ALL\", \"DEFAULT\"], the service uses a logical AND operator to determine which attributes to return (in this case, it is all attributes). If you specify all attributes, Amazon Rekognition performs additional detection. </p>"
         }
       }
     },
@@ -491,7 +491,7 @@
         },
         "OrientationCorrection":{
           "shape":"OrientationCorrection",
-          "documentation":"<p> Amazon Rekognition returns the orientation of the input image that was detected (clockwise direction). If your application displays the image, you can use this value to correct the orientation. If Rekognition detects that the input image was rotated (for example, by 90 degrees), it first corrects the orientation before detecting the labels. </p>"
+          "documentation":"<p> Amazon Rekognition returns the orientation of the input image that was detected (clockwise direction). If your application displays the image, you can use this value to correct the orientation. If Amazon Rekognition detects that the input image was rotated (for example, by 90 degrees), it first corrects the orientation before detecting the labels. </p>"
         }
       }
     },
@@ -724,7 +724,7 @@
           "documentation":"<p>Identifies an S3 object as the image source.</p>"
         }
       },
-      "documentation":"<p>Provides the source image either as bytes or an S3 object.</p>"
+      "documentation":"<p>Provides the source image either as bytes or an S3 object.</p> <p>The region for the S3 bucket containing the S3 object must match the region you use for Amazon Rekognition operations.</p> <p>You may need to Base64-encode the image bytes depending on the language you are using and whether or not you are using the AWS SDK. For more information, see <a>example4</a>.</p> <p>For Amazon Rekognition to process an S3 object, the user must have permission to access the S3 object. For more information, see <a>manage-access-resource-policies</a>. </p>"
     },
     "ImageBlob":{
       "type":"blob",
@@ -774,7 +774,7 @@
         },
         "DetectionAttributes":{
           "shape":"Attributes",
-          "documentation":"<p>(Optional) Returns detailed attributes of indexed faces. By default, the operation returns a subset of the facial attributes. </p> <p>For example, you can specify the value as, [\"ALL\"] or [\"DEFAULT\"]. If you provide both, [\"ALL\", \"DEFAULT\"], Rekognition uses the logical AND operator to determine which attributes to return (in this case, it is all attributes). If you specify all attributes, the service performs additional detection, in addition to the default. </p>"
+          "documentation":"<p>(Optional) Returns detailed attributes of indexed faces. By default, the operation returns a subset of the facial attributes. </p> <p>For example, you can specify the value as, [\"ALL\"] or [\"DEFAULT\"]. If you provide both, [\"ALL\", \"DEFAULT\"], Amazon Rekognition uses the logical AND operator to determine which attributes to return (in this case, it is all attributes). If you specify all attributes, the service performs additional detection, in addition to the default. </p>"
         }
       }
     },
@@ -817,7 +817,7 @@
       "type":"structure",
       "members":{
       },
-      "documentation":"<p>Input parameter violated a constraint. Validate your parameter before calling the API again.</p>",
+      "documentation":"<p>Input parameter violated a constraint. Validate your parameter before calling the API operation again.</p>",
       "exception":true
     },
     "InvalidS3ObjectException":{
@@ -839,7 +839,7 @@
           "documentation":"<p>Level of confidence.</p>"
         }
       },
-      "documentation":"<p>Structure containing details about the detected label, including bounding box, name, and level of confidence.</p>"
+      "documentation":"<p>Structure containing details about the detected label, including name, and level of confidence.</p>"
     },
     "Labels":{
       "type":"list",
@@ -854,11 +854,11 @@
         },
         "X":{
           "shape":"Float",
-          "documentation":"<p>x-coordinate from the top left of the landmark expressed as the ration of the width of the image. For example, if the images is 700x200 and the x-coordinate of the landmark is at 350 pixels, then this value is 0.5. </p>"
+          "documentation":"<p>x-coordinate from the top left of the landmark expressed as the ration of the width of the image. For example, if the images is 700x200 and the x-coordinate of the landmark is at 350 pixels, this value is 0.5. </p>"
         },
         "Y":{
           "shape":"Float",
-          "documentation":"<p>y-coordinate from the top left of the landmark expressed as the ration of the height of the image. For example, if the images is 700x200 and the y-coordinate of the landmark is at 100 pixels, then this value is 0.5.</p>"
+          "documentation":"<p>y-coordinate from the top left of the landmark expressed as the ration of the height of the image. For example, if the images is 700x200 and the y-coordinate of the landmark is at 100 pixels, this value is 0.5.</p>"
         }
       },
       "documentation":"<p>Indicates the location of the landmark on the face.</p>"
@@ -1039,7 +1039,7 @@
       "type":"structure",
       "members":{
       },
-      "documentation":"<p>The collection with specific ID already exist.</p>",
+      "documentation":"<p>A collection with the specified ID already exists.</p>",
       "exception":true
     },
     "ResourceNotFoundException":{
@@ -1071,7 +1071,7 @@
           "documentation":"<p>If the bucket is versioning enabled, you can specify the object version. </p>"
         }
       },
-      "documentation":"<p>Provides the S3 bucket name and object name.</p>"
+      "documentation":"<p>Provides the S3 bucket name and object name.</p> <p>The region for the S3 bucket containing the S3 object must match the region you use for Amazon Rekognition operations.</p> <p>For Amazon Rekognition to process an S3 object, the user must have permission to access the S3 object. For more information, see <a>manage-access-resource-policies</a>. </p>"
     },
     "S3ObjectName":{
       "type":"string",
@@ -1110,7 +1110,7 @@
       "members":{
         "SearchedFaceBoundingBox":{
           "shape":"BoundingBox",
-          "documentation":"<p>The bounding box around the face in the input image that Rekognition used for the search.</p>"
+          "documentation":"<p>The bounding box around the face in the input image that Amazon Rekognition used for the search.</p>"
         },
         "SearchedFaceConfidence":{
           "shape":"Percent",
@@ -1131,7 +1131,7 @@
       "members":{
         "CollectionId":{
           "shape":"CollectionId",
-          "documentation":"<p>ID of the collection to search.</p>"
+          "documentation":"<p>ID of the collection the face belongs to.</p>"
         },
         "FaceId":{
           "shape":"FaceId",
@@ -1139,7 +1139,7 @@
         },
         "MaxFaces":{
           "shape":"MaxFaces",
-          "documentation":"<p>Maximum number of faces to return. The API will return the maximum number of faces with the highest confidence in the match.</p>"
+          "documentation":"<p>Maximum number of faces to return. The operation returns the maximum number of faces with the highest confidence in the match.</p>"
         },
         "FaceMatchThreshold":{
           "shape":"Percent",
@@ -1202,5 +1202,5 @@
       "min":0
     }
   },
-  "documentation":"<p>This is Amazon Rekognition API guide.</p>"
+  "documentation":"<p>This is the Amazon Rekognition API reference.</p>"
 }
diff --git a/botocore/errorfactory.py b/botocore/errorfactory.py
new file mode 100644
index 000000000..05ac5c1ef
--- /dev/null
+++ b/botocore/errorfactory.py
@@ -0,0 +1,95 @@
+# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"). You
+# may not use this file except in compliance with the License. A copy of
+# the License is located at
+#
+# http://aws.amazon.com/apache2.0/
+#
+# or in the "license" file accompanying this file. This file is
+# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
+# ANY KIND, either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+from botocore.exceptions import ClientError
+from botocore.utils import get_service_module_name
+
+
+class BaseClientExceptions(object):
+    ClientError = ClientError
+
+    def __init__(self, code_to_exception):
+        """Base class for exceptions object on a client
+
+        :type code_to_exception: dict
+        :param code_to_exception: Mapping of error codes (strings) to exception
+            class that should be raised when encountering a particular
+            error code.
+        """
+        self._code_to_exception = code_to_exception
+
+    def from_code(self, error_code):
+        """Retrieves the error class based on the error code
+
+        This is helpful for identifying the exception class needing to be
+        caught based on the ClientError.parsed_reponse['Error']['Code'] value
+
+        :type error_code: string
+        :param error_code: The error code associated to a ClientError exception
+
+        :rtype: ClientError or a subclass of ClientError
+        :returns: The appropriate modeled exception class for that error
+            code. If the error code does not match any of the known
+            modeled exceptions then return a generic ClientError.
+        """
+        return self._code_to_exception.get(error_code, self.ClientError)
+
+    def __getattr__(self, name):
+        exception_cls_names = [
+            exception_cls.__name__ for exception_cls
+            in self._code_to_exception.values()
+        ]
+        raise AttributeError(
+            '%r object has no attribute %r. Valid exceptions are: %s' % (
+                self, name, ', '.join(exception_cls_names)))
+
+
+class ClientExceptionsFactory(object):
+    def __init__(self):
+        self._client_exceptions_cache = {}
+
+    def create_client_exceptions(self, service_model):
+        """Creates a ClientExceptions object for the particular service client
+
+        :type service_model: botocore.model.ServiceModel
+        :param service_model: The service model for the client
+
+        :rtype: object that subclasses from BaseClientExceptions
+        :returns: The exceptions object of a client that can be used
+            to grab the various different modeled exceptions.
+        """
+        service_name = service_model.service_name
+        if service_name not in self._client_exceptions_cache:
+            client_exceptions = self._create_client_exceptions(service_model)
+            self._client_exceptions_cache[service_name] = client_exceptions
+        return self._client_exceptions_cache[service_name]
+
+    def _create_client_exceptions(self, service_model):
+        cls_props = {}
+        code_to_exception = {}
+        for shape_name in service_model.shape_names:
+            shape = service_model.shape_for(shape_name)
+            if shape.metadata.get('exception', False):
+                exception_name = str(shape.name)
+                exception_cls = type(exception_name, (ClientError,), {})
+                code = shape.metadata.get("error", {}).get("code")
+                cls_props[exception_name] = exception_cls
+                if code:
+                    code_to_exception[code] = exception_cls
+                else:
+                    # Use the exception name if there is no explicit code
+                    # modeled
+                    code_to_exception[exception_name] = exception_cls
+        cls_name = str(get_service_module_name(service_model) + 'Exceptions')
+        client_exceptions_cls = type(
+            cls_name, (BaseClientExceptions,), cls_props)
+        return client_exceptions_cls(code_to_exception)
diff --git a/botocore/model.py b/botocore/model.py
index a33c2edbc..ff78b5416 100644
--- a/botocore/model.py
+++ b/botocore/model.py
@@ -50,7 +50,7 @@ class Shape(object):
                         'payload', 'streaming', 'timestampFormat',
                         'xmlNamespace', 'resultWrapper', 'xmlAttribute']
     METADATA_ATTRS = ['required', 'min', 'max', 'sensitive', 'enum',
-                      'idempotencyToken']
+                      'idempotencyToken', 'error', 'exception']
     MAP_TYPE = OrderedDict
 
     def __init__(self, shape_name, shape_model, shape_resolver=None):
@@ -243,6 +243,10 @@ class ServiceModel(object):
     def resolve_shape_ref(self, shape_ref):
         return self._shape_resolver.resolve_shape_ref(shape_ref)
 
+    @CachedProperty
+    def shape_names(self):
+        return list(self._service_description.get('shapes', {}))
+
     @instance_cache
     def operation_model(self, operation_name):
         try:
@@ -419,6 +423,11 @@ class OperationModel(object):
                 if 'idempotencyToken' in shape.metadata and
                 shape.metadata['idempotencyToken']]
 
+    @CachedProperty
+    def error_shapes(self):
+        shapes = self._operation_model.get("errors", [])
+        return list(self._service_model.resolve_shape_ref(s) for s in shapes)
+
     @CachedProperty
     def has_streaming_input(self):
         return self.get_streaming_input() is not None
diff --git a/botocore/session.py b/botocore/session.py
index 14794f038..4dacd7969 100644
--- a/botocore/session.py
+++ b/botocore/session.py
@@ -27,6 +27,7 @@ import botocore.credentials
 import botocore.client
 from botocore.exceptions import ConfigNotFound, ProfileNotFound
 from botocore.exceptions import UnknownServiceError, PartialCredentialsError
+from botocore.errorfactory import ClientExceptionsFactory
 from botocore import handlers
 from botocore.hooks import HierarchicalEmitter, first_non_none_response
 from botocore.loaders import create_loader
@@ -164,6 +165,7 @@ class Session(object):
         self._register_endpoint_resolver()
         self._register_event_emitter()
         self._register_response_parser_factory()
+        self._register_exceptions_factory()
 
     def _register_event_emitter(self):
         self._components.register_component('event_emitter', self._events)
@@ -190,6 +192,10 @@ class Session(object):
         self._components.register_component('response_parser_factory',
                                             ResponseParserFactory())
 
+    def _register_exceptions_factory(self):
+        self._components.register_component(
+            'exceptions_factory', ClientExceptionsFactory())
+
     def _register_builtin_handlers(self, events):
         for spec in handlers.BUILTIN_HANDLERS:
             if len(spec) == 2:
@@ -818,9 +824,11 @@ class Session(object):
         else:
             credentials = self.get_credentials()
         endpoint_resolver = self.get_component('endpoint_resolver')
+        exceptions_factory = self.get_component('exceptions_factory')
         client_creator = botocore.client.ClientCreator(
             loader, endpoint_resolver, self.user_agent(), event_emitter,
-            retryhandler, translate, response_parser_factory)
+            retryhandler, translate, response_parser_factory,
+            exceptions_factory)
         client = client_creator.create_client(
             service_name=service_name, region_name=region_name,
             is_secure=use_ssl, endpoint_url=endpoint_url, verify=verify,
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 02d59f1f4..68a7c6728 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -54,7 +54,7 @@ copyright = u'2013, Mitch Garnaat'
 # The short X.Y version.
 version = '1.4.'
 # The full version, including alpha/beta/rc tags.
-release = '1.4.92'
+release = '1.4.93'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.


Test patch:
diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py
index f36b3baec..73f5775f9 100644
--- a/tests/integration/test_client.py
+++ b/tests/integration/test_client.py
@@ -148,15 +148,45 @@ class TestCreateClients(unittest.TestCase):
                 'cloudformation', region_name='invalid region name')
 
 
-class TestClientErrorMessages(unittest.TestCase):
+class TestClientErrors(unittest.TestCase):
+    def setUp(self):
+        self.session = botocore.session.get_session()
+
     def test_region_mentioned_in_invalid_region(self):
-        session = botocore.session.get_session()
-        client = session.create_client(
+        client = self.session.create_client(
             'cloudformation', region_name='us-east-999')
         with self.assertRaisesRegexp(EndpointConnectionError,
                                      'Could not connect to the endpoint URL'):
             client.list_stacks()
 
+    def test_client_modeled_exception(self):
+        client = self.session.create_client(
+            'dynamodb', region_name='us-west-2')
+        with self.assertRaises(client.exceptions.ResourceNotFoundException):
+            client.describe_table(TableName="NonexistentTable")
+
+    def test_client_modeleded_exception_with_differing_code(self):
+        client = self.session.create_client('iam', region_name='us-west-2')
+        # The NoSuchEntityException should be raised on NoSuchEntity error
+        # code.
+        with self.assertRaises(client.exceptions.NoSuchEntityException):
+            client.get_role(RoleName="NonexistentIAMRole")
+
+    def test_raises_general_client_error_for_non_modeled_exception(self):
+        client = self.session.create_client('ec2', region_name='us-west-2')
+        try:
+            client.describe_regions(DryRun=True)
+        except client.exceptions.ClientError as e:
+            self.assertIs(e.__class__, ClientError)
+
+    def test_can_catch_client_exceptions_across_two_different_clients(self):
+        client = self.session.create_client(
+            'dynamodb', region_name='us-west-2')
+        client2 = self.session.create_client(
+            'dynamodb', region_name='us-west-2')
+        with self.assertRaises(client2.exceptions.ResourceNotFoundException):
+            client.describe_table(TableName="NonexistentTable")
+
 
 class TestClientMeta(unittest.TestCase):
     def setUp(self):
diff --git a/tests/unit/cfg/aws_third_config b/tests/unit/cfg/aws_third_config
new file mode 100644
index 000000000..e718adbf8
--- /dev/null
+++ b/tests/unit/cfg/aws_third_config
@@ -0,0 +1,8 @@
+[default]
+aws_access_key_id = third_foo
+aws_secret_access_key = third_bar
+
+[profile "third"]
+aws_access_key_id = third_fie
+aws_secret_access_key = third_baz
+aws_security_token = third_fiebaz
diff --git a/tests/unit/docs/__init__.py b/tests/unit/docs/__init__.py
index ef23eeca9..918cb5bd2 100644
--- a/tests/unit/docs/__init__.py
+++ b/tests/unit/docs/__init__.py
@@ -79,7 +79,8 @@ class BaseDocsTest(unittest.TestCase):
             loader=self.loader, endpoint_resolver=endpoint_resolver,
             user_agent='user-agent', event_emitter=self.events,
             retry_handler_factory=mock.Mock(),
-            retry_config_translator=mock.Mock())
+            retry_config_translator=mock.Mock(),
+            exceptions_factory=mock.Mock())
 
         self.client = self.creator.create_client('myservice', 'us-east-1')
 
diff --git a/tests/unit/test_args.py b/tests/unit/test_args.py
index 576130a70..3142b1d39 100644
--- a/tests/unit/test_args.py
+++ b/tests/unit/test_args.py
@@ -21,7 +21,7 @@ from botocore.config import Config
 
 class TestCreateClientArgs(unittest.TestCase):
     def setUp(self):
-        self.args_create = args.ClientArgsCreator(None, None, None, None)
+        self.args_create = args.ClientArgsCreator(None, None, None, None, None)
 
     def test_compute_s3_configuration(self):
         scoped_config = {}
@@ -106,10 +106,15 @@ class TestCreateClientArgs(unittest.TestCase):
         )
 
     def test_max_pool_from_client_config_forwarded_to_endpoint_creator(self):
-        args_create = args.ClientArgsCreator(mock.Mock(), None, None, None)
+        args_create = args.ClientArgsCreator(
+            mock.Mock(), None, None, None, None)
         config = botocore.config.Config(max_pool_connections=20)
         service_model = mock.Mock()
-        service_model.metadata = {'protocol': 'query'}
+        service_model.metadata = {
+            'serviceFullName': 'MyService',
+            'protocol': 'query'
+        }
+        service_model.operation_names = []
         bridge = mock.Mock()
         bridge.resolve.return_value = {
             'region_name': 'us-west-2', 'signature_version': 'v4',
diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
index e97097ab8..c76089541 100644
--- a/tests/unit/test_client.py
+++ b/tests/unit/test_client.py
@@ -27,6 +27,8 @@ from botocore.exceptions import InvalidS3AddressingStyleError
 from botocore.exceptions import NoRegionError
 from botocore.exceptions import UnknownEndpointError
 from botocore.exceptions import UnknownSignatureVersionError
+from botocore.errorfactory import ClientExceptionsFactory
+from botocore.stub import Stubber
 from botocore import exceptions
 from botocore.compat import six
 
@@ -49,6 +51,7 @@ class TestAutoGeneratedClient(unittest.TestCase):
                         'requestUri': '/',
                     },
                     'input': {'shape': 'TestOperationRequest'},
+                    'errors': [{'shape': 'TestOperationException'}],
                     'documentation': 'Documents TestOperation'
                 }
             },
@@ -63,6 +66,13 @@ class TestAutoGeneratedClient(unittest.TestCase):
                                 'documentation': 'Documents Bar'},
                     }
                 },
+                "TestOperationException": {
+                    'type': 'structure',
+                    'exception': True,
+                    'error': {
+                        'code': 'TestOperationErrorCode'
+                    }
+                },
                 'StringType': {'type': 'string'}
             }
         }
@@ -111,7 +121,8 @@ class TestAutoGeneratedClient(unittest.TestCase):
                               retry_handler_factory=None,
                               retry_config_translator=None,
                               response_parser_factory=None,
-                              endpoint_prefix=None):
+                              endpoint_prefix=None,
+                              exceptions_factory=None):
         if event_emitter is None:
             event_emitter = hooks.HierarchicalEmitter()
         if retry_handler_factory is None:
@@ -124,10 +135,12 @@ class TestAutoGeneratedClient(unittest.TestCase):
 
         if endpoint_creator is not None:
             self.endpoint_creator_cls.return_value = endpoint_creator
+        if exceptions_factory is None:
+            exceptions_factory = ClientExceptionsFactory()
         creator = client.ClientCreator(
             self.loader, self.resolver, 'user-agent', event_emitter,
             retry_handler_factory, retry_config_translator,
-            response_parser_factory)
+            response_parser_factory, exceptions_factory)
         return creator
 
     def assert_no_param_error_raised(self, client):
@@ -268,6 +281,21 @@ class TestAutoGeneratedClient(unittest.TestCase):
         self.assertEqual(service_client.meta.partition,
                          'aws-cn')
 
+    def test_client_has_exceptions_attribute(self):
+        creator = self.create_client_creator()
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+        self.assertTrue(hasattr(service_client, 'exceptions'))
+
+    def test_client_has_modeled_exceptions(self):
+        creator = self.create_client_creator()
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+        self.assertTrue(
+            issubclass(service_client.exceptions.TestOperationException,
+                       client.ClientError)
+        )
+
     def test_api_version_is_passed_to_loader_if_provided(self):
         creator = self.create_client_creator()
         self.endpoint.host = 'https://foo.bar'
@@ -528,20 +556,6 @@ class TestAutoGeneratedClient(unittest.TestCase):
         signer_mock.assert_called_with(
             'test_operation', request)
 
-    def test_client_makes_call_with_error(self):
-        error_response = {
-            'Error': {'Code': 'code', 'Message': 'error occurred'}
-        }
-        self.endpoint.make_request.return_value = (
-            mock.Mock(status_code=400), error_response)
-
-        creator = self.create_client_creator()
-
-        service_client = creator.create_client(
-            'myservice', 'us-west-2', credentials=self.credentials)
-        with self.assertRaises(client.ClientError):
-            service_client.test_operation(Foo='one', Bar='two')
-
     def test_client_validates_params_by_default(self):
         creator = self.create_client_creator()
 
@@ -1355,6 +1369,137 @@ class TestAutoGeneratedClient(unittest.TestCase):
         self.assertFalse(self.endpoint.make_request.called)
 
 
+class TestClientErrors(TestAutoGeneratedClient):
+    def add_error_response(self, error_response):
+        self.endpoint.make_request.return_value = (
+            mock.Mock(status_code=400), error_response)
+
+    def test_client_makes_call_with_error(self):
+        creator = self.create_client_creator()
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        with Stubber(client) as stub:
+            stub.add_client_error(
+                'test_operation', 'TestOperationErrorCode', 'error occurred')
+            with self.assertRaises(client.exceptions.TestOperationException):
+                client.test_operation(Foo='one', Bar='two')
+
+    def test_error_with_no_wire_code(self):
+        creator = self.create_client_creator()
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        with Stubber(client) as stub:
+            stub.add_client_error('test_operation', '404', 'Not Found')
+            try:
+                client.test_operation(Foo='one', Bar='two')
+            except client.exceptions.ClientError as e:
+                # This is needed becasue the error could be a subclass of
+                # ClientError.
+                # We explicitly want it to be a generic ClientError though
+                self.assertEqual(e.__class__, exceptions.ClientError)
+
+    def test_error_with_dot_separated_code(self):
+        creator = self.create_client_creator()
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        with Stubber(client) as stub:
+            stub.add_client_error(
+                'test_operation', 'InvalidAddress.NotFound', 'Not Found')
+            try:
+                client.test_operation(Foo='one', Bar='two')
+            except client.exceptions.ClientError as e:
+                # This is needed becasue the error could be a subclass of
+                # ClientError.
+                # We explicitly want it to be a generic ClientError though
+                self.assertEqual(e.__class__, exceptions.ClientError)
+
+    def test_error_with_empty_message(self):
+        creator = self.create_client_creator()
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        with Stubber(client) as stub:
+            stub.add_client_error(
+                'test_operation', 'TestOperationErrorCode')
+            with self.assertRaises(client.exceptions.TestOperationException):
+                client.test_operation(Foo='one', Bar='two')
+
+    def test_error_with_empty_code(self):
+        creator = self.create_client_creator()
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        with Stubber(client) as stub:
+            stub.add_client_error('test_operation')
+            try:
+                client.test_operation(Foo='one', Bar='two')
+            except client.exceptions.ClientError as e:
+                # This is needed becasue the error could be a subclass of
+                # ClientError.
+                # We explicitly want it to be a generic ClientError though
+                self.assertEqual(e.__class__, exceptions.ClientError)
+
+    def test_error_with_missing_code(self):
+        error_response = {'Error': {'Message': 'error occurred'}}
+        # The stubber is not being used because it will always populate the
+        # the message and code.
+        self.endpoint.make_request.return_value = (
+            mock.Mock(status_code=400), error_response)
+
+        creator = self.create_client_creator()
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        try:
+            client.test_operation(Foo='one', Bar='two')
+        except client.exceptions.ClientError as e:
+            # This is needed becasue the error could be a subclass of
+            # ClientError.
+            # We explicitly want it to be a generic ClientError though
+            self.assertEqual(e.__class__, exceptions.ClientError)
+
+    def test_error_with_empty_contents(self):
+        error_response = {'Error': {}}
+        # The stubber is not being used because it will always populate the
+        # the message and code.
+        self.endpoint.make_request.return_value = (
+            mock.Mock(status_code=400), error_response)
+
+        creator = self.create_client_creator()
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        try:
+            client.test_operation(Foo='one', Bar='two')
+        except client.exceptions.ClientError as e:
+            # This is needed becasue the error could be a subclass of
+            # ClientError.
+            # We explicitly want it to be a generic ClientError though
+            self.assertEqual(e.__class__, exceptions.ClientError)
+
+    def test_exception_classes_across_clients_are_the_same(self):
+        creator = self.create_client_creator(
+            exceptions_factory=ClientExceptionsFactory())
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+        client2 = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        with Stubber(client) as stub:
+            stub.add_client_error(
+                'test_operation', 'TestOperationErrorCode', 'error occurred')
+            try:
+                client.test_operation(Foo='one', Bar='two')
+            except client2.exceptions.TestOperationException as e:
+                # Caught exception should as well be an instance of the
+                # other client's TestOperationException
+                self.assertIsInstance(
+                    e, client.exceptions.TestOperationException)
+
+
 class TestConfig(unittest.TestCase):
     def test_can_use_args_to_construct(self):
         config = botocore.config.Config(*botocore.config.Config.OPTION_DEFAULTS.values())
diff --git a/tests/unit/test_configloader.py b/tests/unit/test_configloader.py
index 8ca139eef..e20aba72f 100644
--- a/tests/unit/test_configloader.py
+++ b/tests/unit/test_configloader.py
@@ -15,7 +15,8 @@
 from tests import unittest, BaseEnvVar
 import os
 import botocore.exceptions
-from botocore.configloader import raw_config_parse, load_config
+from botocore.configloader import raw_config_parse, load_config, \
+    multi_file_load_config
 
 
 def path(filename):
@@ -84,6 +85,24 @@ class TestConfigLoader(BaseEnvVar):
         with self.assertRaises(botocore.exceptions.ConfigParseError):
             loaded_config = load_config(filename)
 
+    def test_multi_file_load(self):
+        filenames = [path('aws_config_other'),
+                     path('aws_config'),
+                     path('aws_third_config'),
+                     path('aws_config_notfound')]
+        loaded_config = multi_file_load_config(*filenames)
+        config = loaded_config['profiles']['default']
+        self.assertEqual(config['aws_access_key_id'], 'other_foo')
+        self.assertEqual(config['aws_secret_access_key'], 'other_bar')
+        second_config = loaded_config['profiles']['personal']
+        self.assertEqual(second_config['aws_access_key_id'], 'fie')
+        self.assertEqual(second_config['aws_secret_access_key'], 'baz')
+        self.assertEqual(second_config['aws_security_token'], 'fiebaz')
+        third_config = loaded_config['profiles']['third']
+        self.assertEqual(third_config['aws_access_key_id'], 'third_fie')
+        self.assertEqual(third_config['aws_secret_access_key'], 'third_baz')
+        self.assertEqual(third_config['aws_security_token'], 'third_fiebaz')
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/unit/test_errorfactory.py b/tests/unit/test_errorfactory.py
new file mode 100644
index 000000000..5b6f6a005
--- /dev/null
+++ b/tests/unit/test_errorfactory.py
@@ -0,0 +1,133 @@
+# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"). You
+# may not use this file except in compliance with the License. A copy of
+# the License is located at
+#
+# http://aws.amazon.com/apache2.0/
+#
+# or in the "license" file accompanying this file. This file is
+# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
+# ANY KIND, either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+from tests import unittest
+
+from botocore.exceptions import ClientError
+from botocore.errorfactory import BaseClientExceptions
+from botocore.errorfactory import ClientExceptionsFactory
+from botocore.model import ServiceModel
+
+
+class TestBaseClientExceptions(unittest.TestCase):
+    def setUp(self):
+        self.code_to_exception = {}
+        self.exceptions = BaseClientExceptions(self.code_to_exception)
+
+    def test_has_client_error(self):
+        self.assertIs(self.exceptions.ClientError, ClientError)
+
+    def test_from_code(self):
+        exception_cls = type('MyException', (ClientError,), {})
+        self.code_to_exception['MyExceptionCode'] = exception_cls
+        self.assertIs(
+            self.exceptions.from_code('MyExceptionCode'), exception_cls)
+
+    def test_from_code_nonmatch_defaults_to_client_error(self):
+        self.assertIs(
+            self.exceptions.from_code('SomeUnknownErrorCode'), ClientError)
+
+    def test_gettattr_message(self):
+        exception_cls = type('MyException', (ClientError,), {})
+        self.code_to_exception['MyExceptionCode'] = exception_cls
+        with self.assertRaisesRegexp(
+                AttributeError, 'Valid exceptions are: MyException'):
+            self.exceptions.SomeUnmodeledError
+
+
+class TestClientExceptionsFactory(unittest.TestCase):
+    def setUp(self):
+        self.model = {
+            "metadata": {
+                'endpointPrefix': 'myservice',
+                'serviceFullName': 'MyService',
+            },
+            'operations': {
+                'OperationName': {
+                    'name': 'OperationName',
+                    'errors': [
+                        {'shape': 'ExceptionMissingCode'},
+                        {'shape': 'ExceptionWithModeledCode'},
+                    ],
+                },
+                'AnotherOperationName': {
+                    'name': 'AnotherOperationName',
+                    'errors': [
+                        {'shape': 'ExceptionForAnotherOperation'},
+                        {'shape': 'ExceptionWithModeledCode'},
+                    ],
+                }
+            },
+            'shapes': {
+                'ExceptionWithModeledCode': {
+                    'type': 'structure',
+                    'members': {},
+                    'error': {
+                        'code': 'ModeledCode'
+                    },
+                    'exception': True,
+                },
+                'ExceptionMissingCode': {
+                    'type': 'structure',
+                    'members': {},
+                    'exception': True,
+                },
+                'ExceptionForAnotherOperation': {
+                    'type': 'structure',
+                    'members': {},
+                    'exception': True,
+                }
+            }
+        }
+        self.service_model = ServiceModel(self.model)
+        self.exceptions_factory = ClientExceptionsFactory()
+
+    def test_class_name(self):
+        exceptions = self.exceptions_factory.create_client_exceptions(
+            self.service_model)
+        self.assertEqual(exceptions.__class__.__name__, 'MyServiceExceptions')
+
+    def test_creates_modeled_exception(self):
+        exceptions = self.exceptions_factory.create_client_exceptions(
+            self.service_model)
+        self.assertTrue(hasattr(exceptions, 'ExceptionWithModeledCode'))
+        modeled_exception = exceptions.ExceptionWithModeledCode
+        self.assertEqual(
+            modeled_exception.__name__, 'ExceptionWithModeledCode')
+        self.assertTrue(issubclass(modeled_exception, ClientError))
+
+    def test_collects_modeled_exceptions_for_all_operations(self):
+        exceptions = self.exceptions_factory.create_client_exceptions(
+            self.service_model)
+        # Make sure exceptions were added for all operations by checking
+        # an exception only found on an a different operation.
+        self.assertTrue(hasattr(exceptions, 'ExceptionForAnotherOperation'))
+        modeled_exception = exceptions.ExceptionForAnotherOperation
+        self.assertEqual(
+            modeled_exception.__name__, 'ExceptionForAnotherOperation')
+        self.assertTrue(issubclass(modeled_exception, ClientError))
+
+    def test_creates_modeled_exception_mapping_that_has_code(self):
+        exceptions = self.exceptions_factory.create_client_exceptions(
+            self.service_model)
+        exception = exceptions.from_code('ModeledCode')
+        self.assertEqual(exception.__name__, 'ExceptionWithModeledCode')
+        self.assertTrue(issubclass(exception, ClientError))
+
+    def test_creates_modeled_exception_mapping_that_has_no_code(self):
+        exceptions = self.exceptions_factory.create_client_exceptions(
+            self.service_model)
+        # For exceptions that do not have an explicit code associated to them,
+        # the code is the name of the exception.
+        exception = exceptions.from_code('ExceptionMissingCode')
+        self.assertEqual(exception.__name__, 'ExceptionMissingCode')
+        self.assertTrue(issubclass(exception, ClientError))
diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py
index 5d5ff6579..368792183 100644
--- a/tests/unit/test_model.py
+++ b/tests/unit/test_model.py
@@ -38,7 +38,9 @@ class TestServiceModel(unittest.TestCase):
                          'endpointPrefix': 'endpoint-prefix'},
             'documentation': 'Documentation value',
             'operations': {},
-            'shapes': {}
+            'shapes': {
+                'StringShape': {'type': 'string'}
+            }
         }
         self.service_model = model.ServiceModel(self.model)
 
@@ -66,6 +68,9 @@ class TestServiceModel(unittest.TestCase):
         self.assertEqual(self.service_model.documentation,
                          'Documentation value')
 
+    def test_shape_names(self):
+        self.assertEqual(self.service_model.shape_names, ['StringShape'])
+
 
 class TestOperationModelFromService(unittest.TestCase):
     def setUp(self):
@@ -188,6 +193,14 @@ class TestOperationModelFromService(unittest.TestCase):
         output_shape = operation.output_shape
         self.assertIsNone(output_shape)
 
+    def test_error_shapes(self):
+        service_model = model.ServiceModel(self.model)
+        operation = service_model.operation_model('OperationName')
+        # OperationName only has a NoSuchResourceException
+        self.assertEqual(len(operation.error_shapes), 1)
+        self.assertEqual(
+            operation.error_shapes[0].name, 'NoSuchResourceException')
+
 
 class TestOperationModelStreamingTypes(unittest.TestCase):
     def setUp(self):