Repository navigation
[Python] Move the TTree branch pythonization to Python - #22512
Merged
Merged
Conversation
Test Results 24 files 24 suites 3d 21h 39m 57s ⏱️ For more details on these failures, see this check. Results for commit 28d8cb6. ♻️ This comment has been updated with latest results. |
vepadulano
reviewed
Jun 8, 2026
guitargeek
force-pushed
the
ttree_pyz
branch
2 times, most recently
from
August 8, 2026 21:44
9024654 to
858b2fe
Compare
guitargeek
force-pushed
the
ttree_pyz
branch
2 times, most recently
from
August 8, 2026 22:26
cc12b77 to
a990e87
Compare
guitargeek
marked this pull request as draft
August 8, 2026 22:26
guitargeek
added a commit
to guitargeek/cppjit
that referenced
this pull request
Sep 3, 2026
LowLevelView.reshape() verified sizes by comparing the sum of the dimensions instead of the number of elements, their product: reshaping a five element array to (2, 3) was accepted because 5 == 2 + 3, while (1, 5) was rejected. The check is skipped for arrays of unknown size, the ones that typically get reshaped, which is why this went unnoticed. A correct size check is not enough, though: the strides and the converter projecting sub-views are chosen for the rank and layout of the view's C++ type and are not re-derived when reshaping. Any rank change produced a view reading garbage, and even the identity reshape of a fixed int[3][5] corrupted its strides. Reshape therefore now does what it is actually used for: providing the extent of dimensions the type leaves open, such as the size of an array behind a pointer. The rank must match, and only an unknown or empty dimension may be set, with -1 still standing for "unknown"; anything else raises ValueError, including dimensions whose byte size would overflow. The byte length is counted in strides of the outermost dimension as the creators count it, which for views with an itemsize override (const char*[], notably) differs from the itemsize, and the strides themselves are left as the creator laid them down. Also share the "fake max" marking an unknown outermost dimension between the creators and reshape (it was rederived from the itemsize, mistaking the unknown size of row-pointer and itemsize-overridden views for a known one), give the shape property a proper setter (reshape was installed directly despite its mismatching signature, so assignment misreported its result and deletion crashed), refuse to reshape a view without dimensions instead of reading through its null strides, and check allocations in the shape getter. Same issue as root-project/root#22512 (159ee7a1); its rework of rank-changing reshapes is left for a follow-up.
guitargeek
force-pushed
the
ttree_pyz
branch
3 times, most recently
from
October 7, 2026 17:47
04c19dc to
54f65af
Compare
guitargeek
marked this pull request as ready for review
October 7, 2026 19:04
TTreePyz.cxx implemented the tree.branch attribute syntax and the TTree::Branch overload dispatch in C++, next to a Python file holding the rest of the TTree pythonization. Both belong with the other pythonizations, where they can be read and changed without a rebuild. What kept them in C++ is gone: wrapping a leaf needs a converter for a type name and a shape (ll.bind_value), and matching the Branch overloads needs argument inspection, which Python does natively. The GetBranchAttr()/__getattr__ two-tuple protocol is gone with it: __getattr__ now returns the value. Left in C++, in ROOT::Internal::TreeUtils next to the other helpers TTree.h declares for internal callers, are three functions that the cppyy API cannot replace: - GetBranchAddress() and GetBranchElementObject(): TBranch::GetAddress() and TBranchElement::GetObject() return char* and so reach Python as str, with the pointer value gone. Reading the data members instead would skip the ValidateAddress() that TBranchElement's getters do. - BranchPtrToPtr<T>(): the address the T** overloads want is the proxy's own pointer, or the caller's pointer behind a reference proxy. That rule lives in cppyy's T** converter and no ll function exposes it, so the helper takes a T** and lets the converter apply it. Being compiled into libTree, the first two need no jitting; the template is instantiated once per proxied type on first use. ttree_branch.py covers the T** case by asserting on the branch address before filling, since filling through a branch bound to a temporary proxy is undefined. 🤖 Done with the help of AI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TTreePyz.cxx implemented the tree.branch attribute syntax and the TTree::Branch overload dispatch in C++, next to a Python file holding the rest of the TTree pythonization. Both belong with the other pythonizations, where they can be read and changed without a rebuild.
What kept them in C++ is gone: wrapping a leaf needs a converter for a type name and a shape (ll.bind_value), and matching the Branch overloads needs argument inspection, which Python does natively. The GetBranchAttr()/getattr two-tuple protocol is gone with it: getattr now returns the value.
Left in C++ are three helpers, declared through the interpreter on first branch access: GetAddress()/GetObject() return char* and so reach Python as str, and the address the T** overload wants depends on what kind of proxy holds it, a rule only the bindings know. The Declares are serialized on a lock: the interpreter must not see them twice and Declare releases the GIL.
ttree_branch.py covers the T** case by asserting on the branch address before filling, since filling through a branch bound to a temporary proxy is undefined.
🤖 Done with the help of AI