Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CPyCppyyModule.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "CallContext.h"
4#include "Converters.h"
5#include "CPPDataMember.h"
6#include "CPPExcInstance.h"
7#include "CPPInstance.h"
8#include "CPPOverload.h"
9#include "CPPScope.h"
10#include "CustomPyTypes.h"
11#include "LowLevelViews.h"
12#include "MemoryRegulator.h"
13#include "ProxyWrappers.h"
14#include "PyStrings.h"
15#include "TemplateProxy.h"
16#include "TupleOfInstances.h"
17#include "Utility.h"
18
19#define CPYCPPYY_INTERNAL 1
21namespace CPyCppyy {
24 void* addr, const std::string& classname, bool python_owns = false);
25} // namespace CPyCppyy
26#undef CPYCPPYY_INTERNAL
27
28// Standard
29#include <algorithm>
30#include <map>
31#include <set>
32#include <string>
33#include <iostream>
34#include <sstream>
35#include <utility>
36#include <vector>
37
38#if PY_VERSION_HEX < 0x030b0000
39namespace CPyCppyy {
42} // namespace CPyCppyy
43#endif
44
45// Note: as of py3.11, dictionary objects no longer carry a function pointer for
46// the lookup, so it can no longer be shimmed and "from cppyy.interactive import *"
47// thus no longer works.
48#if PY_VERSION_HEX < 0x030b0000
49
50//- from Python's dictobject.c -------------------------------------------------
51#if PY_VERSION_HEX >= 0x03030000
52 typedef struct PyDictKeyEntry {
53 /* Cached hash code of me_key. */
56 PyObject *me_value; /* This field is only meaningful for combined tables */
58
59 typedef struct _dictkeysobject {
64#if PY_VERSION_HEX >= 0x03060000
66 union {
67 int8_t as_1[8];
68 int16_t as_2[4];
69 int32_t as_4[2];
70#if SIZEOF_VOID_P > 4
71 int64_t as_8[1];
72#endif
73 } dk_indices;
74#else
76#endif
78
79#define CPYCPPYY_GET_DICT_LOOKUP(mp) \
80 ((dict_lookup_func&)mp->ma_keys->dk_lookup)
81
82#else
83
84#define CPYCPPYY_GET_DICT_LOOKUP(mp) \
85 ((dict_lookup_func&)mp->ma_lookup)
86
87#endif
88
89#endif // PY_VERSION_HEX < 0x030b0000
90
91//- data -----------------------------------------------------------------------
93{
94 return CPyCppyy_PyText_FromString("nullptr");
95}
96
98{
99 Py_FatalError("deallocating nullptr");
100}
101
103{
104 return 0;
105}
106
108 0, 0, 0,
109#if PY_VERSION_HEX < 0x03000000
110 0,
111#endif
112 0, 0, 0, 0, 0, 0,
113 (inquiry)nullptr_nonzero, // tp_nonzero (nb_bool in p3)
114 0, 0, 0, 0, 0, 0,
115#if PY_VERSION_HEX < 0x03000000
116 0, // nb_coerce
117#endif
118 0, 0, 0,
119#if PY_VERSION_HEX < 0x03000000
120 0, 0,
121#endif
122 0, 0, 0,
123#if PY_VERSION_HEX < 0x03000000
124 0, // nb_inplace_divide
125#endif
126 0, 0, 0, 0, 0, 0, 0
127#if PY_VERSION_HEX >= 0x02020000
128 , 0 // nb_floor_divide
129#if PY_VERSION_HEX < 0x03000000
130 , 0 // nb_true_divide
131#else
132 , 0 // nb_true_divide
133#endif
134 , 0, 0
135#endif
136#if PY_VERSION_HEX >= 0x02050000
137 , 0 // nb_index
138#endif
139#if PY_VERSION_HEX >= 0x03050000
140 , 0 // nb_matrix_multiply
141 , 0 // nb_inplace_matrix_multiply
142#endif
143};
144
147 "nullptr_t", // tp_name
148 sizeof(PyObject), // tp_basicsize
149 0, // tp_itemsize
150 nullptr_dealloc, // tp_dealloc (never called)
151 0, 0, 0, 0,
152 nullptr_repr, // tp_repr
153 &nullptr_as_number, // tp_as_number
154 0, 0,
155#if PY_VERSION_HEX >= 0x030d0000
156 (hashfunc)Py_HashPointer, // tp_hash
157#else
158 (hashfunc)_Py_HashPointer, // tp_hash
159#endif
160 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT, 0, 0, 0, 0, 0, 0, 0,
161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
162#if PY_VERSION_HEX >= 0x02030000
163 , 0 // tp_del
164#endif
165#if PY_VERSION_HEX >= 0x02060000
166 , 0 // tp_version_tag
167#endif
168#if PY_VERSION_HEX >= 0x03040000
169 , 0 // tp_finalize
170#endif
171#if PY_VERSION_HEX >= 0x03080000
172 , 0 // tp_vectorcall
173#endif
174#if PY_VERSION_HEX >= 0x030c0000
175 , 0 // tp_watched
176#endif
177#if PY_VERSION_HEX >= 0x030d0000
178 , 0 // tp_versions_used
179#endif
180};
181
182
184{
185 return CPyCppyy_PyText_FromString("type default");
186}
187
189{
190 Py_FatalError("deallocating default");
191}
192
195 "default_t", // tp_name
196 sizeof(PyObject), // tp_basicsize
197 0, // tp_itemsize
198 default_dealloc, // tp_dealloc (never called)
199 0, 0, 0, 0,
200 default_repr, // tp_repr
201 0, 0, 0,
202#if PY_VERSION_HEX >= 0x030d0000
203 (hashfunc)Py_HashPointer, // tp_hash
204#else
205 (hashfunc)_Py_HashPointer, // tp_hash
206#endif
207 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT, 0, 0, 0, 0, 0, 0, 0,
208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
209#if PY_VERSION_HEX >= 0x02030000
210 , 0 // tp_del
211#endif
212#if PY_VERSION_HEX >= 0x02060000
213 , 0 // tp_version_tag
214#endif
215#if PY_VERSION_HEX >= 0x03040000
216 , 0 // tp_finalize
217#endif
218#if PY_VERSION_HEX >= 0x03080000
219 , 0 // tp_vectorcall
220#endif
221#if PY_VERSION_HEX >= 0x030c0000
222 , 0 // tp_watched
223#endif
224#if PY_VERSION_HEX >= 0x030d0000
225 , 0 // tp_versions_used
226#endif
227};
228
229namespace {
230
231struct {
234
235struct {
238
239// TODO: refactor with Converters.cxx
240struct CPyCppyy_tagCDataObject { // non-public (but stable)
242 char* b_ptr;
243 int b_needsfree;
244};
245
246} // unnamed namespace
247
248namespace CPyCppyy {
249 PyObject* gThisModule = nullptr;
251 PyObject* gNullPtrObject = nullptr;
257 std::set<Cppyy::TCppType_t> gPinnedTypes;
258 std::ostringstream gCapturedError;
259 std::streambuf* gOldErrorBuffer = nullptr;
260
261 std::map<std::string, std::vector<PyObject*>> &pythonizations()
262 {
263 static std::map<std::string, std::vector<PyObject*>> pyzMap;
264 return pyzMap;
265 }
266}
267
268
269//- private helpers ------------------------------------------------------------
270namespace {
271
272using namespace CPyCppyy;
273
274
275//----------------------------------------------------------------------------
276#if PY_VERSION_HEX < 0x030b0000
277namespace {
278
279class GblGetter {
280public:
281 GblGetter() {
282 PyObject* cppyy = PyImport_AddModule((char*)"cppyy");
283 fGbl = PyObject_GetAttrString(cppyy, (char*)"gbl");
284 }
285 ~GblGetter() { Py_DECREF(fGbl); }
286
287 PyObject* operator*() { return fGbl; }
288
289private:
290 PyObject* fGbl;
291};
292
293} // unnamed namespace
294
295#if PY_VERSION_HEX >= 0x03060000
298{
299 return (*gDictLookupOrg)(mp, key, hash, value_addr, hashpos);
300}
301#define CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos) \
302 OrgDictLookup(mp, key, hash, value_addr, hashpos)
303
306
307#elif PY_VERSION_HEX >= 0x03030000
310{
311 return (*gDictLookupOrg)(mp, key, hash, value_addr);
312}
313
314#define CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos) \
315 OrgDictLookup(mp, key, hash, value_addr)
316
319
320#else /* < 3.3 */
321
323{
324 return (*gDictLookupOrg)(mp, key, hash);
325}
326
327#define CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos) \
328 OrgDictLookup(mp, key, hash)
329
331#endif
332{
333 static GblGetter gbl;
334#if PY_VERSION_HEX >= 0x03060000
336#else
338#endif
339
340// first search dictionary itself
343 return ep;
344
345#if PY_VERSION_HEX >= 0x03060000
346 if (ep >= 0)
347#else
348 if (!ep || (ep->me_key && ep->me_value))
349#endif
350 return ep;
351
352// filter for builtins
353 if (PyDict_GetItem(PyEval_GetBuiltins(), key) != 0)
354 return ep;
355
356// normal lookup failed, attempt to get C++ enum/global/class from top-level
357 gDictLookupActive = true;
358
359// attempt to get C++ enum/global/class from top-level
360 PyObject* val = PyObject_GetAttr(*gbl, key);
361
362 if (val) {
363 // success ...
364
365 if (CPPDataMember_CheckExact(val)) {
366 // don't want to add to dictionary (the proper place would be the
367 // dictionary of the (meta)class), but modifying ep will be noticed no
368 // matter what; just return the actual value and live with the copy in
369 // the dictionary (mostly, this is correct)
370 PyObject* actual_val = Py_TYPE(val)->tp_descr_get(val, nullptr, nullptr);
371 Py_DECREF(val);
372 val = actual_val;
373 }
374
375 // add reference to C++ entity in the given dictionary
376 CPYCPPYY_GET_DICT_LOOKUP(mp) = gDictLookupOrg; // prevent recursion
377 if (PyDict_SetItem((PyObject*)mp, key, val) == 0) {
379 } else {
380#if PY_VERSION_HEX >= 0x03060000
381 ep = -1;
382#else
383 ep->me_key = nullptr;
384 ep->me_value = nullptr;
385#endif
386 }
388
389 // done with val
390 Py_DECREF(val);
391 } else
392 PyErr_Clear();
393
394#if PY_VERSION_HEX >= 0x03030000
395 if (mp->ma_keys->dk_usable <= 0) {
396 // big risk that this lookup will result in a resize, so force it here
397 // to be able to reset the lookup function; of course, this is nowhere
398 // near fool-proof, but should cover interactive usage ...
400 const int maxinsert = 5;
401 PyObject* buf[maxinsert];
402 for (int varmax = 1; varmax <= maxinsert; ++varmax) {
403 for (int ivar = 0; ivar < varmax; ++ivar) {
404 buf[ivar] = CPyCppyy_PyText_FromFormat("__CPYCPPYY_FORCE_RESIZE_%d", ivar);
406 }
407 for (int ivar = 0; ivar < varmax; ++ivar) {
409 Py_DECREF(buf[ivar]);
410 }
411 if (0 < mp->ma_keys->dk_usable)
412 break;
413 }
414
415 // make sure the entry pointer is still valid by re-doing the lookup
417
418 // full reset of all lookup functions
421 }
422#endif
423
424// stopped calling into the reflection system
425 gDictLookupActive = false;
426 return ep;
427}
428
429#endif // PY_VERSION_HEX < 0x030b0000
430
431//----------------------------------------------------------------------------
433{
434#if PY_VERSION_HEX < 0x030b0000
435// Modify the given dictionary to install the lookup function that also
436// tries the global C++ namespace before failing. Called on a module's dictionary,
437// this allows for lazy lookups. This works fine for p3.2 and earlier, but should
438// not be used beyond interactive code for p3.3 and later b/c resizing causes the
439// lookup function to revert to the default (lookdict_unicode_nodummy).
440 PyDictObject* dict = nullptr;
441 if (!PyArg_ParseTuple(args, const_cast<char*>("O!"), &PyDict_Type, &dict))
442 return nullptr;
443
445#else
446// As of py3.11, there is no longer a lookup function pointer in the dict object
447// to replace. Since this feature is not widely advertised, it's simply dropped
448 if (PyErr_WarnEx(PyExc_RuntimeWarning, (char*)"lazy lookup is no longer supported", 1) < 0)
449 return nullptr;
450 (void)args; // avoid warning about unused parameter
451#endif
452
454}
455
456//----------------------------------------------------------------------------
458{
459// Create a binding for a templated class instantiation.
460
461// args is class name + template arguments; build full instantiation
463 if (nArgs < 2) {
464 PyErr_Format(PyExc_TypeError, "too few arguments for template instantiation");
465 return nullptr;
466 }
467
468// build "< type, type, ... >" part of class name (modifies pyname)
469 const std::string& tmpl_name =
471 if (!tmpl_name.size())
472 return nullptr;
473
475}
476
477//----------------------------------------------------------------------------
478static char* GCIA_kwlist[] = {(char*)"instance", (char*)"field", (char*)"byref", NULL};
479static void* GetCPPInstanceAddress(const char* fname, PyObject* args, PyObject* kwds)
480{
481// Helper to get the address (address-of-address) of various object proxy types.
482 CPPInstance* pyobj = 0; PyObject* pyname = 0; int byref = 0;
483 if (PyArg_ParseTupleAndKeywords(args, kwds, const_cast<char*>("O|O!b"), GCIA_kwlist,
485
487 if (pyname != 0) {
488 // locate property proxy for offset info
489 CPPDataMember* pyprop = nullptr;
490
494 Py_DECREF(dict);
495
497 // this is an address of a value (i.e. &myobj->prop)
498 void* addr = (void*)pyprop->GetAddress(pyobj);
500 return addr;
501 }
502
504
506 "%s is not a valid data member", CPyCppyy_PyText_AsString(pyname));
507 return nullptr;
508 }
509
510 // this is an address of an address (i.e. &myobj, with myobj of type MyObj*)
511 // note that the return result may be null
512 if (!byref) return ((CPPInstance*)pyobj)->GetObject();
513 return &((CPPInstance*)pyobj)->GetObjectRaw();
514
515 } else if (CPyCppyy_PyText_Check(pyobj)) {
516 // special cases for access to the CPyCppyy API
518 if (req == "Instance_AsVoidPtr")
519 return (void*)&Instance_AsVoidPtr;
520 else if (req == "Instance_FromVoidPtr")
521 return (void*)&Instance_FromVoidPtr;
522 }
523 }
524
525 if (!PyErr_Occurred())
526 PyErr_Format(PyExc_ValueError, "invalid argument for %s", fname);
527 return nullptr;
528}
529
530//----------------------------------------------------------------------------
531static PyObject* addressof(PyObject* /* dummy */, PyObject* args, PyObject* kwds)
532{
533// Return object proxy address as a value (cppyy-style), or the same for an array.
534 void* addr = GetCPPInstanceAddress("addressof", args, kwds);
535 if (addr)
536 return PyLong_FromLongLong((intptr_t)addr);
537 else if (!PyErr_Occurred()) {
538 return PyLong_FromLong(0);
539 } else if (PyTuple_CheckExact(args) && PyTuple_GET_SIZE(args) == 1) {
540 PyErr_Clear();
541 PyObject* arg0 = PyTuple_GET_ITEM(args, 0);
542
543 // nullptr special case
544 if (arg0 == gNullPtrObject || (PyInt_Check(arg0) && PyInt_AsLong(arg0) == 0))
545 return PyLong_FromLong(0);
546
547 // overload if unambiguous
549 const auto& methods = ((CPPOverload*)arg0)->fMethodInfo->fMethods;
550 if (methods.size() != 1) {
551 PyErr_SetString(PyExc_TypeError, "overload is not unambiguous");
552 return nullptr;
553 }
554
555 Cppyy::TCppFuncAddr_t caddr = methods[0]->GetFunctionAddress();
556 return PyLong_FromLongLong((intptr_t)caddr);
557 }
558
559 // C functions (incl. ourselves)
560 if (PyCFunction_Check(arg0)) {
561 void* caddr = (void*)PyCFunction_GetFunction(arg0);
562 return PyLong_FromLongLong((intptr_t)caddr);
563 }
564
565 // final attempt: any type of buffer
566 Utility::GetBuffer(arg0, '*', 1, addr, false);
567 if (addr) return PyLong_FromLongLong((intptr_t)addr);
568 }
569
570// error message if not already set
571 if (!PyErr_Occurred()) {
572 if (PyTuple_CheckExact(args) && PyTuple_GET_SIZE(args)) {
573 PyObject* str = PyObject_Str(PyTuple_GET_ITEM(args, 0));
574 if (str && CPyCppyy_PyText_Check(str))
575 PyErr_Format(PyExc_TypeError, "unknown object %s", CPyCppyy_PyText_AsString(str));
576 else
577 PyErr_Format(PyExc_TypeError, "unknown object at %p", (void*)PyTuple_GET_ITEM(args, 0));
578 Py_XDECREF(str);
579 }
580 }
581 return nullptr;
582}
583
584//----------------------------------------------------------------------------
585static PyObject* AsCObject(PyObject* /* unused */, PyObject* args, PyObject* kwds)
586{
587// Return object proxy as an opaque CObject.
588 void* addr = GetCPPInstanceAddress("as_cobject", args, kwds);
589 if (addr)
590 return CPyCppyy_PyCapsule_New((void*)addr, nullptr, nullptr);
591 return nullptr;
592}
593
594//----------------------------------------------------------------------------
595static PyObject* AsCapsule(PyObject* /* unused */, PyObject* args, PyObject* kwds)
596{
597// Return object proxy as an opaque PyCapsule.
598 void* addr = GetCPPInstanceAddress("as_capsule", args, kwds);
599 if (addr)
600#if PY_VERSION_HEX < 0x02060000
601 return PyCObject_FromVoidPtr(addr, nullptr);
602#else
603 return PyCapsule_New(addr, nullptr, nullptr);
604#endif
605 return nullptr;
606}
607
608//----------------------------------------------------------------------------
609static PyObject* AsCTypes(PyObject* /* unused */, PyObject* args, PyObject* kwds)
610{
611// Return object proxy as a ctypes c_void_p
612 void* addr = GetCPPInstanceAddress("as_ctypes", args, kwds);
613 if (!addr)
614 return nullptr;
615
616// TODO: refactor code below with converters code
617 static PyTypeObject* ct_cvoidp = nullptr;
618 if (!ct_cvoidp) {
619 PyObject* ctmod = PyImport_ImportModule("ctypes"); // ref-count kept
620 if (!ctmod) return nullptr;
621
624 if (!ct_cvoidp) return nullptr;
625 Py_DECREF(ct_cvoidp); // module keeps a reference
626 }
627
628 PyObject* ref = ct_cvoidp->tp_new(ct_cvoidp, nullptr, nullptr);
629 *(void**)((CPyCppyy_tagCDataObject*)ref)->b_ptr = addr;
630 ((CPyCppyy_tagCDataObject*)ref)->b_needsfree = 0;
631 return ref;
632}
633
634//----------------------------------------------------------------------------
635static PyObject* AsMemoryView(PyObject* /* unused */, PyObject* pyobject)
636{
637// Return a raw memory view on arrays of PODs.
639 PyErr_SetString(PyExc_TypeError, "C++ object proxy expected");
640 return nullptr;
641 }
642
645
646 Py_ssize_t array_len = pyobj->ArrayLength();
647
648 if (array_len < 0 || !Cppyy::IsAggregate(klass)) {
650 PyExc_TypeError, "object is not a proxy to an array of PODs of known size");
651 return nullptr;
652 }
653
654 Py_buffer view;
655
656 view.obj = pyobject;
657 view.buf = pyobj->GetObject();
658 view.itemsize = Cppyy::SizeOf(klass);
659 view.len = view.itemsize * array_len;
660 view.readonly = 0;
661 view.format = NULL; // i.e. "B" assumed
662 view.ndim = 1;
663 view.shape = NULL;
664 view.strides = NULL;
665 view.suboffsets = NULL;
666 view.internal = NULL;
667
668 return PyMemoryView_FromBuffer(&view);
669}
670
671//----------------------------------------------------------------------------
673{
674// From a long representing an address or a PyCapsule/CObject, bind to a class.
676 if (argc != 2) {
678 "bind_object takes 2 positional arguments but (" PY_SSIZE_T_FORMAT " were given)", argc);
679 return nullptr;
680 }
681
682// convert 2nd argument first (used for both pointer value and instance cases)
684 PyObject* arg1 = PyTuple_GET_ITEM(args, 1);
685 if (!CPyCppyy_PyText_Check(arg1)) { // not string, then class
686 if (CPPScope_Check(arg1))
687 cast_type = ((CPPClass*)arg1)->fCppType;
688 else
690 } else
692
693 if (!cast_type && arg1) {
696 }
697
698 if (!cast_type) {
700 "bind_object expects a valid class or class name as an argument");
701 return nullptr;
702 }
703
704// next, convert the first argument, some pointer value or a pre-existing instance
705 PyObject* arg0 = PyTuple_GET_ITEM(args, 0);
706
707 if (CPPInstance_Check(arg0)) {
708 // if this instance's class has a relation to the requested one, calculate the
709 // offset, erase if from any caches, and update the pointer and type
711 Cppyy::TCppType_t cur_type = arg0_pyobj->ObjectIsA(false /* check_smart */);
712
713 bool isPython = CPPScope_Check(arg1) && \
714 (((CPPClass*)arg1)->fFlags & CPPScope::kIsPython);
715
716 if (cur_type == cast_type && !isPython) {
717 Py_INCREF(arg0); // nothing to do
718 return arg0;
719 }
720
721 int direction = 0;
722 Cppyy::TCppType_t base = 0, derived = 0;
725 base = cur_type;
726 direction = -1; // down-cast
727 } else if (Cppyy::IsSubtype(cur_type, cast_type)) {
728 base = cast_type;
730 direction = 1; // up-cast
731 } else {
733 "provided instance and provided target type are unrelated");
734 return nullptr;
735 }
736
737 Cppyy::TCppObject_t address = (Cppyy::TCppObject_t)arg0_pyobj->GetObject();
738 ptrdiff_t offset = Cppyy::GetBaseOffset(derived, base, address, direction);
739
740 // it's debatable whether a new proxy should be created rather than updating
741 // the old, but changing the old object would be changing the behavior of all
742 // code that has a reference to it, which may not be the intention if the cast
743 // is on a C++ data member; this probably is the "least surprise" option
744
745 // ownership is taken over as needed, again following the principle of "least
746 // surprise" as most likely only the cast object will be retained
747 bool owns = arg0_pyobj->fFlags & CPPInstance::kIsOwner;
748
749 if (!isPython) {
750 // ordinary C++ class
752 (void*)((intptr_t)address + offset), cast_type, owns ? CPPInstance::kIsOwner : 0);
753 if (owns && pyobj) arg0_pyobj->CppOwns();
754 return pyobj;
755
756 } else {
757 // rebinding to a Python-side class, create a fresh instance first to be able to
758 // perform a lookup of the original dispatch object and if found, return original
759 void* cast_address = (void*)((intptr_t)address + offset);
760 PyObject* pyobj = ((PyTypeObject*)arg1)->tp_new((PyTypeObject*)arg1, nullptr, nullptr);
761 ((CPPInstance*)pyobj)->GetObjectRaw() = cast_address;
762
765 /* Note: the resultant object is borrowed */
766 if (CPPInstance_Check(res) && ((CPPInstance*)res)->GetObject() == cast_address) {
767 ((CPPInstance*)pyobj)->CppOwns(); // make sure C++ object isn't deleted
768 Py_DECREF(pyobj); // on DECREF (is default, but still)
769 pyobj = res;
770 } else {
771 if (res) Py_DECREF(res); // most likely Py_None
772 else PyErr_Clear(); // should not happen
773 }
775
776 if (pyobj && owns) {
777 arg0_pyobj->CppOwns();
778 ((CPPInstance*)pyobj)->PythonOwns();
779 }
780
781 return pyobj;
782 }
783 }
784
785// not a pre-existing object; get the address and bind
786 void* addr = nullptr;
787 if (arg0 != gNullPtrObject) {
789 if (PyErr_Occurred()) {
790 PyErr_Clear();
791
793 if (PyErr_Occurred()) {
794 PyErr_Clear();
795
796 // last chance, perhaps it's a buffer/array (return from void*)
797 Py_ssize_t buflen = Utility::GetBuffer(PyTuple_GetItem(args, 0), '*', 1, addr, false);
798 if (!addr || !buflen) {
800 "bind_object requires a CObject/Capsule, long integer, buffer, or instance as first argument");
801 return nullptr;
802 }
803 }
804 }
805 }
806
807 bool do_cast = false;
808 if (kwds) {
811 }
812
813 if (do_cast)
815
817}
818
819//----------------------------------------------------------------------------
820static PyObject* Move(PyObject*, PyObject* pyobject)
821{
822// Prepare the given C++ object for moving.
824 PyErr_SetString(PyExc_TypeError, "C++ object expected");
825 return nullptr;
826 }
827
830 return pyobject;
831}
832
833
834//----------------------------------------------------------------------------
836{
837// Remove a previously registered pythonizor from the given scope.
838 PyObject* pythonizor = nullptr; const char* scope;
839 if (!PyArg_ParseTuple(args, const_cast<char*>("Os"), &pythonizor, &scope))
840 return nullptr;
841
845 "given \'%s\' object is not callable", CPyCppyy_PyText_AsString(pystr));
847 return nullptr;
848 }
849
851 pythonizations()[scope].push_back(pythonizor);
852
854}
855
856
857//----------------------------------------------------------------------------
859{
860// Remove a previously registered pythonizor from the given scope.
861 PyObject* pythonizor = nullptr; const char* scope;
862 if (!PyArg_ParseTuple(args, const_cast<char*>("Os"), &pythonizor, &scope))
863 return nullptr;
864
865 auto &pyzMap = pythonizations();
866 auto p1 = pyzMap.find(scope);
867 if (p1 != pyzMap.end()) {
868 auto p2 = std::find(p1->second.begin(), p1->second.end(), pythonizor);
869 if (p2 != p1->second.end()) {
870 p1->second.erase(p2);
872 }
873 }
874
876}
877
878//----------------------------------------------------------------------------
880{
881// Add a pinning so that objects of type `derived' are interpreted as
882// objects of type `base'.
883 if (!CPPScope_Check(pyclass)) {
884 PyErr_SetString(PyExc_TypeError, "C++ class expected");
885 return nullptr;
886 }
887
888 gPinnedTypes.insert(((CPPClass*)pyclass)->fCppType);
889
891}
892
893//----------------------------------------------------------------------------
895{
896// Add a type reducer to map type2 to type2 on function returns.
897 const char *reducable, *reduced;
898 if (!PyArg_ParseTuple(args, const_cast<char*>("ss"), &reducable, &reduced))
899 return nullptr;
900
902
904}
905
906#define DEFINE_CALL_POLICY_TOGGLE(name, flagname) \
907static PyObject* name(PyObject*, PyObject* args) \
908{ \
909 PyObject* enabled = 0; \
910 if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &enabled)) \
911 return nullptr; \
912 \
913 if (CallContext::SetGlobalPolicy(CallContext::flagname, PyObject_IsTrue(enabled))) { \
914 Py_RETURN_TRUE; \
915 } \
916 \
917 Py_RETURN_FALSE; \
918}
919
923
924//----------------------------------------------------------------------------
925static PyObject* SetOwnership(PyObject*, PyObject* args)
926{
927// Set the ownership (True is python-owns) for the given object.
928 CPPInstance* pyobj = nullptr; PyObject* pykeep = nullptr;
929 if (!PyArg_ParseTuple(args, const_cast<char*>("O!O!"),
931 return nullptr;
932
933 (bool)PyLong_AsLong(pykeep) ? pyobj->PythonOwns() : pyobj->CppOwns();
934
936}
937
938//----------------------------------------------------------------------------
940{
941// Add a smart pointer to the list of known smart pointer types.
942 const char* type_name;
943 if (!PyArg_ParseTuple(args, const_cast<char*>("s"), &type_name))
944 return nullptr;
945
947
949}
950
951//----------------------------------------------------------------------------
953{
954 gOldErrorBuffer = std::cerr.rdbuf();
955 std::cerr.rdbuf(gCapturedError.rdbuf());
956
958}
959
960//----------------------------------------------------------------------------
962{
963// restore old rdbuf and return captured result
964 std::cerr.rdbuf(gOldErrorBuffer);
965 gOldErrorBuffer = nullptr;
966
967 std::string capturedError = std::move(gCapturedError).str();
968
969 gCapturedError.str("");
970 gCapturedError.clear();
971
972 return Py_BuildValue("s", capturedError.c_str());
973}
974} // unnamed namespace
975
976
977//- data -----------------------------------------------------------------------
979 {(char*) "CreateScopeProxy", (PyCFunction)CPyCppyy::CreateScopeProxy,
980 METH_VARARGS, (char*)"cppyy internal function"},
981 {(char*) "MakeCppTemplateClass", (PyCFunction)MakeCppTemplateClass,
982 METH_VARARGS, (char*)"cppyy internal function"},
983 {(char*) "_set_cpp_lazy_lookup", (PyCFunction)SetCppLazyLookup,
984 METH_VARARGS, (char*)"cppyy internal function"},
985 {(char*) "_DestroyPyStrings", (PyCFunction)CPyCppyy::DestroyPyStrings,
986 METH_NOARGS, (char*)"cppyy internal function"},
987 {(char*) "addressof", (PyCFunction)addressof,
988 METH_VARARGS | METH_KEYWORDS, (char*)"Retrieve address of proxied object or field as a value."},
989 {(char*) "as_cobject", (PyCFunction)AsCObject,
990 METH_VARARGS | METH_KEYWORDS, (char*)"Retrieve address of proxied object or field in a CObject."},
991 {(char*) "as_capsule", (PyCFunction)AsCapsule,
992 METH_VARARGS | METH_KEYWORDS, (char*)"Retrieve address of proxied object or field in a PyCapsule."},
993 {(char*) "as_ctypes", (PyCFunction)AsCTypes,
994 METH_VARARGS | METH_KEYWORDS, (char*)"Retrieve address of proxied object or field in a ctypes c_void_p."},
995 {(char*) "as_memoryview", (PyCFunction)AsMemoryView,
996 METH_O, (char*)"Represent an array of objects as raw memory."},
997 {(char*)"bind_object", (PyCFunction)BindObject,
998 METH_VARARGS | METH_KEYWORDS, (char*) "Create an object of given type, from given address."},
999 {(char*) "move", (PyCFunction)Move,
1000 METH_O, (char*)"Cast the C++ object to become movable."},
1001 {(char*) "add_pythonization", (PyCFunction)AddPythonization,
1002 METH_VARARGS, (char*)"Add a pythonizor."},
1003 {(char*) "remove_pythonization", (PyCFunction)RemovePythonization,
1004 METH_VARARGS, (char*)"Remove a pythonizor."},
1005 {(char*) "_pin_type", (PyCFunction)PinType,
1006 METH_O, (char*)"Install a type pinning."},
1007 {(char*) "_add_type_reducer", (PyCFunction)AddTypeReducer,
1008 METH_VARARGS, (char*)"Add a type reducer."},
1009 {(char*) "SetHeuristicMemoryPolicy", (PyCFunction)SetHeuristicMemoryPolicy,
1010 METH_VARARGS, (char*)"Set the global memory policy, which affects object ownership when objects are passed as function arguments."},
1011 {(char*) "SetImplicitSmartPointerConversion", (PyCFunction)SetImplicitSmartPointerConversion,
1012 METH_VARARGS, (char*)"Enable or disable the implicit conversion to smart pointers in function calls (on by default)."},
1013 {(char *)"SetGlobalSignalPolicy", (PyCFunction)SetGlobalSignalPolicy, METH_VARARGS,
1014 (char *)"Set the global signal policy, which determines whether a jmp address should be saved to return to after a "
1015 "C++ segfault. In practical terms: trap signals in safe mode to prevent interpreter abort."},
1016 {(char*) "SetOwnership", (PyCFunction)SetOwnership,
1017 METH_VARARGS, (char*)"Modify held C++ object ownership."},
1018 {(char*) "AddSmartPtrType", (PyCFunction)AddSmartPtrType,
1019 METH_VARARGS, (char*) "Add a smart pointer to the list of known smart pointer types."},
1020 {(char*) "_begin_capture_stderr", (PyCFunction)BeginCaptureStderr,
1021 METH_NOARGS, (char*) "Begin capturing stderr to a in memory buffer."},
1022 {(char*) "_end_capture_stderr", (PyCFunction)EndCaptureStderr,
1023 METH_NOARGS, (char*) "End capturing stderr and returns the captured buffer."},
1024 {nullptr, nullptr, 0, nullptr}
1025};
1026
1027
1028#if PY_VERSION_HEX >= 0x03000000
1029struct module_state {
1030 PyObject *error;
1031};
1032
1033#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
1034
1035static int cpycppyymodule_traverse(PyObject* m, visitproc visit, void* arg)
1036{
1037 Py_VISIT(GETSTATE(m)->error);
1038 return 0;
1039}
1040
1041static int cpycppyymodule_clear(PyObject* m)
1042{
1043 Py_CLEAR(GETSTATE(m)->error);
1044 return 0;
1045}
1046
1047
1048static struct PyModuleDef moduledef = {
1050 "libcppyy",
1051 nullptr,
1052 sizeof(struct module_state),
1054 nullptr,
1057 nullptr
1058};
1059#endif
1060
1061namespace CPyCppyy {
1062
1063//----------------------------------------------------------------------------
1065{
1066// Initialization of extension module libcppyy.
1067
1068// load commonly used python strings
1070 return nullptr;
1071
1072// setup interpreter
1073#if PY_VERSION_HEX < 0x03090000
1075#endif
1076
1077#if PY_VERSION_HEX < 0x030b0000
1078// prepare for laziness (the insert is needed to capture the most generic lookup
1079// function, just in case ...)
1080 PyObject* dict = PyDict_New();
1084#if PY_VERSION_HEX >= 0x03030000
1085 gDictLookupOrg = (dict_lookup_func)((PyDictObject*)dict)->ma_keys->dk_lookup;
1086#else
1088#endif
1089 Py_DECREF(dict);
1090#endif // PY_VERSION_HEX < 0x030b0000
1091
1092// setup this module
1093#if PY_VERSION_HEX >= 0x03000000
1095#else
1096 gThisModule = Py_InitModule(const_cast<char*>("libcppyy"), gCPyCppyyMethods);
1097#endif
1098 if (!gThisModule)
1099 return nullptr;
1100
1101// keep gThisModule, but do not increase its reference count even as it is borrowed,
1102// or a self-referencing cycle would be created
1103
1104// external types
1106 PyModule_AddObject(gThisModule, "type_map", gPyTypeMap); // steals reference
1107
1108// Pythonizations ...
1109 PyModule_AddObject(gThisModule, "UserExceptions", PyDict_New());
1110
1111// inject meta type
1112 if (!Utility::InitProxy(gThisModule, &CPPScope_Type, "CPPScope"))
1113 return nullptr;
1114
1115// inject object proxy type
1116 if (!Utility::InitProxy(gThisModule, &CPPInstance_Type, "CPPInstance"))
1117 return nullptr;
1118
1119// inject exception object proxy type
1120 if (!Utility::InitProxy(gThisModule, &CPPExcInstance_Type, "CPPExcInstance"))
1121 return nullptr;
1122
1123// inject method proxy type
1124 if (!Utility::InitProxy(gThisModule, &CPPOverload_Type, "CPPOverload"))
1125 return nullptr;
1126
1127// inject template proxy type
1128 if (!Utility::InitProxy(gThisModule, &TemplateProxy_Type, "TemplateProxy"))
1129 return nullptr;
1130
1131// inject property proxy type
1132 if (!Utility::InitProxy(gThisModule, &CPPDataMember_Type, "CPPDataMember"))
1133 return nullptr;
1134
1135// inject custom data types
1136#if PY_VERSION_HEX < 0x03000000
1138 return nullptr;
1139
1141 return nullptr;
1142#endif
1143
1145 return nullptr;
1146
1147 if (!Utility::InitProxy(gThisModule, &TupleOfInstances_Type, "InstanceArray"))
1148 return nullptr;
1149
1150 if (!Utility::InitProxy(gThisModule, &LowLevelView_Type, "LowLevelView"))
1151 return nullptr;
1152
1153 if (!Utility::InitProxy(gThisModule, &PyNullPtr_t_Type, "nullptr_t"))
1154 return nullptr;
1155
1156// custom iterators
1158 return nullptr;
1159
1160 if (PyType_Ready(&IndexIter_Type) < 0)
1161 return nullptr;
1162
1163 if (PyType_Ready(&VectorIter_Type) < 0)
1164 return nullptr;
1165
1166// inject identifiable nullptr and default
1169 PyModule_AddObject(gThisModule, (char*)"nullptr", gNullPtrObject);
1170
1173 PyModule_AddObject(gThisModule, (char*)"default", gDefaultObject);
1174
1175// C++-specific exceptions
1176 PyObject* cppfatal = PyErr_NewException((char*)"cppyy.ll.FatalError", nullptr, nullptr);
1177 PyModule_AddObject(gThisModule, (char*)"FatalError", cppfatal);
1178
1179 gBusException = PyErr_NewException((char*)"cppyy.ll.BusError", cppfatal, nullptr);
1180 PyModule_AddObject(gThisModule, (char*)"BusError", gBusException);
1181 gSegvException = PyErr_NewException((char*)"cppyy.ll.SegmentationViolation", cppfatal, nullptr);
1182 PyModule_AddObject(gThisModule, (char*)"SegmentationViolation", gSegvException);
1183 gIllException = PyErr_NewException((char*)"cppyy.ll.IllegalInstruction", cppfatal, nullptr);
1184 PyModule_AddObject(gThisModule, (char*)"IllegalInstruction", gIllException);
1185 gAbrtException = PyErr_NewException((char*)"cppyy.ll.AbortSignal", cppfatal, nullptr);
1186 PyModule_AddObject(gThisModule, (char*)"AbortSignal", gAbrtException);
1187
1188// gbl namespace is injected in cppyy.py
1189
1190// create the memory regulator
1192
1193#if PY_VERSION_HEX >= 0x03000000
1195#endif
1196 return gThisModule;
1197}
1198
1199} // namespace CPyCppyy
static PyObject * default_repr(PyObject *)
#define CPYCPPYY_ORGDICT_LOOKUP(mp, key, hash, value_addr, hashpos)
#define DEFINE_CALL_POLICY_TOGGLE(name, flagname)
static PyObject * nullptr_repr(PyObject *)
static PyNumberMethods nullptr_as_number
static void default_dealloc(PyObject *)
static PyTypeObject PyDefault_t_Type
static void nullptr_dealloc(PyObject *)
static int nullptr_nonzero(PyObject *)
static PyMethodDef gCPyCppyyMethods[]
static PyTypeObject PyNullPtr_t_Type
#define CPYCPPYY_GET_DICT_LOOKUP(mp)
#define Py_TYPE(ob)
Definition CPyCppyy.h:196
PyDictEntry *(* dict_lookup_func)(PyDictObject *, PyObject *, long)
Definition CPyCppyy.h:44
#define Py_RETURN_TRUE
Definition CPyCppyy.h:272
#define Py_RETURN_FALSE
Definition CPyCppyy.h:276
#define PY_SSIZE_T_FORMAT
Definition CPyCppyy.h:218
static void * CPyCppyy_PyCapsule_GetPointer(PyObject *capsule, const char *)
Definition CPyCppyy.h:104
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:76
static PyObject * CPyCppyy_PyCapsule_New(void *cobj, const char *, void(*destr)(void *))
Definition CPyCppyy.h:98
long Py_hash_t
Definition CPyCppyy.h:114
static PyObject * PyObject_CallMethodOneArg(PyObject *obj, PyObject *name, PyObject *arg)
Definition CPyCppyy.h:377
#define CPyCppyy_PyText_FromFormat
Definition CPyCppyy.h:80
#define Py_RETURN_NONE
Definition CPyCppyy.h:268
#define CPyCppyy_PyText_Type
Definition CPyCppyy.h:94
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:81
#define CPyCppyy_PyText_Check
Definition CPyCppyy.h:74
#define PyVarObject_HEAD_INIT(type, size)
Definition CPyCppyy.h:194
_object PyObject
static struct PyModuleDef moduledef
#define GETSTATE(m)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
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 offset
TTime operator*(const TTime &t1, const TTime &t2)
Definition TTime.h:85
const_iterator begin() const
const_iterator end() const
PyObject * gDispGet
Definition PyStrings.cxx:71
Py_ssize_t GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, bool check=true)
Definition Utility.cxx:919
std::string ConstructTemplateArgs(PyObject *pyname, PyObject *tpArgs, PyObject *args=nullptr, ArgPreference=kNone, int argoff=0, int *pcnt=nullptr)
Definition Utility.cxx:635
bool InitProxy(PyObject *module, PyTypeObject *pytype, const char *name)
Definition Utility.cxx:872
PyTypeObject CPPInstance_Type
PyObject * gAbrtException
PyObject * gDefaultObject
bool gDictLookupActive
Definition Utility.cxx:27
PyTypeObject VectorIter_Type
PyTypeObject CPPExcInstance_Type
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
std::ostringstream gCapturedError
dict_lookup_func gDictLookupOrg
PyTypeObject CustomInstanceMethod_Type
PyObject * CreateScopeProxy(Cppyy::TCppScope_t, const unsigned flags=0)
bool CPPDataMember_CheckExact(T *object)
PyTypeObject RefFloat_Type
Custom "builtins," detectable by type, for pass by ref and improved performance.
PyObject * gSegvException
std::set< Cppyy::TCppType_t > gPinnedTypes
PyObject * DestroyPyStrings()
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
std::map< std::string, std::vector< PyObject * > > & pythonizations()
bool CPPScope_Check(T *object)
Definition CPPScope.h:81
PyObject * Init()
bool CreatePyStrings()
Definition PyStrings.cxx:86
CPYCPPYY_EXTERN PyObject * Instance_FromVoidPtr(void *addr, const std::string &classname, bool python_owns=false)
Definition API.cxx:133
bool CPPInstance_Check(T *object)
PyTypeObject IndexIter_Type
PyObject * gNullPtrObject
PyTypeObject CPPOverload_Type
PyTypeObject TemplateProxy_Type
PyObject * gThisModule
Definition CPPMethod.cxx:30
PyTypeObject InstanceArrayIter_Type
bool CPPDataMember_Check(T *object)
PyObject * BindCppObject(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
CPYCPPYY_EXTERN void * Instance_AsVoidPtr(PyObject *pyobject)
Definition API.cxx:118
PyTypeObject CPPScope_Type
Definition CPPScope.cxx:646
PyObject * gIllException
PyTypeObject LowLevelView_Type
PyObject * gPyTypeMap
bool CPPOverload_CheckExact(T *object)
PyTypeObject CPPDataMember_Type
PyObject * gBusException
std::streambuf * gOldErrorBuffer
PyTypeObject TupleOfInstances_Type
Representation of C-style array of instances.
PyTypeObject RefInt_Type
RPY_EXPORTED ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
RPY_EXPORTED size_t SizeOf(TCppType_t klass)
RPY_EXPORTED void AddSmartPtrType(const std::string &)
RPY_EXPORTED bool IsSubtype(TCppType_t derived, TCppType_t base)
void * TCppObject_t
Definition cpp_cppyy.h:37
TCppScope_t TCppType_t
Definition cpp_cppyy.h:35
RPY_EXPORTED void AddTypeReducer(const std::string &reducable, const std::string &reduced)
RPY_EXPORTED bool IsAggregate(TCppType_t type)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
void * TCppFuncAddr_t
Definition cpp_cppyy.h:41
PyObject_HEAD char * b_ptr
PyObject * error
TMarker m
Definition textangle.C:8