Prhub

#25308 [multimodal_gen] Preserve _explicit_fields across dataclasses.replace in DiffGenerator

原始 PR 作者 whn09 合并时间 2026-06-04 11:02 文件变更 2 提交数 5 评论 5 代码增减 +51 / -0

执行摘要

修复 dataclasses.replace 丢失显式字段属性

用户调用 DiffGenerator.generate() 时显式指定 width/height(如请求 1024x1024),但输出被根据宽高比计算的默认值覆盖(如 1248x832)。根本原因是 dataclasses.replace 只复制 dataclass 字段,而 _explicit_fields 是动态属性,新实例丢失了它,导致 InputValidationStage 无法判断用户显式设置了尺寸。

该 PR 值得阅读,因为它揭示了 Python dataclasses.replace 的一个常见陷阱:动态属性不会被复制。代码简洁、修复专注、测试覆盖好,是高质量的小型修复范例。

讨论亮点

Reviewer mickqian 要求在 diffusion_generator.py 清理注释(“please clean this a bit”)。作者 whn09 回应“Done”,并在后续提交(bc7d869)中收紧注释,删除了冗余说明,保留了核心信息。该 reviewer 随后给出了 APPROVED。讨论集中在代码风格和注释清晰度,无设计争议。

实现拆解

  1. DiffGenerator.generate() 的 per-prompt 循环(文件 diffusion_generator.py)中,在 dataclasses.replace 调用后添加一行恢复 _explicit_fields:从原始 sampling_params_orig 获取该属性并与被重写的键(promptoutput_file_nameimage_path)取并集。
  2. 新增单元测试 test_dataclasses_replace_preserves_explicit_fieldstest_sampling_params.py 中,验证两点:(a) 纯 dataclasses.replace 确实丢弃 _explicit_fields;(b) 采用与修复相同的恢复逻辑后,build_request_extra() 返回的 explicit_fields 包含预期键。
文件 模块 状态 重要度
python/sglang/multimodal_gen/runtime/entrypoints/diffusion_generator.py 扩散生成 modified 5.19
python/sglang/multimodal_gen/test/unit/test_sampling_params.py 采样参数 modified 5.56

关键符号

DiffGenerator.generate test_dataclasses_replace_preserves_explicit_fields

关键源码片段

python/sglang/multimodal_gen/runtime/entrypoints/diffusion_generator.py core-logic

修复主文件:在 per-prompt 循环中恢复 _explicit_fields 属性,确保用户显式设置的 width/height 不被覆盖。

# 文件 : python/sglang/multimodal_gen/runtime/entrypoints/diffusion_generator.py
# 在 generate() 方法的 per-prompt 循环中for i, p in enumerate(prompts):
    sampling_params = dataclasses.replace(
        sampling_params_orig,
        prompt=p,
        output_file_name=user_output_file_name,
        image_path=image_paths_per_prompt[i],
    )
    # `dataclasses.replace` 只复制 dataclass 字段,
    # 动态属性 _explicit_fields 会丢失。
    # 以下两行恢复该属性,并将循环中覆盖的键标记为显式设置。
    sampling_params._explicit_fields = getattr(
        sampling_params_orig, "_explicit_fields", set()
    ) | {"prompt", "output_file_name", "image_path"}
    sampling_params._set_output_file_name()
    req = prepare_request(
        server_args=self.server_args,
        sampling_params=sampling_params,
        external_trace_header=external_trace_header,
    )
    # ... 后续处理
python/sglang/multimodal_gen/test/unit/test_sampling_params.py test-coverage

新增回归测试,验证 dataclasses.replace 后恢复 _explicit_fields 的行为,防止将来退化。

# 文件 : python/sglang/multimodal_gen/test/unit/test_sampling_params.py
# 新增的回归测试方法def test_dataclasses_replace_preserves_explicit_fields(self):
    """验证 dataclasses.replace 会丢弃 _explicit_fields,DiffGenerator 必须恢复它。"""
    import dataclasses
​
    # 创建原始 SamplingParams,带有显式 width 和 height
    sampling_params_orig = SamplingParams.from_user_sampling_params_args(
        "dummy-model",
        server_args=server_args,
        prompt="orig",
        image_path="/tmp/in.png",
        width=768,
        height=512,
    )
​
    # 确认原始对象确实记录了 width/height 为显式字段
    self.assertIn("width", sampling_params_orig._explicit_fields)
    self.assertIn("height", sampling_params_orig._explicit_fields)
​
    # 纯 dataclasses.replace 会丢失 _explicit_fields
    cloned = dataclasses.replace(
        sampling_params_orig,
        prompt="new",
        output_file_name=None,
        image_path="/tmp/in2.png",
    )
    self.assertFalse(hasattr(cloned, "_explicit_fields"))
​
    # 模拟 DiffGenerator 中的恢复逻辑:获取原始对象的 _explicit_fields
    # 并与循环中覆盖的键取并集
    cloned._explicit_fields = getattr(
        sampling_params_orig, "_explicit_fields", set()
    ) | {"prompt", "output_file_name", "image_path"}
​
    # 验证 build_request_extra() 中包含 width、height 以及被重写的键
    explicit = set(cloned.build_request_extra()["explicit_fields"])
    self.assertIn("width", explicit)
    self.assertIn("height", explicit)
    self.assertIn("prompt", explicit)
    self.assertIn("image_path", explicit)

评论区精华

清理注释 style

Reviewer mickqian 在 diffusion_generator.py 上评论“please clean this a bit”,指原始注释过于冗长。

结论:作者 whn09 在后续提交中大幅缩减了注释,保留了核心信息。mickqian 随后批准了 PR。 · 已解决

风险与影响

变更极小(6 行源码),仅影响 DiffGenerator 中克隆 SamplingParams 的路径,不涉及模型前向或推理逻辑。无性能影响。风险在于未来如果有人修改 _explicit_fields 的命名或存储方式,可能会遗漏此处的恢复逻辑,但新增的单元测试提供了保护。

只影响通过 DiffGenerator.generate() 显式传递 width/height 等参数的用户。修复后,这些显式参数被正确传递到下游的 InputValidationStage,输出尺寸符合用户预期。对于未显式指定相关参数的用户,行为无变化。

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论