99
1010import botocore .client
1111import botocore .exceptions
12- from botocore .awsrequest import AWSPreparedRequest , create_request_object
1312from botocore .client import ClientError
1413from botocore .exceptions import BotoCoreError
1514from botocore .session import get_session
4241from pynamodb .expressions .operand import Path
4342from pynamodb .expressions .projection import create_projection_expression
4443from pynamodb .expressions .update import Action , Update
45- from pynamodb .settings import get_settings_value , OperationSettings
44+ from pynamodb .settings import get_settings_value
4645from pynamodb .signals import pre_dynamodb_send , post_dynamodb_send
4746from pynamodb .types import HASH , RANGE
4847
@@ -281,28 +280,7 @@ def __init__(self,
281280 def __repr__ (self ) -> str :
282281 return "Connection<{}>" .format (self .client .meta .endpoint_url )
283282
284- def _sign_request (self , request ):
285- auth = self .client ._request_signer .get_auth_instance (
286- self .client ._request_signer .signing_name ,
287- self .client ._request_signer .region_name ,
288- self .client ._request_signer .signature_version )
289- auth .add_auth (request )
290-
291- def _create_prepared_request (
292- self ,
293- params : Dict ,
294- settings : OperationSettings ,
295- ) -> AWSPreparedRequest :
296- request = create_request_object (params )
297- self ._sign_request (request )
298- prepared_request = self .client ._endpoint .prepare_request (request )
299- if self ._extra_headers is not None :
300- prepared_request .headers .update (self ._extra_headers )
301- if settings .extra_headers is not None :
302- prepared_request .headers .update (settings .extra_headers )
303- return prepared_request
304-
305- def dispatch (self , operation_name : str , operation_kwargs : Dict , settings : OperationSettings = OperationSettings .default ) -> Dict :
283+ def dispatch (self , operation_name : str , operation_kwargs : Dict ) -> Dict :
306284 """
307285 Dispatches `operation_name` with arguments `operation_kwargs`
308286
@@ -317,7 +295,7 @@ def dispatch(self, operation_name: str, operation_kwargs: Dict, settings: Operat
317295 req_uuid = uuid .uuid4 ()
318296
319297 self .send_pre_boto_callback (operation_name , req_uuid , table_name )
320- data = self ._make_api_call (operation_name , operation_kwargs , settings )
298+ data = self ._make_api_call (operation_name , operation_kwargs )
321299 self .send_post_boto_callback (operation_name , req_uuid , table_name )
322300
323301 if data and CONSUMED_CAPACITY in data :
@@ -330,17 +308,47 @@ def dispatch(self, operation_name: str, operation_kwargs: Dict, settings: Operat
330308 def send_post_boto_callback (self , operation_name , req_uuid , table_name ):
331309 try :
332310 post_dynamodb_send .send (self , operation_name = operation_name , table_name = table_name , req_uuid = req_uuid )
333- except Exception as e :
311+ except Exception :
334312 log .exception ("post_boto callback threw an exception." )
335313
336314 def send_pre_boto_callback (self , operation_name , req_uuid , table_name ):
337315 try :
338316 pre_dynamodb_send .send (self , operation_name = operation_name , table_name = table_name , req_uuid = req_uuid )
339- except Exception as e :
317+ except Exception :
340318 log .exception ("pre_boto callback threw an exception." )
341319
342- def _make_api_call (self , operation_name : str , operation_kwargs : Dict , settings : OperationSettings = OperationSettings .default ) -> Dict :
343- return self .client ._make_api_call (operation_name , operation_kwargs )
320+ def _before_sign (self , request , ** _ ) -> None :
321+ if self ._extra_headers is not None :
322+ for k , v in self ._extra_headers .items ():
323+ request .headers .add_header (k , v )
324+
325+ def _make_api_call (self , operation_name : str , operation_kwargs : Dict ) -> Dict :
326+ try :
327+ return self .client ._make_api_call (operation_name , operation_kwargs )
328+ except ClientError as e :
329+ resp_metadata = e .response .get ('ResponseMetadata' , {}).get ('HTTPHeaders' , {})
330+
331+ botocore_props = {'Error' : e .response .get ('Error' , {})}
332+ verbose_props = {
333+ 'request_id' : resp_metadata .get ('x-amzn-requestid' , '' ),
334+ 'table_name' : self ._get_table_name_for_error_context (operation_kwargs ),
335+ }
336+ raise VerboseClientError (botocore_props , operation_name , verbose_props ) from e
337+
338+ # todo: should we handle generic BotoCoreError here too?
339+ # todo: should we handle generic HTTPClientError here too? e.g. for timeout
340+
341+ def _get_table_name_for_error_context (self , operation_kwargs ) -> str :
342+ # First handle the two multi-table cases: batch and transaction operations
343+ if REQUEST_ITEMS in operation_kwargs :
344+ return ',' .join (operation_kwargs [REQUEST_ITEMS ])
345+ elif TRANSACT_ITEMS in operation_kwargs :
346+ return "," .join (
347+ op [TABLE_NAME ] for op in (
348+ item for item in operation_kwargs [TRANSACT_ITEMS ]
349+ )
350+ )
351+ return operation_kwargs .get (TABLE_NAME )
344352
345353 @property
346354 def session (self ) -> botocore .session .Session :
@@ -373,6 +381,8 @@ def client(self):
373381 }
374382 )
375383 self ._client = self .session .create_client (SERVICE_NAME , self .region , endpoint_url = self .host , config = config )
384+
385+ self ._client .meta .events .register_first ('before-sign.*.*' , self ._before_sign )
376386 return self ._client
377387
378388 def get_meta_table (self , table_name : str , refresh : bool = False ):
@@ -780,7 +790,6 @@ def delete_item(
780790 return_values : Optional [str ] = None ,
781791 return_consumed_capacity : Optional [str ] = None ,
782792 return_item_collection_metrics : Optional [str ] = None ,
783- settings : OperationSettings = OperationSettings .default ,
784793 ) -> Dict :
785794 """
786795 Performs the DeleteItem operation and returns the result
@@ -795,7 +804,7 @@ def delete_item(
795804 return_item_collection_metrics = return_item_collection_metrics
796805 )
797806 try :
798- return self .dispatch (DELETE_ITEM , operation_kwargs , settings )
807+ return self .dispatch (DELETE_ITEM , operation_kwargs )
799808 except BOTOCORE_EXCEPTIONS as e :
800809 raise DeleteError ("Failed to delete item: {}" .format (e ), e )
801810
@@ -809,7 +818,6 @@ def update_item(
809818 return_consumed_capacity : Optional [str ] = None ,
810819 return_item_collection_metrics : Optional [str ] = None ,
811820 return_values : Optional [str ] = None ,
812- settings : OperationSettings = OperationSettings .default ,
813821 ) -> Dict :
814822 """
815823 Performs the UpdateItem operation
@@ -828,7 +836,7 @@ def update_item(
828836 return_item_collection_metrics = return_item_collection_metrics ,
829837 )
830838 try :
831- return self .dispatch (UPDATE_ITEM , operation_kwargs , settings )
839+ return self .dispatch (UPDATE_ITEM , operation_kwargs )
832840 except BOTOCORE_EXCEPTIONS as e :
833841 raise UpdateError ("Failed to update item: {}" .format (e ), e )
834842
@@ -842,7 +850,6 @@ def put_item(
842850 return_values : Optional [str ] = None ,
843851 return_consumed_capacity : Optional [str ] = None ,
844852 return_item_collection_metrics : Optional [str ] = None ,
845- settings : OperationSettings = OperationSettings .default ,
846853 ) -> Dict :
847854 """
848855 Performs the PutItem operation and returns the result
@@ -859,7 +866,7 @@ def put_item(
859866 return_item_collection_metrics = return_item_collection_metrics
860867 )
861868 try :
862- return self .dispatch (PUT_ITEM , operation_kwargs , settings )
869+ return self .dispatch (PUT_ITEM , operation_kwargs )
863870 except BOTOCORE_EXCEPTIONS as e :
864871 raise PutError ("Failed to put item: {}" .format (e ), e )
865872
@@ -888,7 +895,6 @@ def transact_write_items(
888895 client_request_token : Optional [str ] = None ,
889896 return_consumed_capacity : Optional [str ] = None ,
890897 return_item_collection_metrics : Optional [str ] = None ,
891- settings : OperationSettings = OperationSettings .default ,
892898 ) -> Dict :
893899 """
894900 Performs the TransactWrite operation and returns the result
@@ -915,15 +921,14 @@ def transact_write_items(
915921 operation_kwargs [TRANSACT_ITEMS ] = transact_items
916922
917923 try :
918- return self .dispatch (TRANSACT_WRITE_ITEMS , operation_kwargs , settings )
924+ return self .dispatch (TRANSACT_WRITE_ITEMS , operation_kwargs )
919925 except BOTOCORE_EXCEPTIONS as e :
920926 raise TransactWriteError ("Failed to write transaction items" , e )
921927
922928 def transact_get_items (
923929 self ,
924930 get_items : Sequence [Dict ],
925931 return_consumed_capacity : Optional [str ] = None ,
926- settings : OperationSettings = OperationSettings .default ,
927932 ) -> Dict :
928933 """
929934 Performs the TransactGet operation and returns the result
@@ -934,7 +939,7 @@ def transact_get_items(
934939 ]
935940
936941 try :
937- return self .dispatch (TRANSACT_GET_ITEMS , operation_kwargs , settings )
942+ return self .dispatch (TRANSACT_GET_ITEMS , operation_kwargs )
938943 except BOTOCORE_EXCEPTIONS as e :
939944 raise TransactGetError ("Failed to get transaction items" , e )
940945
@@ -945,7 +950,6 @@ def batch_write_item(
945950 delete_items : Optional [Any ] = None ,
946951 return_consumed_capacity : Optional [str ] = None ,
947952 return_item_collection_metrics : Optional [str ] = None ,
948- settings : OperationSettings = OperationSettings .default ,
949953 ) -> Dict :
950954 """
951955 Performs the batch_write_item operation
@@ -975,7 +979,7 @@ def batch_write_item(
975979 })
976980 operation_kwargs [REQUEST_ITEMS ][table_name ] = delete_items_list + put_items_list
977981 try :
978- return self .dispatch (BATCH_WRITE_ITEM , operation_kwargs , settings )
982+ return self .dispatch (BATCH_WRITE_ITEM , operation_kwargs )
979983 except BOTOCORE_EXCEPTIONS as e :
980984 raise PutError ("Failed to batch write items: {}" .format (e ), e )
981985
@@ -986,7 +990,6 @@ def batch_get_item(
986990 consistent_read : Optional [bool ] = None ,
987991 return_consumed_capacity : Optional [str ] = None ,
988992 attributes_to_get : Optional [Any ] = None ,
989- settings : OperationSettings = OperationSettings .default ,
990993 ) -> Dict :
991994 """
992995 Performs the batch get item operation
@@ -1017,7 +1020,7 @@ def batch_get_item(
10171020 )
10181021 operation_kwargs [REQUEST_ITEMS ][table_name ].update (keys_map )
10191022 try :
1020- return self .dispatch (BATCH_GET_ITEM , operation_kwargs , settings )
1023+ return self .dispatch (BATCH_GET_ITEM , operation_kwargs )
10211024 except BOTOCORE_EXCEPTIONS as e :
10221025 raise GetError ("Failed to batch get items: {}" .format (e ), e )
10231026
@@ -1028,7 +1031,6 @@ def get_item(
10281031 range_key : Optional [str ] = None ,
10291032 consistent_read : bool = False ,
10301033 attributes_to_get : Optional [Any ] = None ,
1031- settings : OperationSettings = OperationSettings .default ,
10321034 ) -> Dict :
10331035 """
10341036 Performs the GetItem operation and returns the result
@@ -1041,7 +1043,7 @@ def get_item(
10411043 attributes_to_get = attributes_to_get
10421044 )
10431045 try :
1044- return self .dispatch (GET_ITEM , operation_kwargs , settings )
1046+ return self .dispatch (GET_ITEM , operation_kwargs )
10451047 except BOTOCORE_EXCEPTIONS as e :
10461048 raise GetError ("Failed to get item: {}" .format (e ), e )
10471049
@@ -1057,7 +1059,6 @@ def scan(
10571059 total_segments : Optional [int ] = None ,
10581060 consistent_read : Optional [bool ] = None ,
10591061 index_name : Optional [str ] = None ,
1060- settings : OperationSettings = OperationSettings .default ,
10611062 ) -> Dict :
10621063 """
10631064 Performs the scan operation
@@ -1094,7 +1095,7 @@ def scan(
10941095 operation_kwargs [EXPRESSION_ATTRIBUTE_VALUES ] = expression_attribute_values
10951096
10961097 try :
1097- return self .dispatch (SCAN , operation_kwargs , settings )
1098+ return self .dispatch (SCAN , operation_kwargs )
10981099 except BOTOCORE_EXCEPTIONS as e :
10991100 raise ScanError ("Failed to scan table: {}" .format (e ), e )
11001101
@@ -1112,7 +1113,6 @@ def query(
11121113 return_consumed_capacity : Optional [str ] = None ,
11131114 scan_index_forward : Optional [bool ] = None ,
11141115 select : Optional [str ] = None ,
1115- settings : OperationSettings = OperationSettings .default ,
11161116 ) -> Dict :
11171117 """
11181118 Performs the Query operation and returns the result
@@ -1169,7 +1169,7 @@ def query(
11691169 operation_kwargs [EXPRESSION_ATTRIBUTE_VALUES ] = expression_attribute_values
11701170
11711171 try :
1172- return self .dispatch (QUERY , operation_kwargs , settings )
1172+ return self .dispatch (QUERY , operation_kwargs )
11731173 except BOTOCORE_EXCEPTIONS as e :
11741174 raise QueryError ("Failed to query items: {}" .format (e ), e )
11751175
0 commit comments