`PyImport_CreateModuleFromInitfunc()`: wrong `__name__` for submodules, non-ASCII names rejected, inittab name clashes
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Python
- Star
- 77.2k
- Fork
- 35.9k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
Bug report
Bug description:
Since PyImport_CreateModuleFromInitfunc() was added (in 3.15, gh-116146), I ran into some issues from real world use internally at Meta (with 3.15+, as well as our 3.14 fork, which has this backported). Collected here as a single issue for convenience - let me know if splitting is preferred.
The API is built on the internal create_builtin() helper, and inherits a few inittab behaviors that don't make sense for an explicitly-passed init function.
- Single-phase submodules get the short name. The package context is never set while
initfuncruns, so a single-phase init that creates its module assub(what pybind11'sPYBIND11_MODULE(sub, m)does) ends up with__name__ == 'sub'while the spec sayspkg.sub. The original impl handled that, but it was lost somewhere on the way. - Non-ASCII spec names raise
UnicodeEncodeError, even for multi-phase modules, which the dynamic loader accepts. - Names registered in
PyImport_Inittabare handled silently. Depending on the state of the builtin,initfuncis ignored, or the module created here replaces the builtin for later imports, or (multi-phase builtin)initfunc's module overwrites the real one insys.modules.sysandbuiltinsfall in the first bucket. - Undocumented semantics. Single-phase modules are added to
sys.modulesby the call itself, multi-phase ones aren't. The spec name is the module's identity, so a second call with the same name and a differentinitfuncreturns the cached module and never calls the new function.
The existing test only covers one top-level single-phase and one top-level multi-phase module, so none of this was caught.
AI disclosure: I ran into the first issue in production, used Claude Opus 5 and Fable 5.1 to root cause, which flagged the other issues while investigating. Fable 5.1 prepared the fixes.
Demo output before any fix:
pkg.sub: repr=<module 'sub'> __name__=sub
non-ASCII name: UnicodeEncodeError: 'ascii' codec can't encode character '\xf6'
same name, initfunc B after A: which=A calls_a=1 calls_b=0
'_random' via custom initfunc, then `import _random`: <module 'same'> hasattr(Random)=False
Tests demonstrating all of the above: https://github.com/itamaro/cpython/tree/gh-116146-initfunc-tests-only
Plan
One PR each:
- Set the package context while calling
initfunc, like the dynamic loader does (1) - Accept non-ASCII names for multi-phase init; single-phase gets the same
SystemErroras dynamic loading (2) - Raise
ImportErrorfor names registered inPyImport_Inittab(3) - Document the
sys.modulesand name-identity behavior (4)
CPython versions tested on:
CPython main branch, 3.15
Operating systems tested on:
Linux, macOS
Linked PRs
- gh-157387
- gh-157388
- gh-157389
- gh-157390
- gh-157758
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu với PyImport_CreateModuleFromInitfunc(), các bài kiểm thử hiện có cho các module cấp cao nhất một pha và đa pha, cùng nhánh kiểm thử được liên kết gh-116146-initfunc-tests-only. So sánh hành vi của nó với PyImport_Inittab và trình nạp động. Công việc được xem là hoàn tất khi bốn mục trong checklist đã được xử lý, bao gồm ngữ nghĩa về sys.modules và tính đồng nhất của tên được ghi chép; các PR được liên kết gh-157387 đến gh-157390 và gh-157758 cho thấy công việc đã được triển khai.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- python
- Lĩnh vực
- backend
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 25/100