6363 + BoltFailure
6464 + BoltProtocolError
6565 + Bolt*
66-
6766"""
6867
68+
69+ from .meta import deprecated
70+
71+
6972CLASSIFICATION_CLIENT = "ClientError"
7073CLASSIFICATION_TRANSIENT = "TransientError"
7174CLASSIFICATION_DATABASE = "DatabaseError"
7275
7376
77+ ERROR_REWRITE_MAP = {
78+ # This error can be retried ed. The driver just needs to re-authenticate
79+ # with the same credentials.
80+ "Neo.ClientError.Security.AuthorizationExpired" : (
81+ CLASSIFICATION_TRANSIENT , None
82+ ),
83+ # In 5.0, this error has been re-classified as ClientError.
84+ # For backwards compatibility with Neo4j 4.4 and earlier, we re-map it in
85+ # the driver, too.
86+ "Neo.TransientError.Transaction.Terminated" : (
87+ CLASSIFICATION_CLIENT , "Neo.ClientError.Transaction.Terminated"
88+ ),
89+ # In 5.0, this error has been re-classified as ClientError.
90+ # For backwards compatibility with Neo4j 4.4 and earlier, we re-map it in
91+ # the driver, too.
92+ "Neo.TransientError.Transaction.LockClientStopped" : (
93+ CLASSIFICATION_CLIENT , "Neo.ClientError.Transaction.LockClientStopped"
94+ ),
95+ }
96+
97+
7498class Neo4jError (Exception ):
7599 """ Raised when the Cypher engine returns an error to the client.
76100 """
@@ -93,12 +117,17 @@ def hydrate(cls, message=None, code=None, **metadata):
93117 code = code or "Neo.DatabaseError.General.UnknownError"
94118 try :
95119 _ , classification , category , title = code .split ("." )
96- if code == "Neo.ClientError.Security.AuthorizationExpired" :
97- classification = CLASSIFICATION_TRANSIENT
98120 except ValueError :
99121 classification = CLASSIFICATION_DATABASE
100122 category = "General"
101123 title = "UnknownError"
124+ else :
125+ classification_override , code_override = \
126+ ERROR_REWRITE_MAP .get (code , (None , None ))
127+ if classification_override is not None :
128+ classification = classification_override
129+ if code_override is not None :
130+ code = code_override
102131
103132 error_class = cls ._extract_error_class (classification , code )
104133
@@ -131,11 +160,31 @@ def _extract_error_class(cls, classification, code):
131160 else :
132161 return cls
133162
163+ # TODO 6.0: Remove this alias
164+ @deprecated (
165+ "Neo4jError.is_retriable is deprecated and will be removed in a "
166+ "future version. Please use Neo4jError.is_retryable instead."
167+ )
134168 def is_retriable (self ):
135169 """Whether the error is retryable.
136170
137- Indicated whether a transaction that yielded this error makes sense to
138- retry. This methods makes mostly sense when implementing a custom
171+ See :meth:`.is_retryable`.
172+
173+ :return: :const:`True` if the error is retryable,
174+ :const:`False` otherwise.
175+ :rtype: bool
176+
177+ .. deprecated:: 5.0
178+ This method will be removed in a future version.
179+ Please use :meth:`.is_retryable` instead.
180+ """
181+ return self .is_retryable ()
182+
183+ def is_retryable (self ):
184+ """Whether the error is retryable.
185+
186+ Indicates whether a transaction that yielded this error makes sense to
187+ retry. This method makes mostly sense when implementing a custom
139188 retry policy in conjunction with :ref:`explicit-transactions-ref`.
140189
141190 :return: :const:`True` if the error is retryable,
@@ -182,14 +231,8 @@ class TransientError(Neo4jError):
182231 """ The database cannot service the request right now, retrying later might yield a successful outcome.
183232 """
184233
185- def is_retriable (self ):
186- # Transient errors are always retriable.
187- # However, there are some errors that are misclassified by the server.
188- # They should really be ClientErrors.
189- return self .code not in (
190- "Neo.TransientError.Transaction.Terminated" ,
191- "Neo.TransientError.Transaction.LockClientStopped" ,
192- )
234+ def is_retryable (self ):
235+ return True
193236
194237
195238class DatabaseUnavailable (TransientError ):
@@ -285,11 +328,11 @@ class TokenExpired(AuthError):
285328class DriverError (Exception ):
286329 """ Raised when the Driver raises an error.
287330 """
288- def is_retriable (self ):
331+ def is_retryable (self ):
289332 """Whether the error is retryable.
290333
291- Indicated whether a transaction that yielded this error makes sense to
292- retry. This methods makes mostly sense when implementing a custom
334+ Indicates whether a transaction that yielded this error makes sense to
335+ retry. This method makes mostly sense when implementing a custom
293336 retry policy in conjunction with :ref:`explicit-transactions-ref`.
294337
295338 :return: :const:`True` if the error is retryable,
@@ -307,7 +350,7 @@ class SessionExpired(DriverError):
307350 def __init__ (self , session , * args , ** kwargs ):
308351 super (SessionExpired , self ).__init__ (session , * args , ** kwargs )
309352
310- def is_retriable (self ):
353+ def is_retryable (self ):
311354 return True
312355
313356
@@ -349,7 +392,7 @@ class ServiceUnavailable(DriverError):
349392 """ Raised when no database service is available.
350393 """
351394
352- def is_retriable (self ):
395+ def is_retryable (self ):
353396 return True
354397
355398
@@ -377,7 +420,7 @@ class IncompleteCommit(ServiceUnavailable):
377420 successfully or not.
378421 """
379422
380- def is_retriable (self ):
423+ def is_retryable (self ):
381424 return False
382425
383426
0 commit comments