Skip to content

Commit 9113778

Browse files
committed
Sync Pythonize
1 parent b784974 commit 9113778

File tree

1 file changed

+47
-13
lines changed

1 file changed

+47
-13
lines changed

src/Pythonize.cxx

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,19 @@ PyObject* FollowGetAttr(PyObject* self, PyObject* name)
202202
return result;
203203
}
204204

205+
//- pointer checking bool converter -------------------------------------------
206+
PyObject* NullCheckBool(PyObject* self)
207+
{
208+
if (!CPPInstance_Check(self)) {
209+
PyErr_SetString(PyExc_TypeError, "C++ object proxy expected");
210+
return nullptr;
211+
}
212+
213+
if (!((CPPInstance*)self)->GetObject())
214+
Py_RETURN_FALSE;
215+
216+
return PyObject_CallMethodNoArgs(self, PyStrings::gCppBool);
217+
}
205218

206219
//- vector behavior as primitives ----------------------------------------------
207220
#if PY_VERSION_HEX < 0x03040000
@@ -345,7 +358,7 @@ static bool FillVector(PyObject* vecin, PyObject* args, ItemGetter* getter)
345358
eb_args = PyTuple_New(1);
346359
PyTuple_SET_ITEM(eb_args, 0, item);
347360
} else if (PyTuple_CheckExact(item)) {
348-
eb_args = item;
361+
eb_args = item;
349362
} else if (PyList_CheckExact(item)) {
350363
Py_ssize_t isz = PyList_GET_SIZE(item);
351364
eb_args = PyTuple_New(isz);
@@ -492,7 +505,8 @@ PyObject* VectorInit(PyObject* self, PyObject* args, PyObject* /* kwds */)
492505
PyObject* VectorData(PyObject* self, PyObject*)
493506
{
494507
PyObject* pydata = CallPyObjMethod(self, "__real_data");
495-
if (!LowLevelView_Check(pydata)) return pydata;
508+
if (!LowLevelView_Check(pydata) && !CPPInstance_Check(pydata))
509+
return pydata;
496510

497511
PyObject* pylen = PyObject_CallMethodNoArgs(self, PyStrings::gSize);
498512
if (!pylen) {
@@ -503,12 +517,12 @@ PyObject* VectorData(PyObject* self, PyObject*)
503517
long clen = PyInt_AsLong(pylen);
504518
Py_DECREF(pylen);
505519

506-
// TODO: should be a LowLevelView helper
507-
Py_buffer& bi = ((LowLevelView*)pydata)->fBufInfo;
508-
bi.len = clen * bi.itemsize;
509-
if (bi.ndim == 1 && bi.shape)
510-
bi.shape[0] = clen;
520+
if (CPPInstance_Check(pydata)) {
521+
((CPPInstance*)pydata)->CastToArray(clen);
522+
return pydata;
523+
}
511524

525+
((LowLevelView*)pydata)->resize((size_t)clen);
512526
return pydata;
513527
}
514528

@@ -549,7 +563,18 @@ static PyObject* vector_iter(PyObject* v) {
549563

550564
if (PyLong_Check(pyvalue_type)) {
551565
Cppyy::TCppType_t value_type = PyLong_AsVoidPtr(pyvalue_type);
566+
value_type = Cppyy::ResolveType(value_type);
552567
vi->vi_klass = Cppyy::GetScopeFromType(value_type);
568+
if (!vi->vi_klass) {
569+
// look for a special case of pointer to a class type (which is a builtin, but it
570+
// is more useful to treat it polymorphically by allowing auto-downcasts)
571+
const std::string& clean_type = TypeManip::clean_type(value_type, false, false);
572+
Cppyy::TCppScope_t c = Cppyy::GetScope(clean_type);
573+
if (c && TypeManip::compound(value_type) == "*") {
574+
vi->vi_klass = c;
575+
vi->vi_flags = vectoriterobject::kIsPolymorphic;
576+
}
577+
}
553578
if (vi->vi_klass) {
554579
vi->vi_converter = nullptr;
555580
if (!vi->vi_flags) {
@@ -810,7 +835,7 @@ static PyObject* MapFromPairs(PyObject* self, PyObject* pairs)
810835
PyObject* MapInit(PyObject* self, PyObject* args, PyObject* /* kwds */)
811836
{
812837
// Specialized map constructor to allow construction from mapping containers and
813-
// from tuples of pairs ("intializer_list style").
838+
// from tuples of pairs ("initializer_list style").
814839

815840
// PyMapping_Check is not very discriminatory, as it basically only checks for the
816841
// existence of __getitem__, hence the most common cases of tuple and list are
@@ -1012,7 +1037,7 @@ PyObject* CheckedGetItem(PyObject* self, PyObject* obj)
10121037
{
10131038
// Implement a generic python __getitem__ for STL-like classes that are missing the
10141039
// reflection info for their iterators. This is then used for iteration by means of
1015-
// consecutive indeces, it such index is of integer type.
1040+
// consecutive indices, it such index is of integer type.
10161041
Py_ssize_t size = PySequence_Size(self);
10171042
Py_ssize_t idx = PyInt_AsSsize_t(obj);
10181043
if ((size == (Py_ssize_t)-1 || idx == (Py_ssize_t)-1) && PyErr_Occurred()) {
@@ -1236,7 +1261,7 @@ PyObject* STLStringContains(CPPInstance* self, PyObject* pyobj)
12361261
Py_RETURN_FALSE;
12371262
}
12381263

1239-
PyObject* STLStringReplace(CPPInstance* self, PyObject* args, PyObject* kwds)
1264+
PyObject* STLStringReplace(CPPInstance* self, PyObject* args, PyObject* /*kwds*/)
12401265
{
12411266
std::string* obj = GetSTLString(self);
12421267
if (!obj)
@@ -1267,7 +1292,7 @@ PyObject* STLStringReplace(CPPInstance* self, PyObject* args, PyObject* kwds)
12671292
}
12681293

12691294
#define CPYCPPYY_STRING_FINDMETHOD(name, cppname, pyname) \
1270-
PyObject* STLString##name(CPPInstance* self, PyObject* args, PyObject* kwds) \
1295+
PyObject* STLString##name(CPPInstance* self, PyObject* args, PyObject* /*kwds*/) \
12711296
{ \
12721297
std::string* obj = GetSTLString(self); \
12731298
if (!obj) \
@@ -1387,7 +1412,6 @@ PyObject* StringViewInit(PyObject* self, PyObject* args, PyObject* /* kwds */)
13871412
}
13881413

13891414

1390-
13911415
//- STL iterator behavior ----------------------------------------------------
13921416
PyObject* STLIterNext(PyObject* self)
13931417
{
@@ -1590,6 +1614,16 @@ bool CPyCppyy::Pythonize(PyObject* pyclass, Cppyy::TCppScope_t scope)
15901614
else if (HasAttrDirect(pyclass, PyStrings::gFollow) && !Cppyy::IsSmartPtr(klass->fCppType))
15911615
Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)FollowGetAttr, METH_O);
15921616

1617+
// for pre-check of nullptr for boolean types
1618+
if (HasAttrDirect(pyclass, PyStrings::gCppBool)) {
1619+
#if PY_VERSION_HEX >= 0x03000000
1620+
const char* pybool_name = "__bool__";
1621+
#else
1622+
const char* pybool_name = "__nonzero__";
1623+
#endif
1624+
Utility::AddToClass(pyclass, pybool_name, (PyCFunction)NullCheckBool, METH_NOARGS);
1625+
}
1626+
15931627
// for STL containers, and user classes modeled after them
15941628
if (HasAttrDirect(pyclass, PyStrings::gSize))
15951629
Utility::AddToClass(pyclass, "__len__", "size");
@@ -1631,7 +1665,7 @@ bool CPyCppyy::Pythonize(PyObject* pyclass, Cppyy::TCppScope_t scope)
16311665
// Python will iterate over __getitem__ using integers, but C++ operator[] will never raise
16321666
// a StopIteration. A checked getitem (raising IndexError if beyond size()) works in some
16331667
// cases but would mess up if operator[] is meant to implement an associative container. So,
1634-
// this has to be implemented as an interator protocol.
1668+
// this has to be implemented as an iterator protocol.
16351669
((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)index_iter;
16361670
Utility::AddToClass(pyclass, "__iter__", (PyCFunction)index_iter, METH_NOARGS);
16371671
}

0 commit comments

Comments
 (0)