Logo ROOT  
Reference Guide
CPPConstructor.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "CPPConstructor.h"
4#include "CPPInstance.h"
5#include "Executors.h"
6#include "MemoryRegulator.h"
7#include "ProxyWrappers.h"
8
10
11// Standard
12#include <string>
13
14
15//- protected members --------------------------------------------------------
17{
18// pick up special case new object executor
19 executor = CreateExecutor("__init__");
20 return true;
21}
22
23//- public members -----------------------------------------------------------
25{
26// GetMethod() may return an empty function if this is just a special case place holder
27 const std::string& clName = Cppyy::GetFinalName(this->GetScope());
28 return CPyCppyy_PyText_FromFormat("%s::%s%s",
29 clName.c_str(), clName.c_str(), this->GetMethod() ? this->GetSignatureString().c_str() : "()");
30}
31
32//----------------------------------------------------------------------------
34 CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt)
35{
36// setup as necessary
37 if (fArgsRequired == -1 && !this->Initialize(ctxt))
38 return nullptr; // important: 0, not Py_None
39
40// fetch self, verify, and put the arguments in usable order
41 if (!(args = this->PreProcessArgs(self, args, kwds)))
42 return nullptr;
43
44// verify existence of self (i.e. tp_new called)
45 if (!self) {
46 PyErr_Print();
47 PyErr_SetString(PyExc_ReferenceError, "no python object allocated");
48 return nullptr;
49 }
50
51 if (self->GetObject()) {
52 Py_DECREF(args);
53 PyErr_SetString(PyExc_ReferenceError,
54 "object already constructed; use __assign__ instead of __init__");
55 return nullptr;
56 }
57
58// perform the call, nullptr 'this' makes the other side allocate the memory
59 Cppyy::TCppScope_t disp = self->ObjectIsA(false /* check_smart */);
60 ptrdiff_t address = 0;
61 if (GetScope() != disp) {
62 // happens for Python derived types, which have a dispatcher inserted that
63 // is not otherwise user-visible: call it instead
64 // first, check whether we at least had a proper meta class, or whether that
65 // was also replaced user-side
66 if (!GetScope() || !disp) {
67 PyErr_SetString(PyExc_TypeError, "can not construct incomplete C++ class");
68 return nullptr;
69 }
70
71 // get the dispatcher class
72 PyObject* dispproxy = CPyCppyy::GetScopeProxy(disp);
73 if (!dispproxy) {
74 PyErr_SetString(PyExc_TypeError, "dispatcher proxy was never created");
75 return nullptr;
76 }
77
78 PyObject* pyobj = PyObject_Call(dispproxy, args, kwds);
79 if (!pyobj)
80 return nullptr;
81
82 // retrieve the actual pointer, take over control, and set m_self
83 address = (ptrdiff_t)((CPPInstance*)pyobj)->GetObject();
84 if (address) {
85 ((CPPInstance*)pyobj)->CppOwns();
86 PyObject* pyoff = PyObject_CallMethod(dispproxy, (char*)"_dispatchptr_offset", nullptr);
87 size_t disp_offset = PyLong_AsSsize_t(pyoff);
88 Py_DECREF(pyoff);
89 new ((void*)(address + disp_offset)) DispatchPtr{(PyObject*)self};
90 }
91 Py_DECREF(pyobj);
92 Py_DECREF(dispproxy);
93
94 } else {
95 // translate the arguments
96 if (!this->ConvertAndSetArgs(args, ctxt)) {
97 Py_DECREF(args);
98 return nullptr;
99 }
100
101 address = (ptrdiff_t)this->Execute(nullptr, 0, ctxt);
102 }
103
104// done with filtered args
105 Py_DECREF(args);
106
107// return object if successful, lament if not
108 if (address) {
109 Py_INCREF(self);
110
111 // note: constructors are no longer set to take ownership by default; instead that is
112 // decided by the method proxy (which carries a creator flag) upon return
113 self->Set((void*)address);
114
115 // TODO: consistent up or down cast ...
117
118 // handling smart types this way is deeply fugly, but if CPPInstance sets the proper
119 // types in op_new first, then the wrong init is called
120 if (((CPPClass*)Py_TYPE(self))->fFlags & CPPScope::kIsSmart) {
122 if (pyclass) {
123 self->SetSmart((PyObject*)Py_TYPE(self));
124 Py_DECREF((PyObject*)Py_TYPE(self));
125 Py_TYPE(self) = (PyTypeObject*)pyclass;
126 }
127 }
128
129 // done with self
130 Py_DECREF(self);
131
132 Py_RETURN_NONE; // by definition
133 }
134
135 if (!PyErr_Occurred()) // should be set, otherwise write a generic error msg
136 PyErr_SetString(PyExc_TypeError, const_cast<char*>(
137 (Cppyy::GetScopedFinalName(GetScope()) + " constructor failed").c_str()));
138
139// do not throw an exception, nullptr might trigger the overload handler to
140// choose a different constructor, which if all fails will throw an exception
141 return nullptr;
142}
143
144
145//----------------------------------------------------------------------------
147 CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt)
148{
149// do not allow instantiation of abstract classes
150 if (self && GetScope() != self->ObjectIsA()) {
151 // happens if a dispatcher is inserted; allow constructor call
152 return CPPConstructor::Call(self, args, kwds, ctxt);
153 }
154
155 PyErr_Format(PyExc_TypeError, "cannot instantiate abstract class \'%s\'"
156 " (from derived classes, use super() instead)",
157 Cppyy::GetScopedFinalName(this->GetScope()).c_str());
158 return nullptr;
159}
160
161//----------------------------------------------------------------------------
164{
165// do not allow instantiation of namespaces
166 PyErr_Format(PyExc_TypeError, "cannot instantiate namespace \'%s\'",
167 Cppyy::GetScopedFinalName(this->GetScope()).c_str());
168 return nullptr;
169}
170
171//----------------------------------------------------------------------------
174{
175// do not allow instantiation of incomplete (forward declared) classes)
176 PyErr_Format(PyExc_TypeError, "cannot instantiate incomplete class \'%s\'",
177 Cppyy::GetScopedFinalName(this->GetScope()).c_str());
178 return nullptr;
179}
#define Py_TYPE(ob)
Definition: CPyCppyy.h:209
#define CPyCppyy_PyText_FromFormat
Definition: CPyCppyy.h:101
#define Py_RETURN_NONE
Definition: CPyCppyy.h:281
Cppyy::TCppType_t fUnderlyingType
unsigned int fFlags
_object PyObject
Definition: PyMethodBase.h:41
virtual PyObject * Call(CPPInstance *&, PyObject *, PyObject *, CallContext *=nullptr)
virtual PyObject * GetDocString()
virtual bool InitExecutor_(Executor *&, CallContext *ctxt=nullptr)
virtual PyObject * Call(CPPInstance *&self, PyObject *args, PyObject *kwds, CallContext *ctxt=nullptr)
virtual PyObject * Call(CPPInstance *&, PyObject *, PyObject *, CallContext *=nullptr)
void Set(void *address, EFlags flags=kDefault)
Definition: CPPInstance.h:85
void SetSmart(PyObject *smart_type)
Cppyy::TCppType_t ObjectIsA(bool check_smart=true) const
Definition: CPPInstance.h:106
virtual PyObject * Call(CPPInstance *&, PyObject *, PyObject *, CallContext *=nullptr)
static bool RegisterPyObject(CPPInstance *pyobj, void *cppobj)
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
CPYCPPYY_EXTERN Executor * CreateExecutor(const std::string &name)
Definition: Executors.cxx:748
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
void * TCppObject_t
Definition: cpp_cppyy.h:21
RPY_EXPORTED std::string GetFinalName(TCppType_t type)
size_t TCppScope_t
Definition: cpp_cppyy.h:18
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
void Initialize(Bool_t useTMVAStyle=kTRUE)
Definition: tmvaglob.cxx:176