Logo ROOT  
Reference Guide
TClassPyz.cxx
Go to the documentation of this file.
1 // Author: Enric Tejedor CERN 02/2019
2 // Original PyROOT code by Wim Lavrijsen, LBL
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 // Bindings
13 #include "CPyCppyy.h"
14 #include "PyROOTPythonize.h"
15 #include "PyROOTStrings.h"
16 #include "CPPInstance.h"
17 #include "Utility.h"
18 #include "ProxyWrappers.h"
19 #include "PyzCppHelpers.hxx"
20 
21 // ROOT
22 #include "TClass.h"
23 
24 using namespace CPyCppyy;
25 
26 // Cast the void* returned by TClass::DynamicCast to the right type
28 {
29  // Parse arguments
30  CPPInstance *pyclass = nullptr;
31  PyObject *pyobject = nullptr;
32  int up = 1;
33  if (!PyArg_ParseTuple(args, const_cast<char *>("O!O|i:DynamicCast"),
34  &CPPInstance_Type, &pyclass,
35  &pyobject,
36  &up))
37  return nullptr;
38 
39  // Perform actual cast - calls default implementation of DynamicCast
40  auto meth = PyObject_GetAttr((PyObject *)self, PyROOT::PyStrings::gTClassDynCast);
41  auto ptr = meth ? PyObject_Call(meth, args, nullptr) : nullptr;
42  Py_XDECREF(meth);
43 
44  // Simply forward in case of call failure
45  if (!ptr)
46  return nullptr;
47 
48  // Retrieve object address
49  void *address = nullptr;
50  if (CPPInstance_Check(pyobject)) {
51  address = ((CPPInstance *)pyobject)->GetObject();
52  } else if (PyInt_Check(pyobject) || PyLong_Check(pyobject)) {
53  address = (void *)PyLong_AsLong(pyobject);
54  } else {
55  Utility::GetBuffer(pyobject, '*', 1, address, false);
56  }
57 
58  if (PyErr_Occurred()) {
59  // Error getting object address, just return the void* wrapper
60  PyErr_Clear();
61  return ptr;
62  }
63 
64  // Now use binding to return a usable class
65  TClass *klass = nullptr;
66  if (up) {
67  // Upcast: result is a base
68  klass = (TClass *)GetTClass(pyclass)->DynamicCast(TClass::Class(), pyclass->GetObject());
69  } else {
70  // Downcast: result is a derived
71  klass = (TClass *)GetTClass(self)->DynamicCast(TClass::Class(), self->GetObject());
72  }
73 
74  PyObject *result = BindCppObjectNoCast(address, Cppyy::GetScope(klass->GetName()));
75  Py_DECREF(ptr);
76 
77  return result;
78 }
79 
80 ////////////////////////////////////////////////////////////////////////////
81 /// \brief Add pythonization for TClass::DynamicCast.
82 /// \param[in] self Always null, since this is a module function.
83 /// \param[in] args Pointer to a Python tuple object containing the arguments
84 /// received from Python.
85 ///
86 /// TClass::DynamicCast returns a void* that the user still has to cast (it
87 /// will have the proper offset, though). Fix this by providing the requested
88 /// binding if the cast succeeded.
90 {
91  PyObject *pyclass = PyTuple_GetItem(args, 0);
92  Utility::AddToClass(pyclass, "_TClass__DynamicCast", "DynamicCast");
93  Utility::AddToClass(pyclass, "DynamicCast", (PyCFunction)TClassDynamicCastPyz);
95 }
CPyCppyy
Set of helper functions that are invoked from the pythonizors, on the Python side.
Definition: TPyClassGenerator.cxx:31
CPPInstance.h
PyObject
_object PyObject
Definition: PyMethodBase.h:42
Utility.h
PyROOTPythonize.h
CPyCppyy::CPPInstance
Definition: CPPInstance.h:26
CPyCppyy::Utility::GetBuffer
Py_ssize_t GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, bool check=true)
Definition: Utility.cxx:614
TClass.h
PyROOT::PyStrings::gTClassDynCast
R__EXTERN PyObject * gTClassDynCast
Definition: PyROOTStrings.h:29
CPyCppyy::CPPInstance::GetObject
void * GetObject()
Definition: CPPInstance.h:93
Cppyy::GetScope
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
Definition: clingwrapper.cxx:497
ProxyWrappers.h
GetTClass
TClass * GetTClass(const CPyCppyy::CPPInstance *pyobj)
Definition: PyzCppHelpers.cxx:44
CPyCppyy.h
PyROOT::AddTClassDynamicCastPyz
PyObject * AddTClassDynamicCastPyz(PyObject *self, PyObject *args)
Add pythonization for TClass::DynamicCast.
Definition: TClassPyz.cxx:89
TClass::DynamicCast
void * DynamicCast(const TClass *base, void *obj, Bool_t up=kTRUE)
Cast obj of this class type up to baseclass cl if up is true.
Definition: TClass.cxx:4891
PyzCppHelpers.hxx
TClass
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
CPyCppyy::Utility::AddToClass
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
Definition: Utility.cxx:169
PyROOTStrings.h
CPyCppyy::CPPInstance_Type
PyTypeObject CPPInstance_Type
Definition: CPPInstance.cxx:745
TNamed::GetName
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Class
void Class()
Definition: Class.C:29
TClassDynamicCastPyz
PyObject * TClassDynamicCastPyz(CPPInstance *self, PyObject *args)
Definition: TClassPyz.cxx:27
CPyCppyy::CPPInstance_Check
bool CPPInstance_Check(T *object)
Definition: CPPInstance.h:118
CPyCppyy::BindCppObjectNoCast
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
Definition: ProxyWrappers.cxx:799
Py_RETURN_NONE
#define Py_RETURN_NONE
Definition: CPyCppyy.h:281