// Author: Danilo Piparo, Stefan Wunsch CERN 08/2018 // Original PyROOT code by Wim Lavrijsen, LBL /************************************************************************* * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #include "CPyCppyy.h" #include "CPPInstance.h" #include "PyROOTPythonize.h" #include "ProxyWrappers.h" #include "Utility.h" #include "PyzCppHelpers.hxx" #include "TClass.h" #include "TDirectory.h" #include "TKey.h" #include "Python.h" using namespace CPyCppyy; //////////////////////////////////////////////////////////////////////////////// /// \brief Implements the WriteObject method of TDirectory /// This method allows to write objects into TDirectory instances with this /// syntax: /// ~~~{.python} /// myDir.WriteObject(myObj, "myKeyName") /// ~~~ PyObject *TDirectoryWriteObject(const CPPInstance *self, PyObject *args) { CPPInstance *wrt = nullptr; PyObject *name = nullptr; PyObject *option = nullptr; Int_t bufsize = 0; if (!PyArg_ParseTuple(args, const_cast<char *>("O!O!|O!i:TDirectory::WriteObject"), &CPPInstance_Type, &wrt, &CPyCppyy_PyUnicode_Type, &name, &CPyCppyy_PyUnicode_Type, &option, &bufsize)) return nullptr; auto dir = (TDirectory *)GetTClass(self)->DynamicCast(TDirectory::Class(), self->GetObject()); if (!dir) { PyErr_SetString(PyExc_TypeError, "TDirectory::WriteObject must be called with a TDirectory instance as first argument"); return nullptr; } Int_t result = 0; if (option != nullptr) { result = dir->WriteObjectAny(wrt->GetObject(), GetTClass(wrt), CPyCppyy_PyUnicode_AsString(name), CPyCppyy_PyUnicode_AsString(option), bufsize); } else { result = dir->WriteObjectAny(wrt->GetObject(), GetTClass(wrt), CPyCppyy_PyUnicode_AsString(name)); } return PyInt_FromLong((Long_t)result); } //////////////////////////////////////////////////////////////////////////////// /// \brief Implement the Get method for TDirectory /// This allows to seamlessly read from a TDirectory, and therefore a TDirectoryFile /// and file objects inputting their key name, being them TObjects or not. PyObject *TDirectoryGet(const CPPInstance *self, PyObject *pynamecycle) { // Pythonization of TDirectory::Get that handles non-TObject deriveds if (!CPPInstance_Check(self)) { PyErr_SetString(PyExc_TypeError, "TDirectory::Get must be called with a TDirectory instance as first argument"); return nullptr; } auto dirf = (TDirectory *)GetTClass(self)->DynamicCast(TDirectory::Class(), self->GetObject()); if (!dirf) { PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer"); return nullptr; } const char *namecycle = CPyCppyy_PyUnicode_AsString(pynamecycle); if (!namecycle) return nullptr; // TypeError already set auto key = dirf->GetKey(namecycle); // We take this branch if the object is a TDirectoryFile (or daughters) if (key) { void *addr = dirf->GetObjectChecked(namecycle, key->GetClassName()); return BindCppObjectNoCast(addr, (Cppyy::TCppType_t)Cppyy::GetScope(key->GetClassName()), kFALSE); } // This branch is taken if the object is a TDirectory. The objects within TDirectories can only be TObjects. // Of course that statement is not their daughters which can contain anything - for example TFile is a daugher of TDirectory! // BindCppObject internally is able to cast the TObject pointer to the right type after interrogating the // type system of ROOT via TClass. void *addr = dirf->Get(namecycle); return BindCppObject(addr, (Cppyy::TCppType_t)Cppyy::GetScope("TObject"), kFALSE); } //////////////////////////////////////////////////////////////////////////// /// \brief Add attr syntax to TDirectory /// \param[in] self Always null, since this is a module function. /// \param[in] args Pointer to a Python tuple object containing the arguments /// This allows to use TDirectory and daughters (such as TDirectoryFile and TFile) /// as follows /// ~~~{.python} /// myfile.mydir.mysubdir.myHist.Draw() /// ~~~ PyObject *PyROOT::AddDirectoryAttrSyntaxPyz(PyObject * /* self */, PyObject *args) { PyObject *pyclass = PyTuple_GetItem(args, 0); Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)TDirectoryGet, METH_O); Py_RETURN_NONE; } //////////////////////////////////////////////////////////////////////////// /// \brief Add pythonisation of TDirectory::WriteObject /// \param[in] self Always null, since this is a module function. /// \param[in] args Pointer to a Python tuple object containing the arguments PyObject *PyROOT::AddDirectoryWritePyz(PyObject * /* self */, PyObject *args) { PyObject *pyclass = PyTuple_GetItem(args, 0); Utility::AddToClass(pyclass, "WriteObject", (PyCFunction)TDirectoryWriteObject); Py_RETURN_NONE; }