Skip to content

Commit 0db7157

Browse files
authored
fix: add error detail handling for Python SDK (#1170)
1 parent a4ac3bc commit 0db7157

File tree

4 files changed

+65
-4
lines changed

4 files changed

+65
-4
lines changed

python/looker_sdk/error.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,34 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
# THE SOFTWARE.
2222

23+
import attr
24+
from typing import Optional, Sequence
25+
2326
"""API error class
2427
"""
2528

29+
@attr.s(auto_attribs=True, kw_only=True)
30+
class ErrorDetail():
31+
"""Error detail:
32+
documentation_url: documentation link
33+
field: field with error
34+
code: error code
35+
message: error info message
36+
"""
37+
documentation_url: str
38+
field: Optional[str] = ""
39+
code: Optional[str] = ""
40+
message: Optional[str] = ""
41+
2642

43+
@attr.s(auto_attribs=True)
2744
class SDKError(Exception):
28-
"""API error class
45+
"""API error class:
46+
message: main error info message
47+
errors: array of error details
48+
documentation_url: documentation link
2949
"""
50+
51+
message: str
52+
errors: Optional[Sequence[ErrorDetail]] = attr.ib(default=[], kw_only=True)
53+
documentation_url: Optional[str] = attr.ib(default="", kw_only=True)

python/looker_sdk/rtl/api_methods.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,21 @@ def __exit__(self, *exc) -> None:
8484
def _return(self, response: transport.Response, structure: TStructure) -> TReturn:
8585
encoding = response.encoding
8686
if not response.ok:
87-
raise error.SDKError(response.value.decode(encoding=encoding))
87+
value = response.value.decode(encoding=encoding)
88+
sdk_error: error.SDKError
89+
try:
90+
sdk_error = self.deserialize(data=value, structure=error.SDKError) # type: ignore
91+
except serialize.DeserializeError:
92+
raise error.SDKError(value)
93+
raise sdk_error
8894
ret: TReturn
8995
if structure is None:
9096
ret = None
9197
elif response.response_mode == transport.ResponseMode.BINARY:
9298
ret = response.value
9399
else:
94100
value = response.value.decode(encoding=encoding)
95-
if structure is Union[str, bytes] or structure is str: # type: ignore
101+
if structure is Union[str, bytes] or structure is str or value == "": # type: ignore
96102
ret = value
97103
else:
98104
# ignore type: mypy bug doesn't recognized kwarg

python/looker_sdk/rtl/auth_session.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def authenticator(
237237

238238
def _ok(self, response: transport.Response) -> str:
239239
if not response.ok:
240-
raise error.SDKError(response.value)
240+
raise error.SDKError(response.value.decode(encoding="utf-8"))
241241
return response.value.decode(encoding="utf-8")
242242

243243

python/tests/integration/test_methods.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,3 +647,34 @@ def get_query_id(
647647
else:
648648
query_id = None
649649
return query_id
650+
651+
def test_validate_theme(sdk: mtds.Looker40SDK):
652+
653+
valid_theme_response = sdk.validate_theme(
654+
body = ml.WriteTheme(
655+
name = 'valid_theme',
656+
settings = ml.ThemeSettings(
657+
show_filters_bar = False,
658+
show_title = False,
659+
tile_shadow = False,
660+
font_family = 'Arial',
661+
)
662+
)
663+
)
664+
assert valid_theme_response == ""
665+
666+
try:
667+
sdk.validate_theme(
668+
body = ml.WriteTheme(
669+
settings = ml.ThemeSettings(
670+
show_filters_bar = False,
671+
show_title = False,
672+
tile_shadow = False,
673+
font_family = 'Arial;',
674+
)
675+
)
676+
)
677+
except Exception as e:
678+
assert e.message is not None
679+
assert e.message != ""
680+
assert len(e.errors) == 3

0 commit comments

Comments
 (0)