Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Pythonize.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "Pythonize.h"
4#include "Converters.h"
5#include "CPPInstance.h"
6#include "CPPOverload.h"
7#include "CustomPyTypes.h"
8#include "LowLevelViews.h"
9#include "ProxyWrappers.h"
10#include "PyCallable.h"
11#include "PyStrings.h"
12#include "TypeManip.h"
13#include "Utility.h"
14
15// Standard
16#include <algorithm>
17#include <complex>
18#include <set>
19#include <stdexcept>
20#include <sstream>
21#include <string>
22#include <utility>
23
24
25//- data and local helpers ---------------------------------------------------
26namespace CPyCppyy {
27 extern PyObject* gThisModule;
28 extern std::map<std::string, std::vector<PyObject*>> gPythonizations;
29}
30
31namespace {
32
33// for convenience
34using namespace CPyCppyy;
35
36//-----------------------------------------------------------------------------
37bool HasAttrDirect(PyObject* pyclass, PyObject* pyname, bool mustBeCPyCppyy = false) {
38// prevents calls to Py_TYPE(pyclass)->tp_getattr, which is unnecessary for our
39// purposes here and could tickle problems w/ spurious lookups into ROOT meta
40 PyObject* dct = PyObject_GetAttr(pyclass, PyStrings::gDict);
41 if (dct) {
42 PyObject* attr = PyObject_GetItem(dct, pyname);
43 Py_DECREF(dct);
44 if (attr) {
45 bool ret = !mustBeCPyCppyy || CPPOverload_Check(attr);
46 Py_DECREF(attr);
47 return ret;
48 }
49 }
50 PyErr_Clear();
51 return false;
52}
53
54//-----------------------------------------------------------------------------
55inline bool IsTemplatedSTLClass(const std::string& name, const std::string& klass) {
56// Scan the name of the class and determine whether it is a template instantiation.
57 auto pos = name.find(klass);
58 return (pos == 0 || pos == 5) && name.find("::", name.rfind(">")) == std::string::npos;
59}
60
61// to prevent compiler warnings about const char* -> char*
62inline PyObject* CallPyObjMethod(PyObject* obj, const char* meth)
63{
64// Helper; call method with signature: obj->meth().
65 Py_INCREF(obj);
66 PyObject* result = PyObject_CallMethod(obj, const_cast<char*>(meth), const_cast<char*>(""));
67 Py_DECREF(obj);
68 return result;
69}
70
71//-----------------------------------------------------------------------------
72inline PyObject* CallPyObjMethod(PyObject* obj, const char* meth, PyObject* arg1)
73{
74// Helper; call method with signature: obj->meth(arg1).
75 Py_INCREF(obj);
76 PyObject* result = PyObject_CallMethod(
77 obj, const_cast<char*>(meth), const_cast<char*>("O"), arg1);
78 Py_DECREF(obj);
79 return result;
80}
81
82//-----------------------------------------------------------------------------
84{
85// Helper; converts python index into straight C index.
86 Py_ssize_t idx = PyInt_AsSsize_t(index);
87 if (idx == (Py_ssize_t)-1 && PyErr_Occurred())
88 return nullptr;
89
90 Py_ssize_t size = PySequence_Size(self);
91 if (idx >= size || (idx < 0 && idx < -size)) {
92 PyErr_SetString(PyExc_IndexError, "index out of range");
93 return nullptr;
94 }
95
96 PyObject* pyindex = nullptr;
97 if (idx >= 0) {
98 Py_INCREF(index);
99 pyindex = index;
100 } else
101 pyindex = PyLong_FromSsize_t(size+idx);
102
103 return pyindex;
104}
105
106//-----------------------------------------------------------------------------
107inline bool AdjustSlice(const Py_ssize_t nlen, Py_ssize_t& start, Py_ssize_t& stop, Py_ssize_t& step)
108{
109// Helper; modify slice range to match the container.
110 if ((step > 0 && stop <= start) || (step < 0 && start <= stop))
111 return false;
112
113 if (start < 0) start = 0;
114 if (start >= nlen) start = nlen-1;
115 if (step >= nlen) step = nlen;
116
117 stop = step > 0 ? std::min(nlen, stop) : (stop >= 0 ? stop : -1);
118 return true;
119}
120
121//-----------------------------------------------------------------------------
122inline PyObject* CallSelfIndex(CPPInstance* self, PyObject* idx, PyObject* pymeth)
123{
124// Helper; call method with signature: meth(pyindex).
125 Py_INCREF((PyObject*)self);
126 PyObject* pyindex = PyStyleIndex((PyObject*)self, idx);
127 if (!pyindex) {
128 Py_DECREF((PyObject*)self);
129 return nullptr;
130 }
131
132 PyObject* result = PyObject_CallMethodObjArgs((PyObject*)self, pymeth, pyindex, nullptr);
133 Py_DECREF(pyindex);
134 Py_DECREF((PyObject*)self);
135 return result;
136}
137
138//- "smart pointer" behavior ---------------------------------------------------
139PyObject* DeRefGetAttr(PyObject* self, PyObject* name)
140{
141// Follow operator*() if present (available in python as __deref__), so that
142// smart pointers behave as expected.
144 // TODO: these calls come from TemplateProxy and are unlikely to be needed in practice,
145 // whereas as-is, they can accidentally dereference the result of end() on some STL
146 // containers. Obviously, this is a dumb hack that should be resolved more fundamentally.
147 PyErr_SetString(PyExc_AttributeError, CPyCppyy_PyText_AsString(name));
148 return nullptr;
149 }
150
152 PyErr_SetString(PyExc_TypeError, "getattr(): attribute name must be string");
153
154 PyObject* pyptr = PyObject_CallMethodObjArgs(self, PyStrings::gDeref, nullptr);
155 if (!pyptr)
156 return nullptr;
157
158// prevent a potential infinite loop
159 if (Py_TYPE(pyptr) == Py_TYPE(self)) {
160 PyObject* val1 = PyObject_Str(self);
161 PyObject* val2 = PyObject_Str(name);
162 PyErr_Format(PyExc_AttributeError, "%s has no attribute \'%s\'",
164 Py_DECREF(val2);
165 Py_DECREF(val1);
166
167 Py_DECREF(pyptr);
168 return nullptr;
169 }
170
171 PyObject* result = PyObject_GetAttr(pyptr, name);
172 Py_DECREF(pyptr);
173 return result;
174}
175
176//-----------------------------------------------------------------------------
177PyObject* FollowGetAttr(PyObject* self, PyObject* name)
178{
179// Follow operator->() if present (available in python as __follow__), so that
180// smart pointers behave as expected.
182 PyErr_SetString(PyExc_TypeError, "getattr(): attribute name must be string");
183
184 PyObject* pyptr = PyObject_CallMethodObjArgs(self, PyStrings::gFollow, nullptr);
185 if (!pyptr)
186 return nullptr;
187
188 PyObject* result = PyObject_GetAttr(pyptr, name);
189 Py_DECREF(pyptr);
190 return result;
191}
192
193
194//- vector behavior as primitives ----------------------------------------------
195#if PY_VERSION_HEX < 0x03040000
196#define PyObject_LengthHint _PyObject_LengthHint
197#endif
198
199// TODO: can probably use the below getters in the InitializerListConverter
200struct ItemGetter {
201 ItemGetter(PyObject* pyobj) : fPyObject(pyobj) { Py_INCREF(fPyObject); }
202 virtual ~ItemGetter() { Py_DECREF(fPyObject); }
203 virtual Py_ssize_t size() = 0;
204 virtual PyObject* get() = 0;
205 PyObject* fPyObject;
206};
207
208struct CountedItemGetter : public ItemGetter {
209 CountedItemGetter(PyObject* pyobj) : ItemGetter(pyobj), fCur(0) {}
210 Py_ssize_t fCur;
211};
212
213struct TupleItemGetter : public CountedItemGetter {
214 using CountedItemGetter::CountedItemGetter;
215 virtual Py_ssize_t size() { return PyTuple_GET_SIZE(fPyObject); }
216 virtual PyObject* get() {
217 if (fCur < PyTuple_GET_SIZE(fPyObject)) {
218 PyObject* item = PyTuple_GET_ITEM(fPyObject, fCur++);
219 Py_INCREF(item);
220 return item;
221 }
222 PyErr_SetString(PyExc_StopIteration, "end of tuple");
223 return nullptr;
224 }
225};
226
227struct ListItemGetter : public CountedItemGetter {
228 using CountedItemGetter::CountedItemGetter;
229 virtual Py_ssize_t size() { return PyList_GET_SIZE(fPyObject); }
230 virtual PyObject* get() {
231 if (fCur < PyList_GET_SIZE(fPyObject)) {
232 PyObject* item = PyList_GET_ITEM(fPyObject, fCur++);
233 Py_INCREF(item);
234 return item;
235 }
236 PyErr_SetString(PyExc_StopIteration, "end of list");
237 return nullptr;
238 }
239};
240
241struct SequenceItemGetter : public CountedItemGetter {
242 using CountedItemGetter::CountedItemGetter;
243 virtual Py_ssize_t size() {
244 Py_ssize_t sz = PySequence_Size(fPyObject);
245 if (sz < 0) {
246 PyErr_Clear();
247 return PyObject_LengthHint(fPyObject, 8);
248 }
249 return sz;
250 }
251 virtual PyObject* get() { return PySequence_GetItem(fPyObject, fCur++); }
252};
253
254struct IterItemGetter : public ItemGetter {
255 using ItemGetter::ItemGetter;
256 virtual Py_ssize_t size() { return PyObject_LengthHint(fPyObject, 8); }
257 virtual PyObject* get() { return (*(Py_TYPE(fPyObject)->tp_iternext))(fPyObject); }
258};
259
260PyObject* VectorInit(PyObject* self, PyObject* args, PyObject* /* kwds */)
261{
262// Specialized vector constructor to allow construction from containers; allowing
263// such construction from initializer_list instead would possible, but can be
264// error-prone. This use case is common enough for std::vector to implement it
265// directly, except for arrays (which can be passed wholesale) and strings (which
266// won't convert properly as they'll be seen as buffers)
267
268 ItemGetter* getter = nullptr;
269 if (PyTuple_GET_SIZE(args) == 1) {
270 PyObject* fi = PyTuple_GET_ITEM(args, 0);
271 if (CPyCppyy_PyText_Check(fi) || PyBytes_Check(fi)) {
272 PyErr_SetString(PyExc_TypeError, "can not convert string to vector");
273 return nullptr;
274 }
275 // TODO: this only tests for new-style buffers, which is too strict, but a
276 // generic check for Py_TYPE(fi)->tp_as_buffer is too loose (note that the
277 // main use case is numpy, which offers the new interface)
278 if (!PyObject_CheckBuffer(fi)) {
279 if (PyTuple_CheckExact(fi))
280 getter = new TupleItemGetter(fi);
281 else if (PyList_CheckExact(fi))
282 getter = new ListItemGetter(fi);
283 else if (PySequence_Check(fi))
284 getter = new SequenceItemGetter(fi);
285 else {
286 PyObject* iter = PyObject_GetIter(fi);
287 if (iter) {
288 getter = new IterItemGetter{iter};
289 Py_DECREF(iter);
290 }
291 else PyErr_Clear();
292 }
293 }
294 }
295
296 if (getter) {
297 // construct an empty vector, then back-fill it
298 PyObject* mname = CPyCppyy_PyText_FromString("__real_init");
299 PyObject* result = PyObject_CallMethodObjArgs(self, mname, nullptr);
300 Py_DECREF(mname);
301 if (!result) {
302 delete getter;
303 return result;
304 }
305
306 Py_ssize_t sz = getter->size();
307 if (sz < 0) {
308 delete getter;
309 return nullptr;
310 }
311
312 // reserve memory as appliable
313 if (0 < sz) {
314 PyObject* res = PyObject_CallMethod(self, (char*)"reserve", (char*)"n", sz);
315 Py_DECREF(res);
316 } else { // empty container
317 delete getter;
318 return result;
319 }
320
321 bool fill_ok = true;
322
323 // two main options: a list of lists (or tuples), or a list of objects; the former
324 // are emplace_back'ed, the latter push_back'ed
325 PyObject* fi = PySequence_GetItem(PyTuple_GET_ITEM(args, 0), 0);
326 if (!fi) PyErr_Clear();
327 if (fi && (PyTuple_CheckExact(fi) || PyList_CheckExact(fi))) {
328 // use emplace_back to construct the vector entries one by one
329 PyObject* eb_call = PyObject_GetAttrString(self, (char*)"emplace_back");
330 PyObject* vtype = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "value_type");
331 bool value_is_vector = false;
332 if (vtype && CPyCppyy_PyText_Check(vtype)) {
333 // if the value_type is a vector, then allow for initialization from sequences
334 if (std::string(CPyCppyy_PyText_AsString(vtype)).rfind("std::vector", 0) != std::string::npos)
335 value_is_vector = true;
336 } else
337 PyErr_Clear();
338 Py_XDECREF(vtype);
339
340 if (eb_call) {
341 PyObject* eb_args;
342 for (int i = 0; /* until break */; ++i) {
343 PyObject* item = getter->get();
344 if (item) {
345 if (value_is_vector && PySequence_Check(item)) {
346 eb_args = PyTuple_New(1);
347 PyTuple_SET_ITEM(eb_args, 0, item);
348 } else if (PyTuple_CheckExact(item)) {
349 eb_args = item;
350 } else if (PyList_CheckExact(item)) {
351 Py_ssize_t isz = PyList_GET_SIZE(item);
352 eb_args = PyTuple_New(isz);
353 for (Py_ssize_t j = 0; j < isz; ++j) {
354 PyObject* iarg = PyList_GET_ITEM(item, j);
355 Py_INCREF(iarg);
356 PyTuple_SET_ITEM(eb_args, j, iarg);
357 }
358 Py_DECREF(item);
359 } else {
360 Py_DECREF(item);
361 PyErr_Format(PyExc_TypeError, "argument %d is not a tuple or list", i);
362 fill_ok = false;
363 break;
364 }
365 PyObject* ebres = PyObject_CallObject(eb_call, eb_args);
366 Py_DECREF(eb_args);
367 if (!ebres) {
368 fill_ok = false;
369 break;
370 }
371 Py_DECREF(ebres);
372 } else {
373 if (PyErr_Occurred()) {
374 if (!(PyErr_ExceptionMatches(PyExc_IndexError) ||
375 PyErr_ExceptionMatches(PyExc_StopIteration)))
376 fill_ok = false;
377 else { PyErr_Clear(); }
378 }
379 break;
380 }
381 }
382 Py_DECREF(eb_call);
383 }
384 } else {
385 // use push_back to add the vector entries one by one
386 PyObject* pb_call = PyObject_GetAttrString(self, (char*)"push_back");
387 if (pb_call) {
388 for (;;) {
389 PyObject* item = getter->get();
390 if (item) {
391 PyObject* pbres = PyObject_CallFunctionObjArgs(pb_call, item, nullptr);
392 Py_DECREF(item);
393 if (!pbres) {
394 fill_ok = false;
395 break;
396 }
397 Py_DECREF(pbres);
398 } else {
399 if (PyErr_Occurred()) {
400 if (!(PyErr_ExceptionMatches(PyExc_IndexError) ||
401 PyErr_ExceptionMatches(PyExc_StopIteration)))
402 fill_ok = false;
403 else { PyErr_Clear(); }
404 }
405 break;
406 }
407 }
408 Py_DECREF(pb_call);
409 }
410 }
411 Py_XDECREF(fi);
412 delete getter;
413
414 if (!fill_ok) {
415 Py_DECREF(result);
416 return nullptr;
417 }
418
419 return result;
420 }
421
422// The given argument wasn't iterable: simply forward to regular constructor
423 PyObject* realInit = PyObject_GetAttrString(self, "__real_init");
424 if (realInit) {
425 PyObject* result = PyObject_Call(realInit, args, nullptr);
426 Py_DECREF(realInit);
427 return result;
428 }
429
430 return nullptr;
431}
432
433//---------------------------------------------------------------------------
434PyObject* VectorData(PyObject* self, PyObject*)
435{
436 PyObject* pydata = CallPyObjMethod(self, "__real_data");
437 if (!LowLevelView_Check(pydata)) return pydata;
438
439 PyObject* pylen = PyObject_CallMethodObjArgs(self, PyStrings::gSize, nullptr);
440 if (!pylen) {
441 PyErr_Clear();
442 return pydata;
443 }
444
445 long clen = PyInt_AsLong(pylen);
446 Py_DECREF(pylen);
447
448// TODO: should be a LowLevelView helper
449 Py_buffer& bi = ((LowLevelView*)pydata)->fBufInfo;
450 bi.len = clen * bi.itemsize;
451 if (bi.ndim == 1 && bi.shape)
452 bi.shape[0] = clen;
453
454 return pydata;
455}
456
457
458//-----------------------------------------------------------------------------
459static PyObject* vector_iter(PyObject* v) {
460 vectoriterobject* vi = PyObject_GC_New(vectoriterobject, &VectorIter_Type);
461 if (!vi) return nullptr;
462
463 Py_INCREF(v);
464 vi->ii_container = v;
465 vi->vi_flags = v->ob_refcnt <= 2 ? 1 : 0; // 2, b/c of preceding INCREF
466
467 PyObject* pyvalue_type = PyObject_GetAttrString((PyObject*)Py_TYPE(v), "value_type");
468 PyObject* pyvalue_size = PyObject_GetAttrString((PyObject*)Py_TYPE(v), "value_size");
469
470 vi->vi_klass = 0;
471 if (pyvalue_type && pyvalue_size) {
472 PyObject* pydata = CallPyObjMethod(v, "data");
473 if (!pydata || Utility::GetBuffer(pydata, '*', 1, vi->vi_data, false) == 0) {
474 if (CPPInstance_Check(pydata)) {
475 vi->vi_data = ((CPPInstance*)pydata)->GetObjectRaw();
476 vi->vi_klass = ((CPPInstance*)pydata)->ObjectIsA(false);
477 } else
478 vi->vi_data = nullptr;
479 }
480 Py_XDECREF(pydata);
481
482 vi->vi_converter = vi->vi_klass ? nullptr : CPyCppyy::CreateConverter(CPyCppyy_PyText_AsString(pyvalue_type));
483 vi->vi_stride = PyLong_AsLong(pyvalue_size);
484 } else {
485 PyErr_Clear();
486 vi->vi_data = nullptr;
487 vi->vi_converter = nullptr;
488 vi->vi_stride = 0;
489 }
490
491 Py_XDECREF(pyvalue_size);
492 Py_XDECREF(pyvalue_type);
493
494 vi->ii_pos = 0;
495 vi->ii_len = PySequence_Size(v);
496
497 PyObject_GC_Track(vi);
498 return (PyObject*)vi;
499}
500
501PyObject* VectorGetItem(CPPInstance* self, PySliceObject* index)
502{
503// Implement python's __getitem__ for std::vector<>s.
504 if (PySlice_Check(index)) {
505 if (!self->GetObject()) {
506 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
507 return nullptr;
508 }
509
510 PyObject* pyclass = (PyObject*)Py_TYPE((PyObject*)self);
511 PyObject* nseq = PyObject_CallObject(pyclass, nullptr);
512
513 Py_ssize_t start, stop, step;
514 PySlice_GetIndices((CPyCppyy_PySliceCast)index, PyObject_Length((PyObject*)self), &start, &stop, &step);
515
516 const Py_ssize_t nlen = PySequence_Size((PyObject*)self);
517 if (!AdjustSlice(nlen, start, stop, step))
518 return nseq;
519
520 const Py_ssize_t sign = step < 0 ? -1 : 1;
521 for (Py_ssize_t i = start; i*sign < stop*sign; i += step) {
522 PyObject* pyidx = PyInt_FromSsize_t(i);
523 PyObject* item = PyObject_CallMethodObjArgs((PyObject*)self, PyStrings::gGetNoCheck, pyidx, nullptr);
524 CallPyObjMethod(nseq, "push_back", item);
525 Py_DECREF(item);
526 Py_DECREF(pyidx);
527 }
528
529 return nseq;
530 }
531
532 return CallSelfIndex(self, (PyObject*)index, PyStrings::gGetNoCheck);
533}
534
535
536static Cppyy::TCppType_t sVectorBoolTypeID = (Cppyy::TCppType_t)0;
537
538PyObject* VectorBoolGetItem(CPPInstance* self, PyObject* idx)
539{
540// std::vector<bool> is a special-case in C++, and its return type depends on
541// the compiler: treat it special here as well
542 if (!CPPInstance_Check(self) || self->ObjectIsA() != sVectorBoolTypeID) {
543 PyErr_Format(PyExc_TypeError,
544 "require object of type std::vector<bool>, but %s given",
545 Cppyy::GetScopedFinalName(self->ObjectIsA()).c_str());
546 return nullptr;
547 }
548
549 if (!self->GetObject()) {
550 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
551 return nullptr;
552 }
553
554 if (PySlice_Check(idx)) {
555 PyObject* pyclass = (PyObject*)Py_TYPE((PyObject*)self);
556 PyObject* nseq = PyObject_CallObject(pyclass, nullptr);
557
558 Py_ssize_t start, stop, step;
559 PySlice_GetIndices((CPyCppyy_PySliceCast)idx, PyObject_Length((PyObject*)self), &start, &stop, &step);
560 const Py_ssize_t nlen = PySequence_Size((PyObject*)self);
561 if (!AdjustSlice(nlen, start, stop, step))
562 return nseq;
563
564 const Py_ssize_t sign = step < 0 ? -1 : 1;
565 for (Py_ssize_t i = start; i*sign < stop*sign; i += step) {
566 PyObject* pyidx = PyInt_FromSsize_t(i);
567 PyObject* item = PyObject_CallMethodObjArgs((PyObject*)self, PyStrings::gGetItem, pyidx, nullptr);
568 CallPyObjMethod(nseq, "push_back", item);
569 Py_DECREF(item);
570 Py_DECREF(pyidx);
571 }
572
573 return nseq;
574 }
575
576 PyObject* pyindex = PyStyleIndex((PyObject*)self, idx);
577 if (!pyindex)
578 return nullptr;
579
580 int index = (int)PyLong_AsLong(pyindex);
581 Py_DECREF(pyindex);
582
583// get hold of the actual std::vector<bool> (no cast, as vector is never a base)
584 std::vector<bool>* vb = (std::vector<bool>*)self->GetObject();
585
586// finally, return the value
587 if (bool((*vb)[index]))
590}
591
592PyObject* VectorBoolSetItem(CPPInstance* self, PyObject* args)
593{
594// std::vector<bool> is a special-case in C++, and its return type depends on
595// the compiler: treat it special here as well
596 if (!CPPInstance_Check(self) || self->ObjectIsA() != sVectorBoolTypeID) {
597 PyErr_Format(PyExc_TypeError,
598 "require object of type std::vector<bool>, but %s given",
599 Cppyy::GetScopedFinalName(self->ObjectIsA()).c_str());
600 return nullptr;
601 }
602
603 if (!self->GetObject()) {
604 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
605 return nullptr;
606 }
607
608 int bval = 0; PyObject* idx = nullptr;
609 if (!PyArg_ParseTuple(args, const_cast<char*>("Oi:__setitem__"), &idx, &bval))
610 return nullptr;
611
612 PyObject* pyindex = PyStyleIndex((PyObject*)self, idx);
613 if (!pyindex)
614 return nullptr;
615
616 int index = (int)PyLong_AsLong(pyindex);
617 Py_DECREF(pyindex);
618
619// get hold of the actual std::vector<bool> (no cast, as vector is never a base)
620 std::vector<bool>* vb = (std::vector<bool>*)self->GetObject();
621
622// finally, set the value
623 (*vb)[index] = (bool)bval;
624
626}
627
628//- map behavior as primitives ------------------------------------------------
629PyObject* MapContains(PyObject* self, PyObject* obj)
630{
631// Implement python's __contains__ for std::map<>s
632 PyObject* result = nullptr;
633
634 PyObject* iter = CallPyObjMethod(self, "find", obj);
635 if (CPPInstance_Check(iter)) {
636 PyObject* end = PyObject_CallMethodObjArgs(self, PyStrings::gEnd, nullptr);
637 if (CPPInstance_Check(end)) {
638 if (!PyObject_RichCompareBool(iter, end, Py_EQ)) {
639 Py_INCREF(Py_True);
640 result = Py_True;
641 }
642 }
643 Py_XDECREF(end);
644 }
645 Py_XDECREF(iter);
646
647 if (!result) {
648 PyErr_Clear(); // e.g. wrong argument type, which should always lead to False
649 Py_INCREF(Py_False);
650 result = Py_False;
651 }
652
653 return result;
654}
655
656//- STL container iterator support --------------------------------------------
657PyObject* StlSequenceIter(PyObject* self)
658{
659// Implement python's __iter__ for std::iterator<>s
660 PyObject* iter = PyObject_CallMethodObjArgs(self, PyStrings::gBegin, nullptr);
661 if (iter) {
662 PyObject* end = PyObject_CallMethodObjArgs(self, PyStrings::gEnd, nullptr);
663 if (end)
664 PyObject_SetAttr(iter, PyStrings::gEnd, end);
665 Py_XDECREF(end);
666
667 // add iterated collection as attribute so its refcount stays >= 1 while it's being iterated over
668 PyObject_SetAttr(iter, CPyCppyy_PyText_FromString("_collection"), self);
669 }
670 return iter;
671}
672
673//- generic iterator support over a sequence with operator[] and size ---------
674//-----------------------------------------------------------------------------
675static PyObject* index_iter(PyObject* c) {
676 indexiterobject* ii = PyObject_GC_New(indexiterobject, &IndexIter_Type);
677 if (!ii) return nullptr;
678
679 Py_INCREF(c);
680 ii->ii_container = c;
681 ii->ii_pos = 0;
682 ii->ii_len = PySequence_Size(c);
683
684 PyObject_GC_Track(ii);
685 return (PyObject*)ii;
686}
687
688
689//- safe indexing for STL-like vector w/o iterator dictionaries ---------------
690/* replaced by indexiterobject iteration, but may still have some future use ...
691PyObject* CheckedGetItem(PyObject* self, PyObject* obj)
692{
693// Implement a generic python __getitem__ for STL-like classes that are missing the
694// reflection info for their iterators. This is then used for iteration by means of
695// consecutive indeces, it such index is of integer type.
696 Py_ssize_t size = PySequence_Size(self);
697 Py_ssize_t idx = PyInt_AsSsize_t(obj);
698 if ((size == (Py_ssize_t)-1 || idx == (Py_ssize_t)-1) && PyErr_Occurred()) {
699 // argument conversion problem: let method itself resolve anew and report
700 PyErr_Clear();
701 return PyObject_CallMethodObjArgs(self, PyStrings::gGetNoCheck, obj, nullptr);
702 }
703
704 bool inbounds = false;
705 if (idx < 0) idx += size;
706 if (0 <= idx && 0 <= size && idx < size)
707 inbounds = true;
708
709 if (inbounds)
710 return PyObject_CallMethodObjArgs(self, PyStrings::gGetNoCheck, obj, nullptr);
711 else
712 PyErr_SetString( PyExc_IndexError, "index out of range" );
713
714 return nullptr;
715}*/
716
717//- pair as sequence to allow tuple unpacking --------------------------------
718PyObject* PairUnpack(PyObject* self, PyObject* pyindex)
719{
720// For std::map<> iteration, unpack std::pair<>s into tuples for the loop.
721 long idx = PyLong_AsLong(pyindex);
722 if (idx == -1 && PyErr_Occurred())
723 return nullptr;
724
725 if (!CPPInstance_Check(self) || !((CPPInstance*)self)->GetObject()) {
726 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
727 return nullptr;
728 }
729
730 if ((int)idx == 0)
731 return PyObject_GetAttr(self, PyStrings::gFirst);
732 else if ((int)idx == 1)
733 return PyObject_GetAttr(self, PyStrings::gSecond);
734
735// still here? Trigger stop iteration
736 PyErr_SetString(PyExc_IndexError, "out of bounds");
737 return nullptr;
738}
739
740//- simplistic len() functions -----------------------------------------------
741PyObject* ReturnTwo(CPPInstance*, PyObject*) {
742 return PyInt_FromLong(2);
743}
744
745
746//- shared_ptr behavior --------------------------------------------------------
747PyObject* SharedPtrInit(PyObject* self, PyObject* args, PyObject* /* kwds */)
748{
749// since the shared pointer will take ownership, we need to relinquish it
750 PyObject* realInit = PyObject_GetAttrString(self, "__real_init");
751 if (realInit) {
752 PyObject* result = PyObject_Call(realInit, args, nullptr);
753 Py_DECREF(realInit);
754 if (result && PyTuple_GET_SIZE(args) == 1 && CPPInstance_Check(PyTuple_GET_ITEM(args, 0)))
755 PyObject_SetAttrString(PyTuple_GET_ITEM(args, 0), "__python_owns__", Py_False);
756 return result;
757 }
758 return nullptr;
759}
760
761
762//- string behavior as primitives --------------------------------------------
763#if PY_VERSION_HEX >= 0x03000000
764// TODO: this is wrong, b/c it doesn't order
765static int PyObject_Compare(PyObject* one, PyObject* other) {
766 return !PyObject_RichCompareBool(one, other, Py_EQ);
767}
768#endif
769static inline PyObject* CPyCppyy_PyString_FromCppString(std::string* s) {
770 return CPyCppyy_PyText_FromStringAndSize(s->c_str(), s->size());
771}
772
773static inline PyObject* CPyCppyy_PyString_FromCppString(std::wstring* s) {
774 return PyUnicode_FromWideChar(s->c_str(), s->size());
775}
776
777#define CPPYY_IMPL_STRING_PYTHONIZATION(type, name) \
778static PyObject* name##StringGetData(PyObject* self) \
779{ \
780 if (CPyCppyy::CPPInstance_Check(self)) { \
781 type* obj = ((type*)((CPPInstance*)self)->GetObject()); \
782 if (obj) { \
783 return CPyCppyy_PyString_FromCppString(obj); \
784 } else { \
785 return CPPInstance_Type.tp_str(self); \
786 } \
787 } \
788 PyErr_Format(PyExc_TypeError, "object mismatch (%s expected)", #type); \
789 return nullptr; \
790} \
791 \
792PyObject* name##StringRepr(PyObject* self) \
793{ \
794 PyObject* data = name##StringGetData(self); \
795 if (data) { \
796 PyObject* repr = PyObject_Repr(data); \
797 Py_DECREF(data); \
798 return repr; \
799 } \
800 return nullptr; \
801} \
802 \
803PyObject* name##StringIsEqual(PyObject* self, PyObject* obj) \
804{ \
805 PyObject* data = name##StringGetData(self); \
806 if (data) { \
807 PyObject* result = PyObject_RichCompare(data, obj, Py_EQ); \
808 Py_DECREF(data); \
809 return result; \
810 } \
811 return nullptr; \
812} \
813 \
814PyObject* name##StringIsNotEqual(PyObject* self, PyObject* obj) \
815{ \
816 PyObject* data = name##StringGetData(self); \
817 if (data) { \
818 PyObject* result = PyObject_RichCompare(data, obj, Py_NE); \
819 Py_DECREF(data); \
820 return result; \
821 } \
822 return nullptr; \
823}
824
825// Only define StlStringCompare:
826#define CPPYY_IMPL_STRING_PYTHONIZATION_CMP(type, name) \
827CPPYY_IMPL_STRING_PYTHONIZATION(type, name) \
828PyObject* name##StringCompare(PyObject* self, PyObject* obj) \
829{ \
830 PyObject* data = name##StringGetData(self); \
831 int result = 0; \
832 if (data) { \
833 result = PyObject_Compare(data, obj); \
834 Py_DECREF(data); \
835 } \
836 if (PyErr_Occurred()) \
837 return nullptr; \
838 return PyInt_FromLong(result); \
839}
840
842CPPYY_IMPL_STRING_PYTHONIZATION_CMP(std::wstring, StlW)
843
844Py_hash_t StlStringHash(PyObject* self)
845{
846// std::string objects hash to the same values as Python strings to allow
847// matches in dictionaries etc.
848 PyObject* data = StlStringGetData(self);
849 Py_hash_t h = CPyCppyy_PyText_Type.tp_hash(data);
850 Py_DECREF(data);
851 return h;
852}
853
854
855//- STL iterator behavior ----------------------------------------------------
856PyObject* StlIterNext(PyObject* self)
857{
858// Python iterator protocol __next__ for STL forward iterators.
859 PyObject* next = nullptr;
860 PyObject* last = PyObject_GetAttr(self, PyStrings::gEnd);
861
862 if (last) {
863 // handle special case of empty container (i.e. self is end)
864 if (PyObject_RichCompareBool(last, self, Py_EQ) == 0) {
865 // first, get next from the _current_ iterator as internal state may change
866 // when call post or pre increment
867 next = PyObject_CallMethodObjArgs(self, PyStrings::gDeref, nullptr);
868 if (!next) PyErr_Clear();
869
870 // use postinc, even as the C++11 range-based for loops prefer preinc b/c
871 // that allows the current value from the iterator to be had from __deref__,
872 // an issue that does not come up in C++
873 static PyObject* dummy = PyInt_FromLong(1l);
874 PyObject* iter = PyObject_CallMethodObjArgs(self, PyStrings::gPostInc, dummy, nullptr);
875 if (!iter) {
876 // allow preinc, as in that case likely __deref__ is not defined and it
877 // is the iterator rather that is returned in the loop
878 PyErr_Clear();
879 iter = PyObject_CallMethodObjArgs(self, PyStrings::gPreInc, nullptr);
880 }
881 if (iter) {
882 // prefer != as per C++11 range-based for
883 int isNotEnd = PyObject_RichCompareBool(last, iter, Py_NE);
884 if (isNotEnd && !next) {
885 // if no dereference, continue iterating over the iterator
886 Py_INCREF(iter);
887 next = iter;
888 }
889 Py_DECREF(iter);
890 } else {
891 // fail current next, even if available
892 Py_XDECREF(next);
893 next = nullptr;
894 }
895 } else {
896 PyErr_SetString(PyExc_StopIteration, "");
897 }
898 Py_DECREF(last);
899 }
900
901 if (!next) PyErr_SetString(PyExc_StopIteration, "");
902 return next;
903}
904
905
906//- STL complex<T> behavior --------------------------------------------------
907#define COMPLEX_METH_GETSET(name, cppname) \
908static PyObject* name##ComplexGet(PyObject* self, void*) { \
909 return PyObject_CallMethodObjArgs(self, cppname, nullptr); \
910} \
911static int name##ComplexSet(PyObject* self, PyObject* value, void*) { \
912 PyObject* result = PyObject_CallMethodObjArgs(self, cppname, value, nullptr);\
913 if (result) { \
914 Py_DECREF(result); \
915 return 0; \
916 } \
917 return -1; \
918} \
919PyGetSetDef name##Complex{(char*)#name, (getter)name##ComplexGet, (setter)name##ComplexSet, nullptr, nullptr};
920
923
924static PyObject* ComplexComplex(PyObject* self) {
925 PyObject* real = PyObject_CallMethodObjArgs(self, PyStrings::gCppReal, nullptr);
926 if (!real) return nullptr;
927 double r = PyFloat_AsDouble(real);
928 Py_DECREF(real);
929 if (r == -1. && PyErr_Occurred())
930 return nullptr;
931
932 PyObject* imag = PyObject_CallMethodObjArgs(self, PyStrings::gCppImag, nullptr);
933 if (!imag) return nullptr;
934 double i = PyFloat_AsDouble(imag);
935 Py_DECREF(imag);
936 if (i == -1. && PyErr_Occurred())
937 return nullptr;
938
939 return PyComplex_FromDoubles(r, i);
940}
941
942static PyObject* ComplexRepr(PyObject* self) {
943 PyObject* real = PyObject_CallMethodObjArgs(self, PyStrings::gCppReal, nullptr);
944 if (!real) return nullptr;
945 double r = PyFloat_AsDouble(real);
946 Py_DECREF(real);
947 if (r == -1. && PyErr_Occurred())
948 return nullptr;
949
950 PyObject* imag = PyObject_CallMethodObjArgs(self, PyStrings::gCppImag, nullptr);
951 if (!imag) return nullptr;
952 double i = PyFloat_AsDouble(imag);
953 Py_DECREF(imag);
954 if (i == -1. && PyErr_Occurred())
955 return nullptr;
956
957 std::ostringstream s;
958 s << '(' << r << '+' << i << "j)";
959 return CPyCppyy_PyText_FromString(s.str().c_str());
960}
961
962static PyObject* ComplexDRealGet(CPPInstance* self, void*)
963{
964 return PyFloat_FromDouble(((std::complex<double>*)self->GetObject())->real());
965}
966
967static int ComplexDRealSet(CPPInstance* self, PyObject* value, void*)
968{
969 double d = PyFloat_AsDouble(value);
970 if (d == -1.0 && PyErr_Occurred())
971 return -1;
972 ((std::complex<double>*)self->GetObject())->real(d);
973 return 0;
974}
975
976PyGetSetDef ComplexDReal{(char*)"real", (getter)ComplexDRealGet, (setter)ComplexDRealSet, nullptr, nullptr};
977
978
979static PyObject* ComplexDImagGet(CPPInstance* self, void*)
980{
981 return PyFloat_FromDouble(((std::complex<double>*)self->GetObject())->imag());
982}
983
984static int ComplexDImagSet(CPPInstance* self, PyObject* value, void*)
985{
986 double d = PyFloat_AsDouble(value);
987 if (d == -1.0 && PyErr_Occurred())
988 return -1;
989 ((std::complex<double>*)self->GetObject())->imag(d);
990 return 0;
991}
992
993PyGetSetDef ComplexDImag{(char*)"imag", (getter)ComplexDImagGet, (setter)ComplexDImagSet, nullptr, nullptr};
994
995static PyObject* ComplexDComplex(CPPInstance* self)
996{
997 double r = ((std::complex<double>*)self->GetObject())->real();
998 double i = ((std::complex<double>*)self->GetObject())->imag();
999 return PyComplex_FromDoubles(r, i);
1000}
1001
1002
1003} // unnamed namespace
1004
1005
1006//- public functions ---------------------------------------------------------
1007namespace CPyCppyy {
1008 std::set<std::string> gIteratorTypes;
1009}
1010
1011bool CPyCppyy::Pythonize(PyObject* pyclass, const std::string& name)
1012{
1013// Add pre-defined pythonizations (for STL and ROOT) to classes based on their
1014// signature and/or class name.
1015 if (!pyclass)
1016 return false;
1017
1018 CPPScope* klass = (CPPScope*)pyclass;
1019
1020//- method name based pythonization ------------------------------------------
1021
1022// for smart pointer style classes that are otherwise not known as such; would
1023// prefer operator-> as that returns a pointer (which is simpler since it never
1024// has to deal with ref-assignment), but operator* plays better with STL iters
1025// and algorithms
1026 if (HasAttrDirect(pyclass, PyStrings::gDeref) && !Cppyy::IsSmartPtr(klass->fCppType))
1027 Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)DeRefGetAttr, METH_O);
1028 else if (HasAttrDirect(pyclass, PyStrings::gFollow) && !Cppyy::IsSmartPtr(klass->fCppType))
1029 Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)FollowGetAttr, METH_O);
1030
1031// for STL containers, and user classes modeled after them
1032 if (HasAttrDirect(pyclass, PyStrings::gSize))
1033 Utility::AddToClass(pyclass, "__len__", "size");
1034
1035 if (!IsTemplatedSTLClass(name, "vector") && // vector is dealt with below
1036 !((PyTypeObject*)pyclass)->tp_iter) {
1037 if (HasAttrDirect(pyclass, PyStrings::gBegin) && HasAttrDirect(pyclass, PyStrings::gEnd)) {
1038 // obtain the name of the return type
1039 const auto& v = Cppyy::GetMethodIndicesFromName(klass->fCppType, "begin");
1040 if (!v.empty()) {
1041 // check return type; if not explicitly an iterator, add it to the "known" return
1042 // types to add the "next" method on use
1044 const std::string& resname = Cppyy::GetMethodResultType(meth);
1045 if (Cppyy::GetScope(resname)) {
1046 if (resname.find("iterator") == std::string::npos)
1047 gIteratorTypes.insert(resname);
1048
1049 // install iterator protocol a la STL
1050 ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)StlSequenceIter;
1051 Utility::AddToClass(pyclass, "__iter__", (PyCFunction)StlSequenceIter, METH_NOARGS);
1052 }
1053 }
1054 }
1055 if (!((PyTypeObject*)pyclass)->tp_iter && // no iterator resolved
1056 HasAttrDirect(pyclass, PyStrings::gGetItem) && HasAttrDirect(pyclass, PyStrings::gLen)) {
1057 // Python will iterate over __getitem__ using integers, but C++ operator[] will never raise
1058 // a StopIteration. A checked getitem (raising IndexError if beyond size()) works in some
1059 // cases but would mess up if operator[] is meant to implement an associative container. So,
1060 // this has to be implemented as an interator protocol.
1061 ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)index_iter;
1062 Utility::AddToClass(pyclass, "__iter__", (PyCFunction)index_iter, METH_NOARGS);
1063 }
1064 }
1065
1066// operator==/!= are used in op_richcompare of CPPInstance, which subsequently allows
1067// comparisons to None; if no operator is available, a hook is installed for lazy
1068// lookups in the global and/or class namespace
1069 if (HasAttrDirect(pyclass, PyStrings::gEq, true)) {
1070 PyObject* cppol = PyObject_GetAttr(pyclass, PyStrings::gEq);
1071 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators();
1072 klass->fOperators->fEq = cppol;
1073 // re-insert the forwarding __eq__ from the CPPInstance in case there was a Python-side
1074 // override in the base class
1075 static PyObject* top_eq = nullptr;
1076 if (!top_eq) {
1077 PyObject* top_cls = PyObject_GetAttrString(gThisModule, "CPPInstance");
1078 top_eq = PyObject_GetAttr(top_cls, PyStrings::gEq);
1079 Py_DECREF(top_eq); // make it borrowed
1080 Py_DECREF(top_cls);
1081 }
1082 PyObject_SetAttr(pyclass, PyStrings::gEq, top_eq);
1083 }
1084
1085 if (HasAttrDirect(pyclass, PyStrings::gNe, true)) {
1086 PyObject* cppol = PyObject_GetAttr(pyclass, PyStrings::gNe);
1087 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators();
1088 klass->fOperators->fNe = cppol;
1089 // re-insert the forwarding __ne__ (same reason as above for __eq__)
1090 static PyObject* top_ne = nullptr;
1091 if (!top_ne) {
1092 PyObject* top_cls = PyObject_GetAttrString(gThisModule, "CPPInstance");
1093 top_ne = PyObject_GetAttr(top_cls, PyStrings::gNe);
1094 Py_DECREF(top_ne); // make it borrowed
1095 Py_DECREF(top_cls);
1096 }
1097 PyObject_SetAttr(pyclass, PyStrings::gNe, top_ne);
1098 }
1099
1100
1101//- class name based pythonization -------------------------------------------
1102
1103 if (IsTemplatedSTLClass(name, "vector")) {
1104
1105 // std::vector<bool> is a special case in C++
1106 if (!sVectorBoolTypeID) sVectorBoolTypeID = (Cppyy::TCppType_t)Cppyy::GetScope("std::vector<bool>");
1107 if (klass->fCppType == sVectorBoolTypeID) {
1108 Utility::AddToClass(pyclass, "__getitem__", (PyCFunction)VectorBoolGetItem, METH_O);
1109 Utility::AddToClass(pyclass, "__setitem__", (PyCFunction)VectorBoolSetItem);
1110 } else {
1111 // constructor that takes python collections
1112 Utility::AddToClass(pyclass, "__real_init", "__init__");
1113 Utility::AddToClass(pyclass, "__init__", (PyCFunction)VectorInit, METH_VARARGS | METH_KEYWORDS);
1114
1115 // data with size
1116 Utility::AddToClass(pyclass, "__real_data", "data");
1117 Utility::AddToClass(pyclass, "data", (PyCFunction)VectorData);
1118
1119 // checked getitem
1120 if (HasAttrDirect(pyclass, PyStrings::gLen)) {
1121 Utility::AddToClass(pyclass, "_getitem__unchecked", "__getitem__");
1122 Utility::AddToClass(pyclass, "__getitem__", (PyCFunction)VectorGetItem, METH_O);
1123 }
1124
1125 // vector-optimized iterator protocol
1126 ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)vector_iter;
1127
1128 // helpers for iteration
1129 const std::string& vtype = Cppyy::ResolveName(name+"::value_type");
1130 size_t typesz = Cppyy::SizeOf(vtype);
1131 if (typesz) {
1132 PyObject* pyvalue_size = PyLong_FromSsize_t(typesz);
1133 PyObject_SetAttrString(pyclass, "value_size", pyvalue_size);
1134 Py_DECREF(pyvalue_size);
1135
1136 PyObject* pyvalue_type = CPyCppyy_PyText_FromString(vtype.c_str());
1137 PyObject_SetAttrString(pyclass, "value_type", pyvalue_type);
1138 Py_DECREF(pyvalue_type);
1139 }
1140 }
1141 }
1142
1143 else if (IsTemplatedSTLClass(name, "map")) {
1144 Utility::AddToClass(pyclass, "__contains__", (PyCFunction)MapContains, METH_O);
1145 }
1146
1147 else if (IsTemplatedSTLClass(name, "pair")) {
1148 Utility::AddToClass(pyclass, "__getitem__", (PyCFunction)PairUnpack, METH_O);
1149 Utility::AddToClass(pyclass, "__len__", (PyCFunction)ReturnTwo, METH_NOARGS);
1150 }
1151
1152 if (IsTemplatedSTLClass(name, "shared_ptr")) {
1153 Utility::AddToClass(pyclass, "__real_init", "__init__");
1154 Utility::AddToClass(pyclass, "__init__", (PyCFunction)SharedPtrInit, METH_VARARGS | METH_KEYWORDS);
1155 }
1156
1157 else if (name.find("iterator") != std::string::npos || gIteratorTypes.find(name) != gIteratorTypes.end()) {
1158 ((PyTypeObject*)pyclass)->tp_iternext = (iternextfunc)StlIterNext;
1159 Utility::AddToClass(pyclass, CPPYY__next__, (PyCFunction)StlIterNext, METH_NOARGS);
1160 ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)PyObject_SelfIter;
1161 Utility::AddToClass(pyclass, "__iter__", (PyCFunction)PyObject_SelfIter, METH_NOARGS);
1162 }
1163
1164 else if (name == "string" || name == "std::string") { // TODO: ask backend as well
1165 Utility::AddToClass(pyclass, "__repr__", (PyCFunction)StlStringRepr, METH_NOARGS);
1166 Utility::AddToClass(pyclass, "__str__", (PyCFunction)StlStringGetData, METH_NOARGS);
1167 Utility::AddToClass(pyclass, "__cmp__", (PyCFunction)StlStringCompare, METH_O);
1168 Utility::AddToClass(pyclass, "__eq__", (PyCFunction)StlStringIsEqual, METH_O);
1169 Utility::AddToClass(pyclass, "__ne__", (PyCFunction)StlStringIsNotEqual, METH_O);
1170 ((PyTypeObject*)pyclass)->tp_hash = (hashfunc)StlStringHash;
1171 }
1172
1173 else if (name == "basic_string<wchar_t,char_traits<wchar_t>,allocator<wchar_t> >" || \
1174 name == "std::basic_string<wchar_t,char_traits<wchar_t>,allocator<wchar_t> >") {
1175 Utility::AddToClass(pyclass, "__repr__", (PyCFunction)StlWStringRepr, METH_NOARGS);
1176 Utility::AddToClass(pyclass, "__str__", (PyCFunction)StlWStringGetData, METH_NOARGS);
1177 Utility::AddToClass(pyclass, "__cmp__", (PyCFunction)StlWStringCompare, METH_O);
1178 Utility::AddToClass(pyclass, "__eq__", (PyCFunction)StlWStringIsEqual, METH_O);
1179 Utility::AddToClass(pyclass, "__ne__", (PyCFunction)StlWStringIsNotEqual, METH_O);
1180 }
1181
1182 else if (name == "complex<double>" || name == "std::complex<double>") {
1183 Utility::AddToClass(pyclass, "__cpp_real", "real");
1184 PyObject_SetAttrString(pyclass, "real", PyDescr_NewGetSet((PyTypeObject*)pyclass, &ComplexDReal));
1185 Utility::AddToClass(pyclass, "__cpp_imag", "imag");
1186 PyObject_SetAttrString(pyclass, "imag", PyDescr_NewGetSet((PyTypeObject*)pyclass, &ComplexDImag));
1187 Utility::AddToClass(pyclass, "__complex__", (PyCFunction)ComplexDComplex, METH_NOARGS);
1188 Utility::AddToClass(pyclass, "__repr__", (PyCFunction)ComplexRepr, METH_NOARGS);
1189 }
1190
1191 else if (IsTemplatedSTLClass(name, "complex")) {
1192 Utility::AddToClass(pyclass, "__cpp_real", "real");
1193 PyObject_SetAttrString(pyclass, "real", PyDescr_NewGetSet((PyTypeObject*)pyclass, &realComplex));
1194 Utility::AddToClass(pyclass, "__cpp_imag", "imag");
1195 PyObject_SetAttrString(pyclass, "imag", PyDescr_NewGetSet((PyTypeObject*)pyclass, &imagComplex));
1196 Utility::AddToClass(pyclass, "__complex__", (PyCFunction)ComplexComplex, METH_NOARGS);
1197 Utility::AddToClass(pyclass, "__repr__", (PyCFunction)ComplexRepr, METH_NOARGS);
1198 }
1199
1200// direct user access; there are two calls here:
1201// - explicit pythonization: won't fall through to the base classes and is preferred if present
1202// - normal pythonization: only called if explicit isn't present, falls through to base classes
1203 bool bUserOk = true; PyObject* res = nullptr;
1205 if (HasAttrDirect(pyclass, PyStrings::gExPythonize)) {
1206 res = PyObject_CallMethodObjArgs(pyclass, PyStrings::gExPythonize, pyclass, pyname, nullptr);
1207 bUserOk = (bool)res;
1208 } else {
1209 PyObject* func = PyObject_GetAttr(pyclass, PyStrings::gPythonize);
1210 if (func) {
1211 res = PyObject_CallFunctionObjArgs(func, pyclass, pyname, nullptr);
1212 Py_DECREF(func);
1213 bUserOk = (bool)res;
1214 } else
1215 PyErr_Clear();
1216 }
1217 if (!bUserOk) {
1218 Py_DECREF(pyname);
1219 return false;
1220 } else {
1221 Py_XDECREF(res);
1222 // pyname handed to tuple below
1223 }
1224
1225// call registered pythonizors, if any
1226 PyObject* args = PyTuple_New(2);
1227 Py_INCREF(pyclass);
1228 PyTuple_SET_ITEM(args, 0, pyclass);
1229
1230 std::string outer_scope = TypeManip::extract_namespace(name);
1231
1232 bool pstatus = true;
1233 auto p = outer_scope.empty() ? gPythonizations.end() : gPythonizations.find(outer_scope);
1234 if (p == gPythonizations.end()) {
1235 p = gPythonizations.find("");
1236 PyTuple_SET_ITEM(args, 1, pyname);
1237 } else {
1238 PyTuple_SET_ITEM(args, 1, CPyCppyy_PyText_FromString(
1239 name.substr(outer_scope.size()+2, std::string::npos).c_str()));
1240 Py_DECREF(pyname);
1241 }
1242
1243 if (p != gPythonizations.end()) {
1244 for (auto pythonizor : p->second) {
1245 PyObject* result = PyObject_CallObject(pythonizor, args);
1246 if (!result) {
1247 // TODO: detail error handling for the pythonizors
1248 pstatus = false;
1249 break;
1250 }
1251 Py_DECREF(result);
1252 }
1253 }
1254
1255 Py_DECREF(args);
1256
1257// phew! all done ...
1258 return pstatus;
1259}
#define Py_TYPE(ob)
Definition CPyCppyy.h:217
#define Py_RETURN_TRUE
Definition CPyCppyy.h:293
#define Py_RETURN_FALSE
Definition CPyCppyy.h:297
#define PyInt_FromSsize_t
Definition CPyCppyy.h:238
#define CPyCppyy_PyText_FromStringAndSize
Definition CPyCppyy.h:106
#define PyBytes_Check
Definition CPyCppyy.h:83
#define PyInt_AsSsize_t
Definition CPyCppyy.h:237
#define CPyCppyy_PySliceCast
Definition CPyCppyy.h:210
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:97
long Py_hash_t
Definition CPyCppyy.h:135
#define Py_RETURN_NONE
Definition CPyCppyy.h:289
#define CPyCppyy_PyText_Type
Definition CPyCppyy.h:115
#define CPPYY__next__
Definition CPyCppyy.h:133
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:102
#define CPyCppyy_PyText_Check
Definition CPyCppyy.h:95
PyFloat_FromDouble
PyFloat_AsDouble
PyInt_FromLong
ROOT::R::TRInterface & r
Definition Object.C:4
_object PyObject
#define CPPYY_IMPL_STRING_PYTHONIZATION_CMP(type, name)
#define COMPLEX_METH_GETSET(name, cppname)
#define PyObject_LengthHint
PyObject * CallPyObjMethod(PyObject *obj, const char *meth)
Set of helper functions that are invoked from the C++ implementation of pythonizations.
#define d(i)
Definition RSha256.hxx:102
#define c(i)
Definition RSha256.hxx:101
#define h(i)
Definition RSha256.hxx:106
static PyObject * PyStyleIndex(PyObject *self, PyObject *index)
char name[80]
Definition TGX11.cxx:110
#define pyname
Cppyy::TCppType_t ObjectIsA(bool check_smart=true) const
Utility::PyOperators * fOperators
Definition CPPScope.h:56
Cppyy::TCppType_t fCppType
Definition CPPScope.h:50
PyObject * gCTypesType
Definition PyStrings.cxx:29
PyObject * gExPythonize
Definition PyStrings.cxx:58
PyObject * gGetItem
Definition PyStrings.cxx:18
PyObject * gCppReal
Definition PyStrings.cxx:50
PyObject * gPythonize
Definition PyStrings.cxx:59
PyObject * gTypeCode
Definition PyStrings.cxx:28
PyObject * gPostInc
Definition PyStrings.cxx:13
PyObject * gCppImag
Definition PyStrings.cxx:51
PyObject * gGetNoCheck
Definition PyStrings.cxx:19
std::string extract_namespace(const std::string &name)
Py_ssize_t GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, bool check=true)
Definition Utility.cxx:614
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
Definition Utility.cxx:169
Set of helper functions that are invoked from the pythonizors, on the Python side.
PyTypeObject VectorIter_Type
bool Pythonize(PyObject *pyclass, const std::string &name)
bool CPPOverload_Check(T *object)
Definition CPPOverload.h:79
std::map< std::string, std::vector< PyObject * > > gPythonizations
bool LowLevelView_Check(T *object)
bool CPPInstance_Check(T *object)
PyTypeObject IndexIter_Type
R__EXTERN PyObject * gThisModule
Definition TPython.cxx:100
std::set< std::string > gIteratorTypes
CPYCPPYY_EXTERN Converter * CreateConverter(const std::string &name, Py_ssize_t *dims=nullptr)
RPY_EXPORTED std::vector< TCppIndex_t > GetMethodIndicesFromName(TCppScope_t scope, const std::string &name)
intptr_t TCppMethod_t
Definition cpp_cppyy.h:22
TCppScope_t TCppType_t
Definition cpp_cppyy.h:19
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
RPY_EXPORTED size_t SizeOf(TCppType_t klass)
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED bool IsSmartPtr(TCppType_t type)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED std::string GetMethodResultType(TCppMethod_t)
PyObject_HEAD PyObject * ii_container
Cppyy::TCppType_t vi_klass
CPyCppyy::Converter * vi_converter