diff --git a/bindings/pyroot/pythonizations/CMakeLists.txt b/bindings/pyroot/pythonizations/CMakeLists.txt index 351cae618516e..dc05451a1f56d 100644 --- a/bindings/pyroot/pythonizations/CMakeLists.txt +++ b/bindings/pyroot/pythonizations/CMakeLists.txt @@ -97,6 +97,8 @@ set(py_sources ROOT/_pythonization/_tdirectory.py ROOT/_pythonization/_tdirectoryfile.py ROOT/_pythonization/_tf1.py + ROOT/_pythonization/_tf2.py + ROOT/_pythonization/_tf3.py ROOT/_pythonization/_tfile.py ROOT/_pythonization/_tformula.py ROOT/_pythonization/_tgraph.py diff --git a/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tf2.py b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tf2.py new file mode 100644 index 0000000000000..0ce9220100c00 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tf2.py @@ -0,0 +1,25 @@ +# Author: Vincenzo Eduardo Padulano CERN 11/2024 + +################################################################################ +# Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ +from . import pythonization + +def _TF2_constructor(self, *args, **kwargs): + """ + Forward the arguments to the C++ constructor and retain ownership. This + helps avoiding double deletes due to ROOT automatic memory management. + """ + self._cpp_constructor(*args, **kwargs) + import ROOT + ROOT.SetOwnership(self, False) + + +@pythonization("TF2") +def pythonize_tf2(klass): + klass._cpp_constructor = klass.__init__ + klass.__init__ = _TF2_constructor diff --git a/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tf3.py b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tf3.py new file mode 100644 index 0000000000000..11f5e8db240f6 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tf3.py @@ -0,0 +1,25 @@ +# Author: Vincenzo Eduardo Padulano CERN 11/2024 + +################################################################################ +# Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ +from . import pythonization + +def _TF3_constructor(self, *args, **kwargs): + """ + Forward the arguments to the C++ constructor and retain ownership. This + helps avoiding double deletes due to ROOT automatic memory management. + """ + self._cpp_constructor(*args, **kwargs) + import ROOT + ROOT.SetOwnership(self, False) + + +@pythonization("TF3") +def pythonize_tf3(klass): + klass._cpp_constructor = klass.__init__ + klass.__init__ = _TF3_constructor diff --git a/bindings/pyroot/pythonizations/test/memory.py b/bindings/pyroot/pythonizations/test/memory.py index 8a065938a80e9..488e6a2052261 100644 --- a/bindings/pyroot/pythonizations/test/memory.py +++ b/bindings/pyroot/pythonizations/test/memory.py @@ -53,5 +53,18 @@ def test_tstyle_memory_management(self): groot.SetStyle(style.GetName()) groot.ForceStyle() + def test_tf2_memory_regulation(self): + """Regression test for https://github.com/root-project/root/issues/16942""" + # The test is just that the memory regulation works correctly and the + # application does not segfault + f2 = ROOT.TF2("f2", "sin(x)*sin(y)/x/y") + + + def test_tf3_memory_regulation(self): + """Make sure TF3 is properly managed by the memory regulation logic""" + # The test is just that the memory regulation works correctly and the + # application does not segfault + f3 = ROOT.TF3("f3","[0] * sin(x) + [1] * cos(y) + [2] * z",0,10,0,10,0,10) + if __name__ == '__main__': unittest.main()