@@ -219,6 +219,14 @@ class GqlError(Exception):
219219 Instead, only subclasses are raised.
220220 Further, it is used as the :attr:`__cause__` of GqlError subclasses.
221221
222+ Sometimes it is helpful or necessary to traverse the cause chain of
223+ GqlErrors to fully understand or appropriately handle the error. In such
224+ cases, users can either traverse the :attr:`__cause__` attribute of the
225+ error(s) or use the helper method :meth:`.find_by_gql_status`. Note that
226+ :attr:`__cause__` is a standard attribute of all Python
227+ :class:`BaseException` s: the cause chain may contain other exception types
228+ besides GqlError.
229+
222230 .. versionadded: 5.26
223231
224232 .. versionchanged:: 6.0 Stabilized from preview.
@@ -233,6 +241,16 @@ class GqlError(Exception):
233241 _diagnostic_record : dict [str , _t .Any ] # copy to be used externally
234242 _gql_cause : GqlError | None
235243
244+ __cause__ : BaseException | None
245+ """
246+ The GqlError's cause, if any.
247+
248+ Sometimes it is helpful or necessary to traverse the cause chain of
249+ GqlErrors to fully understand or appropriately handle the error.
250+
251+ .. seealso:: :meth:`.find_by_gql_status`
252+ """
253+
236254 @staticmethod
237255 def _hydrate_cause (** metadata : _t .Any ) -> GqlError :
238256 meta_extractor = _MetaExtractor (metadata )
@@ -427,6 +445,36 @@ def _get_status_diagnostic_record(self) -> dict[str, _t.Any]:
427445 self ._status_diagnostic_record = dict (_UNKNOWN_GQL_DIAGNOSTIC_RECORD )
428446 return self ._status_diagnostic_record
429447
448+ def find_by_gql_status (self , status : str ) -> GqlError | None :
449+ """
450+ Return the first GqlError in the cause chain with the given GQL status.
451+
452+ This method traverses this GQLErorrs's :attr:`__cause__` chain,
453+ starting with this error itself, and returns the first error that has
454+ the given GQL status. If no error matches, :data:`None` is returned.
455+
456+ Example::
457+
458+ def invalid_syntax(err: GqlError) -> bool:
459+ return err.find_by_gql_status("42001") is not None
460+
461+ :param status: The GQL status to search for.
462+
463+ :returns: The first matching error or :data:`None`.
464+
465+ .. versionadded:: 6.0
466+ """
467+ if self .gql_status == status :
468+ return self
469+
470+ cause = self .__cause__
471+ while cause is not None :
472+ if isinstance (cause , GqlError ) and cause .gql_status == status :
473+ return cause
474+ cause = getattr (cause , "__cause__" , None )
475+
476+ return None
477+
430478 def __str__ (self ):
431479 return (
432480 f"{{gql_status: { self .gql_status } }} "
0 commit comments