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#include "PyStrings.h"
9
11
12// Standard
13#include <string>
14
15
16//- protected members --------------------------------------------------------
18{
19// pick up special case new object executor
20 executor = CreateExecutor("__init__");
21 return true;
22}
23
24//- public members -----------------------------------------------------------
26{
27// GetMethod() may return an empty function if this is just a special case place holder
28 const std::string& clName = Cppyy::GetFinalName(this->GetScope());
29 return CPyCppyy_PyText_FromFormat("%s::%s%s",
30 clName.c_str(), clName.c_str(), this->GetMethod() ? this->GetSignatureString().c_str() : "()");
31}
32
33//----------------------------------------------------------------------------
35 CPPInstance*& self, PyObject* args, PyObject* kwds, CallContext* ctxt)
36{
37// setup as necessary
38 if (fArgsRequired == -1 && !this->Initialize(ctxt))
39 return nullptr; // important: 0, not Py_None
40
41// fetch self, verify, and put the arguments in usable order
42 if (!(args = this->PreProcessArgs(self, args, kwds)))
43 return nullptr;
44
45// verify existence of self (i.e. tp_new called)
46 if (!self) {
47 PyErr_Print();
48 PyErr_SetString(PyExc_ReferenceError, "no python object allocated");
49 return nullptr;
50 }
51
52 if (self->GetObject()) {
53 Py_DECREF(args);
54 PyErr_SetString(PyExc_ReferenceError,
55 "object already constructed; use __assign__ instead of __init__");
56 return nullptr;
57 }
58
59// perform the call, nullptr 'this' makes the other side allocate the memory
60 Cppyy::TCppScope_t disp = self->ObjectIsA(false /* check_smart */);
61 ptrdiff_t address = 0;
62 if (GetScope() != disp) {
63 // happens for Python derived types, which have a dispatcher inserted that
64 // is not otherwise user-visible: call it instead
65 // first, check whether we at least had a proper meta class, or whether that
66 // was also replaced user-side
67 if (!GetScope() || !disp) {
68 PyErr_SetString(PyExc_TypeError, "can not construct incomplete C++ class");
69 return nullptr;
70 }
71
72 // get the dispatcher class
73 PyObject* dispproxy = CPyCppyy::GetScopeProxy(disp);
74 if (!dispproxy) {
75 PyErr_SetString(PyExc_TypeError, "dispatcher proxy was never created");
76 return nullptr;
77 }
78
79 PyObject* pyobj = PyObject_Call(dispproxy, args, kwds);
80 if (!pyobj)
81 return nullptr;
82
83 // retrieve the actual pointer, take over control, and set m_self
84 address = (ptrdiff_t)((CPPInstance*)pyobj)->GetObject();
85 if (address) {
86 ((CPPInstance*)pyobj)->CppOwns();
87 PyObject* res = PyObject_CallMethodObjArgs(
88 dispproxy, PyStrings::gDispInit, pyobj, (PyObject*)self, nullptr);
89 Py_XDECREF(res);
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:217
#define CPyCppyy_PyText_FromFormat
Definition: CPyCppyy.h:101
#define Py_RETURN_NONE
Definition: CPyCppyy.h:289
Cppyy::TCppType_t fUnderlyingType
unsigned int fFlags
_object PyObject
Definition: PyMethodBase.h:42
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 * gDispInit
Definition: PyStrings.cxx:56
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