Skip to content

feat: add swanlab.merge_callbacks API and callbacker tests#1591

Merged
SAKURA-CAT merged 3 commits intomainfrom
feat/merge-callbacks
Apr 30, 2026
Merged

feat: add swanlab.merge_callbacks API and callbacker tests#1591
SAKURA-CAT merged 3 commits intomainfrom
feat/merge-callbacks

Conversation

@SAKURA-CAT
Copy link
Copy Markdown
Member

Summary

  • 新增 swanlab.merge_callbacks() 公开 API,允许用户在 swanlab.init() 之前注册全局回调
  • 重构 CallbackManager,移除 callbacks_dict 构造参数,统一通过 merge_callbacks 注入
  • 新增 callbacker 模块单元测试(12 cases)

Changes

文件 说明
swanlab/sdk/cmd/merge_callbacks.py 新增 merge_callbacks 命令实现
swanlab/__init__.py 对外暴露 merge_callbacks
swanlab/__init__.pyi 添加 merge_callbacks 类型声明
swanlab/sdk/__init__.py 导出 merge_callbacks
swanlab/sdk/internal/context/components/callbacker/__init__.py 重构 CallbackManager
tests/unit/sdk/internal/context/components/callbacker/test_callbacker.py 新增单元测试

Usage

import swanlab
from swanlab import Callback

class MyCallback(Callback):
    @property
    def name(self) -> str:
        return "my_callback"

    def on_run_initialized(self, run_dir, path):
        print("Run initialized!")

# 单个
swanlab.merge_callbacks(MyCallback())
# 多个
swanlab.merge_callbacks([MyCallback(), AnotherCallback()])

swanlab.init()

Refactor callback handling to support injecting per-run callbacks while preserving global defaults. Key changes:

- swanlab/sdk/cmd/init.py: Accept callbacks as Iterable, pass callbacks into _init and into RunContext instead of merging into a global callbacker.
- swanlab/sdk/internal/context/__init__.py: RunContext now accepts optional callbacks and builds its callback manager from them.
- swanlab/sdk/internal/context/components/callbacker/__init__.py: Introduce global_callbacker, make CallbackManager accept an initial dict, and change create_callback_manager to merge global callbacks with injected per-run callbacks (local callbacks take precedence). Adjust type hints and API accordingly.
- swanlab/sdk/internal/context/components/__init__.py: Remove exporting the previous global callbacker symbol.
- tests/unit/conftest.py: Updated to reference global_callbacker and clear its registered callbacks during test isolation.

Notes: This is a behavioral/API change — the old module-level "callbacker" usage was removed in favor of "global_callbacker" plus per-run injection via create_callback_manager(callbacks=...). Call signatures and exported symbols were updated accordingly.
Introduce a merge_callbacks API and refactor callback manager behavior.

- Add swanlab/sdk/cmd/merge_callbacks.py implementing merge_callbacks (protected by with_cmd_lock and without_run) and export it from swanlab.sdk and top-level swanlab package (including .pyi typing stub).
- Refactor CallbackManager: simplify __init__ to start with an empty registry and accept Optional[Iterable[Callback]] in merge_callbacks (no-op for None/empty).
- Change create_callback_manager to build a new CallbackManager that first merges global callbacks and then local ones (local callbacks override global and do not mutate global state).
- Add comprehensive unit tests tests/unit/sdk/internal/context/components/callbacker/test_callbacker.py to cover merging, overwriting, removal, dispatch, and isolation between global and local callbacks.

These changes allow registering global callbacks before swanlab.init(), ensure local callbacks can override globals without polluting global state, and add tests to verify behavior.
@SAKURA-CAT SAKURA-CAT requested a review from Nexisato April 30, 2026 07:20
@SAKURA-CAT SAKURA-CAT self-assigned this Apr 30, 2026
@SAKURA-CAT SAKURA-CAT added the 💪 enhancement New feature or request label Apr 30, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the merge_callbacks function to the SwanLab SDK, allowing users to register custom callbacks before run initialization. The internal architecture has been refactored to support both global and local callback registries, ensuring that local callbacks take precedence. The review feedback focuses on improving type hint consistency across the SDK by suggesting the use of Union[Iterable[Callback], Callback] for callback parameters in several internal functions and ensuring the necessary Union typing import is included. Additionally, a refactoring opportunity was identified to simplify callback merging if internal methods are updated to handle the union type directly.

Comment thread swanlab/sdk/internal/context/components/callbacker/__init__.py Outdated
Comment thread swanlab/sdk/internal/context/components/callbacker/__init__.py Outdated
Comment thread swanlab/sdk/cmd/init.py Outdated
Comment thread swanlab/sdk/cmd/init.py Outdated
Comment thread swanlab/sdk/internal/context/__init__.py Outdated
Comment thread swanlab/sdk/internal/context/__init__.py Outdated
Comment thread swanlab/sdk/cmd/merge_callbacks.py Outdated
Introduce swanlab.sdk.typings.context.CallbacksType (single Callback or iterable) and update callback-related APIs to use it. Change callback manager to accept a single Callback instance (normalize to list) and guard against None, update merge_callbacks, RunContext, init internals, and type stubs to use the new alias. Add a deprecated register_callbacks wrapper in package __init__ for backwards compatibility and update tests to cover single-callback cases.
@SAKURA-CAT SAKURA-CAT merged commit 7f2b259 into main Apr 30, 2026
18 checks passed
@SAKURA-CAT SAKURA-CAT deleted the feat/merge-callbacks branch April 30, 2026 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💪 enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants