Skip to content

[API Compatibility] Change compatibility apis to ChangePrefixMatcher, inject paddle.enable_compat(), fix test environment context pollution -part#895

Open
Manfredss wants to merge 25 commits into
PaddlePaddle:masterfrom
Manfredss:patch_compat
Open

[API Compatibility] Change compatibility apis to ChangePrefixMatcher, inject paddle.enable_compat(), fix test environment context pollution -part#895
Manfredss wants to merge 25 commits into
PaddlePaddle:masterfrom
Manfredss:patch_compat

Conversation

@Manfredss

@Manfredss Manfredss commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

PR Docs

For the 24 torch.* APIs that are aligned through paddle.compat.*, switch the converter to the "prefix-only + enable_compat" strategy instead of mapping each to paddle.compat.X explicitly:

  1. api_mapping.json — change those 24 entries from ChangeAPIMatcher → paddle.compat.X to {"Matcher": "ChangePrefixMatcher"} . Converted calls now use the corresponding paddle.* prefix while preserving Torch-style signatures and argument names. For example, torch.sort(x, dim=-1) is converted to: paddle.sort(x, dim=-1). At runtime, enable_compat(level=2) dispatches the external paddle.sort call to its Torch-aligned implementation. Related mappings are adjusted accordingly: torch.nn.Softmax2d uses dim instead of the native Paddle axis; torch.nn.functional.softmin preserves input and dim.

  2. transformer/import_transformer.py — for converted files whose mapped packages include paddle, inject a deduplicated import paddle and a single paddle.enable_compat(level=2). In default mode, the code is inserted after the existing import block. In min mode, it is inserted after the module docstring and any __future__ imports, but before retained Torch imports, ensuring that the compat proxy is enabled before Torch is imported.

  3. tests/apibase.pypaddle.enable_compat(level=2) installs process-wide Torch proxy and Paddle namespace dispatch state. Call the shared disable_paddle_compat() helper immediately before every real PyTorch reference execution, ensuring that the reference always runs against real PyTorch, including when a test invokes run() multiple times. Cross-test process state is restored separately by the autouse fixture in tests/conftest.py.

PR APIs

torch.Tensor.allclose
torch.Tensor.max
torch.Tensor.median
torch.Tensor.min
torch.Tensor.sort

torch.allclose
torch.equal
torch.max
torch.median
torch.min
torch.nanmedian
torch.seed
torch.sort
torch.split
torch.unique

torch.nn.Linear
torch.nn.Softmax
torch.nn.Unfold

torch.nn.functional.linear
torch.nn.functional.log_softmax
torch.nn.functional.pad
torch.nn.functional.scaled_dot_product_attention
torch.nn.functional.softmax
torch.nn.functional.unfold

related Paddle PR:

paddle.Tensor.split is a known failure. It will be fixed in

Also in this PR

The issue of Cross-Test Global State Pollution in conftest.py is fixed. Originally PaConvert tests execute the original torch code and converted Paddle code sequentially in the same pytest worker. Some tests modify process-wide state without restoring it, including:

  • the compat proxy installed by paddle.enable_compat(level=2)
  • default device, dtype, and gradient state in PyTorch and Paddle;
  • environment variables such as CPU_NUM;
  • runtime monkeypatches applied to paddle.Tensor and paddle.nn.* classes.

Some generated helpers are defined inside temporary exec namespaces. After those namespaces are cleared, the class-level monkeypatches may remain and reference invalid globals, affecting subsequent tests. Therefore, cleaning up only the compat proxy is insufficient.

This change adds an autouse fixture that snapshots the relevant state before each test and restores it afterward. It disables compat, restores PyTorch/Paddle defaults and environment variables, and reverts modified class attributes. This isolates tests without changing PaConvert’s conversion behavior.

Co-authored by Claude and Codex

@Manfredss Manfredss closed this Jun 29, 2026
@Manfredss Manfredss reopened this Jun 29, 2026
@Manfredss
Manfredss marked this pull request as draft June 29, 2026 12:59
@Manfredss
Manfredss marked this pull request as ready for review June 29, 2026 13:00
@paddle-bot paddle-bot Bot added the contributor External developers label Jun 29, 2026
Manfredss and others added 6 commits July 2, 2026 20:37
… calls hit the alias

