diff --git a/CHANGELOG.md b/CHANGELOG.md index 222c7f81bc..a39f7b8f96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-cloud-spanner/#history +## [3.22.0](https://github.com/googleapis/python-spanner/compare/v3.21.0...v3.22.0) (2022-09-26) + + +### Features + +* Adding reason, domain, metadata & error_details fields in Custom Exceptions for additional info ([#804](https://github.com/googleapis/python-spanner/issues/804)) ([2a74060](https://github.com/googleapis/python-spanner/commit/2a740607a00cb622ac9ce4005c12afd52114b4a5)) + ## [3.21.0](https://github.com/googleapis/python-spanner/compare/v3.20.0...v3.21.0) (2022-09-16) diff --git a/google/cloud/spanner_dbapi/cursor.py b/google/cloud/spanner_dbapi/cursor.py index 0fc36a72a9..4ffeac1a70 100644 --- a/google/cloud/spanner_dbapi/cursor.py +++ b/google/cloud/spanner_dbapi/cursor.py @@ -281,11 +281,11 @@ def execute(self, sql, args=None): self._do_execute_update, sql, args or None ) except (AlreadyExists, FailedPrecondition, OutOfRange) as e: - raise IntegrityError(getattr(e, "details", e)) + raise IntegrityError(getattr(e, "details", e)) from e except InvalidArgument as e: - raise ProgrammingError(getattr(e, "details", e)) + raise ProgrammingError(getattr(e, "details", e)) from e except InternalServerError as e: - raise OperationalError(getattr(e, "details", e)) + raise OperationalError(getattr(e, "details", e)) from e @check_not_closed def executemany(self, operation, seq_of_params): diff --git a/google/cloud/spanner_dbapi/exceptions.py b/google/cloud/spanner_dbapi/exceptions.py index f5f85a752a..723ee34fd2 100644 --- a/google/cloud/spanner_dbapi/exceptions.py +++ b/google/cloud/spanner_dbapi/exceptions.py @@ -14,6 +14,8 @@ """Spanner DB API exceptions.""" +from google.api_core.exceptions import GoogleAPICallError + class Warning(Exception): """Important DB API warning.""" @@ -27,7 +29,65 @@ class Error(Exception): Does not include :class:`Warning`. """ - pass + def _is_error_cause_instance_of_google_api_exception(self): + return isinstance(self.__cause__, GoogleAPICallError) + + @property + def reason(self): + """The reason of the error. + Reference: + https://cloud.google.com/apis/design/errors#error_info + Returns: + Union[str, None]: An optional string containing reason of the error. + """ + return ( + self.__cause__.reason + if self._is_error_cause_instance_of_google_api_exception() + else None + ) + + @property + def domain(self): + """The logical grouping to which the "reason" belongs. + Reference: + https://cloud.google.com/apis/design/errors#error_info + Returns: + Union[str, None]: An optional string containing a logical grouping to which the "reason" belongs. + """ + return ( + self.__cause__.domain + if self._is_error_cause_instance_of_google_api_exception() + else None + ) + + @property + def metadata(self): + """Additional structured details about this error. + Reference: + https://cloud.google.com/apis/design/errors#error_info + Returns: + Union[Dict[str, str], None]: An optional object containing structured details about the error. + """ + return ( + self.__cause__.metadata + if self._is_error_cause_instance_of_google_api_exception() + else None + ) + + @property + def details(self): + """Information contained in google.rpc.status.details. + Reference: + https://cloud.google.com/apis/design/errors#error_model + https://cloud.google.com/apis/design/errors#error_details + Returns: + Sequence[Any]: A list of structured objects from error_details.proto + """ + return ( + self.__cause__.details + if self._is_error_cause_instance_of_google_api_exception() + else None + ) class InterfaceError(Error): diff --git a/samples/samples/requirements.txt b/samples/samples/requirements.txt index e75fc9fdc5..8f9b8ad280 100644 --- a/samples/samples/requirements.txt +++ b/samples/samples/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-spanner==3.20.0 +google-cloud-spanner==3.21.0 futures==3.3.0; python_version < "3" diff --git a/setup.py b/setup.py index 048d1ec80a..faf8a4685c 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ name = "google-cloud-spanner" description = "Cloud Spanner API client library" -version = "3.21.0" +version = "3.22.0" # Should be one of: # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta'