Skip to content

Commit a5479bf

Browse files
NexisatoSAKURA-CAT
andauthored
fix: relogin judgement (#1542)
* fix: relogin judgement * Move client implementation to internal.pkg.client Refactor: extract and relocate the HTTP client implementation from internal.core_python.client to a new internal.pkg.client package (including session, bootstrap and utils). Update all imports/usages across the codebase and tests to reference the new package, adjust typing modules accordingly, and add new pkg typing stubs. Add/rename login helpers (login_raw / login_interactive) and wire them through CLI and init code. Update top-level exports (sdk and package __init__ files) to expose helper/console/fs/safe and updated run/login APIs, and use helper.get_swanlab_version for __version__. Minor cleanup: fix safe package import, add __all__ entries, and move/rename multiple tests to match the new module layout. * Export raw auth funcs; update imports/tests Expose low-level auth helpers at swanlab.sdk (verify_raw, logout_raw, etc.) and flatten cmd exports. Update CLI auth commands to import swanlab.sdk and call the new top-level raw functions. Rename raw_logout to logout_raw and wire logout() to call it. Adjust unit tests and fixtures to use the new function names and corrected patch targets for the pkg client, plus minor test refactors to match the new API surface. --------- Co-authored-by: Kang Li <79990647+SAKURA-CAT@users.noreply.github.com>
1 parent f4ec630 commit a5479bf

28 files changed

Lines changed: 355 additions & 292 deletions

swanlab/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
define_scalar,
1212
finish,
1313
get_run,
14-
get_swanlab_version,
1514
has_run,
15+
helper,
1616
init,
1717
log,
1818
log_audio,
@@ -27,7 +27,7 @@
2727

2828
from . import utils
2929

30-
__version__ = get_swanlab_version()
30+
__version__ = helper.get_swanlab_version()
3131

3232
__all__ = [
3333
# cmd

swanlab/__init__.pyi

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ from concurrent.futures import Future
1010
from typing import Any, Callable, List, Mapping, Optional, Union
1111

1212
from . import utils
13-
from .sdk import Callback, config
13+
from .sdk import Audio, Callback, Image, Run, Settings, Text, Video, config, logout, verify
1414
from .sdk.cmd.init import ConfigLike
15-
from .sdk.internal.run import Run
16-
from .sdk.internal.run.transforms import Audio, Image, Text, Video
17-
from .sdk.internal.settings import Settings
1815
from .sdk.typings.run import AsyncLogType, FinishType, ModeType, ResumeType
1916
from .sdk.typings.run.column import ScalarXAxisType
2017
from .sdk.typings.run.transforms import CaptionsType
@@ -31,6 +28,8 @@ __all__ = [
3128
"init",
3229
"finish",
3330
"login",
31+
"logout",
32+
"verify",
3433
"log",
3534
"log_text",
3635
"log_image",
@@ -39,7 +38,7 @@ __all__ = [
3938
"define_scalar",
4039
"async_log",
4140
# run
42-
"run",
41+
"run", # type: ignore [no-redef]
4342
"Run",
4443
"has_run",
4544
"get_run",
@@ -52,8 +51,8 @@ __all__ = [
5251
"Video",
5352
# utils
5453
"utils",
55-
"Callback",
5654
"Settings",
55+
"Callback",
5756
]
5857

5958
# ── lifecycle ──────────────────────────────────────────────────────────────────

swanlab/cli/auth/login.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import click
99

10-
from swanlab.sdk.cmd.login import interactive_login
10+
from swanlab import sdk
1111

1212

1313
@click.command()
@@ -40,4 +40,4 @@
4040
)
4141
def login(api_key: str, relogin: bool, host: str, save: bool):
4242
"""Login to the SwanLab cloud."""
43-
interactive_login(api_key=api_key, relogin=relogin, host=host, save=save)
43+
sdk.login_interactive(api_key=api_key, relogin=relogin, host=host, save=save)

swanlab/cli/auth/logout.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import click
1111

12-
from swanlab.sdk.cmd.logout import raw_logout
12+
from swanlab import sdk
1313

1414

1515
@click.command()
@@ -22,6 +22,6 @@
2222
)
2323
def logout(force: bool):
2424
"""Logout from the SwanLab cloud."""
25-
success = raw_logout(force=force)
25+
success = sdk.logout_raw(force=force)
2626
if not success:
2727
sys.exit(1)

swanlab/cli/auth/verify.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99

1010
import click
1111

12-
from swanlab.sdk.cmd.verify import raw_verify
12+
from swanlab import sdk
1313

1414

1515
@click.command()
1616
def verify():
1717
"""Verify the current login status."""
18-
success = raw_verify()
18+
success = sdk.verify_raw()
1919
if not success:
2020
sys.exit(1)

swanlab/sdk/__init__.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,20 @@
66
"""
77

88
from .cmd.init import init
9-
from .cmd.login import login
10-
from .cmd.logout import logout
11-
from .cmd.merge_settings import Settings, merge_settings
9+
from .cmd.login import login, login_interactive
10+
from .cmd.logout import logout, logout_raw
11+
from .cmd.merge_settings import merge_settings
1212
from .cmd.run import async_log, define_scalar, finish, log, log_audio, log_image, log_text, log_video
13-
from .cmd.verify import verify
14-
from .internal.pkg.helper import get_swanlab_version
15-
from .internal.pkg.safe import block, decorator
13+
from .cmd.verify import verify, verify_raw
14+
from .internal.pkg import console, fs, helper, safe
1615
from .internal.protocol import Callback
1716
from .internal.run import Run, clear_run, get_run, has_run, set_run
1817
from .internal.run.config import config
1918
from .internal.run.transforms import Audio, Image, Text, Video
19+
from .internal.settings import Settings
2020

2121
__all__ = [
22-
"Callback",
23-
"get_swanlab_version",
24-
"Audio",
25-
"Image",
26-
"Text",
27-
"Video",
28-
"merge_settings",
29-
"Settings",
22+
# cmd
3023
"init",
3124
"finish",
3225
"login",
@@ -38,13 +31,29 @@
3831
"log_audio",
3932
"log_video",
4033
"async_log",
34+
"verify_raw",
35+
"logout_raw",
4136
"define_scalar",
42-
"Run",
37+
"merge_settings",
38+
"login_interactive",
39+
# run
4340
"has_run",
4441
"get_run",
4542
"set_run",
4643
"clear_run",
4744
"config",
48-
"block",
49-
"decorator",
45+
# utils
46+
"safe",
47+
"helper",
48+
"console",
49+
"fs",
50+
# data
51+
"Audio",
52+
"Image",
53+
"Text",
54+
"Video",
55+
# protocol
56+
"Callback",
57+
"Settings",
58+
"Run",
5059
]

swanlab/sdk/cmd/init.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
from ..internal.settings import Settings
3737
from ..internal.settings import settings as global_settings
3838
from ..typings.run import ModeType, ResumeType
39-
from .login import interactive_login, raw_login
39+
from .login import login_interactive, login_raw
40+
41+
__all__ = ["init", "ConfigLike"]
4042

4143

4244
def set_nested_value(d: dict, key: str, value: Any):
@@ -443,7 +445,7 @@ def prompt_init_mode(settings: Settings) -> Tuple[ModeType, bool]:
443445
return mode, client.exists()
444446
if mode == "cloud":
445447
if apikey.exists():
446-
raw_login(api_key=apikey.get())
448+
login_raw(api_key=apikey.get())
447449
return "cloud", True
448450

449451
console.info("Using SwanLab to track your experiments.")
@@ -464,13 +466,13 @@ def prompt_init_mode(settings: Settings) -> Tuple[ModeType, bool]:
464466
console.info("Create a SwanLab account here:", "yellow")
465467
console.info(f"{settings.web_host}/login", "blue")
466468
# 注册后紧接着触发登录循环
467-
success = interactive_login(save=True)
469+
success = login_interactive(save=True)
468470
return "cloud", success
469471

470472
if choice == "2":
471473
console.info(f"Logging into {settings.web_host}...")
472474
# 触发带循环容错的登录接口
473-
success = interactive_login(save=True)
475+
success = login_interactive(save=True)
474476
return "cloud", success
475477

476478
console.warning("Invalid choice, please enter 1, 2, or 3.")

swanlab/sdk/cmd/login.py

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
from swanlab.sdk.internal.core_python import client
1919
from swanlab.sdk.internal.pkg import console, helper, scope
2020
from swanlab.sdk.internal.settings import Settings, settings
21-
from swanlab.sdk.typings.core_python.api.bootstrap import LoginResponse
21+
from swanlab.sdk.typings.pkg.client.bootstrap import LoginResponse
22+
23+
__all__ = ["login", "login_interactive", "login_raw"]
2224

2325

2426
@with_cmd_lock
@@ -74,10 +76,53 @@ def login(
7476
>>> swanlab.login(api_key="new_api_key", relogin=True, save=True)
7577
>>> swanlab.init(mode="cloud")
7678
"""
77-
return raw_login(api_key=api_key, relogin=relogin, host=host, save=save, timeout=timeout)
79+
return login_raw(api_key=api_key, relogin=relogin, host=host, save=save, timeout=timeout)
80+
81+
82+
def login_interactive(
83+
api_key: Optional[str] = None,
84+
relogin: bool = False,
85+
host: Optional[str] = None,
86+
save: bool = False,
87+
timeout: int = 10,
88+
) -> bool:
89+
"""
90+
带循环输入容错的交互式登录接口。
91+
主要为 CLI 环境或需要极高容错的终端调用设计。
92+
当捕获到 AuthenticationError 时,如果环境允许交互,则会无限循环提示用户重新输入 API Key。
93+
"""
94+
# CLI 每次是新进程,client.exists() 必为 False,需要检查本地凭证判断是否已登录
95+
if apikey.exists_locally() and not relogin:
96+
console.info(
97+
"You are already logged in. Use",
98+
Text("`swanlab login --relogin`", style="bold"),
99+
"to force relogin.",
100+
sep=" ",
101+
)
102+
return True
103+
try:
104+
# 首次尝试登录,复用原子接口
105+
return login_raw(api_key=api_key, relogin=relogin, host=host, save=save, timeout=timeout)
106+
except AuthenticationError as e:
107+
# 如果全局配置禁用了交互模式,直接抛出异常
108+
if not settings.interactive:
109+
raise e
110+
console.error(str(e))
111+
112+
# 进入容错重试循环
113+
while True:
114+
try:
115+
# 重新要求用户输入新的 Key
116+
new_key = apikey.prompt()
117+
return login_raw(api_key=new_key, relogin=relogin, host=host, save=save, timeout=timeout)
118+
except AuthenticationError as e:
119+
console.error(str(e))
120+
except (KeyboardInterrupt, EOFError):
121+
console.info("\nLogin cancelled by user.")
122+
return False
78123

79124

80-
def raw_login(
125+
def login_raw(
81126
api_key: Optional[str] = None,
82127
relogin: bool = False,
83128
host: Optional[str] = None,
@@ -150,49 +195,6 @@ def raw_login(
150195
return True
151196

152197

153-
def interactive_login(
154-
api_key: Optional[str] = None,
155-
relogin: bool = False,
156-
host: Optional[str] = None,
157-
save: bool = False,
158-
timeout: int = 10,
159-
) -> bool:
160-
"""
161-
带循环输入容错的交互式登录接口。
162-
主要为 CLI 环境或需要极高容错的终端调用设计。
163-
当捕获到 AuthenticationError 时,如果环境允许交互,则会无限循环提示用户重新输入 API Key。
164-
"""
165-
# CLI 每次是新进程,client.exists() 必为 False,需要检查本地凭证判断是否已登录
166-
if not relogin and api_key is None and host is None and apikey.exists():
167-
console.info(
168-
"You are already logged in. Use",
169-
Text("`swanlab login --relogin`", style="bold"),
170-
"to force relogin.",
171-
sep=" ",
172-
)
173-
return True
174-
try:
175-
# 首次尝试登录,复用原子接口
176-
return raw_login(api_key=api_key, relogin=relogin, host=host, save=save, timeout=timeout)
177-
except AuthenticationError as e:
178-
# 如果全局配置禁用了交互模式,直接抛出异常
179-
if not settings.interactive:
180-
raise e
181-
console.error(str(e))
182-
183-
# 进入容错重试循环
184-
while True:
185-
try:
186-
# 重新要求用户输入新的 Key
187-
new_key = apikey.prompt()
188-
return raw_login(api_key=new_key, relogin=relogin, host=host, save=save, timeout=timeout)
189-
except AuthenticationError as e:
190-
console.error(str(e))
191-
except (KeyboardInterrupt, EOFError):
192-
console.info("\nLogin cancelled by user.")
193-
return False
194-
195-
196198
@helper.with_loading_animation()
197199
def create_client(ctx: RunContext, timeout: int = 10):
198200
assert ctx.config.settings.api_key is not None, "API Key not provided"

swanlab/sdk/cmd/logout.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from swanlab.sdk.internal.pkg import console
1212
from swanlab.sdk.internal.settings import settings
1313

14+
__all__ = ["logout", "logout_raw"]
15+
1416

1517
@with_cmd_lock
1618
@without_run("logout")
@@ -39,10 +41,10 @@ def logout(force: bool = False) -> bool:
3941
>>> import swanlab
4042
>>> swanlab.logout(force=True)
4143
"""
42-
return raw_logout(force=force)
44+
return logout_raw(force=force)
4345

4446

45-
def raw_logout(force: bool = False) -> bool:
47+
def logout_raw(force: bool = False) -> bool:
4648
# 1. 检查是否已登录
4749
if not apikey.exists():
4850
console.info("You are not logged in. Use `swanlab login` to login.")

swanlab/sdk/cmd/merge_settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from swanlab.sdk.internal.settings import Settings
1212
from swanlab.sdk.internal.settings import settings as swanlab_settings
1313

14+
__all__ = ["merge_settings"]
15+
1416

1517
@with_cmd_lock
1618
@without_run("merge_settings")

0 commit comments

Comments
 (0)