Skip to content

Commit f2983b3

Browse files
authored
Render API errors in a more user-friendly way (#34)
1 parent 9e492b6 commit f2983b3

File tree

7 files changed

+27
-15
lines changed

7 files changed

+27
-15
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Changed
2+
-------
3+
4+
* Render API errors in a more user-friendly way.

src/globus_registered_api/cli.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55

66
from __future__ import annotations
77

8+
import json
89
import os
9-
import sys
1010
import typing as t
1111
from collections.abc import Iterable
1212
from uuid import UUID
1313

1414
import click
15+
import click.exceptions
1516
from globus_sdk import AuthClient
1617
from globus_sdk import ClientApp
1718
from globus_sdk import FlowsClient
@@ -119,8 +120,10 @@ def _handle_globus_api_error(err: GlobusAPIError) -> None:
119120
"to re-authenticate.",
120121
err=True,
121122
)
122-
sys.exit(1)
123-
raise err
123+
else:
124+
msg = json.dumps(err.raw_json, indent=2)
125+
click.secho(msg, fg="yellow", err=True)
126+
raise click.exceptions.Exit(code=1)
124127

125128

126129
class ExceptionHandlingGroup(click.Group):

tests/commands/api/test_create.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def test_create_registered_api_api_error(gra, patch_create, spec_path):
369369

370370
# Assert
371371
assert result.exit_code != 0
372-
assert "Invalid target specification" in str(result.exception)
372+
assert "Invalid target specification" in result.stderr
373373

374374

375375
@pytest.mark.parametrize(

tests/commands/api/test_delete.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def test_delete_registered_api_not_found(gra, patch_delete):
100100
result = gra(["api", "delete", api_id])
101101

102102
assert result.exit_code != 0
103-
assert "No Registered API exists" in str(result.exception)
103+
assert "No Registered API exists" in result.stderr
104104

105105

106106
def test_delete_registered_api_forbidden(gra, patch_delete):
@@ -119,7 +119,7 @@ def test_delete_registered_api_forbidden(gra, patch_delete):
119119
result = gra(["api", "delete", api_id])
120120

121121
assert result.exit_code != 0
122-
assert "FORBIDDEN" in str(result.exception)
122+
assert "FORBIDDEN" in result.stderr
123123

124124

125125
def test_delete_registered_api_invalid_uuid(gra):

tests/commands/api/test_show.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,4 @@ def test_get_registered_api_not_found(gra, patch_show):
112112
result = gra(["api", "show", api_id])
113113

114114
assert result.exit_code != 0
115-
assert "No Registered API exists" in str(result.exception)
115+
assert "No Registered API exists" in result.stderr

tests/commands/api/test_update.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def test_update_registered_api_not_found(gra, patch_update):
108108
result = gra(["api", "update", api_id, "--name", "Test"])
109109

110110
assert result.exit_code != 0
111-
assert "No Registered API exists" in str(result.exception)
111+
assert "No Registered API exists" in result.stderr
112112

113113

114114
def test_update_registered_api_with_description(gra, patch_update):

tests/test_error_handling.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from unittest.mock import MagicMock
77

8+
import click.exceptions
89
import pytest
910
from globus_sdk import GlobusAPIError
1011

@@ -15,29 +16,33 @@ def _make_api_error(code: str) -> GlobusAPIError:
1516
"""Create a GlobusAPIError with a specific error code."""
1617
err = MagicMock(spec=GlobusAPIError)
1718
err.code = code
18-
err.message = None
19+
err.message = "Something is very wrong here."
1920
# Make it a proper exception so it can be raised
2021
err.__class__ = GlobusAPIError
22+
err.raw_json = {"code": code, "message": "Something is very wrong here."}
2123
return err
2224

2325

2426
def test_handle_auth_error_exits_with_message(capsys):
2527
err = _make_api_error("AUTHENTICATION_ERROR")
2628

27-
with pytest.raises(SystemExit) as exc_info:
29+
with pytest.raises(click.exceptions.Exit) as exc_info:
2830
_handle_globus_api_error(err)
2931

30-
assert exc_info.value.code == 1
32+
assert exc_info.value.exit_code == 1
3133
captured = capsys.readouterr()
3234
assert "Authentication Error" in captured.err
3335
assert "globus-registered-api logout" in captured.err
3436
assert "globus-registered-api whoami" in captured.err
3537

3638

37-
def test_handle_non_auth_error_reraises():
39+
def test_handle_non_auth_error_reraises(capsys):
3840
err = _make_api_error("NOT_FOUND")
3941

40-
with pytest.raises(TypeError):
41-
# TypeError because mock can't be raised, but this proves the
42-
# function attempted to re-raise rather than handling the error
42+
with pytest.raises(click.exceptions.Exit) as exc_info:
4343
_handle_globus_api_error(err)
44+
45+
assert exc_info.value.exit_code == 1
46+
captured = capsys.readouterr()
47+
assert err.code in captured.err
48+
assert err.message in captured.err

0 commit comments

Comments
 (0)