Skip to content
Snippets Groups Projects
Commit a11b3250 authored by Enric Tejedor Saavedra's avatar Enric Tejedor Saavedra
Browse files

[Exp PyROOT] Pythonize TClass::DynamicCast to provide right binding

TClass::DynamicCast returns a void* that the user still has to cast.
This pythonisation provides the requested binding if the cast succeeded.
parent b7ee051a
No related branches found
No related tags found
No related merge requests found
...@@ -26,14 +26,15 @@ set(sources ...@@ -26,14 +26,15 @@ set(sources
src/PyROOTModule.cxx src/PyROOTModule.cxx
src/PyROOTStrings.cxx src/PyROOTStrings.cxx
src/PyROOTWrapper.cxx src/PyROOTWrapper.cxx
src/GenericPyz.cxx
src/RVecPyz.cxx
src/TClassPyz.cxx
src/TClonesArrayPyz.cxx
src/TDirectoryPyz.cxx src/TDirectoryPyz.cxx
src/TFilePyz.cxx src/TFilePyz.cxx
src/TTreePyz.cxx src/TTreePyz.cxx
src/TClonesArrayPyz.cxx
src/GenericPyz.cxx
src/RVecPyz.cxx
src/PyzPythonHelpers.cxx
src/PyzCppHelpers.cxx src/PyzCppHelpers.cxx
src/PyzPythonHelpers.cxx
) )
file(COPY python/ROOT DESTINATION ${localruntimedir}) file(COPY python/ROOT DESTINATION ${localruntimedir})
......
# Author: Enric Tejedor CERN 02/2019
################################################################################
# Copyright (C) 1995-2019, 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 ROOT import pythonization
import cppyy
from libROOTPython import AddTClassDynamicCastPyz
@pythonization(lazy = False)
def pythonize_tclass():
klass = cppyy.gbl.TClass
# DynamicCast
AddTClassDynamicCastPyz(klass)
return True
...@@ -45,6 +45,8 @@ static PyMethodDef gPyROOTMethods[] = {{(char *)"AddDirectoryWritePyz", (PyCFunc ...@@ -45,6 +45,8 @@ static PyMethodDef gPyROOTMethods[] = {{(char *)"AddDirectoryWritePyz", (PyCFunc
(char *)"Allow to access branches as tree attributes"}, (char *)"Allow to access branches as tree attributes"},
{(char *)"AddFileOpenPyz", (PyCFunction)PyROOT::AddFileOpenPyz, METH_VARARGS, {(char *)"AddFileOpenPyz", (PyCFunction)PyROOT::AddFileOpenPyz, METH_VARARGS,
(char *)"Make TFile::Open a constructor, adjusting for example the reference count"}, (char *)"Make TFile::Open a constructor, adjusting for example the reference count"},
{(char *)"AddTClassDynamicCastPyz", (PyCFunction)PyROOT::AddTClassDynamicCastPyz, METH_VARARGS,
(char *)"Cast the void* returned by TClass::DynamicCast to the right type"},
{(char *)"SetBranchAddressPyz", (PyCFunction)PyROOT::SetBranchAddressPyz, METH_VARARGS, {(char *)"SetBranchAddressPyz", (PyCFunction)PyROOT::SetBranchAddressPyz, METH_VARARGS,
(char *)"Fully enable the use of TTree::SetBranchAddress from Python"}, (char *)"Fully enable the use of TTree::SetBranchAddress from Python"},
{(char *)"BranchPyz", (PyCFunction)PyROOT::BranchPyz, METH_VARARGS, {(char *)"BranchPyz", (PyCFunction)PyROOT::BranchPyz, METH_VARARGS,
......
...@@ -17,17 +17,24 @@ ...@@ -17,17 +17,24 @@
namespace PyROOT { namespace PyROOT {
PyObject *AddPrettyPrintingPyz(PyObject *self, PyObject *args); PyObject *AddPrettyPrintingPyz(PyObject *self, PyObject *args);
PyObject *AddDirectoryWritePyz(PyObject *self, PyObject *args);
PyObject *AddDirectoryAttrSyntaxPyz(PyObject *self, PyObject *args); PyObject *AddDirectoryAttrSyntaxPyz(PyObject *self, PyObject *args);
PyObject *AddBranchAttrSyntax(PyObject *self, PyObject *args); PyObject *AddDirectoryWritePyz(PyObject *self, PyObject *args);
PyObject *AddFileOpenPyz(PyObject *self, PyObject *args); PyObject *AddFileOpenPyz(PyObject *self, PyObject *args);
PyObject *AddSetItemTCAPyz(PyObject *self, PyObject *args);
PyObject *SetBranchAddressPyz(PyObject *self, PyObject *args); PyObject *AddBranchAttrSyntax(PyObject *self, PyObject *args);
PyObject *BranchPyz(PyObject *self, PyObject *args); PyObject *BranchPyz(PyObject *self, PyObject *args);
PyObject *SetBranchAddressPyz(PyObject *self, PyObject *args);
PyObject *AddTClassDynamicCastPyz(PyObject *self, PyObject *args);
PyObject *AddSetItemTCAPyz(PyObject *self, PyObject *args);
PyObject *AsRVec(PyObject *self, PyObject *obj);
PyObject *GetEndianess(PyObject *self); PyObject *GetEndianess(PyObject *self);
PyObject *GetVectorDataPointer(PyObject *self, PyObject *args); PyObject *GetVectorDataPointer(PyObject *self, PyObject *args);
PyObject *GetSizeOfType(PyObject *self, PyObject *args); PyObject *GetSizeOfType(PyObject *self, PyObject *args);
PyObject *AsRVec(PyObject *self, PyObject *obj);
} // namespace PyROOT } // namespace PyROOT
......
// Author: Enric Tejedor CERN 02/2019
// Original PyROOT code by Wim Lavrijsen, LBL
/*************************************************************************
* Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
// Bindings
#include "CPyCppyy.h"
#include "PyROOTPythonize.h"
#include "PyROOTStrings.h"
#include "CPPInstance.h"
#include "Utility.h"
#include "ProxyWrappers.h"
#include "PyzCppHelpers.hxx"
// ROOT
#include "TClass.h"
using namespace CPyCppyy;
// Cast the void* returned by TClass::DynamicCast to the right type
PyObject *TClassDynamicCastPyz(CPPInstance *self, PyObject *args)
{
// Parse arguments
CPPInstance *pyclass = nullptr;
PyObject *pyobject = nullptr;
int up = 1;
if (!PyArg_ParseTuple(args, const_cast<char *>("O!O|i:DynamicCast"),
&CPPInstance_Type, &pyclass,
&pyobject,
&up))
return nullptr;
// Perform actual cast - calls default implementation of DynamicCast
auto meth = PyObject_GetAttr((PyObject *)self, PyROOT::PyStrings::gTClassDynCast);
auto ptr = meth ? PyObject_Call(meth, args, nullptr) : nullptr;
Py_XDECREF(meth);
// Simply forward in case of call failure
if (!ptr)
return nullptr;
// Retrieve object address
void *address = nullptr;
if (CPPInstance_Check(pyobject)) {
address = ((CPPInstance *)pyobject)->GetObject();
} else if (PyInt_Check(pyobject) || PyLong_Check(pyobject)) {
address = (void *)PyLong_AsLong(pyobject);
} else {
Utility::GetBuffer(pyobject, '*', 1, address, false);
}
if (PyErr_Occurred()) {
// Error getting object address, just return the void* wrapper
PyErr_Clear();
return ptr;
}
// Now use binding to return a usable class
TClass *klass = nullptr;
if (up) {
// Upcast: result is a base
klass = (TClass *)GetTClass(pyclass)->DynamicCast(TClass::Class(), pyclass->GetObject());
} else {
// Downcast: result is a derived
klass = (TClass *)GetTClass(self)->DynamicCast(TClass::Class(), self->GetObject());
}
PyObject *result = BindCppObjectNoCast(address, Cppyy::GetScope(klass->GetName()));
Py_DECREF(ptr);
return result;
}
////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TClass::DynamicCast.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// TClass::DynamicCast returns a void* that the user still has to cast (it
/// will have the proper offset, though). Fix this by providing the requested
/// binding if the cast succeeded.
PyObject *PyROOT::AddTClassDynamicCastPyz(PyObject * /* self */, PyObject *args)
{
PyObject *pyclass = PyTuple_GetItem(args, 0);
Utility::AddToClass(pyclass, "_TClass__DynamicCast", "DynamicCast");
Utility::AddToClass(pyclass, "DynamicCast", (PyCFunction)TClassDynamicCastPyz);
Py_RETURN_NONE;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment