Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
00579c1
bump version
wangxingjun778 Jul 20, 2026
31f224c
fix(download): forward progress_callbacks through HubApi.download_rep…
wangxingjun778 Jul 20, 2026
85436d9
merge main
wangxingjun778 Jul 20, 2026
306f145
fix(download): harden legacy cache auto-detection for pre-1.38 layouts
wangxingjun778 Jul 21, 2026
e4acbfe
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Jul 21, 2026
07aec55
fix(packaging): rename console scripts to modelscope-hub/ms-hub to av…
wangxingjun778 Jul 21, 2026
47b866a
update cli: ms/modelscope -> ms-hub/modelscope-hub
wangxingjun778 Jul 21, 2026
84b6e64
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Jul 21, 2026
dde1875
docs(readme): expand recent version news, fold older, group by type
wangxingjun778 Jul 21, 2026
d0ea9e6
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Jul 22, 2026
3665978
fix revision pass
wangxingjun778 Jul 22, 2026
a9839e6
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Jul 31, 2026
17244b2
bump version
wangxingjun778 Jul 31, 2026
91a5489
fix lint and NixOS UT
wangxingjun778 Jul 31, 2026
402f7c5
update readme
wangxingjun778 Jul 31, 2026
2375141
fix 3.10 citest
wangxingjun778 Jul 31, 2026
74a6357
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Aug 1, 2026
2d082bd
fix(auth): stop misreporting login failures and revoking credentials
wangxingjun778 Aug 1, 2026
bb2eb63
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Aug 1, 2026
ce5c7b8
update news and bump version
wangxingjun778 Aug 1, 2026
3facbce
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Aug 3, 2026
d59c734
fix(api): recover full repo file list past the server's 3000-entry cap
wangxingjun778 Aug 4, 2026
8287606
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Aug 6, 2026
89f2924
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Aug 13, 2026
9ae5a5c
Move CLI script ownership to modelscope-hub
wangxingjun778 Aug 18, 2026
cc83c47
ok Merge branch 'main' of github.com:modelscope/modelscope_hub into f…
wangxingjun778 Aug 19, 2026
dfa1487
fix logout
wangxingjun778 Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions src/modelscope_hub/cli/login.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""``ms login`` and ``ms whoami`` commands.
"""``ms login``, ``ms logout`` and ``ms whoami`` commands.

The two flows share their HubApi construction but live in distinct
The three flows share their HubApi construction but live in distinct
:class:`CLICommand` classes so each can be registered, tested and evolved
independently.
"""
Expand Down Expand Up @@ -57,6 +57,29 @@ def execute(self) -> None:
success(f"Logged in as {identity}.")


class LogoutCommand(CLICommand):
"""Clear locally persisted ModelScope credentials."""

@staticmethod
def register(subparsers: SubParsers) -> None:
parser = subparsers.add_parser(
"logout",
help="Clear locally persisted ModelScope credentials.",
description="Removes saved cookies, git token and cached user identity.",
)
# Legacy compat: allow subcommand-level auth flags even though logout
# never contacts the server. This keeps `ms logout --token ...` from
# failing on argument parsing in scripts that pass shared auth flags to
# every command.
add_subcmd_token_endpoint(parser)
parser.set_defaults(_command=LogoutCommand)

def execute(self) -> None:
api = make_api(self.args)
api.logout()
success("Logged out.")


class WhoamiCommand(CLICommand):
"""Show the currently authenticated user."""

Expand Down
3 changes: 2 additions & 1 deletion src/modelscope_hub/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from .cache import CacheCommand, _CacheClear, _CacheScan
from .deploy import DeployCommand, LogsCommand, SettingsCommand, StopCommand
from .download import DownloadCommand
from .login import LoginCommand, WhoamiCommand
from .login import LoginCommand, LogoutCommand, WhoamiCommand
from .mcp import McpCommand
from .repo import CreateCommand, DeleteCommand, InfoCommand, ListCommand, RepoCommand
from .secret import SecretCommand
Expand All @@ -48,6 +48,7 @@
# importing it above and appending it here — that's it.
_COMMANDS = [
LoginCommand,
LogoutCommand,
WhoamiCommand,
CreateCommand,
InfoCommand,
Expand Down
46 changes: 43 additions & 3 deletions tests/cli/test_login.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Tests for ``ms login`` and ``ms whoami`` commands.
"""Tests for ``ms login``, ``ms logout`` and ``ms whoami`` commands.

Includes:
- Parser tests: argument parsing
- Execution tests: mock HubApi for login/whoami logic
- Execution tests: mock HubApi for login/logout/whoami logic
- Remote tests: real API (existing)
"""

Expand All @@ -12,7 +12,7 @@

import pytest

from modelscope_hub.cli.login import LoginCommand, WhoamiCommand
from modelscope_hub.cli.login import LoginCommand, LogoutCommand, WhoamiCommand
from modelscope_hub.types import UserInfo

from .conftest import run_cli
Expand All @@ -37,6 +37,27 @@ def test_subcmd_endpoint(self, parser):
assert args.subcmd_endpoint == "https://custom.cn"


class TestLogoutParser:
"""``ms logout`` argument parsing."""

def test_no_args(self, parser):
args = parser.parse_args(["logout"])
assert args._command is LogoutCommand

def test_subcmd_token_endpoint_is_accepted(self, parser):
args = parser.parse_args(
[
"logout",
"--token",
"my-tok",
"--endpoint",
"https://x.cn",
]
)
assert args.subcmd_token == "my-tok"
assert args.subcmd_endpoint == "https://x.cn"


class TestWhoamiParser:
"""``ms whoami`` argument parsing."""

Expand Down Expand Up @@ -144,6 +165,25 @@ def test_login_subcmd_endpoint_merged(self, parser, mock_api, capsys):
assert args.endpoint == "https://custom.cn"


@pytest.mark.mock_only
class TestLogoutExecute:
"""LogoutCommand.execute() logic."""

def test_logout_clears_credentials(self, parser, mock_api, capsys):
args = parser.parse_args(["logout"])
with patch("modelscope_hub.cli.login.make_api", return_value=mock_api):
LogoutCommand(args).execute()
mock_api.logout.assert_called_once()
assert "Logged out" in capsys.readouterr().out

def test_logout_dispatches_through_run_cmd(self, mock_api):
with patch("modelscope_hub.cli.login.make_api", return_value=mock_api):
code, out, err = run_cli(["logout"])
assert code == 0
assert "Logged out" in out
mock_api.logout.assert_called_once()


@pytest.mark.mock_only
class TestWhoamiExecute:
"""WhoamiCommand.execute() logic."""
Expand Down
Loading