The default enable_compat() (level=1) does not alias paddle.*, so prefix-converted
calls (torch.X -> paddle.X) would run native and reject torch-style kwargs. level=2
turns on the paddle.* alias; caller-aware dispatch keeps paddle internals native.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eset

import_transformer.py:
- Inject paddle.enable_compat(level=2) via a transform() post-pass so it lands
  after the docstring, __future__ imports and the import block (fixes a
  pre-existing SyntaxError where injected imports preceded `from __future__`).
- Gate on real torch imports (torch_packages), not paddle_package_list, so a
  torch-free file importing only os/einops/setuptools no longer gains a needless
  paddle import or the process-global compat switch.

tests:
- Rename confest.py -> conftest.py so the autouse compat-reset fixture is loaded
  by pytest (was dead due to the typo).
- Dedupe the disable logic into conftest.disable_paddle_compat(), imported by
  apibase and called before each torch reference exec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Manfredss added 4 commits July 8, 2026 08:22
…ompat

Switch Tensor.allclose and Tensor.sort to ChangePrefixMatcher and keep
softmin's softmax call using torch arg names (input/dim), since compat
paddle APIs now accept torch-style args and reject paddle-native ones.
Update tests to inject enable_compat(level=2); fix torchvision
model_apibase proxy leak around the torch reference forward.
# enable_compat is injected in transform() (needs all imports in the body).
# Gate on real torch imports, not paddle_package_list: the latter also holds
# MAY_TORCH packages (os/einops/setuptools) that need no compat switch.
if self.imports_map[self.file]["torch_packages"]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

简化下代码,看有无更简单的写法,是否只需要修改visit_Module就可以?

@zhwesky2010

Copy link
Copy Markdown
Collaborator

PR冲突了

@zhwesky2010 zhwesky2010 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这些插入操作能不能复用已有的函数record_scope

@zhwesky2010

zhwesky2010 commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

注意代码风格简化并贴合已有架构来写,不要让AI随意发挥:

  1. 贴合已有架构、功能和风格来开发,不要从0开始(AI不懂代码库架构 喜欢重起炉灶)
  2. 非代码复用的情况下,不需要封各种类函数(只会增加代码复杂度并无意义)
  3. 移除冗余注释

return True
return False

def _inject_enable_compat(self):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这个使用record_scope不能插入吗?插入这个不需要从0开始重写吧

Manfredss and others added 2 commits July 14, 2026 02:53
Bring the latest API compatibility coverage into the branch while preserving the record_scope-based compat injection and test state isolation fixes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@paddle-bot

paddle-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

Thanks for your contribution!

Manfredss and others added 2 commits July 14, 2026 06:40
Align expected diffs with compat injection and intentional ChangePrefixMatcher behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Deduplicate paddle_package_list in ImportTransformer.visit_Module: since
imports are now batched into one record_scope call, its cross-call dedup
no longer removes duplicates, producing two 'import paddle' lines when a
file imports multiple torch-family packages (e.g. torchvision + datasets).

Regenerate default-mode goldens for the paddle.enable_compat(level=2)
injection and the intentional compat-prefix removals (equal, BatchNorm1d/2d),
matching the min-mode baseline update in f7e1c04.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@zhwesky2010 zhwesky2010 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

简单问题不用复杂化:这里的node进来时已经是一个处理干净的node,所有torch相关的import都清除干净了,只用在这个基础上插入好paddle相关import即可

line_NO += 1
import_nodes = []
for paddle_package in dict.fromkeys(paddle_package_list):
import_nodes.extend(ast.parse(f"import {paddle_package}").body)

@zhwesky2010 zhwesky2010 Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

直接在这里判断是否为 paddle_package=='paddle'

如果是,则import_nodes.extend(ast.parse(f"import paddle;paddle.enable_compat(2)").body)

并且该操作仅执行一次(当然执行多次问题也不大,后续会被isort校正)


