Skip to content

Commit 6b65b98

Browse files
github-actions[bot]patrick91
authored andcommitted
🎨 Auto format
1 parent 0ad8909 commit 6b65b98

5 files changed

Lines changed: 75 additions & 97 deletions

File tree

‎src/fastapi_cloud_cli/commands/login.py‎

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,48 +77,50 @@ def login() -> Any:
7777
Login to FastAPI Cloud. 🚀
7878
"""
7979
identity = Identity()
80+
is_logged_in = identity.is_logged_in()
8081

81-
if identity.is_logged_in():
82-
with get_rich_toolkit(minimal=True) as toolkit:
82+
with get_rich_toolkit(minimal=is_logged_in) as toolkit:
83+
if is_logged_in:
8384
toolkit.print("You are already logged in.")
8485
toolkit.print(
8586
"Run [bold]fastapi cloud logout[/bold] first if you want to switch accounts."
8687
)
8788

88-
return
89+
return
8990

90-
if identity.has_deploy_token():
91-
with get_rich_toolkit() as toolkit:
91+
if identity.has_deploy_token():
9292
toolkit.print(
9393
"You have [bold blue]FASTAPI_CLOUD_TOKEN[/] environment variable set.\n"
9494
"This token will take precedence over the user token for "
9595
"[blue]`fastapi deploy`[/] command.",
9696
tag="Warning",
9797
)
9898

99-
with get_rich_toolkit() as toolkit, APIClient() as client:
100-
toolkit.print_title("Login to FastAPI Cloud", tag="FastAPI")
99+
with APIClient() as client:
100+
toolkit.print_title("Login to FastAPI Cloud", tag="FastAPI")
101101

102-
toolkit.print_line()
102+
toolkit.print_line()
103103

104-
with toolkit.progress("Starting authorization") as progress:
105-
with client.handle_http_errors(progress):
106-
authorization_data = _start_device_authorization(client)
104+
with toolkit.progress("Starting authorization") as progress:
105+
with client.handle_http_errors(progress):
106+
authorization_data = _start_device_authorization(client)
107107

108-
url = authorization_data.verification_uri_complete
108+
url = authorization_data.verification_uri_complete
109109

110-
progress.log(f"Opening [link={url}]{url}[/link]")
110+
progress.log(f"Opening [link={url}]{url}[/link]")
111111

112-
toolkit.print_line()
112+
toolkit.print_line()
113113

114-
with toolkit.progress("Waiting for user to authorize...") as progress:
115-
typer.launch(url)
114+
with toolkit.progress("Waiting for user to authorize...") as progress:
115+
typer.launch(url)
116116

117-
with client.handle_http_errors(progress):
118-
access_token = _fetch_access_token(
119-
client, authorization_data.device_code, authorization_data.interval
120-
)
117+
with client.handle_http_errors(progress):
118+
access_token = _fetch_access_token(
119+
client,
120+
authorization_data.device_code,
121+
authorization_data.interval,
122+
)
121123

122-
write_auth_config(AuthConfig(access_token=access_token))
124+
write_auth_config(AuthConfig(access_token=access_token))
123125

124-
progress.log("Now you are logged in! 🚀")
126+
progress.log("Now you are logged in! 🚀")

‎src/fastapi_cloud_cli/commands/whoami.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ def whoami() -> Any:
1313

1414
with get_rich_toolkit(minimal=True) as toolkit:
1515
if not identity.is_logged_in():
16-
toolkit.print("No credentials found. Use [blue]`fastapi login`[/] to login.")
16+
toolkit.print(
17+
"No credentials found. Use [blue]`fastapi login`[/] to login."
18+
)
1719
else:
1820
with APIClient() as client:
1921
with toolkit.progress(

‎src/fastapi_cloud_cli/utils/cli.py‎

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
)
1717

1818
logger = logging.getLogger(__name__)
19-
VERSION_CHECK_CONTEXT_KEY = "fastapi_cloud_cli.version_check"
2019

2120

2221
class FastAPIStyle(TaggedStyle):
@@ -71,23 +70,15 @@ def __init__(
7170
self,
7271
style: BaseStyle | None = None,
7372
theme: RichToolkitTheme | None = None,
74-
handle_keyboard_interrupts: bool = True,
75-
print_spacing: bool = True,
7673
) -> None:
77-
super().__init__(
78-
style=style,
79-
theme=theme,
80-
handle_keyboard_interrupts=handle_keyboard_interrupts,
81-
)
82-
self._print_spacing = print_spacing
74+
super().__init__(style=style, theme=theme)
75+
8376
self._version_check: BackgroundVersionCheck | None = None
84-
self._print_update_on_exit = False
8577

8678
def __enter__(self) -> "FastAPIRichToolkit":
8779
self._version_check = self._get_version_check()
8880

89-
if self._print_spacing:
90-
self.console.print()
81+
super().__enter__() # type: ignore[no-untyped-call]
9182
return self
9283

9384
def __exit__(
@@ -100,13 +91,11 @@ def __exit__(
10091

10192
if is_keyboard_interrupt and self._version_check is not None:
10293
self._version_check.suppress()
103-
elif self._print_update_on_exit:
104-
self._print_update_message()
10594

106-
if self._print_spacing and not is_keyboard_interrupt:
95+
if not is_keyboard_interrupt:
10796
self.console.print()
10897

109-
if self.handle_keyboard_interrupts and is_keyboard_interrupt:
98+
if is_keyboard_interrupt:
11099
return True
111100

112101
return None
@@ -117,18 +106,10 @@ def _get_version_check(self) -> BackgroundVersionCheck | None:
117106

118107
context = click.get_current_context(silent=True)
119108
if context is None:
120-
version_check = BackgroundVersionCheck()
121-
version_check.start()
122-
self._print_update_on_exit = True
123-
return version_check
124-
125-
stored_version_check = context.meta.get(VERSION_CHECK_CONTEXT_KEY)
126-
if isinstance(stored_version_check, BackgroundVersionCheck):
127-
return stored_version_check
109+
return None
128110

129111
version_check = BackgroundVersionCheck()
130112
version_check.start()
131-
context.meta[VERSION_CHECK_CONTEXT_KEY] = version_check
132113
context.call_on_close(self._print_update_message)
133114

134115
return version_check
@@ -142,12 +123,7 @@ def _print_update_message(self) -> None:
142123
self.print(Text.from_markup(message), tag="update", tag_style="tag.update")
143124

144125

145-
def get_rich_toolkit(
146-
minimal: bool = False,
147-
*,
148-
print_spacing: bool = True,
149-
handle_keyboard_interrupts: bool = True,
150-
) -> RichToolkit:
126+
def get_rich_toolkit(minimal: bool = False) -> RichToolkit:
151127
style = MinimalStyle() if minimal else FastAPIStyle(tag_width=11)
152128

153129
theme = RichToolkitTheme(
@@ -166,8 +142,4 @@ def get_rich_toolkit(
166142
},
167143
)
168144

169-
return FastAPIRichToolkit(
170-
theme=theme,
171-
handle_keyboard_interrupts=handle_keyboard_interrupts,
172-
print_spacing=print_spacing,
173-
)
145+
return FastAPIRichToolkit(theme=theme)

‎src/fastapi_cloud_cli/utils/version_check.py‎

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,7 @@ def get_upgrade_command(
176176
*,
177177
detector: Callable[[str], InstallerInfo | None] = detect_installer,
178178
) -> str:
179-
try:
180-
installer_info = detector(PACKAGE_NAME)
181-
except Exception as error:
182-
logger.debug("Could not detect CLI installer: %s", error)
183-
return DEFAULT_UPGRADE_COMMAND
179+
installer_info = detector(PACKAGE_NAME)
184180

185181
if installer_info is None or installer_info.upgrade_cmd is None:
186182
return DEFAULT_UPGRADE_COMMAND
@@ -220,10 +216,7 @@ def start(self) -> None:
220216
self._thread.start()
221217

222218
def _run(self) -> None:
223-
try:
224-
self._update = self._check_for_update()
225-
except Exception as error:
226-
logger.debug("Could not check latest CLI version: %s", error)
219+
self._update = self._check_for_update()
227220

228221
def suppress(self) -> None:
229222
self._message_returned = True

‎tests/test_version_check.py‎

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import inspect
21
import json
32
import os
3+
import threading
44
from datetime import datetime, timedelta, timezone
55
from pathlib import Path
66
from types import SimpleNamespace
@@ -37,10 +37,6 @@ def test_is_newer_version() -> None:
3737
assert not is_newer_version("not-a-version", "0.17.1")
3838

3939

40-
def test_get_rich_toolkit_has_no_invocation_args_override() -> None:
41-
assert "args" not in inspect.signature(get_rich_toolkit).parameters
42-
43-
4440
@respx.mock
4541
def test_check_for_update_returns_update_when_pypi_has_newer_version() -> None:
4642
route = respx.get(PYPI_JSON_URL).mock(
@@ -225,6 +221,14 @@ def test_get_upgrade_command_falls_back_when_installer_is_unknown() -> None:
225221
)
226222

227223

224+
def test_get_upgrade_command_propagates_detector_errors() -> None:
225+
def broken_detector(package_name: str) -> None:
226+
raise RuntimeError(f"Could not inspect {package_name}")
227+
228+
with pytest.raises(RuntimeError, match="Could not inspect fastapi-cloud-cli"):
229+
get_upgrade_command(detector=broken_detector)
230+
231+
228232
def test_format_update_message() -> None:
229233
message = format_update_message(
230234
VersionUpdate(current="0.17.1", latest="0.18.0"),
@@ -245,41 +249,22 @@ def _seed_fresh_update_cache(latest_version: str = "999.0.0") -> None:
245249
)
246250

247251

248-
def test_get_rich_toolkit_prints_forced_update_message_without_wrapper(
249-
monkeypatch: pytest.MonkeyPatch,
250-
capsys: pytest.CaptureFixture[str],
251-
) -> None:
252-
monkeypatch.setenv("FASTAPI_CLOUD_DISABLE_VERSION_CHECK", "")
253-
_seed_fresh_update_cache()
254-
255-
with get_rich_toolkit() as toolkit:
256-
toolkit.print("command output")
257-
258-
output = capsys.readouterr().out
259-
assert "command output" in output
260-
assert "update" in output
261-
assert "A newer FastAPI Cloud CLI version is available" in output
262-
263-
264-
def test_get_rich_toolkit_prints_forced_update_once_per_click_command() -> None:
252+
def test_get_rich_toolkit_prints_update_when_click_command_closes() -> None:
265253
@click.command()
266-
def command_with_multiple_toolkits() -> None:
267-
with get_rich_toolkit() as toolkit:
268-
toolkit.print("first output")
254+
def command_with_toolkit() -> None:
269255
with get_rich_toolkit() as toolkit:
270-
toolkit.print("second output")
256+
toolkit.print("command output")
271257
click.echo("after command body")
272258

273259
_seed_fresh_update_cache()
274260
result = CliRunner().invoke(
275-
command_with_multiple_toolkits,
261+
command_with_toolkit,
276262
[],
277263
env={"FASTAPI_CLOUD_DISABLE_VERSION_CHECK": ""},
278264
)
279265

280266
assert result.exit_code == 0, result.output
281-
assert "first output" in result.output
282-
assert "second output" in result.output
267+
assert "command output" in result.output
283268
assert "after command body" in result.output
284269
assert result.output.count("A newer FastAPI Cloud CLI version is available") == 1
285270
assert result.output.rfind("after command body") < result.output.rfind("A newer")
@@ -322,3 +307,27 @@ def test_background_check_returns_no_message_without_update() -> None:
322307
message = check.get_update_message()
323308

324309
assert message is None
310+
311+
312+
def test_background_check_exposes_unexpected_errors() -> None:
313+
captured_errors: list[threading.ExceptHookArgs] = []
314+
original_hook = threading.excepthook
315+
316+
def capture_thread_error(args: threading.ExceptHookArgs) -> None:
317+
captured_errors.append(args)
318+
319+
def broken_check() -> None:
320+
raise RuntimeError("version check failed unexpectedly")
321+
322+
threading.excepthook = capture_thread_error
323+
try:
324+
check = BackgroundVersionCheck(check_for_update=broken_check, join_timeout=1)
325+
check.start()
326+
assert check._thread is not None
327+
check._thread.join(timeout=1)
328+
finally:
329+
threading.excepthook = original_hook
330+
331+
assert captured_errors
332+
assert captured_errors[0].exc_type is RuntimeError
333+
assert str(captured_errors[0].exc_value) == "version check failed unexpectedly"

0 commit comments

Comments
 (0)