TDirectoryFile Crashes when passed to a new scope

So I have a root file with directories in it which holds output from plugins that ran on the data. When I Get(“Name of Plugin”), I can use GetListOfKeys(), and other functions without a problem. However if I Get() inside a function and then return DirectoryFile for the plugin to another scope and use GetListOfKeys, or any other members of DirectoryFile, it crashes.

from ROOT import *
#prints the keys' name for a directory
def printKeys(directory,show_key=False):
    keys=directory.GetListOfKeys()
    for key in keys:
        if show_key:
            print key 
        else:
            print key.GetName()


#Loads the plugin with pName from file fName
def getPluginData(fName,pName):
    tfile=TFile("Analyzer.root")
    plugin= tfile.Get("MuIndNeuSpallPlugin")
    #This works just fine
    printKeys(plugin)
    #outputs <class 'ROOT.TDirectoryFile'>
    print type(MuIndNeuSpallPlugin)
    return plugin
    

#Loads in file, works
tfile=TFile("Analyzer.root")
#If I Get the MuIndNeuSpallPlugin this way no problem
MuIndNeuSpallPlugin=tfile.Get("MuIndNeuSpallPlugin")
#outputs <class 'ROOT.TDirectoryFile'>
print type(MuIndNeuSpallPlugin)
#However this object is broken
MuIndNeuSpallPlugin=getPluginData("Analyzer.root","MuIndNeuSpallPlugin")
#outputs <class 'ROOT.TDirectoryFile'>
print type(MuIndNeuSpallPlugin)
#This Crashes
printKeys(MuIndNeuSpallPlugin)

So after further investigation, whats happening is instead of returning TDirectoryFile the function returns a NoneType object, even though before the returning plugin, plugin is TDirectoryFile object. It’s as if python forgot what plugin is and returns NoneType instead.

Hi,

If I recall correctly the problem is the lack of ‘reference’ to the ‘tfile’ define in getPluginData. Once getPluginData exits, the usage count of tfile goes down to zero, consequently the underlying resource must be release. This means that the C++ version of the TFile is deleted/destructed. In turn this means that its content (for example the TDirectoryFile) are unloaded.

I.e. you need to find a way to ‘peg’ the tfile for the length of time you need any of its content (note that this is strictly true for the directory object for other objects, you can detach them from the file).

Cheers,
Philippe.

So the work around I did was declare tfile in global scope, and passed it into the getPluginData instead of fName (the name of the file).

from ROOT import *
#prints the keys' name for a directory
def printKeys(directory,show_key=False):
    keys=directory.GetListOfKeys()
    for key in keys:
        if show_key:
            print key
        else:
            print key.GetName()


#Loads the plugin with pName from file fName
def getPluginData(tfile,pName):
    plugin= tfile.Get("MuIndNeuSpallPlugin")
    return plugin
   

#Loads in file, works
tfile=TFile("Analyzer.root")
MuIndNeuSpallPlugin=getPluginData(tfile,"MuIndNeuSpallPlugin")
#Works !!!
printKeys(MuIndNeuSpallPlugin)

This works, but seems very counter-intuitive solution(at least from pythonic viewpoint). Also if I’m understanding you correctly, I have grab all my relevant objects in the plugin before I load a new TFile, or my plugin object will be deleted(I could hard code a separate TFile for each data file, but this doesn’t scale).

I wonder is the a feature or bug, because it seems to break python closure. If it is a feature, is there a tutorial, or documentation explaining how deal with it?

Thank you
Daniel

So a quick update that should be added. If you want grab an Object in a root file, and return it to another scope, you need to copy it.

from ROOT import *
from copy import copy
def getHist(hName,fName='Analyzer.root',pName='MuIndNeuSpallPlugin',process=True):
    tfile=TFile(fName)
    plugin= tfile.Get('MuIndNeuSpallPlugin')
    h= plugin.Get(hName)
    return copy(h)
hNeutron=getHist('hNeutron')

This creates a copy the hist because the original one is contained in the TFIle which is destroyed after it leaves the function. (at least that’s how I understand it, in any case without the copy this code crashes )

1 Like