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