has_torch_package = bool(self.imports_map[self.file]["torch_packages"])

has_enable_compat = any(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这些判断都需要吗?后面也会经过isort、black的格式化处理,移除多余import,这里不要想的太复杂了

if has_torch_package and not has_enable_compat:
import_nodes.extend(ast.parse("paddle.enable_compat(level=2)").body)

import_end = 1 if node.body and ast.get_docstring(node, clean=False) else 0

@zhwesky2010 zhwesky2010 Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

for循环,self.record_scope((self.root, "body", line_NO), import_nodes) 就行了吧。

原始的node在visit_Import、visit_ImportFrom时就已经被清除,原始node的import内容应该已经被清理掉了。

另外加上log_info,这个是比较重要的调试信息

…a single paddle.enable_compat(level=2) on top of the already-cleaned node, dropping redundant enable_compat/torch-package scans and adding log_info
# Under `paddle.enable_compat(level=2)` the prefix-converted calls
# (torch.X -> paddle.X) resolve to the torch-aligned paddle.compat.* impls,
# so inject it once when `import paddle` is added. isort/black dedupe repeats.
if "paddle" in paddle_package_list:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这个应该得 == "paddle" ,然后做个一次性判断 "enable_compat" not in import_code

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

我看一下

@Manfredss Manfredss changed the title [API Compatibility] Change compatibility apis to ChangePrefixMatcher, inject paddle.enable_compat() -part [API Compatibility] Change compatibility apis to ChangePrefixMatcher, inject paddle.enable_compat(), fix test environment context pollution -part Jul 24, 2026
while (
import_end < len(node.body)
and isinstance(node.body[import_end], ast.ImportFrom)
and node.body[import_end].module == "__future__"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这个写得有点hard code,直接修改diff文件吧


python -m pytest -v -s -p no:warnings "${PYTEST_IGNORE[@]}" \
--ignore=tests/test_cuda_stream.py \
--ignore=tests/test_cuda_CUDAGraph.py \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这三个单测不跑了吗,建议在这里加个list维护一个隔离的单测名单,分两批来跑

后面这个list还可以根据实际情况进一步扩容

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

跑的,分别在 53、59、64 行单独跑了

# internal `import torch` / `torch.SymInt` etc. resolve through the
# paddle proxy and blow up. Disable compat for the torch forward, then
# restore it so the paddle forward matches how a user runs the output.
from paddle.compat.proxy import TORCH_PROXY_FINDER

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这个是影响到了paddle内部的paddle.vision.* API吗

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

不是 paddle.vision.* API 本身受到影响

转换后的 Paddle 代码执行 paddle.enable_compat(level=2) 后会全局启用 Torch proxy;随后执行真实 torchvision 模型 forward 时,其内部的 Torch 引用可能被代理到 Paddle;因此这里临时关闭 compat,完成 Torch 侧计算后再恢复

Comment thread tests/apibase.py
)
assert paddle_code == expect_paddle_code, error_msg
elif compared_tensor_names:
disable_paddle_compat()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这里为何需要disable

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

APIBase.run() 会先执行真实 torch 代码,再执行转换后的 paddle 代码。paddle 代码中的 paddle.enable_compat(level=2) 执行后,compat 状态会一直保持到这次 run() 结束之后;如果同一个 pytest case 再次调用 run(),那 autouse fixture 这个时候还没有执行清理,第二次运行的 import torch 就会被代理到 paddle,导致 torch 基准结果实际上由 paddle 计算 所以必须在每次执行 torch 代码前关闭 compat

Comment thread tests/apibase.py
except Exception as e:
raise AssertionError(f"Unable to align results: {e}")
else:
disable_paddle_compat()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这里为何需要disable

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

同上

Comment thread tests/conftest.py
The logic is lazy and best-effort: it only touches a framework that is already in
``sys.modules``, so it never forces an import of torch/paddle (which would change
import ordering) for tests that don't use them.
"""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这个的作用是,看起来是paddle的改动还有些判断不完善吗,是不是应该去改paddle?

尽量是去完善问题的根源,避免在其他地方打补丁,不然就把坑留给用户了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor External developers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants