diff --git a/python/basic/PyROOT_basictests.py b/python/basic/PyROOT_basictests.py index a90e865806..4615ff65a9 100644 --- a/python/basic/PyROOT_basictests.py +++ b/python/basic/PyROOT_basictests.py @@ -279,17 +279,25 @@ def test1Strings( self ): def test2Lists( self ): """Test list/TList behavior and compatibility""" + # A TList is non-owning. In order to fill the TList with in-place created + # objects, we write this little helper to create a new TObjectString + # whose lifetime is managed by a separate owning Python list. + objects = [] + def make_obj_str(s): + objects.append(TObjString(s)) + return objects[-1] + l = TList() - l.Add( TObjString('a') ) - l.Add( TObjString('b') ) - l.Add( TObjString('c') ) - l.Add( TObjString('d') ) - l.Add( TObjString('e') ) - l.Add( TObjString('f') ) - l.Add( TObjString('g') ) - l.Add( TObjString('h') ) - l.Add( TObjString('i') ) - l.Add( TObjString('j') ) + l.Add( make_obj_str('a') ) + l.Add( make_obj_str('b') ) + l.Add( make_obj_str('c') ) + l.Add( make_obj_str('d') ) + l.Add( make_obj_str('e') ) + l.Add( make_obj_str('f') ) + l.Add( make_obj_str('g') ) + l.Add( make_obj_str('h') ) + l.Add( make_obj_str('i') ) + l.Add( make_obj_str('j') ) self.assertEqual( len(l), 10 ) self.assertEqual( l[3], 'd' ) @@ -299,14 +307,14 @@ def test2Lists( self ): self.assertEqual( list(l), ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] ) - l[3] = TObjString('z') + l[3] = make_obj_str('z') self.assertEqual( list(l), ['a', 'b', 'c', 'z', 'e', 'f', 'g', 'h', 'i', 'j'] ) del l[2] self.assertEqual( list(l), ['a', 'b', 'z', 'e', 'f', 'g', 'h', 'i', 'j'] ) - self.assertTrue( TObjString('b') in l ) - self.assertTrue( not TObjString('x') in l ) + self.assertTrue( make_obj_str('b') in l ) + self.assertTrue( not make_obj_str('x') in l ) self.assertEqual( list(l[2:6]), ['z', 'e', 'f', 'g'] ) self.assertEqual( list(l[2:6:2]), ['z', 'f'] ) @@ -317,27 +325,27 @@ def test2Lists( self ): del l[2:4] self.assertEqual( list(l), ['a', 'b', 'f', 'g', 'h', 'i', 'j'] ) - l[2:5] = [ TObjString('1'), TObjString('2') ] + l[2:5] = [ make_obj_str('1'), make_obj_str('2') ] self.assertEqual( list(l), ['a', 'b', '1', '2', 'i', 'j'] ) - l[6:6] = [ TObjString('3') ] + l[6:6] = [ make_obj_str('3') ] self.assertEqual( list(l), ['a', 'b', '1', '2', 'i', 'j', '3'] ) - l.append( TObjString('4') ) + l.append( make_obj_str('4') ) self.assertEqual( list(l), ['a', 'b', '1', '2', 'i', 'j', '3', '4'] ) - l.extend( [ TObjString('5'), TObjString('j') ] ) + l.extend( [ make_obj_str('5'), make_obj_str('j') ] ) self.assertEqual( list(l), ['a', 'b', '1', '2', 'i', 'j', '3', '4', '5', 'j'] ) self.assertEqual( l.count( 'b' ), 1 ) self.assertEqual( l.count( 'j' ), 2 ) self.assertEqual( l.count( 'x' ), 0 ) - self.assertEqual( l.index( TObjString( 'i' ) ), 4 ) - self.assertRaises( ValueError, l.index, TObjString( 'x' ) ) + self.assertEqual( l.index( make_obj_str( 'i' ) ), 4 ) + self.assertRaises( ValueError, l.index, make_obj_str( 'x' ) ) - l.insert( 3, TObjString('6') ) - l.insert( 20, TObjString('7') ) - l.insert( -1, TObjString('8') ) + l.insert( 3, make_obj_str('6') ) + l.insert( 20, make_obj_str('7') ) + l.insert( -1, make_obj_str('8') ) if not self.legacy_pyroot: # The pythonisation of TSeqCollection in experimental PyROOT mimics the # behaviour of the Python list, in this case for insert. @@ -346,7 +354,7 @@ def test2Lists( self ): # element of the list. self.assertEqual(list(l), ['a', 'b', '1', '6', '2', 'i', 'j', '3', '4', '5', 'j', '8', '7']) # Re-synchronize with current PyROOT's list - l.insert(0, TObjString('8')) + l.insert(0, make_obj_str('8')) self.assertEqual(list(l), ['8', 'a', 'b', '1', '6', '2', 'i', 'j', '3', '4', '5', 'j', '8', '7']) l.pop(-2) self.assertEqual(list(l), ['8', 'a', 'b', '1', '6', '2', 'i', 'j', '3', '4', '5', 'j', '7']) @@ -356,10 +364,10 @@ def test2Lists( self ): self.assertEqual( l.pop(3), '1' ) self.assertEqual( list(l), ['8', 'a', 'b', '6', '2', 'i', 'j', '3', '4', '5', 'j'] ) - l.remove( TObjString( 'j' ) ) - l.remove( TObjString( '3' ) ) + l.remove( make_obj_str( 'j' ) ) + l.remove( make_obj_str( '3' ) ) - self.assertRaises( ValueError, l.remove, TObjString( 'x' ) ) + self.assertRaises( ValueError, l.remove, make_obj_str( 'x' ) ) self.assertEqual( list(l), ['8', 'a', 'b', '6', '2', 'i', '4', '5', 'j'] ) l.reverse() diff --git a/python/distrdf/dask/check_friend_trees_alignment.py b/python/distrdf/dask/check_friend_trees_alignment.py index a55698e404..e4c1c42697 100644 --- a/python/distrdf/dask/check_friend_trees_alignment.py +++ b/python/distrdf/dask/check_friend_trees_alignment.py @@ -30,6 +30,8 @@ def create_chain(): for i in range(3, 6): friend.Add(f"{FILENAMES[i]}?#{TREENAMES[i]}") + # The friend will be owned by the main TChain + ROOT.SetOwnership(friend, False) main.AddFriend(friend, "friend") return main diff --git a/python/distrdf/spark/check_friend_trees_alignment.py b/python/distrdf/spark/check_friend_trees_alignment.py index e6276818fa..bcec2ee350 100644 --- a/python/distrdf/spark/check_friend_trees_alignment.py +++ b/python/distrdf/spark/check_friend_trees_alignment.py @@ -30,6 +30,8 @@ def create_chain(): for i in range(3, 6): friend.Add(f"{FILENAMES[i]}?#{TREENAMES[i]}") + # The friend will be owned by the main TChain + ROOT.SetOwnership(friend, False) main.AddFriend(friend, "friend") return main diff --git a/python/memory/PyROOT_memorytests.py b/python/memory/PyROOT_memorytests.py index 8eaf114880..1135369187 100644 --- a/python/memory/PyROOT_memorytests.py +++ b/python/memory/PyROOT_memorytests.py @@ -97,6 +97,12 @@ def test3ObjectCallHeuristics( self ): kMemoryStrict = ROOT.kMemoryStrict kMemoryHeuristics = ROOT.kMemoryHeuristics + # This unit test assumes that the global memory policy is set to + # "heuristics" at the beginning. However, as of ROOT 6.32, the default + # policy is "strict", so we need to reset this at the beginning to + # "heuristics" and reset the default policy at the end. + old_memory_policy = SetMemoryPolicy( kMemoryHeuristics ) + # reference calls should not give up ownership a = MemTester() self.assertEqual( MemTester.counter, 1 ) @@ -191,6 +197,8 @@ def test3ObjectCallHeuristics( self ): del c # c not derived from TObject, no notification self.assertEqual( MemTester.counter, 0 ) + SetMemoryPolicy( old_memory_policy ) + def test4DestructionOfDerivedClass( self ): """Derived classes should call base dtor automatically""" diff --git a/python/pythonizations/PyROOT_smartptrtest.py b/python/pythonizations/PyROOT_smartptrtest.py index 701e6c27c1..429bcc19ae 100644 --- a/python/pythonizations/PyROOT_smartptrtest.py +++ b/python/pythonizations/PyROOT_smartptrtest.py @@ -110,8 +110,9 @@ def test04_reset(self): # ROOT-10245 import ROOT - ROOT.gROOT.ProcessLine('std::shared_ptr optr(new TObject());') + ROOT.gROOT.ProcessLine('auto optr = std::make_shared();') o2 = ROOT.TObject() + ROOT.SetOwnership(o2, False) # This object will be owned by the smart pointer ROOT.optr.__smartptr__().reset(o2) assert ROOT.optr == o2 diff --git a/python/pythonizations/SmartPtr.h b/python/pythonizations/SmartPtr.h index 5989f190b0..4fc1ec624a 100644 --- a/python/pythonizations/SmartPtr.h +++ b/python/pythonizations/SmartPtr.h @@ -22,9 +22,9 @@ class MyShareable { int MyShareable::sInstances = 0; -shared_ptr mine = shared_ptr(new MyShareable); +shared_ptr mine = std::make_shared(); -void renew_mine() { mine = shared_ptr(new MyShareable); } +void renew_mine() { mine = std::make_shared(); } shared_ptr gime_mine(); shared_ptr* gime_mine_ptr(); diff --git a/python/regression/PyROOT_regressiontests.py b/python/regression/PyROOT_regressiontests.py index 382dd9f37d..39e6bec467 100644 --- a/python/regression/PyROOT_regressiontests.py +++ b/python/regression/PyROOT_regressiontests.py @@ -591,7 +591,10 @@ def test1GetListOfGraphs(self): # ROOT-9040 if not legacy_pyroot: mg = ROOT.TMultiGraph() - mg.Add(ROOT.TGraph()) + tg = ROOT.TGraph() + # The TMultiGraph will take the ownership of the added TGraphs + ROOT.SetOwnership(tg, False) + mg.Add(tg) l = mg.GetListOfGraphs() self.assertEqual(l.TestBit(ROOT.kMustCleanup), False)