Skip to content

Commit

Permalink
[PyROOT] Don't assume ownership of TTree created by CloneTree()
Browse files Browse the repository at this point in the history
Just like in the case of the TTree constructor, Python does not own the
TTree if the current directory is a TFile.

Fixes a failure in the CMSSW unit tests.
  • Loading branch information
guitargeek committed Dec 4, 2024
1 parent f79b53c commit 575201e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,20 @@ def _TTree__getattr__(self, key):
out = cppyy.ll.cast[cast_type](out)
return out

def _TTree_CloneTree(self, *args, **kwargs):
"""
Forward the arguments to the C++ function and give up ownership if the
TTree is attached to a TFile, which is the owner in that case.
"""
import ROOT

out_tree = self._CloneTree(*args, **kwargs)
tdir = out_tree.GetDirectory()
if tdir and type(tdir).__cpp_name__ == "TFile":
ROOT.SetOwnership(out_tree, False)

return out_tree

def _TTree_Constructor(self, *args, **kwargs):
"""
Forward the arguments to the C++ constructor and give up ownership if the
Expand All @@ -326,9 +340,14 @@ def pythonize_ttree(klass, name):
# klass: class to be pythonized
# name: string containing the name of the class

# Functions that need to drop the ownership if the current directory is a TFile

klass._cpp_constructor = klass.__init__
klass.__init__ = _TTree_Constructor

klass._CloneTree = klass.CloneTree
klass.CloneTree = _TTree_CloneTree

# Pythonizations that are common to TTree and its subclasses.
# To avoid duplicating the same logic in the pythonizors of
# the subclasses, inject the pythonizations for all the target
Expand Down
16 changes: 15 additions & 1 deletion bindings/pyroot/pythonizations/test/memory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gc
import ROOT
import gc
import os
import unittest


Expand Down Expand Up @@ -71,5 +72,18 @@ def test_tcolor_memory_regulation(self):
# application does not segfault
c = ROOT.TColor(42, 42, 42)

def test_ttree_clone_in_file_context(self):
"""Test that CloneTree() doesn't give the ownership to Python when
TFile is opened."""

filename = "test_ttree_clone_in_file_context"

ttree = ROOT.TTree("tree", "tree")

with ROOT.TFile(filename, "RECREATE") as infile:
ttree_clone = ttree.CloneTree()

os.remove(filename)

if __name__ == '__main__':
unittest.main()

0 comments on commit 575201e

Please sign in to comment.