From eacb15e1e341a031dfc86b104ffa5a72b6d54f54 Mon Sep 17 00:00:00 2001 From: nyx-c-language Date: Wed, 12 Aug 2026 08:57:19 +0800 Subject: [PATCH] [SWE-Paddle] Add task PaddlePaddle__Paddle_78932 --- .../PaddlePaddle__Paddle-78932/README.md | 44 ++++ .../environment/README.md | 27 +++ .../PaddlePaddle__Paddle-78932/instruction.md | 19 ++ .../PaddlePaddle__Paddle-78932/proposal.md | 55 +++++ .../solution/code.patch | 92 +++++++ .../tests/test.patch | 229 ++++++++++++++++++ .../PaddlePaddle__Paddle-78932/tests/test.sh | 4 + 7 files changed, 470 insertions(+) create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-78932/README.md create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-78932/environment/README.md create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-78932/instruction.md create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-78932/proposal.md create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-78932/solution/code.patch create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-78932/tests/test.patch create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-78932/tests/test.sh diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78932/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/README.md new file mode 100644 index 000000000..6b2e66749 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/README.md @@ -0,0 +1,44 @@ +# PaddlePaddle__Paddle-78932 + +This directory converts Paddle PR #78932 into a SWE-Paddle community task candidate. + +## Source + +| Field | Value | +| --- | --- | +| Repo | `PaddlePaddle/Paddle` | +| PR | [78932](https://github.com/PaddlePaddle/Paddle/pull/78932) | +| PR title | `[API Compatibility] Support vararg and add alias for paddle.io.TensorDataset` | +| Base commit | `7b7e53fd28956700e5ed1ce68eb2aaeb59829777` | +| Merged at | `2026-05-11T08:51:45Z` | +| Task type | `feature_enhancement` | +| Resource | CPU | + +## Summary + +Allow `TensorDataset` to accept one or more tensors directly and expose it through `paddle.utils.data`, while preserving the existing list/tuple calling convention. + +## Why This Is A Good SWE-Paddle Candidate + +- The task reflects a common data-loading compatibility issue with clear inputs and observable dataset behavior. +- The change must distinguish a single Tensor from a list/tuple and from multiple positional tensors without breaking existing calls. +- The source PR provides real tests for list-based construction, single- and multi-Tensor varargs, item structure, dataset length, and public alias availability. +- The tests run deterministically on CPU without workers, external datasets, network access, or distributed devices. + +## Files + +- `proposal.md`: candidate proposal for maintainer triage. +- `instruction.md`: self-contained problem statement for the coding agent. +- `solution/code.patch`: gold patch from the merged PR. +- `tests/test.patch`: exact upstream test changes exposing the target behavior. +- `tests/test.sh`: minimal target test command. +- `environment/README.md`: environment notes for reproduction. +- `README.md`: task overview and verification entrypoint. + +## Verification + +```bash +bash tests/test.sh +``` + +Expected behavior: applying `tests/test.patch` to `base_commit` should preserve the existing list-based cases but fail on direct Tensor arguments and the missing public alias; applying both `tests/test.patch` and `solution/code.patch` should pass all target tests. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78932/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/environment/README.md new file mode 100644 index 000000000..233cfb8cb --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/environment/README.md @@ -0,0 +1,27 @@ +# Environment Notes + +This candidate is part of the SWE-Paddle community task set. + +## Expected Environment + +- Repository: `PaddlePaddle/Paddle` +- Base commit: `7b7e53fd28956700e5ed1ce68eb2aaeb59829777` +- Resource: CPU +- GPU required: no +- Build path: use an installed CPU Paddle wheel for the native runtime and load the target Python behavior from the source checkout; a Paddle source rebuild is not required. + +## Run Order + +1. Check out `PaddlePaddle/Paddle` at the base commit. +2. Apply `tests/test.patch`. +3. Run `bash tests/test.sh`; the direct Tensor and public alias cases should fail before the fix. +4. Apply `solution/code.patch`. +5. Run `bash tests/test.sh` again; all target tests should pass after the gold patch. + +## Minimal Test Command + +```bash +bash tests/test.sh +``` + +The verifier is responsible for deriving stable F2P and P2P node IDs from repeated runs. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78932/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/instruction.md new file mode 100644 index 000000000..8ff534a60 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/instruction.md @@ -0,0 +1,19 @@ +# 让 TensorDataset 支持常见的多参数写法 + +## 详细描述 + +目前 `paddle.io.TensorDataset` 需要把所有 Tensor 先放进一个 list 或 tuple 再传入。很多数据加载代码会直接使用 `TensorDataset(features, labels)` 这种写法,在 Paddle 中会报参数错误。只传一个 Tensor 时问题更隐蔽:Tensor 会被当成一组 Tensor 来处理,导致数据集长度和取出的数据结构不正确。 + +同时,使用 `paddle.utils.data` 的代码目前也找不到 `TensorDataset`。需要补齐这些常见调用方式,且不影响 Paddle 现有的 list/tuple 写法。 + +## 验收说明 + +- 传入多个 Tensor 时,数据集长度应取各 Tensor 的第一维,按索引读取时应返回包含对应行的 tuple。 +- 直接传入单个 Tensor 时,应得到只包含一项的 tuple,数据集长度仍为该 Tensor 的第一维。 +- 原有 list/tuple 调用必须继续正常工作,并且 `paddle.utils.data.TensorDataset` 应可正常访问。 + +## 技术要求 + +- 熟悉 Python 位置参数、可变参数和 decorator。 +- 熟悉 Paddle `Dataset` 和 Tensor 索引行为。 +- 能够使用现有 DataLoader 与 API compatibility 测试验证新旧调用方式。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78932/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/proposal.md new file mode 100644 index 000000000..aba0e29ea --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/proposal.md @@ -0,0 +1,55 @@ +# Task Proposal: PaddlePaddle__Paddle-78932 + +## 1. 来源信息 + +- Instance ID:`PaddlePaddle__Paddle-78932` +- PR 链接:https://github.com/PaddlePaddle/Paddle/pull/78932 +- PR 标题:`[API Compatibility] Support vararg and add alias for paddle.io.TensorDataset` +- `base_commit`:`7b7e53fd28956700e5ed1ce68eb2aaeb59829777` +- merged 时间:`2026-05-11T08:51:45Z` +- 你的身份:熟悉该模块的 contributor +- 后续联系人:TBD + +## 2. 问题一句话 + +`TensorDataset` 无法直接接收一个或多个 Tensor 作为独立参数,并且不能从 `paddle.utils.data` 使用同名 API。 + +## 3. 为什么适合作为 SWE-Paddle 样本 + +- **真实性**:目标调用方式在数据加载代码迁移时很常见,当前会直接报参数错误或得到错误的数据集长度。 +- **代表性**:要求同时兼容 list/tuple、单 Tensor 和多 Tensor 三种入参形式,与常见的 Python API 兼容问题一致。 +- **边界清楚**:修改集中在 `TensorDataset` 的参数处理和公开导出,不涉及 DataLoader worker 或数据集外部资源。 +- **非平凡性**:单 Tensor 在 Python 中可迭代,不能简单当作 Tensor 列表处理;还要保证共享参数适配逻辑不破坏已有 API。 +- **环境友好性**:所有目标测试只使用小型 CPU Tensor,可稳定重复。 + +## 4. 任务类型和标签 + +- 任务类型:`feature_enhancement` +- 执行后端:`cpu` +- 设备范围:`cpu_only` +- 模块标签:`[data, dataset, api-compatibility]` + +## 5. 验证思路 + +- 目标测试命令:`bash tests/test.sh` +- 目标测试文件:`test/ai_edited_test/test_ai_dataloader.py` 和 `test/legacy_test/test_paddle_utils_data.py` +- 修复前预期:现有 list 调用正常;多 Tensor 位置参数报错,单 Tensor 被误解为可迭代的 Tensor 集合,`paddle.utils.data.TensorDataset` 不可用。 +- 修复后预期:旧 list 调用保持不变,单 Tensor 和多 Tensor 调用返回正确长度与 tuple item,新公开入口可正常访问。 +- P2P 候选:`test_tensor_dataset_basic`、`test_tensor_dataset_1d`、`test_tensor_dataset_iter`。 +- F2P 候选:`test_tensor_dataset_varargs`、`test_tensor_dataset_varargs_single`、`TestAlias::test_compatibility`。 + +## 6. 环境与资源 + +- 资源需求:CPU +- Paddle 来源:`PaddlePaddle/Paddle` source checkout at `base_commit` +- 是否能提供 Docker:暂无 +- patch 类型:Python-only +- 最小测试命令:`bash tests/test.sh` +- 是否有 oracle 日志:由 SWE-Paddle verifier 结果另行维护 + +## 7. 风险自查 + +- 泄露风险:任务描述只说明用户可见的入参方式和数据集行为,未说明 Gold patch 的具体实现。 +- 环境风险:历史 checkout 与已安装 wheel 可能有 Python 模块差异,cross verifier 需要使用受控的 source overlay。 +- flaky 风险:测试只校验 shape、长度、tuple 结构和 API 可访问性,不依赖随机数值、worker 时序或外部资源。 +- 拆分风险:varargs 和 `paddle.utils.data` 导出都围绕同一个 `TensorDataset` API 兼容问题,与来源 PR 的单一目标一致。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78932/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/solution/code.patch new file mode 100644 index 000000000..e3950694e --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/solution/code.patch @@ -0,0 +1,92 @@ +diff --git a/python/paddle/io/dataloader/dataset.py b/python/paddle/io/dataloader/dataset.py +index e7519ae2cfe0401b029d2f91a904915a2894afa0..2a8ecb8c1bb0659ec90d46697ed05f9483a91d96 100755 +--- a/python/paddle/io/dataloader/dataset.py ++++ b/python/paddle/io/dataloader/dataset.py +@@ -25,9 +25,10 @@ from typing import ( + TypeVar, + ) + +-from typing_extensions import Never, TypeVarTuple, Unpack ++from typing_extensions import Never, TypeVarTuple, Unpack, overload + + import paddle ++from paddle.utils.decorator_utils import variadic_tensor_decorator + + from ... import framework + +@@ -319,6 +320,13 @@ class TensorDataset(Dataset["Tensor"]): + + tensors: Sequence[Tensor] + ++ @overload ++ def __init__(self, tensors: Sequence[Tensor]) -> None: ... ++ ++ @overload ++ def __init__(self, *tensors: Tensor) -> None: ... ++ ++ @variadic_tensor_decorator('tensors', 1) + def __init__(self, tensors: Sequence[Tensor]) -> None: + if not framework.in_dynamic_mode(): + raise RuntimeError( +diff --git a/python/paddle/utils/data/__init__.py b/python/paddle/utils/data/__init__.py +index 34502b82e20c8dc0235e3a842d10649824dbd2af..49358baf5bf1033accb2530f613049304dd8c810 100644 +--- a/python/paddle/utils/data/__init__.py ++++ b/python/paddle/utils/data/__init__.py +@@ -22,6 +22,7 @@ from .dataset import ( + Dataset, + IterableDataset, + Subset, ++ TensorDataset, + random_split, + ) + from .sampler import ( +@@ -44,4 +45,5 @@ __all__ = [ + 'RandomSampler', + 'Sampler', + 'SequentialSampler', ++ 'TensorDataset', + ] +diff --git a/python/paddle/utils/data/dataset.py b/python/paddle/utils/data/dataset.py +index f4a5f8a70c43162fa3886f33d187d0bca68eebe6..469280a61bb22f9601eec3b26670e9e0087d9787 100644 +--- a/python/paddle/utils/data/dataset.py ++++ b/python/paddle/utils/data/dataset.py +@@ -18,5 +18,6 @@ from paddle.io import ( + Dataset as Dataset, + IterableDataset as IterableDataset, + Subset as Subset, ++ TensorDataset as TensorDataset, + random_split as random_split, + ) +diff --git a/python/paddle/utils/decorator_utils.py b/python/paddle/utils/decorator_utils.py +index b7f55e0cf05f66d7c02d073a76e0918803c3a6d7..bda544574049e16960c50709466ea0ff17ad8a55 100644 +--- a/python/paddle/utils/decorator_utils.py ++++ b/python/paddle/utils/decorator_utils.py +@@ -1001,6 +1001,7 @@ def use_first_signature( + + def variadic_tensor_decorator( + param_name: str, ++ param_pos: int = 0, + ) -> Callable[[Callable[_InputT, _RetT]], Callable[_InputT, _RetT]]: + """ + Decorator to handle variadic tensor arguments. +@@ -1018,14 +1019,14 @@ def variadic_tensor_decorator( + def wrapper(*args: _InputT.args, **kwargs: _InputT.kwargs) -> _RetT: + # PyTorch usage: variadic tensor arguments + if len(args) >= 1 and isinstance( +- args[0], (paddle.Tensor, paddle.pir.Value) ++ args[param_pos], (paddle.Tensor, paddle.pir.Value) + ): +- kwargs[param_name] = list(args) +- args = () ++ kwargs[param_name] = list(args[param_pos:]) ++ args = args[:param_pos] + # Paddle usage: list/tuple argument +- elif len(args) >= 1 and isinstance(args[0], (list, tuple)): +- kwargs[param_name] = args[0] +- args = () ++ elif len(args) >= 1 and isinstance(args[param_pos], (list, tuple)): ++ kwargs[param_name] = args[param_pos] ++ args = args[:param_pos] + return func(*args, **kwargs) + + wrapper.__signature__ = inspect.signature(func) diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78932/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/tests/test.patch new file mode 100644 index 000000000..a3bc635af --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/tests/test.patch @@ -0,0 +1,229 @@ +diff --git a/test/ai_edited_test/test_ai_dataloader.py b/test/ai_edited_test/test_ai_dataloader.py +index 2622fc76d665e17ffd6f60706390dcc9103e8bbe..002173f41490e209b227cf541ad4aa9d84387824 100644 +--- a/test/ai_edited_test/test_ai_dataloader.py ++++ b/test/ai_edited_test/test_ai_dataloader.py +@@ -96,6 +96,30 @@ class TestTensorDataset(unittest.TestCase): + items = [dataset[i] for i in range(5)] + self.assertEqual(len(items), 5) + ++ def test_tensor_dataset_varargs(self): ++ """TensorDataset with variable arguments (*args).""" ++ data1 = paddle.randn([10, 5]) ++ data2 = paddle.randn([10, 3]) ++ data3 = paddle.randn([10, 2]) ++ dataset = TensorDataset(data1, data2, data3) ++ self.assertEqual(len(dataset), 10) ++ item = dataset[0] ++ self.assertIsInstance(item, tuple) ++ self.assertEqual(len(item), 3) ++ self.assertEqual(item[0].shape, [5]) ++ self.assertEqual(item[1].shape, [3]) ++ self.assertEqual(item[2].shape, [2]) ++ ++ def test_tensor_dataset_varargs_single(self): ++ """TensorDataset with single tensor as vararg.""" ++ data = paddle.randn([8, 4]) ++ dataset = TensorDataset(data) ++ self.assertEqual(len(dataset), 8) ++ item = dataset[0] ++ self.assertIsInstance(item, tuple) ++ self.assertEqual(len(item), 1) ++ self.assertEqual(item[0].shape, [4]) ++ + + class TestComposeDataset(unittest.TestCase): + """Test ComposeDataset.""" +diff --git a/test/legacy_test/test_paddle_utils_data.py b/test/legacy_test/test_paddle_utils_data.py +index e5e0c2306201dc0018c6bbdbee6ff60f0e32f2be..717385f88f046b9e86c58455689020993a3ba35c 100644 +--- a/test/legacy_test/test_paddle_utils_data.py ++++ b/test/legacy_test/test_paddle_utils_data.py +@@ -24,104 +24,93 @@ class TestUtilsAttrError(unittest.TestCase): + + class TestAlias(unittest.TestCase): + def setUp(self): +- self.ioObject = paddle.io.Dataset +- self.utilsObject = paddle.utils.data.Dataset +- self.directObject = paddle.utils.data.dataset.Dataset ++ self.api_map = [ ++ ( ++ paddle.io.Dataset, ++ paddle.utils.data.Dataset, ++ paddle.utils.data.dataset.Dataset, ++ None, ++ ), ++ ( ++ paddle.io.ChainDataset, ++ paddle.utils.data.ChainDataset, ++ paddle.utils.data.dataset.ChainDataset, ++ None, ++ ), ++ ( ++ paddle.io.ConcatDataset, ++ paddle.utils.data.ConcatDataset, ++ paddle.utils.data.dataset.ConcatDataset, ++ None, ++ ), ++ ( ++ paddle.io.IterableDataset, ++ paddle.utils.data.IterableDataset, ++ paddle.utils.data.dataset.IterableDataset, ++ None, ++ ), ++ ( ++ paddle.io.Sampler, ++ paddle.utils.data.Sampler, ++ paddle.utils.data.sampler.Sampler, ++ None, ++ ), ++ ( ++ paddle.io.SequenceSampler, ++ paddle.utils.data.SequentialSampler, ++ paddle.utils.data.sampler.SequentialSampler, ++ None, ++ ), ++ ( ++ paddle.io.Subset, ++ paddle.utils.data.Subset, ++ paddle.utils.data.dataset.Subset, ++ None, ++ ), ++ ( ++ paddle.io.get_worker_info, ++ paddle.utils.data.get_worker_info, ++ paddle.utils.data.dataloader.get_worker_info, ++ paddle.utils.data._utils.worker.get_worker_info, ++ ), ++ ( ++ paddle.io.random_split, ++ paddle.utils.data.random_split, ++ paddle.utils.data.dataset.random_split, ++ None, ++ ), ++ ( ++ paddle.io.dataloader.collate.default_collate_fn, ++ paddle.utils.data.default_collate, ++ paddle.utils.data.dataloader.default_collate, ++ paddle.utils.data._utils.collate.default_collate, ++ ), ++ ( ++ paddle.io.BatchSampler, ++ paddle.utils.data.BatchSampler, ++ paddle.utils.data.sampler.BatchSampler, ++ None, ++ ), ++ ( ++ paddle.io.RandomSampler, ++ paddle.utils.data.RandomSampler, ++ paddle.utils.data.sampler.RandomSampler, ++ None, ++ ), ++ ( ++ paddle.io.TensorDataset, ++ paddle.utils.data.TensorDataset, ++ paddle.utils.data.dataset.TensorDataset, ++ None, ++ ), ++ ] + + def test_compatibility(self): +- self.assertTrue(self.ioObject is self.utilsObject) +- self.assertTrue(self.ioObject is self.directObject) +- +- +-class TestChainDatasetAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.ChainDataset +- self.utilsObject = paddle.utils.data.ChainDataset +- self.directObject = paddle.utils.data.dataset.ChainDataset +- +- +-class TestConcatDatasetAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.ConcatDataset +- self.utilsObject = paddle.utils.data.ConcatDataset +- self.directObject = paddle.utils.data.dataset.ConcatDataset +- +- +-class TestIterableDatasetAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.IterableDataset +- self.utilsObject = paddle.utils.data.IterableDataset +- self.directObject = paddle.utils.data.dataset.IterableDataset +- +- +-class TestSamplerAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.Sampler +- self.utilsObject = paddle.utils.data.Sampler +- self.directObject = paddle.utils.data.sampler.Sampler +- +- +-class TestSequentialSamplerAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.SequenceSampler +- self.utilsObject = paddle.utils.data.SequentialSampler +- self.directObject = paddle.utils.data.sampler.SequentialSampler +- +- +-class TestSubsetAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.Subset +- self.utilsObject = paddle.utils.data.Subset +- self.directObject = paddle.utils.data.dataset.Subset +- +- +-class TestGetWorkerInfoAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.get_worker_info +- self.utilsObject = paddle.utils.data.get_worker_info +- self.directObject = paddle.utils.data.dataloader.get_worker_info +- self.internalUtilsObject = ( +- paddle.utils.data._utils.worker.get_worker_info +- ) +- +- def test_compatibility(self): +- super().test_compatibility() +- self.assertTrue(self.ioObject is self.internalUtilsObject) +- +- +-class TestRandomSplitAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.random_split +- self.utilsObject = paddle.utils.data.random_split +- self.directObject = paddle.utils.data.dataset.random_split +- +- +-class TestDefaultCollateAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.dataloader.collate.default_collate_fn +- self.utilsObject = paddle.utils.data.default_collate +- self.directObject = paddle.utils.data.dataloader.default_collate +- self.internalUtilsObject = ( +- paddle.utils.data._utils.collate.default_collate +- ) +- +- def test_compatibility(self): +- super().test_compatibility() +- self.assertTrue(self.ioObject is self.internalUtilsObject) +- +- +-class TestBatchSamplerAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.BatchSampler +- self.utilsObject = paddle.utils.data.BatchSampler +- self.directObject = paddle.utils.data.sampler.BatchSampler +- +- +-class TestRandomSamplerAlias(TestAlias): +- def setUp(self): +- self.ioObject = paddle.io.RandomSampler +- self.utilsObject = paddle.utils.data.RandomSampler +- self.directObject = paddle.utils.data.sampler.RandomSampler ++ for pairs in self.api_map: ++ self.assertTrue(pairs[0], pairs[1]) ++ self.assertTrue(pairs[0], pairs[2]) ++ if pairs[3] is not None: ++ self.assertTrue(pairs[0], pairs[3]) + + + if __name__ == "__main__": diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78932/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/tests/test.sh new file mode 100644 index 000000000..e786b31b0 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78932/tests/test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +set -euo pipefail +python -m pytest test/ai_edited_test/test_ai_dataloader.py::TestTensorDataset test/legacy_test/test_paddle_utils_data.py::TestAlias::test_compatibility -q