1
1
"""
2
2
PynamoDB exceptions
3
3
"""
4
-
5
- from typing import Any , Optional
4
+ from typing import Any
5
+ from typing import Dict
6
+ from typing import Iterable
7
+ from typing import List
8
+ from typing import Optional
6
9
7
10
import botocore .exceptions
8
11
@@ -99,18 +102,59 @@ def __init__(self, table_name: str) -> None:
99
102
super (TableDoesNotExist , self ).__init__ (msg )
100
103
101
104
105
+ class CancellationReason :
106
+ """
107
+ A reason for a transaction cancellation.
108
+ """
109
+ def __init__ (self , * , code : str , message : Optional [str ]) -> None :
110
+ self .code = code
111
+ self .message = message
112
+
113
+ def __eq__ (self , other : Any ) -> bool :
114
+ return isinstance (other , CancellationReason ) and self .code == other .code and self .message == other .message
115
+
116
+
102
117
class TransactWriteError (PynamoDBException ):
103
118
"""
104
119
Raised when a TransactWrite operation fails
105
120
"""
106
- pass
121
+
122
+ @property
123
+ def cancellation_reasons (self ) -> List [Optional [CancellationReason ]]:
124
+ """
125
+ When :attr:`.cause_response_code` is ``TransactionCanceledException``, this property lists
126
+ cancellation reasons in the same order as the transaction items (one-to-one).
127
+ Items which were not part of the reason for cancellation would have :code:`None` as the value.
128
+
129
+ For a list of possible cancellation reasons and their semantics,
130
+ see `TransactWriteItems`_ in the AWS documentation.
131
+
132
+ .. _TransactWriteItems: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html
133
+ """
134
+ if not isinstance (self .cause , VerboseClientError ):
135
+ return []
136
+ return self .cause .cancellation_reasons
107
137
108
138
109
139
class TransactGetError (PynamoDBException ):
110
140
"""
111
141
Raised when a TransactGet operation fails
112
142
"""
113
- pass
143
+ @property
144
+ def cancellation_reasons (self ) -> List [Optional [CancellationReason ]]:
145
+ """
146
+ When :attr:`.cause_response_code` is ``TransactionCanceledException``, this property lists
147
+ cancellation reasons in the same order as the transaction items (one-to-one).
148
+ Items which were not part of the reason for cancellation would have :code:`None` as the value.
149
+
150
+ For a list of possible cancellation reasons and their semantics,
151
+ see `TransactGetItems`_ in the AWS documentation.
152
+
153
+ .. _TransactGetItems: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html
154
+ """
155
+ if not isinstance (self .cause , VerboseClientError ):
156
+ return []
157
+ return self .cause .cancellation_reasons
114
158
115
159
116
160
class InvalidStateError (PynamoDBException ):
@@ -141,8 +185,24 @@ def prepend_path(self, attr_name: str) -> None:
141
185
142
186
143
187
class VerboseClientError (botocore .exceptions .ClientError ):
144
- def __init__ (self , error_response : Any , operation_name : str , verbose_properties : Optional [Any ] = None ):
145
- """ Modify the message template to include the desired verbose properties """
188
+ def __init__ (
189
+ self ,
190
+ error_response : Dict [str , Any ],
191
+ operation_name : str ,
192
+ verbose_properties : Optional [Any ] = None ,
193
+ * ,
194
+ cancellation_reasons : Iterable [Optional [CancellationReason ]] = (),
195
+ ) -> None :
196
+ """
197
+ Like ClientError, but with a verbose message.
198
+
199
+ :param error_response: Error response in shape expected by ClientError.
200
+ :param operation_name: The name of the operation that failed.
201
+ :param verbose_properties: A dict of properties to include in the verbose message.
202
+ :param cancellation_reasons: For `TransactionCanceledException` error code,
203
+ a list of cancellation reasons in the same order as the transaction's items (one to one).
204
+ For items which were not a reason for the transaction cancellation, :code:`None` will be the value.
205
+ """
146
206
if not verbose_properties :
147
207
verbose_properties = {}
148
208
@@ -152,4 +212,9 @@ def __init__(self, error_response: Any, operation_name: str, verbose_properties:
152
212
'operation: {{error_message}}'
153
213
).format (request_id = verbose_properties .get ('request_id' ), table_name = verbose_properties .get ('table_name' ))
154
214
155
- super (VerboseClientError , self ).__init__ (error_response , operation_name )
215
+ self .cancellation_reasons = list (cancellation_reasons )
216
+
217
+ super (VerboseClientError , self ).__init__ (
218
+ error_response , # type:ignore[arg-type] # in stubs: botocore.exceptions._ClientErrorResponseTypeDef
219
+ operation_name ,
220
+ )
0 commit comments