Skip to content

Commit ab18427

Browse files
authored
feat: show elapsed time after model downloads (#427)
1 parent b414616 commit ab18427

2 files changed

Lines changed: 44 additions & 2 deletions

File tree

comfy_cli/command/models/models.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import contextlib
22
import os
33
import pathlib
4+
import time
45
from typing import Annotated
56
from urllib.parse import parse_qs, unquote, urlparse
67

@@ -33,6 +34,18 @@ def get_workspace() -> pathlib.Path:
3334
return pathlib.Path(workspace_manager.workspace_path)
3435

3536

37+
def _format_elapsed(seconds: float) -> str:
38+
"""Format elapsed seconds into a human-readable string."""
39+
rounded = round(seconds, 1)
40+
if rounded < 60:
41+
return f"{rounded:.1f}s"
42+
minutes, secs = divmod(int(rounded), 60)
43+
if minutes < 60:
44+
return f"{minutes}m {secs}s"
45+
hours, minutes = divmod(minutes, 60)
46+
return f"{hours}h {minutes}m {secs}s"
47+
48+
3649
def potentially_strip_param_url(path_name: str) -> str:
3750
return path_name.split("?")[0]
3851

@@ -307,6 +320,8 @@ def download(
307320
print(f"[bold red]File already exists: {local_filepath}[/bold red]")
308321
return
309322

323+
start_time = time.monotonic()
324+
310325
if is_huggingface_url and check_unauthorized(url, headers):
311326
if hf_api_token is None:
312327
print(
@@ -341,6 +356,9 @@ def download(
341356
print(f"Start downloading URL: {url} into {local_filepath}")
342357
download_file(url, local_filepath, headers, downloader=resolved_downloader)
343358

359+
elapsed = time.monotonic() - start_time
360+
print(f"Done in {_format_elapsed(elapsed)}")
361+
344362

345363
@app.command()
346364
@tracking.track_command("model")

tests/comfy_cli/command/models/test_models.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import typer.testing
55

66
from comfy_cli import constants
7-
from comfy_cli.command.models.models import app, check_civitai_url, check_huggingface_url, list_models
7+
from comfy_cli.command.models.models import _format_elapsed, app, check_civitai_url, check_huggingface_url, list_models
88

99

1010
def _make_model_tree(tmp_path: pathlib.Path) -> pathlib.Path:
@@ -307,6 +307,29 @@ def test_huggingface_url_with_folder_structure():
307307
)
308308

309309

310+
class TestFormatElapsed:
311+
def test_under_one_minute(self):
312+
assert _format_elapsed(5.3) == "5.3s"
313+
314+
def test_fractional_seconds(self):
315+
assert _format_elapsed(0.4) == "0.4s"
316+
317+
def test_rounds_up_to_minute_boundary(self):
318+
assert _format_elapsed(59.95) == "1m 0s"
319+
320+
def test_exactly_sixty_seconds(self):
321+
assert _format_elapsed(60) == "1m 0s"
322+
323+
def test_minutes_and_seconds(self):
324+
assert _format_elapsed(154) == "2m 34s"
325+
326+
def test_over_one_hour(self):
327+
assert _format_elapsed(3661) == "1h 1m 1s"
328+
329+
def test_large_duration(self):
330+
assert _format_elapsed(7384) == "2h 3m 4s"
331+
332+
310333
# ---------------------------------------------------------------------------
311334
# --downloader CLI option tests
312335
# ---------------------------------------------------------------------------
@@ -327,7 +350,7 @@ def test_downloader_flag_forwarded(self, tmp_path):
327350
patch("comfy_cli.tracking.track_command", lambda _cmd: lambda fn: fn),
328351
):
329352
mock_ui.prompt_input.side_effect = ["mymodel.bin", ""]
330-
runner.invoke(
353+
result = runner.invoke(
331354
app,
332355
[
333356
"download",
@@ -343,6 +366,7 @@ def test_downloader_flag_forwarded(self, tmp_path):
343366
assert mock_dl.called
344367
_, kwargs = mock_dl.call_args
345368
assert kwargs.get("downloader") == "aria2"
369+
assert "Done in " in result.output
346370

347371
def test_default_from_config(self, tmp_path):
348372
"""Config default_downloader is used when no --downloader flag."""

0 commit comments

Comments
 (0)