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