Skip to content

Commit ceb097d

Browse files
authored
Merge pull request fastapi#11 from fastapilabs/08-01-_add_whoami_command
✨ Add whoami command
2 parents efafee2 + b0188b2 commit ceb097d

File tree

4 files changed

+109
-0
lines changed

4 files changed

+109
-0
lines changed

src/fastapi_cli/cli.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from . import __version__
1515
from .commands.login import login
16+
from .commands.whoami import whoami
1617
from .config import settings
1718
from .logging import setup_logging
1819

@@ -281,6 +282,7 @@ def run(
281282

282283
# Additional commands
283284
app.command()(login)
285+
app.command()(whoami)
284286

285287

286288
def main() -> None:

src/fastapi_cli/commands/whoami.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import logging
2+
from typing import Any
3+
4+
import httpx
5+
import typer
6+
from rich import print
7+
8+
from fastapi_cli.utils.api import APIClient
9+
from fastapi_cli.utils.auth import is_logged_in
10+
11+
logger = logging.getLogger(__name__)
12+
13+
14+
def whoami() -> Any:
15+
if not is_logged_in():
16+
print("No credentials found. Use [blue]`fastapi login`[/] to login.")
17+
return
18+
19+
with APIClient() as client:
20+
try:
21+
response = client.get("/users/me")
22+
except httpx.ReadTimeout:
23+
print(
24+
"[red]Error[/]: The request to the FastAPI Cloud server timed out. Please try again later."
25+
)
26+
raise typer.Exit(code=1) from None
27+
28+
if response.status_code in (401, 403):
29+
print(
30+
"[red]Error[/]: The specified token is not valid. Use [blue]`fastapi login`[/] to generate a new token."
31+
)
32+
raise typer.Exit(code=1) from None
33+
34+
try:
35+
response.raise_for_status()
36+
except httpx.HTTPError as e:
37+
logger.debug("Error: %s", e)
38+
39+
print(
40+
"[red]Error[/]: Something went wrong while contacting the FastAPI Cloud server. Please try again later."
41+
)
42+
raise typer.Exit(code=1) from None
43+
44+
data = response.json()
45+
46+
print(f"⚡[bold]{data['email']}[/bold]")

src/fastapi_cli/utils/auth.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ def get_auth_token() -> Optional[str]:
3131
return None
3232

3333
return auth_data.access_token
34+
35+
36+
def is_logged_in() -> bool:
37+
return get_auth_token() is not None

tests/test_cli_whoami.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from pathlib import Path
2+
3+
import pytest
4+
import respx
5+
from fastapi_cli.cli import app
6+
from fastapi_cli.config import settings
7+
from httpx import ReadTimeout, Response
8+
from typer.testing import CliRunner
9+
10+
runner = CliRunner()
11+
12+
assets_path = Path(__file__).parent / "assets"
13+
14+
15+
@pytest.mark.respx(base_url=settings.base_api_url)
16+
def test_shows_a_message_if_something_is_wrong(respx_mock: respx.MockRouter) -> None:
17+
respx_mock.get("/users/me").mock(return_value=Response(500))
18+
19+
result = runner.invoke(app, ["whoami"])
20+
21+
assert result.exit_code == 1
22+
assert (
23+
"Something went wrong while contacting the FastAPI Cloud server."
24+
in result.output
25+
)
26+
27+
28+
@pytest.mark.respx(base_url=settings.base_api_url)
29+
def test_shows_a_message_when_not_logged_in(respx_mock: respx.MockRouter) -> None:
30+
respx_mock.get("/users/me").mock(return_value=Response(401))
31+
32+
result = runner.invoke(app, ["whoami"])
33+
34+
assert result.exit_code == 1
35+
assert "The specified token is not valid" in result.output
36+
37+
38+
@pytest.mark.respx(base_url=settings.base_api_url)
39+
def test_shows_email(respx_mock: respx.MockRouter) -> None:
40+
respx_mock.get("/users/me").mock(
41+
return_value=Response(200, json={"email": "[email protected]"})
42+
)
43+
44+
result = runner.invoke(app, ["whoami"])
45+
46+
assert result.exit_code == 0
47+
assert "[email protected]" in result.output
48+
49+
50+
@pytest.mark.respx(base_url=settings.base_api_url)
51+
def test_handles_read_timeout(respx_mock: respx.MockRouter) -> None:
52+
respx_mock.get("/users/me").mock(side_effect=ReadTimeout)
53+
54+
result = runner.invoke(app, ["whoami"])
55+
56+
assert result.exit_code == 1
57+
assert "The request to the FastAPI Cloud server timed out" in result.output

0 commit comments

Comments
 (0)