Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CPPScope.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "CPPScope.h"
4#include "CPPDataMember.h"
5#include "CPPEnum.h"
6#include "CPPFunction.h"
7#include "CPPOverload.h"
8#include "CustomPyTypes.h"
9#include "Dispatcher.h"
10#include "ProxyWrappers.h"
11#include "PyStrings.h"
12#include "TemplateProxy.h"
13#include "TypeManip.h"
14#include "Utility.h"
15
16// Standard
17#include <string.h>
18#include <algorithm> // for for_each
19#include <set>
20#include <string>
21#include <vector>
22
23
24namespace CPyCppyy {
25
26extern PyTypeObject CPPInstance_Type;
27
28//- helpers ------------------------------------------------------------------
29static inline PyObject* add_template(PyObject* pyclass,
30 const std::string& name, std::vector<PyCallable*>* overloads = nullptr)
31{
32// If templated, the user-facing function must be the template proxy, but the
33// specific lookup must be the current overload, if already found.
34
35 const std::string& ncl = TypeManip::clean_type(name);
36 PyObject* pyncl = CPyCppyy_PyText_FromString(ncl.c_str());
37 TemplateProxy* pytmpl = (TemplateProxy*)PyType_Type.tp_getattro(pyclass, pyncl);
38 if (!pytmpl) {
39 PyErr_Clear();
40 pytmpl = TemplateProxy_New(ncl, ncl, pyclass);
41 // cache the template on its clean name
42 PyType_Type.tp_setattro(pyclass, pyncl, (PyObject*)pytmpl);
43 Py_DECREF(pyncl);
44 } else if (!TemplateProxy_CheckExact((PyObject*)pytmpl)) {
45 Py_DECREF(pytmpl);
46 return nullptr;
47 }
48
49 if (overloads) {
50 // adopt the new overloads
51 if (ncl != name)
52 for (auto clb : *overloads) pytmpl->AdoptTemplate(clb);
53 else
54 for (auto clb : *overloads) pytmpl->AdoptMethod(clb);
55 }
56
57// the caller expects a method matching the full name, thus is a specialization
58// was requested, do not return the template yet
59 if (ncl == name)
60 return (PyObject*)pytmpl;
61
62 Py_DECREF(pytmpl);
63 return nullptr; // so that caller caches the method on full name
64}
65
66
67//= CPyCppyy type proxy construction/destruction =============================
68static PyObject* meta_alloc(PyTypeObject* meta, Py_ssize_t nitems)
69{
70// pure memory allocation; object initialization is in pt_new
71 return PyType_Type.tp_alloc(meta, nitems);
72}
73
74//----------------------------------------------------------------------------
75static void meta_dealloc(CPPScope* scope)
76{
77 if (scope->fFlags & CPPScope::kIsNamespace) {
78 if (scope->fImp.fUsing) {
79 for (auto pyobj : *scope->fImp.fUsing) Py_DECREF(pyobj);
80 delete scope->fImp.fUsing; scope->fImp.fUsing = nullptr;
81 }
82 } else if (!(scope->fFlags & CPPScope::kIsPython)) {
83 delete scope->fImp.fCppObjects; scope->fImp.fCppObjects = nullptr;
84 }
85 delete scope->fOperators;
86 free(scope->fModuleName);
87 return PyType_Type.tp_dealloc((PyObject*)scope);
88}
89
90//-----------------------------------------------------------------------------
91static PyObject* meta_getcppname(CPPScope* scope, void*)
92{
93 if ((void*)scope == (void*)&CPPInstance_Type)
94 return CPyCppyy_PyText_FromString("CPPInstance_Type");
96}
97
98//-----------------------------------------------------------------------------
99static PyObject* meta_getmodule(CPPScope* scope, void*)
100{
101 if ((void*)scope == (void*)&CPPInstance_Type)
102 return CPyCppyy_PyText_FromString("cppyy.gbl");
103
104 if (scope->fModuleName)
106
107// get C++ representation of outer scope
108 std::string modname =
110 if (modname.empty())
111 return CPyCppyy_PyText_FromString(const_cast<char*>("cppyy.gbl"));
112
113// now peel scopes one by one, pulling in the python naming (which will
114// simply recurse if not overridden in python)
115 PyObject* pymodule = nullptr;
117 if (pyscope) {
118 // get the module of our module
119 pymodule = PyObject_GetAttr(pyscope, PyStrings::gModule);
120 if (pymodule) {
121 // append name of our module
122 PyObject* pymodname = PyObject_GetAttr(pyscope, PyStrings::gName);
123 if (pymodname) {
125 CPyCppyy_PyText_AppendAndDel(&pymodule, pymodname);
126 }
127 }
128 Py_DECREF(pyscope);
129 }
130
131 if (pymodule)
132 return pymodule;
133 PyErr_Clear();
134
135// lookup through python failed, so simply cook up a '::' -> '.' replacement
137 return CPyCppyy_PyText_FromString(("cppyy.gbl."+modname).c_str());
138}
139
140//-----------------------------------------------------------------------------
141static int meta_setmodule(CPPScope* scope, PyObject* value, void*)
142{
143 if ((void*)scope == (void*)&CPPInstance_Type) {
144 PyErr_SetString(PyExc_AttributeError,
145 "attribute \'__module__\' of 'cppyy.CPPScope\' objects is not writable");
146 return -1;
147 }
148
149 const char* newname = CPyCppyy_PyText_AsStringChecked(value);
150 if (!value)
151 return -1;
152
153 free(scope->fModuleName);
155 scope->fModuleName = (char*)malloc(sz+1);
156 memcpy(scope->fModuleName, newname, sz+1);
157
158 return 0;
159}
160
161//----------------------------------------------------------------------------
163{
164// Specialized b/c type_repr expects __module__ to live in the dictionary,
165// whereas it is a property (to save memory).
166 if ((void*)scope == (void*)&CPPInstance_Type)
168 const_cast<char*>("<class cppyy.CPPInstance at %p>"), scope);
169
171 // either meta type or Python-side derived class: use default type printing
172 return PyType_Type.tp_repr((PyObject*)scope);
173 }
174
175// skip in case some Python-side derived meta class
176 if (!CPPScope_Check(scope) || !scope->fCppType)
177 return PyType_Type.tp_repr((PyObject*)scope);
178
179// printing of C++ classes
180 PyObject* modname = meta_getmodule(scope, nullptr);
181 std::string clName = Cppyy::GetFinalName(scope->fCppType);
182 const char* kind = (scope->fFlags & CPPScope::kIsNamespace) ? "namespace" : "class";
183
184 PyObject* repr = CPyCppyy_PyText_FromFormat("<%s %s.%s at %p>",
185 kind, CPyCppyy_PyText_AsString(modname), clName.c_str(), scope);
186
187 Py_DECREF(modname);
188 return repr;
189}
190
191
192//= CPyCppyy type metaclass behavior =========================================
193static PyObject* pt_new(PyTypeObject* subtype, PyObject* args, PyObject* kwds)
194{
195// Called when CPPScope acts as a metaclass; since type_new always resets
196// tp_alloc, and since it does not call tp_init on types, the metaclass is
197// being fixed up here, and the class is initialized here as well.
198
199// fixup of metaclass (left permanent, and in principle only called once b/c
200// cppyy caches python classes)
201 subtype->tp_alloc = (allocfunc)meta_alloc;
202 subtype->tp_dealloc = (destructor)meta_dealloc;
203
204// creation of the python-side class; extend the size if this is a smart ptr
205 Cppyy::TCppType_t raw{0}; Cppyy::TCppMethod_t deref{0};
206 if (CPPScope_CheckExact(subtype)) {
207 if (Cppyy::GetSmartPtrInfo(Cppyy::GetScopedFinalName(((CPPScope*)subtype)->fCppType), &raw, &deref))
208 subtype->tp_basicsize = sizeof(CPPSmartClass);
209 }
210
211 CPPScope* result = (CPPScope*)PyType_Type.tp_new(subtype, args, kwds);
212 if (!CPPScope_Check(result)) {
213 // either failed or custom user-side metaclass that can't be handled here
214 return nullptr;
215 }
216
217 result->fFlags = CPPScope::kNone;
218 result->fOperators = nullptr;
219 result->fModuleName = nullptr;
220
221 if (raw && deref) {
222 result->fFlags |= CPPScope::kIsSmart;
223 ((CPPSmartClass*)result)->fUnderlyingType = raw;
224 ((CPPSmartClass*)result)->fDereferencer = deref;
225 }
226
227// initialization of class (based on metatype)
228 if (!CPPScope_CheckExact(subtype) || !strstr(subtype->tp_name, "_meta") /* convention */) {
229 // there has been a user meta class override in a derived class, so do
230 // the consistent thing, thus allowing user control over naming
231 result->fCppType = Cppyy::GetScope(
232 CPyCppyy_PyText_AsString(PyTuple_GET_ITEM(args, 0)));
233 } else {
234 // coming here from cppyy or from sub-classing in python; take the
235 // C++ type from the meta class to make sure that the latter category
236 // has fCppType properly set (it inherits the meta class, but has an
237 // otherwise unknown (or wrong) C++ type)
238 result->fCppType = ((CPPScope*)subtype)->fCppType;
239
240 // the following is not robust, but by design, C++ classes get their
241 // dictionaries filled after creation (chicken & egg problem as they
242 // can return themselves in methods), whereas a derived Python class
243 // with method overrides will have a non-empty dictionary (even if it
244 // has no methods, it will at least have a module name)
245 if (3 <= PyTuple_GET_SIZE(args)) {
246 PyObject* dct = PyTuple_GET_ITEM(args, 2);
247 Py_ssize_t sz = PyDict_Size(dct);
248 if (0 < sz && !Cppyy::IsNamespace(result->fCppType)) {
249 result->fFlags |= CPPScope::kIsPython;
250 if (1 < PyTuple_GET_SIZE(PyTuple_GET_ITEM(args, 1)))
252 std::ostringstream errmsg;
253 if (!InsertDispatcher(result, PyTuple_GET_ITEM(args, 1), dct, errmsg)) {
254 PyErr_Format(PyExc_TypeError, "no python-side overrides supported (%s)", errmsg.str().c_str());
255 return nullptr;
256 } else {
257 // the direct base can be useful for some templates, such as shared_ptrs,
258 // so make it accessible (the __cpp_cross__ data member also signals that
259 // this is a cross-inheritance class)
260 PyObject* bname = CPyCppyy_PyText_FromString(Cppyy::GetBaseName(result->fCppType, 0).c_str());
261 if (PyObject_SetAttrString((PyObject*)result, "__cpp_cross__", bname) == -1)
262 PyErr_Clear();
263 Py_DECREF(bname);
264 }
265 } else if (sz == (Py_ssize_t)-1)
266 PyErr_Clear();
267 }
268 }
269
270// if the user messed with the metaclass, then we may not have a C++ type,
271// simply return here before more damage gets done
272 if (!result->fCppType)
273 return (PyObject*)result;
274
275// maps for using namespaces and tracking objects
276 if (!Cppyy::IsNamespace(result->fCppType)) {
277 static Cppyy::TCppType_t exc_type = (Cppyy::TCppType_t)Cppyy::GetScope("std::exception");
278 if (Cppyy::IsSubtype(result->fCppType, exc_type))
280 if (!(result->fFlags & CPPScope::kIsPython))
281 result->fImp.fCppObjects = new CppToPyMap_t;
282 else {
283 // special case: the C++ objects should be stored with the associated C++, not Python, type
284 CPPClass* kls = (CPPClass*)GetScopeProxy(result->fCppType);
285 if (kls) {
286 result->fImp.fCppObjects = kls->fImp.fCppObjects;
287 Py_DECREF(kls);
288 } else
289 result->fImp.fCppObjects = nullptr;
290 }
291 } else {
292 result->fImp.fUsing = nullptr;
294 }
295
296 if (PyErr_Occurred()) {
297 Py_DECREF((PyObject*)result);
298 return nullptr;
299 }
300
301 return (PyObject*)result;
302}
303
304
305//----------------------------------------------------------------------------
306static PyObject* meta_getattro(PyObject* pyclass, PyObject* pyname)
307{
308// normal type-based lookup
309 PyObject* attr = PyType_Type.tp_getattro(pyclass, pyname);
310 if (pyclass == (PyObject*)&CPPInstance_Type)
311 return attr;
312
313 PyObject* possibly_shadowed = nullptr;
314 if (attr) {
315 if (CPPScope_Check(attr) && CPPScope_Check(pyclass) && !(((CPPScope*)pyclass)->fFlags & CPPScope::kIsNamespace)) {
316 // TODO: the goal here is to prevent typedefs that are shadowed in subclasses
317 // to be found as from the base class. The better approach would be to find
318 // all typedefs at class creation and insert placeholders to flag here. The
319 // current typedef loop in gInterpreter won't do, however.
320 PyObject* dct = PyObject_GetAttr(pyclass, PyStrings::gDict);
321 if (dct) {
322 PyObject* attr_from_dict = PyObject_GetItem(dct, pyname);
323 Py_DECREF(dct);
324 if (attr_from_dict) {
325 Py_DECREF(attr);
326 return attr_from_dict;
327 }
328 possibly_shadowed = attr;
329 attr = nullptr;
330 }
331 PyErr_Clear();
332 } else
333 return attr;
334 }
335
336 if (!CPyCppyy_PyText_CheckExact(pyname) || !CPPScope_Check(pyclass))
337 return possibly_shadowed;
338
339// filter for python specials
340 std::string name = CPyCppyy_PyText_AsString(pyname);
341 if (name.size() >= 5 && name.compare(0, 2, "__") == 0 &&
342 name.compare(name.size()-2, name.size(), "__") == 0)
343 return possibly_shadowed;
344
345// more elaborate search in case of failure (eg. for inner classes on demand)
346 std::vector<Utility::PyError_t> errors;
347 Utility::FetchError(errors);
348 attr = CreateScopeProxy(name, pyclass);
349
351 // Instead of the CPPScope, return a fresh exception class derived from CPPExcInstance.
352 return CreateExcScopeProxy(attr, pyname, pyclass);
353 }
354
355 bool templated_functions_checked = false;
356 CPPScope* klass = ((CPPScope*)pyclass);
357 if (!attr) {
358 Utility::FetchError(errors);
359 Cppyy::TCppScope_t scope = klass->fCppType;
360
361 // namespaces may have seen updates in their list of global functions, which
362 // are available as "methods" even though they're not really that
363 if (klass->fFlags & CPPScope::kIsNamespace) {
364 // tickle lazy lookup of functions
365 const std::vector<Cppyy::TCppIndex_t> methods =
367 if (!methods.empty()) {
368 // function exists, now collect overloads
369 std::vector<PyCallable*> overloads;
370 for (auto idx : methods) {
371 overloads.push_back(
372 new CPPFunction(scope, Cppyy::GetMethod(scope, idx)));
373 }
374
375 // Note: can't re-use Utility::AddClass here, as there's the risk of
376 // a recursive call. Simply add method directly, as we're guaranteed
377 // that it doesn't exist yet.
379 attr = add_template(pyclass, name, &overloads);
380 else
381 attr = (PyObject*)CPPOverload_New(name, overloads);
382 templated_functions_checked = true;
383 }
384
385 // tickle lazy lookup of data members
386 if (!attr) {
388 if (dmi != (Cppyy::TCppIndex_t)-1) attr = (PyObject*)CPPDataMember_New(scope, dmi);
389 }
390 }
391
392 // this may be a typedef that resolves to a sugared type
393 if (!attr) {
394 const std::string& lookup = Cppyy::GetScopedFinalName(klass->fCppType) + "::" + name;
395 const std::string& resolved = Cppyy::ResolveName(lookup);
396 if (resolved != lookup) {
397 const std::string& cpd = TypeManip::compound(resolved);
398 if (cpd == "*") {
399 const std::string& clean = TypeManip::clean_type(resolved, false, true);
401 if (tcl) {
404 tpc->fCppType = tcl;
405 tpc->fDict = PyDict_New();
406 attr = (PyObject*)tpc;
407 }
408 }
409 }
410 }
411
412 // function templates that have not been instantiated (namespaces _may_ have already
413 // been taken care of, by their general function lookup above)
414 if (!attr && !templated_functions_checked) {
416 attr = add_template(pyclass, name);
417 else {
418 // for completeness in error reporting
419 PyErr_Format(PyExc_TypeError, "\'%s\' is not a known C++ template", name.c_str());
420 Utility::FetchError(errors);
421 }
422 }
423
424 // enums types requested as type (rather than the constants)
425 if (!attr) {
426 // TODO: IsEnum should deal with the scope, using klass->GetListOfEnums()->FindObject()
427 const std::string& ename = scope == Cppyy::gGlobalScope ? name : Cppyy::GetScopedFinalName(scope)+"::"+name;
428 if (Cppyy::IsEnum(ename)) {
429 // enum types (incl. named and class enums)
430 attr = (PyObject*)CPPEnum_New(name, scope);
431 } else {
432 // for completeness in error reporting
433 PyErr_Format(PyExc_TypeError, "\'%s\' is not a known C++ enum", name.c_str());
434 Utility::FetchError(errors);
435 }
436 }
437
438 if (attr) {
439 // cache the result
441 PyType_Type.tp_setattro((PyObject*)Py_TYPE(pyclass), pyname, attr);
442 Py_DECREF(attr);
443 attr = PyType_Type.tp_getattro(pyclass, pyname);
444 if (!attr && PyErr_Occurred())
445 Utility::FetchError(errors);
446 } else
447 PyType_Type.tp_setattro(pyclass, pyname, attr);
448
449 } else {
450 Utility::FetchError(errors);
451 }
452 }
453
454 if (!attr && (klass->fFlags & CPPScope::kIsNamespace)) {
455 // refresh using list as necessary
456 const std::vector<Cppyy::TCppScope_t>& uv = Cppyy::GetUsingNamespaces(klass->fCppType);
457 if (!klass->fImp.fUsing || uv.size() != klass->fImp.fUsing->size()) {
458 if (klass->fImp.fUsing) {
459 for (auto pyref : *klass->fImp.fUsing) Py_DECREF(pyref);
460 klass->fImp.fUsing->clear();
461 } else
462 klass->fImp.fUsing = new std::vector<PyObject*>;
463
464 // reload and reset weak refs
465 for (auto uid : uv) {
466 std::string uname = Cppyy::GetScopedFinalName(uid);
467 PyObject* pyuscope = CreateScopeProxy(uname);
468 if (pyuscope) {
469 klass->fImp.fUsing->push_back(PyWeakref_NewRef(pyuscope, nullptr));
470 // the namespace may not otherwise be held, so tie the lifetimes
471 PyObject* llname = CPyCppyy_PyText_FromString(("__lifeline_"+uname).c_str());
472 PyType_Type.tp_setattro(pyclass, llname, pyuscope);
473 Py_DECREF(llname);
474 Py_DECREF(pyuscope);
475 }
476 }
477 }
478
479 // try all outstanding using namespaces in turn to find the attribute (will cache
480 // locally later; TODO: doing so may cause pathological cases)
481 for (auto pyref : *klass->fImp.fUsing) {
482 PyObject* pyuscope = PyWeakref_GetObject(pyref);
483 if (pyuscope) {
484 attr = PyObject_GetAttr(pyuscope, pyname);
485 if (attr) break;
486 PyErr_Clear();
487 }
488 }
489 }
490
491// if the attribute was not found but could possibly have been shadowed, insert it into
492// the dict now, to short-circuit future lookups (TODO: this is part of the workaround
493// described above of which the true solution is to loop over all typedefs at creation
494// time for the class)
495 if (possibly_shadowed) {
496 if (attr) {
497 Py_DECREF(possibly_shadowed);
498 } else {
499 attr = possibly_shadowed;
500 PyType_Type.tp_setattro(pyclass, pyname, attr);
501 }
502 }
503
504 if (attr) {
505 std::for_each(errors.begin(), errors.end(), Utility::PyError_t::Clear);
506 PyErr_Clear();
507 } else {
508 // not found: prepare a full error report
509 PyObject* topmsg = nullptr;
510 PyObject* sklass = PyObject_Str(pyclass);
511 if (sklass) {
512 topmsg = CPyCppyy_PyText_FromFormat("%s has no attribute \'%s\'. Full details:",
514 Py_DECREF(sklass);
515 } else {
516 topmsg = CPyCppyy_PyText_FromFormat("no such attribute \'%s\'. Full details:",
518 }
519 SetDetailedException(errors, topmsg /* steals */, PyExc_AttributeError /* default error */);
520 }
521
522 return attr;
523}
524
525//----------------------------------------------------------------------------
526static int meta_setattro(PyObject* pyclass, PyObject* pyname, PyObject* pyval)
527{
528// Global data and static data in namespaces is found lazily, thus if the first
529// use is setting of the global data by the user, it will not be reflected on
530// the C++ side, b/c there is no descriptor yet. This triggers the creation for
531// for such data as necessary. The many checks to narrow down the specific case
532// are needed to prevent unnecessary lookups and recursion.
533 if (((CPPScope*)pyclass)->fFlags & CPPScope::kIsNamespace) {
534 // skip if the given pyval is a descriptor already, or an unassignable class
536 std::string name = CPyCppyy_PyText_AsString(pyname);
537 Cppyy::TCppIndex_t dmi = Cppyy::GetDatamemberIndex(((CPPScope*)pyclass)->fCppType, name);
538 if (dmi != (Cppyy::TCppIndex_t)-1)
539 meta_getattro(pyclass, pyname); // triggers creation
540 }
541 }
542
543 return PyType_Type.tp_setattro(pyclass, pyname, pyval);
544}
545
546
547//----------------------------------------------------------------------------
548static PyObject* meta_reflex(CPPScope* klass, PyObject* args)
549{
550// Provide the requested reflection information.
551 Cppyy::Reflex::RequestId_t request = -1;
553 if (!PyArg_ParseTuple(args, const_cast<char*>("i|i:__cpp_reflex__"), &request, &format))
554 return nullptr;
555
556 switch (request) {
558 if (klass->fFlags & CPPScope::kIsNamespace)
561 break;
563 // this is not the strict C++ definition of aggregates, but is closer to what
564 // is needed for Numba and C calling conventions (TODO: probably have to check
565 // for all public data types, too, and maybe for no padding?)
569 break;
570 }
571
572 PyErr_Format(PyExc_ValueError, "unsupported reflex request %d or format %d", request, format);
573 return nullptr;
574}
575
576//----------------------------------------------------------------------------
577// p2.7 does not have a __dir__ in object, and object.__dir__ in p3 does not
578// quite what I'd expected of it, so the following pulls in the internal code
579#include "PyObjectDir27.inc"
580
582{
583// Collect a list of everything (currently) available in the namespace.
584// The backend can filter by returning empty strings. Special care is
585// taken for functions, which need not be unique (overloading).
586 using namespace Cppyy;
587
588 if ((void*)klass == (void*)&CPPInstance_Type)
589 return PyList_New(0);
590
591 if (!CPyCppyy::CPPScope_Check((PyObject*)klass)) {
592 PyErr_SetString(PyExc_TypeError, "C++ proxy scope expected");
593 return nullptr;
594 }
595
596 PyObject* dirlist = _generic_dir((PyObject*)klass);
597 if (!(klass->fFlags & CPPScope::kIsNamespace))
598 return dirlist;
599
600 std::set<std::string> cppnames;
601 Cppyy::GetAllCppNames(klass->fCppType, cppnames);
602
603// cleanup names
604 std::set<std::string> dir_cppnames;
605 for (const std::string& name : cppnames) {
606 if (name.find("__", 0, 2) != std::string::npos || \
607 name.find("<") != std::string::npos || \
608 name.find("operator", 0, 8) != std::string::npos) continue;
609 dir_cppnames.insert(name);
610 }
611
612// get rid of duplicates
613 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(dirlist); ++i)
614 dir_cppnames.insert(CPyCppyy_PyText_AsString(PyList_GET_ITEM(dirlist, i)));
615
616 Py_DECREF(dirlist);
617 dirlist = PyList_New(dir_cppnames.size());
618
619// copy total onto python list
620 Py_ssize_t i = 0;
621 for (const auto& name : dir_cppnames) {
622 PyList_SET_ITEM(dirlist, i++, CPyCppyy_PyText_FromString(name.c_str()));
623 }
624 return dirlist;
625}
626
627//-----------------------------------------------------------------------------
628static PyMethodDef meta_methods[] = {
629 {(char*)"__cpp_reflex__", (PyCFunction)meta_reflex, METH_VARARGS,
630 (char*)"C++ datamember reflection information" },
631 {(char*)"__dir__", (PyCFunction)meta_dir, METH_NOARGS, nullptr},
632 {(char*)nullptr, nullptr, 0, nullptr}
633};
634
635
636//-----------------------------------------------------------------------------
637static PyGetSetDef meta_getset[] = {
638 {(char*)"__cpp_name__", (getter)meta_getcppname, nullptr, nullptr, nullptr},
639 {(char*)"__module__", (getter)meta_getmodule, (setter)meta_setmodule, nullptr, nullptr},
640 {(char*)nullptr, nullptr, nullptr, nullptr, nullptr}
641};
642
643
644//= CPyCppyy object proxy type type ==========================================
645PyTypeObject CPPScope_Type = {
646 PyVarObject_HEAD_INIT(&PyType_Type, 0)
647 (char*)"cppyy.CPPScope", // tp_name
648 sizeof(CPyCppyy::CPPScope), // tp_basicsize
649 0, // tp_itemsize
650 0, // tp_dealloc
651 0, // tp_vectorcall_offset / tp_print
652 0, // tp_getattr
653 0, // tp_setattr
654 0, // tp_as_async / tp_compare
655 (reprfunc)meta_repr, // tp_repr
656 0, // tp_as_number
657 0, // tp_as_sequence
658 0, // tp_as_mapping
659 0, // tp_hash
660 0, // tp_call
661 0, // tp_str
662 (getattrofunc)meta_getattro, // tp_getattro
663 (setattrofunc)meta_setattro, // tp_setattro
664 0, // tp_as_buffer
665 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
666#if PY_VERSION_HEX >= 0x03040000
667 | Py_TPFLAGS_TYPE_SUBCLASS
668#endif
669 , // tp_flags
670 (char*)"CPyCppyy metatype (internal)", // tp_doc
671 0, // tp_traverse
672 0, // tp_clear
673 0, // tp_richcompare
674 0, // tp_weaklistoffset
675 0, // tp_iter
676 0, // tp_iternext
677 meta_methods, // tp_methods
678 0, // tp_members
679 meta_getset, // tp_getset
680 &PyType_Type, // tp_base
681 0, // tp_dict
682 0, // tp_descr_get
683 0, // tp_descr_set
684 0, // tp_dictoffset
685 0, // tp_init
686 0, // tp_alloc
687 (newfunc)pt_new, // tp_new
688 0, // tp_free
689 0, // tp_is_gc
690 0, // tp_bases
691 0, // tp_mro
692 0, // tp_cache
693 0, // tp_subclasses
694 0 // tp_weaklist
695#if PY_VERSION_HEX >= 0x02030000
696 , 0 // tp_del
697#endif
698#if PY_VERSION_HEX >= 0x02060000
699 , 0 // tp_version_tag
700#endif
701#if PY_VERSION_HEX >= 0x03040000
702 , 0 // tp_finalize
703#endif
704#if PY_VERSION_HEX >= 0x03080000
705 , 0 // tp_vectorcall
706#endif
707#if PY_VERSION_HEX >= 0x030c0000
708 , 0 // tp_watched
709#endif
710};
711
712} // namespace CPyCppyy
#define Py_TYPE(ob)
Definition CPyCppyy.h:196
#define Py_RETURN_TRUE
Definition CPyCppyy.h:272
#define Py_RETURN_FALSE
Definition CPyCppyy.h:276
int Py_ssize_t
Definition CPyCppyy.h:215
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:76
#define CPyCppyy_PyText_GET_SIZE
Definition CPyCppyy.h:78
#define CPyCppyy_PyText_AppendAndDel
Definition CPyCppyy.h:84
#define CPyCppyy_PyText_FromFormat
Definition CPyCppyy.h:80
#define CPyCppyy_PyText_AsStringChecked
Definition CPyCppyy.h:77
#define CPyCppyy_PyText_CheckExact
Definition CPyCppyy.h:75
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:81
#define PyVarObject_HEAD_INIT(type, size)
Definition CPyCppyy.h:194
_object PyObject
std::ios_base::fmtflags fFlags
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t nitems
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t format
char name[80]
Definition TGX11.cxx:110
#define free
Definition civetweb.c:1539
#define malloc
Definition civetweb.c:1536
uint32_t fFlags
Definition CPPScope.h:56
Utility::PyOperators * fOperators
Definition CPPScope.h:61
union CPyCppyy::CPPScope::@206 fImp
Cppyy::TCppType_t fCppType
Definition CPPScope.h:55
std::vector< PyObject * > * fUsing
Definition CPPScope.h:59
CppToPyMap_t * fCppObjects
Definition CPPScope.h:58
void AdoptTemplate(PyCallable *pc)
void AdoptMethod(PyCallable *pc)
void cppscope_to_pyscope(std::string &cppscope)
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
std::string compound(const std::string &name)
std::string extract_namespace(const std::string &name)
size_t FetchError(std::vector< PyError_t > &, bool is_cpp=false)
Definition Utility.cxx:1074
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
PyTypeObject CPPInstance_Type
static PyObject * add_template(PyObject *pyclass, const std::string &name, std::vector< PyCallable * > *overloads=nullptr)
Definition CPPScope.cxx:29
std::map< Cppyy::TCppObject_t, PyObject * > CppToPyMap_t
Type object to hold class reference (this is only semantically a presentation of CPPScope instances,...
Definition CPPScope.h:34
static PyObject * meta_reflex(CPPScope *klass, PyObject *args)
Definition CPPScope.cxx:548
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
static int meta_setmodule(CPPScope *scope, PyObject *value, void *)
Definition CPPScope.cxx:141
CPPEnum * CPPEnum_New(const std::string &name, Cppyy::TCppScope_t scope)
Definition CPPEnum.cxx:133
static PyObject * meta_dir(CPPScope *klass)
Definition CPPScope.cxx:581
PyObject * CreateScopeProxy(Cppyy::TCppScope_t, const unsigned flags=0)
static PyObject * meta_alloc(PyTypeObject *meta, Py_ssize_t nitems)
Definition CPPScope.cxx:68
PyTypeObject TypedefPointerToClass_Type
static PyObject * pt_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
Definition CPPScope.cxx:193
bool CPPScope_Check(T *object)
Definition CPPScope.h:81
bool TemplateProxy_CheckExact(T *object)
static int meta_setattro(PyObject *pyclass, PyObject *pyname, PyObject *pyval)
Definition CPPScope.cxx:526
static PyObject * meta_getmodule(CPPScope *scope, void *)
Definition CPPScope.cxx:99
CPPDataMember * CPPDataMember_New(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata)
static PyGetSetDef meta_getset[]
Definition CPPScope.cxx:637
static void meta_dealloc(CPPScope *scope)
Definition CPPScope.cxx:75
PyObject * CreateExcScopeProxy(PyObject *pyscope, PyObject *pyname, PyObject *parent)
bool CPPScope_CheckExact(T *object)
Definition CPPScope.h:91
static PyMethodDef meta_methods[]
Definition CPPScope.cxx:628
bool CPPDataMember_Check(T *object)
static PyObject * meta_getattro(PyObject *pyclass, PyObject *pyname)
Definition CPPScope.cxx:306
static PyObject * meta_getcppname(CPPScope *scope, void *)
Definition CPPScope.cxx:91
bool InsertDispatcher(CPPScope *klass, PyObject *bases, PyObject *dct, std::ostringstream &err)
PyTypeObject CPPScope_Type
Definition CPPScope.cxx:645
static PyObject * meta_repr(CPPScope *scope)
Definition CPPScope.cxx:162
TemplateProxy * TemplateProxy_New(const std::string &cppname, const std::string &pyname, PyObject *pyclass)
const RequestId_t IS_AGGREGATE
Definition Reflex.h:15
const FormatId_t OPTIMAL
Definition Reflex.h:22
const RequestId_t IS_NAMESPACE
Definition Reflex.h:14
size_t TCppIndex_t
Definition cpp_cppyy.h:24
intptr_t TCppMethod_t
Definition cpp_cppyy.h:22
RPY_EXPORTED bool IsEnum(const std::string &type_name)
RPY_EXPORTED std::vector< TCppIndex_t > GetMethodIndicesFromName(TCppScope_t scope, const std::string &name)
RPY_EXPORTED bool ExistsMethodTemplate(TCppScope_t scope, const std::string &name)
RPY_EXPORTED TCppScope_t gGlobalScope
Definition cpp_cppyy.h:53
RPY_EXPORTED bool IsSubtype(TCppType_t derived, TCppType_t base)
RPY_EXPORTED bool GetSmartPtrInfo(const std::string &, TCppType_t *raw, TCppMethod_t *deref)
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
TCppScope_t TCppType_t
Definition cpp_cppyy.h:19
RPY_EXPORTED bool IsAggregate(TCppType_t type)
RPY_EXPORTED std::string GetBaseName(TCppType_t type, TCppIndex_t ibase)
RPY_EXPORTED bool IsNamespace(TCppScope_t scope)
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED void GetAllCppNames(TCppScope_t scope, std::set< std::string > &cppnames)
RPY_EXPORTED TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string &name)
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED bool HasVirtualDestructor(TCppType_t type)
RPY_EXPORTED std::vector< TCppScope_t > GetUsingNamespaces(TCppScope_t)
size_t TCppScope_t
Definition cpp_cppyy.h:18
RPY_EXPORTED std::string GetFinalName(TCppType_t type)
static void Clear(PyError_t &e)
Definition Utility.h:90
PyObject_HEAD Cppyy::TCppType_t fCppType