diff --git a/caller.h b/caller.h index 00cf65b7..43da3d91 100644 --- a/caller.h +++ b/caller.h @@ -6,7 +6,7 @@ // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. // -// This file generated for 10-argument member functions and 11-argument free +// This file generated for 5-argument member functions and 6-argument free // functions by gen_caller.python #ifndef CALLER_DWA05090_H_ @@ -17,6 +17,7 @@ # include # include "signatures.h" # include "none.h" +# include "objects.h" namespace python { @@ -103,126 +104,6 @@ struct caller from_python(a5, type()))); } - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()))); - } - - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()))); - } - - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()))); - } - - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()))); - } - - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()), - from_python(a10, type()))); - } - template static PyObject* call(R (T::*pmf)() const, PyObject* args, PyObject* /* keywords */ ) { @@ -303,126 +184,6 @@ struct caller from_python(a5, type()))); } - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()))); - } - - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()))); - } - - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()))); - } - - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()))); - } - - template - static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) - return 0; - T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()), - from_python(a10, type()))); - } - // Free functions static PyObject* call(R (*f)(), PyObject* args, PyObject* /* keywords */ ) { if (!PyArg_ParseTuple(args, const_cast(""))) @@ -508,126 +269,6 @@ struct caller from_python(a6, type()))); } - template - static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7)) - return 0; - return to_python(f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()))); - } - - template - static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7, A8), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) - return 0; - return to_python(f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()))); - } - - template - static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) - return 0; - return to_python(f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()))); - } - - template - static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) - return 0; - return to_python(f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()), - from_python(a10, type()))); - } - - template - static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - PyObject* a11; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11)) - return 0; - return to_python(f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()), - from_python(a10, type()), - from_python(a11, type()))); - } - }; template <> @@ -718,131 +359,6 @@ struct caller return detail::none(); } - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type())); - return detail::none(); - } - - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type())); - return detail::none(); - } - - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type())); - return detail::none(); - } - - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type())); - return detail::none(); - } - - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()), - from_python(a10, type())); - return detail::none(); - } - template static PyObject* call(void (T::*pmf)() const, PyObject* args, PyObject* /* keywords */ ) { @@ -929,131 +445,6 @@ struct caller return detail::none(); } - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type())); - return detail::none(); - } - - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type())); - return detail::none(); - } - - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type())); - return detail::none(); - } - - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type())); - return detail::none(); - } - - template - static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) const, PyObject* args, PyObject* /* keywords */ ) { - PyObject* self; - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) - return 0; - T& target = from_python(self, type()); - (target.*pmf)(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()), - from_python(a10, type())); - return detail::none(); - } - // Free functions static PyObject* call(void (*f)(), PyObject* args, PyObject* /* keywords */ ) { @@ -1147,133 +538,270 @@ struct caller return detail::none(); } - template - static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7)) - return 0; - f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type())); - return detail::none(); - } - - template - static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7, A8), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) - return 0; - f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type())); - return detail::none(); - } - - template - static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) - return 0; - f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type())); - return detail::none(); - } - - template - static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) - return 0; - f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()), - from_python(a10, type())); - return detail::none(); - } - - template - static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11), PyObject* args, PyObject* /* keywords */ ) { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - PyObject* a11; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11)) - return 0; - f(from_python(a1, type()), - from_python(a2, type()), - from_python(a3, type()), - from_python(a4, type()), - from_python(a5, type()), - from_python(a6, type()), - from_python(a7, type()), - from_python(a8, type()), - from_python(a9, type()), - from_python(a10, type()), - from_python(a11, type())); - return detail::none(); - } - }; +namespace detail +{ + +// create signature tuples +inline +PyObject* function_signature() { + tuple result(0); + + return result.reference().release(); } -#endif +template +PyObject* function_signature(type) { + static const bool is_plain_A1 = BOOST_PYTHON_IS_PLAIN(A1); + tuple result(1); + result.set_item(0, python_type_name_selector::get(type())); + + return result.reference().release(); +} + +template +PyObject* function_signature(type, type) { + static const bool is_plain_A1 = BOOST_PYTHON_IS_PLAIN(A1); + static const bool is_plain_A2 = BOOST_PYTHON_IS_PLAIN(A2); + tuple result(2); + result.set_item(0, python_type_name_selector::get(type())); + result.set_item(1, python_type_name_selector::get(type())); + + return result.reference().release(); +} + +template +PyObject* function_signature(type, type, type) { + static const bool is_plain_A1 = BOOST_PYTHON_IS_PLAIN(A1); + static const bool is_plain_A2 = BOOST_PYTHON_IS_PLAIN(A2); + static const bool is_plain_A3 = BOOST_PYTHON_IS_PLAIN(A3); + tuple result(3); + result.set_item(0, python_type_name_selector::get(type())); + result.set_item(1, python_type_name_selector::get(type())); + result.set_item(2, python_type_name_selector::get(type())); + + return result.reference().release(); +} + +template +PyObject* function_signature(type, type, type, type) { + static const bool is_plain_A1 = BOOST_PYTHON_IS_PLAIN(A1); + static const bool is_plain_A2 = BOOST_PYTHON_IS_PLAIN(A2); + static const bool is_plain_A3 = BOOST_PYTHON_IS_PLAIN(A3); + static const bool is_plain_A4 = BOOST_PYTHON_IS_PLAIN(A4); + tuple result(4); + result.set_item(0, python_type_name_selector::get(type())); + result.set_item(1, python_type_name_selector::get(type())); + result.set_item(2, python_type_name_selector::get(type())); + result.set_item(3, python_type_name_selector::get(type())); + + return result.reference().release(); +} + +template +PyObject* function_signature(type, type, type, type, type) { + static const bool is_plain_A1 = BOOST_PYTHON_IS_PLAIN(A1); + static const bool is_plain_A2 = BOOST_PYTHON_IS_PLAIN(A2); + static const bool is_plain_A3 = BOOST_PYTHON_IS_PLAIN(A3); + static const bool is_plain_A4 = BOOST_PYTHON_IS_PLAIN(A4); + static const bool is_plain_A5 = BOOST_PYTHON_IS_PLAIN(A5); + tuple result(5); + result.set_item(0, python_type_name_selector::get(type())); + result.set_item(1, python_type_name_selector::get(type())); + result.set_item(2, python_type_name_selector::get(type())); + result.set_item(3, python_type_name_selector::get(type())); + result.set_item(4, python_type_name_selector::get(type())); + + return result.reference().release(); +} + +template +PyObject* function_signature(type, type, type, type, type, type) { + static const bool is_plain_A1 = BOOST_PYTHON_IS_PLAIN(A1); + static const bool is_plain_A2 = BOOST_PYTHON_IS_PLAIN(A2); + static const bool is_plain_A3 = BOOST_PYTHON_IS_PLAIN(A3); + static const bool is_plain_A4 = BOOST_PYTHON_IS_PLAIN(A4); + static const bool is_plain_A5 = BOOST_PYTHON_IS_PLAIN(A5); + static const bool is_plain_A6 = BOOST_PYTHON_IS_PLAIN(A6); + tuple result(6); + result.set_item(0, python_type_name_selector::get(type())); + result.set_item(1, python_type_name_selector::get(type())); + result.set_item(2, python_type_name_selector::get(type())); + result.set_item(3, python_type_name_selector::get(type())); + result.set_item(4, python_type_name_selector::get(type())); + result.set_item(5, python_type_name_selector::get(type())); + + return result.reference().release(); +} + + +// member functions +template +inline PyObject* function_signature(R (T::*pmf)()) { + return function_signature( + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1)) { + return function_signature( + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1, A2)) { + return function_signature( + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1, A2, A3)) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1, A2, A3, A4)) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1, A2, A3, A4, A5)) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type(), + python::type(), + python::type()); +} + + +// const member functions +template +inline PyObject* function_signature(R (T::*pmf)() const) { + return function_signature( + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1) const) { + return function_signature( + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1, A2) const) { + return function_signature( + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1, A2, A3) const) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1, A2, A3, A4) const) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (T::*pmf)(A1, A2, A3, A4, A5) const) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type(), + python::type(), + python::type()); +} + + +// free functions +template +inline PyObject* function_signature(R (*f)()) { + return function_signature(); +} + +template +inline PyObject* function_signature(R (*f)(A1)) { + return function_signature( + python::type()); +} + +template +inline PyObject* function_signature(R (*f)(A1, A2)) { + return function_signature( + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (*f)(A1, A2, A3)) { + return function_signature( + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (*f)(A1, A2, A3, A4)) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (*f)(A1, A2, A3, A4, A5)) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type(), + python::type()); +} + +template +inline PyObject* function_signature(R (*f)(A1, A2, A3, A4, A5, A6)) { + return function_signature( + python::type(), + python::type(), + python::type(), + python::type(), + python::type(), + python::type()); +} + +} // namespace detail + +} // namespace python + +#endif // CALLER_DWA05090_H_ + diff --git a/extclass.cpp b/extclass.cpp index 94d9bf68..68941c0e 100644 --- a/extclass.cpp +++ b/extclass.cpp @@ -329,9 +329,9 @@ PyObject* read_only_setattr_function::do_call(PyObject* /*args*/, PyObject* /*ke return 0; } -const char* read_only_setattr_function::description() const +PyObject* read_only_setattr_function::description() const { - return "uncallable"; + return BOOST_PYTHON_CONVERSION::to_python("uncallable"); } extension_class_base::extension_class_base(const char* name) @@ -469,6 +469,19 @@ operator_dispatcher::create(const ref& object, const ref& self) return result; } +namespace { + +void set_attribute_error(const char* oper, tuple args) +{ + PyErr_Clear(); + string message(oper); + message += argument_tuple_as_string(args); + message += " undefined."; + PyErr_SetObject(PyExc_TypeError, message.get()); +} + +} // anonymous namespace + extern "C" { @@ -498,7 +511,7 @@ int operator_dispatcher_coerce(PyObject** l, PyObject** r) #define PY_DEFINE_OPERATOR(id, symbol) \ - PyObject* operator_dispatcher_call_##id(PyObject* left, PyObject* right) \ + PyObject* operator_dispatcher_call_##id(PyObject* left, PyObject* right) \ { \ /* unwrap the arguments from their OperatorDispatcher */ \ PyObject* self; \ @@ -506,17 +519,20 @@ int operator_dispatcher_coerce(PyObject** l, PyObject** r) int reverse = unwrap_args(left, right, self, other); \ if (reverse == unwrap_exception_code) \ return 0; \ + const char * oper = reverse \ + ? "__r" #id "__" \ + : "__" #id "__"; \ \ /* call the function */ \ PyObject* result = \ PyEval_CallMethod(self, \ - const_cast(reverse ? "__r" #id "__" : "__" #id "__"), \ + const_cast(oper), \ const_cast("(O)"), \ other); \ if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) \ { \ - PyErr_Clear(); \ - PyErr_SetString(PyExc_TypeError, "bad operand type(s) for " #symbol); \ + tuple args(ref(self, ref::increment_count), ref(other, ref::increment_count)); \ + set_attribute_error(oper , args); \ } \ return result; \ } @@ -562,24 +578,34 @@ PyObject* operator_dispatcher_call_pow(PyObject* left, PyObject* right, PyObject if (reverse == unwrap_exception_code) return 0; - + + const char * oper = (reverse == 0) + ? "__pow__" + : (reverse == 1) + ? "__rpow__" + : "__rrpow__"; // call the function PyObject* result = PyEval_CallMethod(self, - const_cast((reverse == 0) - ? "__pow__" - : (reverse == 1) - ? "__rpow__" - : "__rrpow__"), + const_cast(oper), const_cast("(OO)"), first, second); - if (result == 0 && - (PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError) || - PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError))) - { - PyErr_Clear(); - PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()"); - } + + if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) + { + if(m == Py_None) + { + tuple args(ref(self, ref::increment_count), ref(first, ref::increment_count)); + set_attribute_error(oper , args); + } + else + { + tuple args(ref(self, ref::increment_count), + ref(first, ref::increment_count), + ref(second, ref::increment_count)); + set_attribute_error(oper , args); + } + } return result; } @@ -592,16 +618,23 @@ int operator_dispatcher_call_cmp(PyObject* left, PyObject* right) if (reverse == unwrap_exception_code) return -1; + const char * oper = reverse + ? "__rcmp__" + : "__cmp__"; // call the function PyObject* result = PyEval_CallMethod(self, - const_cast(reverse ? "__rcmp__" : "__cmp__"), + const_cast(oper), const_cast("(O)"), other); + if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) + { + tuple args(ref(self, ref::increment_count), ref(other, ref::increment_count)); + set_attribute_error(oper , args); + } + if (result == 0) { - PyErr_Clear(); - PyErr_SetString(PyExc_TypeError, "bad operand type(s) for cmp() or <"); return -1; } else diff --git a/extclass.h b/extclass.h index 925f441b..bb59eb39 100644 --- a/extclass.h +++ b/extclass.h @@ -133,6 +133,39 @@ class class_registry static std::vector static_derived_class_info; }; +template +no_t* is_plain_aux(type >); + +template +string forward_python_type_name(python::type >) +{ + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); +} + +template +no_t* is_plain_aux(type >); + +template +string forward_python_type_name(python::type >) +{ + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); +} + +template +string python_type_name(type) +{ + if(class_registry::class_object() == 0) + { + return string("UnknownType"); + } + else + { + return class_registry::class_object()->complete_class_name(); + } +} + }} // namespace python::detail BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE @@ -314,7 +347,9 @@ class read_only_setattr_function : public function public: read_only_setattr_function(const char* name); PyObject* do_call(PyObject* args, PyObject* keywords) const; - const char* description() const; + PyObject* description() const; + string function_name() const + { return m_name; } private: string m_name; }; @@ -428,7 +463,7 @@ class extension_class template inline void def_raw(Fn fn, const char* name) { - this->add_method(new_raw_arguments_function(fn), name); + this->add_method(new_raw_arguments_function(fn, name), name); } // define member functions. In fact this works for free functions, too - @@ -438,7 +473,7 @@ class extension_class template inline void def(Fn fn, const char* name) { - this->add_method(new_wrapped_function(fn), name); + this->add_method(new_wrapped_function(fn, name), name); } // Define a virtual member function with a default implementation. @@ -447,7 +482,7 @@ class extension_class template inline void def(Fn fn, const char* name, DefaultFn default_fn) { - this->add_method(new_virtual_function(type(), fn, default_fn), name); + this->add_method(new_virtual_function(type(), fn, default_fn, name), name); } // Provide a function which implements x., reading from the given @@ -455,7 +490,7 @@ class extension_class template inline void def_getter(MemberType T::*pm, const char* name) { - this->add_getter_method(new getter_function(pm), name); + this->add_getter_method(new getter_function(pm, name), name); } // Provide a function which implements assignment to x., writing to @@ -463,7 +498,7 @@ class extension_class template inline void def_setter(MemberType T::*pm, const char* name) { - this->add_setter_method(new setter_function(pm), name); + this->add_setter_method(new setter_function(pm, name), name); } // Expose the given member (pm) of the T obj as a read-only attribute diff --git a/functions.cpp b/functions.cpp index 0cd24306..24e99502 100644 --- a/functions.cpp +++ b/functions.cpp @@ -11,13 +11,35 @@ #include "singleton.h" #include "objects.h" #include "errors.h" +#include "extclass.h" namespace python { namespace detail { -struct function::type_object : - singleton > > +string argument_tuple_as_string(tuple arguments) { - type_object() : singleton_base(&PyType_Type) {} + string result("("); + for (std::size_t i = 0; i < arguments.size(); ++i) + { + if (i != 0) + result += ", "; + if(arguments[i]->ob_type->ob_type == extension_meta_class()) + { + result += downcast(arguments[i]->ob_type).get()->complete_class_name(); + } + else + { + result += arguments[i]->ob_type->tp_name; + } + } + result += ")"; + return result; +} + +struct function::type_object : + singleton > > > +{ + type_object() : singleton_base(&PyType_Type) + {} }; @@ -56,6 +78,38 @@ function::function() { } +PyObject* function::getattr(const char * name) const +{ + if(strcmp(name, "__signatures__") == 0) + { + list signatures; + for (const function* f = this; f != 0; f = f->m_overloads.get()) + { + signatures.push_back(f->description()); + } + return signatures.reference().release(); + + } + else if(strcmp(name, "__name__") == 0) + { + return function_name().reference().release(); + + } + else if(strcmp(name, "__dict__") == 0) + { + dictionary items; + items.set_item(string("__name__"), detail::none()); + items.set_item(string("__signatures__"), detail::none()); + return items.reference().release(); + + } + else + { + PyErr_SetString(PyExc_AttributeError, name); + return 0; + } +} + PyObject* function::call(PyObject* args, PyObject* keywords) const { for (const function* f = this; f != 0; f = f->m_overloads.get()) @@ -69,6 +123,26 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const } catch(const argument_error&) { + if(m_overloads.get() == 0 && rephrase_argument_error() && + PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError)) + { + PyErr_Clear(); + string message(""); + string name(this->function_name()); + if(name.size() != 0) + { + message += "'"; + message += name; + message += "' "; + } + message += "expected argument(s) "; + message += description_as_string(); + message += ",\nbut got "; + tuple arguments(ref(args, ref::increment_count)); + message += argument_types_as_string(arguments); + message += " instead."; + PyErr_SetObject(PyExc_TypeError, message.get()); + } } } @@ -76,27 +150,52 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const return 0; PyErr_Clear(); - string message("No overloaded functions match ("); - tuple arguments(ref(args, ref::increment_count)); - for (std::size_t i = 0; i < arguments.size(); ++i) + string message("No variant of overloaded function"); + string name(this->function_name()); + + if(name.size() != 0) { - if (i != 0) - message += ", "; - message += arguments[i]->ob_type->tp_name; + message += " '"; + message += name; + message += "'"; } + message += " matches argument(s):\n"; + + tuple arguments(ref(args, ref::increment_count)); + message += argument_types_as_string(arguments); - message += "). Candidates are:\n"; + message += "\nCandidates are:\n"; for (const function* f1 = this; f1 != 0; f1 = f1->m_overloads.get()) { if (f1 != this) message += "\n"; - message += f1->description(); + message += f1->description_as_string(); } PyErr_SetObject(PyExc_TypeError, message.get()); return 0; } +string function::description_as_string() const +{ + string result("("); + tuple arguments(ref(this->description())); + for (std::size_t i = 0; i < arguments.size(); ++i) + { + if (i != 0) + result += ", "; + result += string(arguments[i]); + } + + result += ")"; + return result; +} + +string function::argument_types_as_string(tuple arguments) const +{ + return argument_tuple_as_string(arguments); +} + bound_function* bound_function::create(const ref& target, const ref& fn) { bound_function* const result = free_list; diff --git a/functions.h b/functions.h index ec982f53..13d05550 100644 --- a/functions.h +++ b/functions.h @@ -25,6 +25,8 @@ namespace python { namespace detail { // forward declaration class extension_instance; +string argument_tuple_as_string(tuple args); + // function -- // the common base class for all overloadable function and method objects @@ -38,17 +40,36 @@ class function : public python_object virtual ~function() {} PyObject* call(PyObject* args, PyObject* keywords) const; + PyObject* getattr(const char * name) const; static void add_to_namespace(reference f, const char* name, PyObject* dict); - + + protected: + virtual PyObject* description() const = 0; private: virtual PyObject* do_call(PyObject* args, PyObject* keywords) const = 0; - virtual const char* description() const = 0; + virtual string description_as_string() const; + virtual string argument_types_as_string(tuple args) const; + virtual string function_name() const = 0; + virtual bool rephrase_argument_error() const + { return true; } private: struct type_object; private: reference m_overloads; }; +struct named_function : function +{ + named_function(const char * name) + : m_name(name) + {} + + string function_name() const + { return m_name; } + + string m_name; +}; + // wrapped_function_pointer<> -- // A single function or member function pointer wrapped and presented to // Python as a callable object. @@ -57,19 +78,19 @@ class function : public python_object // R - the return type of the function pointer // F - the complete type of the wrapped function pointer template -struct wrapped_function_pointer : function +struct wrapped_function_pointer : named_function { typedef F ptr_fun; // pointer-to--function or pointer-to-member-function - wrapped_function_pointer(ptr_fun pf) - : m_pf(pf) {} + wrapped_function_pointer(ptr_fun pf, const char * name) + : named_function(name), m_pf(pf) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const { return caller::call(m_pf, args, keywords); } - const char* description() const - { return typeid(F).name(); } + PyObject* description() const + { return function_signature(m_pf); } private: const ptr_fun m_pf; @@ -80,15 +101,15 @@ struct wrapped_function_pointer : function // verbatim to C++ (useful for customized argument parsing and variable // argument lists) template -struct raw_arguments_function : function +struct raw_arguments_function : named_function { typedef Ret (*ptr_fun)(Args, Keywords); - raw_arguments_function(ptr_fun pf) - : m_pf(pf) {} + raw_arguments_function(ptr_fun pf, const char * name) + : named_function(name), m_pf(pf) {} private: - PyObject* do_call(PyObject* args, PyObject* keywords) const + PyObject* do_call(PyObject* args, PyObject* keywords) const { ref dict(keywords ? ref(keywords, ref::increment_count) : @@ -99,9 +120,17 @@ struct raw_arguments_function : function from_python(dict.get(), python::type()))); } - const char* description() const - { return typeid(ptr_fun).name(); } + PyObject* description() const + { + tuple result(1); + result.set_item(0, string("...")); + + return result.reference().release(); + } + virtual bool rephrase_argument_error() const + { return false; } + private: const ptr_fun m_pf; }; @@ -119,19 +148,20 @@ struct raw_arguments_function : function // parameter and calls T::f on it /non-virtually/, where V // approximates &T::f. template -class virtual_function : public function +class virtual_function : public named_function { public: - virtual_function(V virtual_function_ptr, D default_implementation) - : m_virtual_function_ptr(virtual_function_ptr), + virtual_function(V virtual_function_ptr, D default_implementation, const char * name) + : named_function(name), + m_virtual_function_ptr(virtual_function_ptr), m_default_implementation(default_implementation) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const; - const char* description() const - { return typeid(V).name(); } + PyObject* description() const + { return function_signature(m_virtual_function_ptr); } private: const V m_virtual_function_ptr; @@ -142,26 +172,26 @@ class virtual_function : public function // functionality once the return type has already been deduced. R is expected to // be type, where X is the actual return type of pmf. template -function* new_wrapped_function_aux(R, F pmf) +function* new_wrapped_function_aux(R, F pmf, const char * name) { // We can't just use "typename R::Type" below because MSVC (incorrectly) pukes. typedef typename R::type return_type; - return new wrapped_function_pointer(pmf); + return new wrapped_function_pointer(pmf, name); } // Create and return a new member function object wrapping the given // pointer-to-member function template -inline function* new_wrapped_function(F pmf) +inline function* new_wrapped_function(F pmf, const char * name) { // Deduce the return type and pass it off to the helper function above - return new_wrapped_function_aux(return_value(pmf), pmf); + return new_wrapped_function_aux(return_value(pmf), pmf, name); } template -function* new_raw_arguments_function(R (*pmf)(Args, keywords)) +function* new_raw_arguments_function(R (*pmf)(Args, keywords), const char * name) { - return new raw_arguments_function(pmf); + return new raw_arguments_function(pmf, name); } @@ -170,26 +200,26 @@ function* new_raw_arguments_function(R (*pmf)(Args, keywords)) // be type, where X is the actual return type of V. template inline function* new_virtual_function_aux( - type, R, V virtual_function_ptr, D default_implementation - ) + type, R, V virtual_function_ptr, D default_implementation, + const char * name) { // We can't just use "typename R::Type" below because MSVC (incorrectly) pukes. typedef typename R::type return_type; return new virtual_function( - virtual_function_ptr, default_implementation); + virtual_function_ptr, default_implementation, name); } // Create and return a new virtual_function object wrapping the given // virtual_function_ptr and default_implementation template inline function* new_virtual_function( - type, V virtual_function_ptr, D default_implementation - ) + type, V virtual_function_ptr, D default_implementation, + const char * name) { // Deduce the return type and pass it off to the helper function above return new_virtual_function_aux( type(), return_value(virtual_function_ptr), - virtual_function_ptr, default_implementation); + virtual_function_ptr, default_implementation, name); } // A function with a bundled "bound target" object. This is what is produced by @@ -220,37 +250,37 @@ class bound_function : public python_object // Special functions designed to access data members of a wrapped C++ object. template -class getter_function : public function +class getter_function : public named_function { public: typedef MemberType ClassType::* pointer_to_member; - getter_function(pointer_to_member pm) - : m_pm(pm) {} + getter_function(pointer_to_member pm, const char * name) + : named_function(name), m_pm(pm) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const; - const char* description() const - { return typeid(MemberType (*)(const ClassType&)).name(); } + PyObject* description() const + { return function_signature((MemberType (*)(const ClassType&))0); } private: pointer_to_member m_pm; }; template -class setter_function : public function +class setter_function : public named_function { public: typedef MemberType ClassType::* pointer_to_member; - setter_function(pointer_to_member pm) - : m_pm(pm) {} + setter_function(pointer_to_member pm, const char * name) + : named_function(name), m_pm(pm) {} private: PyObject* do_call(PyObject* args, PyObject* keywords) const; - const char* description() const - { return typeid(void (*)(const ClassType&, const MemberType&)).name(); } + PyObject* description() const + { return function_signature((void (*)(const ClassType&, const MemberType&))0); } private: pointer_to_member m_pm; }; diff --git a/gen_caller.py b/gen_caller.py index f0e65d49..7aaac5cf 100644 --- a/gen_caller.py +++ b/gen_caller.py @@ -31,6 +31,7 @@ body_sections = ( # include # include "signatures.h" # include "none.h" +# include "objects.h" namespace python { @@ -56,9 +57,25 @@ struct caller ''', '''}; -} +namespace detail +{ + +// create signature tuples +inline''', +''' +// member functions +''', +''' +// const member functions +''', +''' +// free functions +''', +'''} // namespace detail -#endif +} // namespace python + +#endif // CALLER_DWA05090_H_ ''') #' @@ -87,6 +104,34 @@ free_function = '''%{ template <%(class A%n%:, %)> ''' +function_signature = '''%{template <%}%(class A%n%:, %)%{>%} +PyObject* function_signature(%(type%:, %)) { +%( static const bool is_plain_A%n = BOOST_PYTHON_IS_PLAIN(A%n); +%) tuple result(%x); +%( result.set_item(%N, python_type_name_selector::get(type())); +%) + return result.reference().release(); +} + +''' + +member_function_signature = '''template +inline PyObject* function_signature(R (T::*pmf)(%(A%n%:, %))%1) { + return function_signature( + python::type()%(, + python::type()%)); +} + +''' + +free_function_signature = '''template +inline PyObject* function_signature(R (*f)(%(A%n%:, %))) { + return function_signature(%( + python::type()%:,%)); +} + +''' + def gen_caller(member_function_args, free_function_args = None): if free_function_args is None: free_function_args = member_function_args + 1 @@ -118,6 +163,16 @@ def gen_caller(member_function_args, free_function_args = None): + gen_functions(free_function, free_function_args, 'void', '', return_none) + body_sections[6] + + # create lists describing the function signatures + + gen_functions(function_signature, free_function_args) + + body_sections[7] + + gen_functions(member_function_signature, member_function_args, '') + + body_sections[8] + + gen_functions(member_function_signature, member_function_args, ' const') + + body_sections[9] + + gen_functions(free_function_signature, free_function_args) + + body_sections[10] ) if __name__ == '__main__': diff --git a/gen_extclass.py b/gen_extclass.py index 81ea4942..380d7d91 100644 --- a/gen_extclass.py +++ b/gen_extclass.py @@ -138,6 +138,39 @@ class class_registry static std::vector static_derived_class_info; }; +template +no_t* is_plain_aux(type >); + +template +string forward_python_type_name(python::type >) +{ + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); +} + +template +no_t* is_plain_aux(type >); + +template +string forward_python_type_name(python::type >) +{ + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); +} + +template +string python_type_name(type) +{ + if(class_registry::class_object() == 0) + { + return string("UnknownType"); + } + else + { + return class_registry::class_object()->complete_class_name(); + } +} + }} // namespace python::detail BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE @@ -319,7 +352,9 @@ class read_only_setattr_function : public function public: read_only_setattr_function(const char* name); PyObject* do_call(PyObject* args, PyObject* keywords) const; - const char* description() const; + PyObject* description() const; + string function_name() const + { return m_name; } private: string m_name; }; @@ -433,7 +468,7 @@ class extension_class template inline void def_raw(Fn fn, const char* name) { - this->add_method(new_raw_arguments_function(fn), name); + this->add_method(new_raw_arguments_function(fn, name), name); } // define member functions. In fact this works for free functions, too - @@ -443,7 +478,7 @@ class extension_class template inline void def(Fn fn, const char* name) { - this->add_method(new_wrapped_function(fn), name); + this->add_method(new_wrapped_function(fn, name), name); } // Define a virtual member function with a default implementation. @@ -452,7 +487,7 @@ class extension_class template inline void def(Fn fn, const char* name, DefaultFn default_fn) { - this->add_method(new_virtual_function(type(), fn, default_fn), name); + this->add_method(new_virtual_function(type(), fn, default_fn, name), name); } // Provide a function which implements x., reading from the given @@ -460,7 +495,7 @@ class extension_class template inline void def_getter(MemberType T::*pm, const char* name) { - this->add_getter_method(new getter_function(pm), name); + this->add_getter_method(new getter_function(pm, name), name); } // Provide a function which implements assignment to x., writing to @@ -468,7 +503,7 @@ class extension_class template inline void def_setter(MemberType T::*pm, const char* name) { - this->add_setter_method(new setter_function(pm), name); + this->add_setter_method(new setter_function(pm, name), name); } // Expose the given member (pm) of the T obj as a read-only attribute diff --git a/gen_function.py b/gen_function.py index bebbc818..5137d44b 100644 --- a/gen_function.py +++ b/gen_function.py @@ -35,6 +35,8 @@ def _gen_arg(template, n, args, delimiter = '%'): if key == 'n': result = result + `n` + elif key == 'N': + result = result + `n-1` else: result = result + _gen_common_key(key, n, args) @@ -55,8 +57,13 @@ def gen_function(template, n, *args, **keywords): %n is transformed into the string representation of 1..n for each repetition of n. - %x, where x is a digit, is transformed into the corresponding additional + %N is transformed into the string representation of 0..(n-1) for each repetition + of n. + + %i, where i is a digit, is transformed into the corresponding additional argument. + + %x is transformed into the number of the current repetition for example, diff --git a/gen_init_function.py b/gen_init_function.py index 9fedec2c..ab6e3422 100644 --- a/gen_init_function.py +++ b/gen_init_function.py @@ -130,6 +130,8 @@ private: // override function hook PyObject* do_call(PyObject* args, PyObject* keywords) const; private: virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0; + string description_as_string() const; + string argument_types_as_string(tuple args) const; }; """ + gen_functions(""" @@ -145,8 +147,20 @@ struct init%x : init python::detail::reference_parameter(from_python(a%n, type()))%) ); } - const char* description() const - { return typeid(void (*)(T&%(, A%n%%))).name(); } + + PyObject* description() const + { + return function_signature(python::type()%(, + python::type()%)); + } + + string function_name() const + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + string result(python_type_name_selector::get(python::type())); + result += ".__init__"; + return result; + } };""", args) + """ }} // namespace python::detail diff --git a/init_function.cpp b/init_function.cpp index f29e914a..de6c3c99 100644 --- a/init_function.cpp +++ b/init_function.cpp @@ -33,4 +33,24 @@ namespace python { namespace detail { return none(); } +string init::description_as_string() const +{ + tuple arguments(ref(this->description())); + string result("("); + for (std::size_t i = 1; i < arguments.size(); ++i) + { + if (i != 1) + result += ", "; + result += string(arguments[i]); + } + + result += ")"; + return result; +} + +string init::argument_types_as_string(tuple arguments) const +{ + return argument_tuple_as_string(arguments.slice(1,arguments.size())); +} + }} // namespace python::detail diff --git a/init_function.h b/init_function.h index 14da7842..dfc2fea0 100644 --- a/init_function.h +++ b/init_function.h @@ -110,11 +110,6 @@ template struct init2; template struct init3; template struct init4; template struct init5; -template struct Init6; -template struct Init7; -template struct Init8; -template struct Init9; -template struct Init10; template struct init_function @@ -162,71 +157,6 @@ struct init_function detail::parameter_traits::const_reference, detail::parameter_traits::const_reference>; } - - template - static init* create(signature6) { - return new Init6::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference>; - } - - template - static init* create(signature7) { - return new Init7::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference>; - } - - template - static init* create(signature8) { - return new Init8::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference>; - } - - template - static init* create(signature9) { - return new Init9::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference>; - } - - template - static init* create(signature10) { - return new Init10::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference, - detail::parameter_traits::const_reference>; - } }; class init : public function @@ -235,6 +165,8 @@ private: // override function hook PyObject* do_call(PyObject* args, PyObject* keywords) const; private: virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0; + string description_as_string() const; + string argument_types_as_string(tuple args) const; }; @@ -248,8 +180,19 @@ struct init0 : init return new T(self ); } - const char* description() const - { return typeid(void (*)(T&)).name(); } + + PyObject* description() const + { + return function_signature(python::type()); + } + + string function_name() const + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + string result(python_type_name_selector::get(python::type())); + result += ".__init__"; + return result; + } }; template @@ -264,8 +207,20 @@ struct init1 : init python::detail::reference_parameter(from_python(a1, type())) ); } - const char* description() const - { return typeid(void (*)(T&, A1)).name(); } + + PyObject* description() const + { + return function_signature(python::type(), + python::type()); + } + + string function_name() const + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + string result(python_type_name_selector::get(python::type())); + result += ".__init__"; + return result; + } }; template @@ -282,8 +237,21 @@ struct init2 : init python::detail::reference_parameter(from_python(a2, type())) ); } - const char* description() const - { return typeid(void (*)(T&, A1, A2)).name(); } + + PyObject* description() const + { + return function_signature(python::type(), + python::type(), + python::type()); + } + + string function_name() const + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + string result(python_type_name_selector::get(python::type())); + result += ".__init__"; + return result; + } }; template @@ -302,8 +270,22 @@ struct init3 : init python::detail::reference_parameter(from_python(a3, type())) ); } - const char* description() const - { return typeid(void (*)(T&, A1, A2, A3)).name(); } + + PyObject* description() const + { + return function_signature(python::type(), + python::type(), + python::type(), + python::type()); + } + + string function_name() const + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + string result(python_type_name_selector::get(python::type())); + result += ".__init__"; + return result; + } }; template @@ -324,8 +306,23 @@ struct init4 : init python::detail::reference_parameter(from_python(a4, type())) ); } - const char* description() const - { return typeid(void (*)(T&, A1, A2, A3, A4)).name(); } + + PyObject* description() const + { + return function_signature(python::type(), + python::type(), + python::type(), + python::type(), + python::type()); + } + + string function_name() const + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + string result(python_type_name_selector::get(python::type())); + result += ".__init__"; + return result; + } }; template @@ -348,160 +345,27 @@ struct init5 : init python::detail::reference_parameter(from_python(a5, type())) ); } - const char* description() const - { return typeid(void (*)(T&, A1, A2, A3, A4, A5)).name(); } -}; - -template -struct Init6 : init -{ - virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const - { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6)) - throw argument_error(); - return new T(self, - python::detail::reference_parameter(from_python(a1, type())), - python::detail::reference_parameter(from_python(a2, type())), - python::detail::reference_parameter(from_python(a3, type())), - python::detail::reference_parameter(from_python(a4, type())), - python::detail::reference_parameter(from_python(a5, type())), - python::detail::reference_parameter(from_python(a6, type())) - ); + + PyObject* description() const + { + return function_signature(python::type(), + python::type(), + python::type(), + python::type(), + python::type(), + python::type()); } - const char* description() const - { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6)).name(); } -}; - -template -struct Init7 : init -{ - virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const - { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7)) - throw argument_error(); - return new T(self, - python::detail::reference_parameter(from_python(a1, type())), - python::detail::reference_parameter(from_python(a2, type())), - python::detail::reference_parameter(from_python(a3, type())), - python::detail::reference_parameter(from_python(a4, type())), - python::detail::reference_parameter(from_python(a5, type())), - python::detail::reference_parameter(from_python(a6, type())), - python::detail::reference_parameter(from_python(a7, type())) - ); + + string function_name() const + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + string result(python_type_name_selector::get(python::type())); + result += ".__init__"; + return result; } - const char* description() const - { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7)).name(); } -}; - -template -struct Init8 : init -{ - virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const - { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) - throw argument_error(); - return new T(self, - python::detail::reference_parameter(from_python(a1, type())), - python::detail::reference_parameter(from_python(a2, type())), - python::detail::reference_parameter(from_python(a3, type())), - python::detail::reference_parameter(from_python(a4, type())), - python::detail::reference_parameter(from_python(a5, type())), - python::detail::reference_parameter(from_python(a6, type())), - python::detail::reference_parameter(from_python(a7, type())), - python::detail::reference_parameter(from_python(a8, type())) - ); - } - const char* description() const - { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8)).name(); } -}; - -template -struct Init9 : init -{ - virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const - { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) - throw argument_error(); - return new T(self, - python::detail::reference_parameter(from_python(a1, type())), - python::detail::reference_parameter(from_python(a2, type())), - python::detail::reference_parameter(from_python(a3, type())), - python::detail::reference_parameter(from_python(a4, type())), - python::detail::reference_parameter(from_python(a5, type())), - python::detail::reference_parameter(from_python(a6, type())), - python::detail::reference_parameter(from_python(a7, type())), - python::detail::reference_parameter(from_python(a8, type())), - python::detail::reference_parameter(from_python(a9, type())) - ); - } - const char* description() const - { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8, A9)).name(); } -}; - -template -struct Init10 : init -{ - virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const - { - PyObject* a1; - PyObject* a2; - PyObject* a3; - PyObject* a4; - PyObject* a5; - PyObject* a6; - PyObject* a7; - PyObject* a8; - PyObject* a9; - PyObject* a10; - if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) - throw argument_error(); - return new T(self, - python::detail::reference_parameter(from_python(a1, type())), - python::detail::reference_parameter(from_python(a2, type())), - python::detail::reference_parameter(from_python(a3, type())), - python::detail::reference_parameter(from_python(a4, type())), - python::detail::reference_parameter(from_python(a5, type())), - python::detail::reference_parameter(from_python(a6, type())), - python::detail::reference_parameter(from_python(a7, type())), - python::detail::reference_parameter(from_python(a8, type())), - python::detail::reference_parameter(from_python(a9, type())), - python::detail::reference_parameter(from_python(a10, type())) - ); - } - const char* description() const - { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)).name(); } }; }} // namespace python::detail #endif // INIT_FUNCTION_DWA052000_H_ + diff --git a/module.h b/module.h index 601ef17d..fd92f5a6 100644 --- a/module.h +++ b/module.h @@ -18,8 +18,6 @@ namespace python { class module_builder { - typedef PyObject * (*raw_function_ptr)(python::tuple const &, python::dictionary const &); - public: // Create a module. REQUIRES: only one module_builder is created per module. module_builder(const char* name); @@ -32,13 +30,13 @@ class module_builder template void def_raw(Fn fn, const char* name) { - add(detail::new_raw_arguments_function(fn), name); + add(detail::new_raw_arguments_function(fn, name), name); } template void def(Fn fn, const char* name) { - add(detail::new_wrapped_function(fn), name); + add(detail::new_wrapped_function(fn, name), name); } static string name(); diff --git a/objects.h b/objects.h index 31ac3284..e9d8a240 100644 --- a/objects.h +++ b/objects.h @@ -293,6 +293,152 @@ struct list::slice_proxy int m_low, m_high; }; +namespace detail +{ +#define BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(T, name) \ + inline string python_type_name(python::type) \ + { return string(#name); } + +#if 0 + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(long, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned long, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(int, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned int, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(short, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned short, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(signed char, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned char, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(bool, types.IntType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(float, types.FloatType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(double, types.FloatType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(void, types.NoneType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(const char *, types.StringType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(std::string, types.StringType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(PyObject, AnyType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(reference, AnyType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(list, types.ListType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(tuple, types.TupleType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(dictionary, types.DictionaryType); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(string, types.StringType); +#endif /* #if 0 */ + + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(long, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned long, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(int, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned int, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(short, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned short, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(signed char, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned char, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(bool, int); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(float, float); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(double, float); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(void, None); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(const char *, string); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(std::string, string); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(PyObject, any); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(reference, any); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(list, list); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(tuple, tuple); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(dictionary, dictionary); + BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(string, string); + + typedef char no_t[1]; + typedef char yes_t[2]; + + yes_t* is_plain_aux(...); + + template + no_t* is_plain_aux(type); + + template + no_t* is_plain_aux(type); + + template + no_t* is_plain_aux(type); + + template + no_t* is_plain_aux(type); + + template + no_t* is_plain_aux(type >); + + template + no_t* is_plain_aux(type >); + + template + no_t* is_plain_aux(type >); + +#define BOOST_PYTHON_IS_PLAIN(T) \ + (sizeof(*python::detail::is_plain_aux(python::type())) == \ + sizeof(python::detail::yes_t)) + + template + struct python_type_name_selector + { + template + static string get(python::type t) + { return python_type_name(t); } + }; + + template + string forward_python_type_name(python::type) + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); + } + + template + string forward_python_type_name(python::type) + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); + } + + template + string forward_python_type_name(python::type) + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); + } + + template + string forward_python_type_name(python::type) + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); + } + + template + string forward_python_type_name(python::type >) + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); + } + + template + string forward_python_type_name(python::type >) + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); + } + + template + string forward_python_type_name(python::type >) + { + static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T); + return python_type_name_selector::get(python::type()); + } + + template <> + struct python_type_name_selector + { + template + static string get(python::type t) + { return forward_python_type_name(t); } + }; +} // namespace detail + } // namespace python BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE diff --git a/operators.h b/operators.h index 95528bc8..1c07f346 100644 --- a/operators.h +++ b/operators.h @@ -197,8 +197,7 @@ namespace detail }; }; - - + // Fully specialize define_operator for all operators defined in operator_id above. // Every specialization defines one function object for normal operator calls and one // for operator calls with operands reversed ("__r*__" function variants). @@ -214,15 +213,20 @@ namespace detail { \ PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ { \ - tuple args(ref(arguments, ref::increment_count)); \ + tuple args(ref(arguments, ref::increment_count)); \ \ return BOOST_PYTHON_CONVERSION::to_python( \ BOOST_PYTHON_CONVERSION::from_python(args[0].get(), python::type()) oper \ BOOST_PYTHON_CONVERSION::from_python(args[1].get(), python::type())); \ } \ \ - const char* description() const \ - { return "__" #id "__"; } \ + string function_name() const \ + { return string(name()); } \ + \ + PyObject* description() const \ + { \ + return function_signature(python::type(), python::type()); \ + } \ }; \ \ template \ @@ -230,15 +234,20 @@ namespace detail { \ PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ { \ - tuple args(ref(arguments, ref::increment_count)); \ + tuple args(ref(arguments, ref::increment_count)); \ \ - return BOOST_PYTHON_CONVERSION::to_python( \ + return BOOST_PYTHON_CONVERSION::to_python( \ BOOST_PYTHON_CONVERSION::from_python(args[1].get(), python::type()) oper \ BOOST_PYTHON_CONVERSION::from_python(args[0].get(), python::type())); \ } \ \ - const char* description() const \ - { return "__r" #id "__"; } \ + string function_name() const \ + { return string(rname()); } \ + \ + PyObject* description() const \ + { \ + return function_signature(python::type(), python::type()); \ + } \ \ }; \ \ @@ -255,14 +264,19 @@ namespace detail { \ PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ { \ - tuple args(ref(arguments, ref::increment_count)); \ + tuple args(ref(arguments, ref::increment_count)); \ \ - return BOOST_PYTHON_CONVERSION::to_python( \ + return BOOST_PYTHON_CONVERSION::to_python( \ oper(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), python::type()))); \ } \ \ - const char* description() const \ - { return "__" #id "__"; } \ + string function_name() const \ + { return string(name()); } \ + \ + PyObject* description() const \ + { \ + return function_signature(python::type()); \ + } \ }; \ \ static const char * name() { return "__" #id "__"; } \ @@ -317,8 +331,13 @@ namespace detail BOOST_PYTHON_CONVERSION::from_python(args[1].get(), python::type()))); } - const char* description() const - { return "__pow__"; } + string function_name() const + { return string(name()); } + + PyObject* description() const + { + return function_signature(python::type(), python::type()); + } }; @@ -331,7 +350,7 @@ namespace detail if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type) { - PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()"); + PyErr_SetString(PyExc_TypeError, "'__pow__' expected 2 arguments, got 3."); throw argument_error(); } @@ -340,8 +359,13 @@ namespace detail BOOST_PYTHON_CONVERSION::from_python(args[0].get(), python::type()))); } - const char* description() const - { return "__rpow__"; } + string function_name() const + { return string(rname()); } + + PyObject* description() const + { + return function_signature(python::type(), python::type()); + } }; @@ -374,8 +398,13 @@ namespace detail return res; } - const char* description() const - { return "__divmod__"; } + string function_name() const + { return string(name()); } + + PyObject* description() const + { + return function_signature(python::type(), python::type()); + } }; @@ -399,9 +428,13 @@ namespace detail return res; } - const char* description() const - { return "__rdivmod__"; } + string function_name() const + { return string(rname()); } + PyObject* description() const + { + return function_signature(python::type(), python::type()); + } }; static const char * name() { return "__divmod__"; } @@ -430,8 +463,13 @@ namespace detail 0) ; } - const char* description() const - { return "__cmp__"; } + string function_name() const + { return string(name()); } + + PyObject* description() const + { + return function_signature(python::type(), python::type()); + } }; @@ -452,8 +490,13 @@ namespace detail 0) ; } - const char* description() const - { return "__rcmp__"; } + string function_name() const + { return string(rname()); } + + PyObject* description() const + { + return function_signature(python::type(), python::type()); + } }; @@ -488,8 +531,13 @@ namespace detail #endif } - const char* description() const - { return "__str__"; } + string function_name() const + { return string(name()); } + + PyObject* description() const + { + return function_signature(python::type()); + } }; diff --git a/signatures.h b/signatures.h index 39dd94c2..ec345dfe 100644 --- a/signatures.h +++ b/signatures.h @@ -18,7 +18,7 @@ namespace detail { // A stand-in for the built-in void. This one can be passed to functions and // (under MSVC, which has a bug, be used as a default template type parameter). struct void_t {}; -} +} // namespace detail // An envelope in which type information can be delivered for the purposes // of selecting an overloaded from_python() function. This is needed to work diff --git a/special.html b/special.html index d32b843b..ea7cd2c0 100644 --- a/special.html +++ b/special.html @@ -1,598 +1,136 @@ - Special Method and Operator Support + Special Method Name Support

c++boost.gif (8819 bytes)Special Method and - Operator Support + "c++boost.gif" alt="c++boost.gif (8819 bytes)">Special Method Name + Support

Overview

- Py_cpp is able to wrap suitable C++ functions and C++ operators into - Python operators. It supports all of the standard - special method names supported by real Python class instances - except __complex__ (more on the reasons below). Supported operators include - general, numeric, and sequence and mapping operators. In - addition, py_cpp provides a simple way to export member variables and - define attributes by means of getters and - setters. -

- General Operators -

- Python provides a number of special operatos for basic customization of a - class: -
-
- __repr__: -
- create a string representation from which the object can be - reconstructed -
- __str__: -
- create a string representation which is suitable for printing -
- __cmp__: -
- three-way compare function, used to implement comparison operators - (< etc.) -
- __hash__: -
- needed to use the object as a dictionary key (only allowed if __cmp__ - is also defined) -
- __nonzero__: -
- called if the object is used as a truth value (e.g. in an if - statement) -
- __call__: -
- make instances of the class callable like a function -
- If we have a suitable C++ function that supports any of these features, - we can export it like any other function, using its Python special name. - For example, suppose that class Foo provides a string - conversion function: -
-    std::string to_string(Foo const & f)
-    {
-        std::ostringstream s;
-        s << f;
-        return s.str();
-    }
-
- This function would be wrapped like this: -
-    python::class_builder<Foo> foo_class(my_module, "Foo");
-    foo_class.def(&to_string, "__str__");
-
+ special method names supported by real Python class instances except + __complex__ (more on the reasons below). + + +

Numeric Operators

+ +There are two fundamental ways to define numeric operators within py_cpp: automatic wrapping +and manual wrapping. Suppose, C++ defines an addition operator for type Rational, so that we can write: - Note that py_cpp also supports automatic wrapping of - "__str__" and "__cmp__". This is explained in the next - section and the table of numeric - operators. - - -

- Numeric Operators -

- There are two fundamental ways to define numeric operators within py_cpp: - manual wrapping (as is done with general - operators) and automatic wrapping. Lets start with the second - possibility. Suppose, C++ defines a class Int (which might - represent an infinite-precision integer) which supports addition, so that - we can write (in C++):
-    Int a, b, c;
+    Rational a, b, c;
     ...
     c = a + b;
 
- To enable the same functionality in Python, we first wrap the - Int class as usual: + +To enable the same functionality in Python, we first wrap the Rational class as usual: +
-    python::class_builder<Int> int_class(my_module, "Int");
-    int_class.def(python::constructor<>());
+    py::ClassWrapper<Rational> rational_class(my_module, "Rational");
+    rational_class.def(py::Constructor<>());
     ...
 
- Then we export the addition operator like this: + +Then we export the addition operator like this: +
-    int_class.def(python::operators<python::op_add>());
+    rational_class.def(py::operators<py::op_add>());
 
- Since Int also supports subtraction, multiplication, adn division, we - want to export those also. This can be done in a single command by - 'or'ing the operator identifiers together (a complete list of these - identifiers and the corresponding operators can be found in the table): + +Since Rational also supports subtraction, multiplication, adn division, we want to export those also. This can be done in a single command by 'or'ing the operator identifiers together (a complete list of these identifiers and the corresponding operators can be found in the table): +
-    int_class.def(python::operators<(python::op_sub | python::op_mul | python::op_div)>());
+    rational_class.def(py::operators<(py::op_sub | py::op_mul | py::op_div)>());
 
- Note that the or-expression must be enclosed in parentheses. This form of - operator definition will wrap homogeneous operators, i.e. operators whose - left and right operand have the same type. Now, suppose that our C++ - library also supports addition of Ints and plain integers: + +Note that the or-expression must be enclosed in parentheses. This form of operator definition will wrap homogeneous operators, that is operators whose left and right operand have the same type. Now, suppose that our C++ library also supports addition of Rationals and integers: +
-    Int a, b;
+    Rational a, b;
     int i;
     ...
     a = b + i;
     a = i + b;
 
- To wrap these heterogeneous operators (left and right hand side have - different types), we need a possibility to specify a different type for - one of the operands. This is done using the right_operand - and left_operand templates: + +To wrap these heterogeneous operators (left and right hand side have different types), we need a possibility to specify a different operand type. This is done using the right_operand and left_operand templates: +
-    int_class.def(python::operators<python::op_add>(), python::right_operand<int>());
-    int_class.def(python::operators<python::op_add>(), python::left_operand<int>());
+    rational_class.def(py::operators<py::op_add>(), py::right_operand<int>());
+    rational_class.def(py::operators<py::op_add>(), py::left_operand<int>());
 
- Py_cpp uses overloading to register several variants of the same - operation (more on this in the context of - coercion). Again, several operators can be exported at once: + +Py_cpp uses overloading to register several variants of the same operation (more on this in the context of coercion). Again, several operators can be exported at once: +
-    int_class.def(python::operators<(python::op_sub | python::op_mul | python::op_div)>(),
-                       python::right_operand<int>());
-    int_class.def(python::operators<(python::op_sub | python::op_mul | python::op_div)>(), 
-                       python::left_operand<int>());
+    rational_class.def(py::operators<(py::op_sub | py::op_mul | py::op_div)>(),
+                       py::right_operand<int>());
+    rational_class.def(py::operators<(py::op_sub | py::op_mul | py::op_div)>(), 
+                       py::left_operand<int>());
 
- The type of the operand not mentioned is taken from the class object. In - our example, the class object is int_class, and thus the - other operand's type is `Int const &'. You can override - this default by explicitly specifying a type in the - operators template: + + +The type of the operand not mentioned is taken from the class object. In our example, the class object is rational_class, and thus the other operand's type is `Rational const &'. You can override this default by explicitly specifying a type in the operators template: +
-    int_class.def(python::operators<python::op_add, Int>(), python::right_operand<int>());
+    rational_class.def(py::operators<py::op_add, Rational>(), py::right_operand<int>());
 
- Here, `Int' would be used instead of `Int const - &'. -

- Note that automatic wrapping doesn't need any specific form of - operator+() (or one of the other operators), but rather wraps - the expression `left + right'. That is, this - mechanism can be used for any definition of operator+(), - such as a free function `Int operator+(Int, Int)' or a - member function `Int Int::operator+(Int)'. -

- For the Python operators pow() and abs(), - there is no corresponding C++ operator. Instead, automatic wrapping - attempts to wrap C++ functions of the same name. This only works if - those functions are known in namespace python::detail. - Thus it might be necessary to add a using declaration prior to - wrapping: + +Here, `Rational' would be used instead of `Rational const &'. +

+Note that automatic wrapping doesn't need any specific form of operator+() (or any other operator), but rather wraps the expression `left + right'. That is, this mechanism can be used for any definition of operator+(), such as a free function `Rational operator+(Rational, Rational)' or a member function `Rational Rational::operator+(Rational)'. + +

+In some cases, automatic wrapping of operators is not possible or not desirable. Suppose, for example, that the power operation for Rationals is defined by a set of functions pow(): +

-    namespace python { 
-      namespace detail {
-        using my_namespace::pow;
-        using my_namespace::abs;
-    }}
+    Rational pow(Rational const & left, Rational const & right);
+    Rational pow(Rational const & left, int right);
+    Rational pow(int left, Rational const & right);
 
-

- In some cases, automatic wrapping of operators is not possible or not - desirable. Suppose, for example, that the modulo operation for Ints is - defined by a set of functions mod() (for automatic - wrapping, we would need operator%()): + +In order to create the Python operator "pow" from these functions, we have to wrap them manually: +

-    Int mod(Int const & left, Int const & right);
-    Int mod(Int const & left, int right);
-    Int mod(int left, Int const & right);
+    rational_class.def((Rational (*)(Rational const &, Rational const &))&pow, "__pow__");
+    rational_class.def((Rational (*)(Rational const &, int))&pow, "__pow__");
 
- In order to create the Python operator "__mod__" from these functions, we - have to wrap them manually: + +The third form (with int as left operand) cannot be wrapped this way. We must first create a function rpow() with the operands reversed: +
-    int_class.def((Int (*)(Int const &, Int const &))&mod, "__mod__");
-    int_class.def((Int (*)(Int const &, int))&mod, "__mod__");
-
- The third form (with int as left operand) cannot be wrapped - this way. We must first create a function rmod() with the - operands reversed: -
-    Int rmod(Int const & right, int left)
+    Rational rpow(Rational const & right, int left)
     {
-        return mod(left, right);
+        return pow(left, right);
     }
 
- This function must be wrapped under the name "__rmod__": + +This function must be wrapped under the name "__rpow__": +
-    int_class.def(&rmod,  "__rmod__");
+    rational_class.def(&rpow,  "__rpow__");
 
- A list of the possible operator names is also found in the table. Special treatment is necessary to export the - ternary pow operator. -

- Automatic and manual wrapping can be mixed arbitrarily. Note that you - cannot overload the same operator for a given extension class on both - `int' and `float', because Python implicitly - converts these types into each other. Thus, the overloaded variant - found first (be it `int' or `float') will be - used for either of the two types. -

- Coercion -

- Plain Python can only execute operators with identical types on the left - and right hand side. If it encounters an expression where the types of - the left and right operand differ, it tries to coerce these type to a - common type before invoking the actual operator. Implementing good - coercion functions can be difficult if many type combinations must be - supported. -

- In contrast, py_cpp provides - overloading. By means of overloading, operator calling can be - simplyfied drastically: you just register operators for all desired - type combinations, and py_cpp automatically ensures that the correct - function is called in each case. User defined coercion functions are - not necessary. To enable operator overloading, py_cpp provides - a standard coercion which is implicitly registered whenever - automatic operator wrapping is used. -

- If you wrap all operator functions manually, but still want to use - operator overloading, you have to register the standard coercion - function explicitly: -

-    // this is not necessary if automatic operator wrapping is used
-    int_class.def_standard_coerce();
-
- In case you encounter a situation where you absolutely need a customized - coercion, you can overload the "__coerce__" operator itself. The - signature of a coercion function must look like this: -
-    python::tuple custom_coerce(PyObject * left, PyObject * right);
-
- The resulting tuple must contain two elements which - represent the values of left and right - converted to the same type. Such a function is wrapped as usual: -
-    some_class.def(&custom_coerce, "__coerce__");
-
- Note that the custom coercion function is only used if it is defined - before any automatic operator wrapping on the given class or a call - to `some_class.def_standard_coerce()'. -

- The Ternary pow() Operator -

- In addition to the usual binary pow()-operator (meaning - x^y), Python also provides a ternary variant that implements - (x^y) % z (presumably using a more efficient algorithm than - concatenation of power and modulo operators). Automatic operator wrapping - can only be used with the binary variant. Ternary pow() must - always be wrapped manually. For a homgeneous ternary pow(), - this is done as usual: -
-    Int power(Int const & first, Int const & second, Int const & module);
-    typedef Int (ternary_function1)(const Int&, const Int&, const Int&);
-    ...
-    int_class.def((ternary_function1)&power,  "__pow__");
-
- In case you want to support this function with non-uniform argument - types, wrapping is a little more involved. Suppose, you have to wrap: -
-    Int power(Int const & first, int second, int module);
-    Int power(int first, Int const & second, int module);
-    Int power(int first, int second, Int const & module);
-
- The first variant can be wrapped as usual: -
-    typedef Int (ternary_function2)(const Int&, int, int);
-    int_class.def((ternary_function2)&power,  "__pow__");
-
- In the second variant, however, Int appears only as second - argument, and in the last one it is the third argument. Therefor we must - first provide functions where the argumant order is changed so that - Int appears in first place: -
-    Int rpower(Int const & second, int first, int module)
-    {
-        return power(first, second, third);
-    }
-    Int rrpower(Int const & third, int first, int second)
-    {
-        return power(first, second, third);
-    }
-
- These functions must be wrapped under the names "__rpow__" and - "__rrpow__" respectively: -
-    int_class.def((ternary_function2)&rpower,  "__rpow__");
-    int_class.def((ternary_function2)&rrpower,  "__rrpow__");
-
- Note that "__rrpow__" is an extension not present in plain Python. -

- Table of Numeric Operators -

-

- Py_cpp supports the - Python operators listed in the following table. Note that - comparison (__cmp__) and string conversion (__str__) operators are - included in the list, although they are not strictly "numeric". -

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Python Operator Name - - Python Expression - - C++ Operator Id - - C++ Expression Used For Automatic Wrapping
- with cpp_left = from_python(left, - type<Left>()),
- cpp_right = from_python(right, - type<Right>()),
- and cpp_oper = from_python(oper, type<Oper>()) -
- __add__, __radd__ - - left + right - - python::op_add - - cpp_left + cpp_right -
- __sub__, __rsub__ - - left - right - - python::op_sub - - cpp_left - cpp_right -
- __mul__, __rmul__ - - left * right - - python::op_mul - - cpp_left * cpp_right -
- __div__, __rdiv__ - - left / right - - python::op_div - - cpp_left / cpp_right -
- __mod__, __rmod__ - - left % right - - python::op_mod - - cpp_left % cpp_right -
- __divmod__, __rdivmod__ - - (quotient, remainder)
- = divmod(left, right)
-
- python::op_divmod - - cpp_left / cpp_right  and  cpp_left % - cpp_right -
- __pow__, __rpow__ - - pow(left, right)
- (binary power) -
- python::op_pow - - pow(cpp_left, cpp_right) -
- __pow__ - - pow(left, right, modulo)
- (ternary power modulo) -
- no automatic wrapping, special treatment - required -
- __lshift__, __rlshift__ - - left << right - - python::op_lshift - - cpp_left << cpp_right -
- __rshift__, __rrshift__ - - left >> right - - python::op_rshift - - cpp_left >> cpp_right -
- __and__, __rand__ - - left & right - - python::op_and - - cpp_left & cpp_right -
- __xor__, __rxor__ - - left ^ right - - python::op_xor - - cpp_left ^ cpp_right -
- __or__, __ror__ - - left | right - - python::op_or - - cpp_left | cpp_right -
- __cmp__, __rcmp__ - - cmp(left, right) (3-way compare)
- left < right
- left <= right
- left > right
- left >= right
- left == right
- left != right -
- python::op_cmp - - cpp_left < cpp_right  and  cpp_right < - cpp_left -
- __neg__ - - -oper  (unary negation) - - python::op_neg - - -cpp_oper -
- __pos__ - - +oper  (identity) - - python::op_pos - - +cpp_oper -
- __abs__ - - abs(oper)  (absolute value) - - python::op_abs - - abs(cpp_oper) -
- __invert__ - - ~oper  (bitwise inversion) - - python::op_invert - - ~cpp_oper -
- __int__ - - int(oper)  (integer conversion) - - python::op_int - - long(cpp_oper) -
- __long__ - - long(oper) 
- (infinite precision integer conversion) -
- python::op_long - - PyLong_FromLong(cpp_oper) -
- __float__ - - float(oper)  (float conversion) - - python::op_float - - double(cpp_oper) -
- __oct__ - - oct(oper)  (octal conversion) - - must be wrapped manually (wrapped function should return a string) -
- __hex__ - - hex(oper)  (hex conversion) - - must be wrapped manually (wrapped function should return a string) -
- __str__ - - str(oper)  (string conversion) - - python::op_str - - std::ostringstream s; s << oper; -
- __coerce__ - - coerce(left, right) - - usually defined automatically, otherwise - special treatment required -
- - + +A list of the possible operator names is also found in the table. +Special treatment is necessary to define the ternary pow. + + +

Coercion

+ + + So, for example, we can wrap a + std::map<std::size_t,std::string> as follows:

- Sequence and Mapping Operators + Example

- Sequence and mapping operators let wrapped objects behave in accordance - to Python's iteration and access protocols. These protocols differ - considerably from the ones found in C++. For example, Python's typically - iteration idiom looks like  "for i in S:" , while in C++ one - uses  "for(iterator i = S.begin(); i != S.end(); ++i)". One - could try to wrap C++ iterators in order to carry the C++ idiom into - Python. However, this does not work very well because (1) it leads to - non-uniform Python code (wrapped types must be used in a different way - than Python built-in types) and (2) iterators are often implemented as - plain C++ pointers which cannot be wrapped easily because py_cpp is - designed to handle objects only. -

- Thus, it is a good idea to provide sequence and mapping operators for - your wrapped containers. These operators have to be wrapped manually - because there are no corresponding C++ operators that could be used for - automatic wrapping. The Python documentation lists the relevant - container operators. In particular, expose __getitem__, __setitem__ - and remember to throw the PyExc_IndexError when the index - is out-of-range in order to enable the  "for i in S:"  - idiom. -

- Here is an example. Suppose, we want to wrap a - std::map<std::size_t,std::string>. This is done as follows - as follows:

 typedef std::map<std::size_t, std::string> StringMap;
@@ -606,8 +144,8 @@ void throw_key_error_if_end(
 {
     if (p == m.end())
     {
-        PyErr_SetObject(PyExc_KeyError, python::converters::to_python(key));
-        throw python::error_already_set();
+        PyErr_SetObject(PyExc_KeyError, py::converters::to_python(key));
+        throw py::ErrorAlreadySet();
     }
 }
 
@@ -636,8 +174,8 @@ void StringMapPythonClass::del_item(StringMap& self, std::size_t key)
     self.erase(p);
 }
 
-class_builder<StringMap> string_map(my_module, "StringMap");
-string_map.def(python::constructor<>());
+ClassWrapper<StringMap> string_map(my_module, "StringMap");
+string_map.def(py::Constructor<>());
 string_map.def(&StringMap::size, "__len__");
 string_map.def(get_item, "__getitem__");
 string_map.def(set_item, "__setitem__");
@@ -667,19 +205,9 @@ Traceback (innermost last):
 KeyError: 2
 >>> len(m)
 0
->>> m[0] = 'zero'
->>> m[1] = 'one'
->>> m[2] = 'two'
->>> m[3] = 'three'
+>>> m[3] = 'farther'
 >>> len(m)
-4
->>> for i in m:
-...    print i
-...
-zero
-one
-two
-three
+1
 

@@ -688,10 +216,10 @@ three

Py_cpp extension classes support some additional "special method" protocols not supported by built-in Python classes. Because writing - __getattr__, __setattr__, and - __delattr__ functions can be tedious in the common case where - the attributes being accessed are known statically, py_cpp checks the - special names + __getattr__, __setattr__, and + __delattr__ functions can be tedious in the common case + where the attributes being accessed are known statically, py_cpp checks + the special names

  • __getattr__<name>__ @@ -717,15 +245,15 @@ three 6 -

    +

    Direct Access to Data Members -

    +

Py_cpp uses the special __xxxattr__<name>__ functionality described above to allow direct access to data members through the following special - functions on class_builder<> and - extension_class<>: + functions on ClassWrapper<> and + ExtensionClass<>:

  • def_getter(pointer-to-member, name) // @@ -761,9 +289,9 @@ long second(const Pil& x) { return x.second; } my_module.def(first, "first"); my_module.def(second, "second"); -class_builder<Pil> pair_int_long(my_module, "Pair"); -pair_int_long.def(python::constructor<>()); -pair_int_long.def(python::constructor<int,long>()); +ClassWrapper<Pil> pair_int_long(my_module, "Pair"); +pair_int_long.def(py::Constructor<>()); +pair_int_long.def(py::Constructor<int,long>()); pair_int_long.def_read_write(&Pil::first, "first"); pair_int_long.def_read_write(&Pil::second, "second"); @@ -788,29 +316,184 @@ pair_int_long.def_read_write(&Pil::second, "second");

    - And what about __complex__? + Numeric Method Support

    - That, dear reader, is one problem we don't know how to solve. The - Python source contains the following fragment, indicating the - special-case code really is hardwired: -

    + Py_cpp supports the following + Python special numeric method names: +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Name + + Notes +
    + __add__(self, other) + + operator+(const T&, const T&) +
    + __sub__(self, other) + + operator-(const T&, const T&) +
    + __mul__(self, other) + + operator*(const T&, const T&) +
    + __div__(self, other) + + operator/(const T&, const T&) +
    + __mod__(self, other) + + operator%(const T&, const T&) +
    + __divmod__(self, other) + + return a py::Tuple initialized with + (quotient, + remainder). +
    + __pow__(self, other [, modulo]) + + use overloading to support both + forms of __pow__ +
    + __lshift__(self, other) + + operator<<(const T&, const T&) +
    + __rshift__(self, other) + + operator>>(const T&, const T&) +
    + __and__(self, other) + + operator&(const T&, const T&) +
    + __xor__(self, other) + + operator^(const T&, const T&) +
    + __or__(self, other) + + operator|(const T&, const T&) +
    + __neg__(self) + + operator-(const T&) (unary negation) +
    + __pos__(self) + + operator+(const T&) (identity) +
    + __abs__(self) + + Called to implement the built-in function abs() +
    + __invert__(self) + + operator~(const T&) +
    + __int__(self) + + operator long() const +
    + __long__(self) + + Should return a Python long object. Can be + implemented with PyLong_FromLong(value), + for example. +
    + __float__(self) + + operator double() const +
    + __oct__(self) + + Called to implement the built-in function oct(). Should return a + string value. +
    + __hex__(self) + + Called to implement the built-in function hex(). Should return a + string value. +
    + __coerce__(self, other) + + Should return a Python 2-tuple (C++ code may return a + py::Tuple) where the elements represent the values + of self and other converted to the + same type. +
    + +

    Where are the __r<name>__ +functions?

    + +

    + At first we thought that supporting __radd__ and its ilk would be + impossible, since Python doesn't supply any direct support and in fact + implements a special case for its built-in class instances. This + article gives a pretty good overview of the direct support for numerics + that Python supplies for extension types. We've since discovered that it can + be done, but there are some pretty convincing arguments + out there that this arrangement is less-than-ideal. Instead of supplying a + sub-optimal solution for the sake of compatibility with built-in Python + classes, we're doing the neccessary research so we can "do it right". This + will also give us a little time to hear from users about what they want. The + direction we're headed in is based on the idea of multimethods + rather than on trying to find a coercion function bound to one of the + arguments. + +

    And what about __complex__?

    +

    That, dear reader, is one problem we don't know how to solve. The Python + source contains the following fragment, indicating the special-case code really + is hardwired: +

     /* XXX Hack to support classes with __complex__ method */
     if (PyInstance_Check(r)) { ...
     
    -
    +

    - Previous: Inheritance Next: A Peek Under the Hood Up: Inheritance Next: A Peek Under the Hood Up: Top

    - © Copyright David Abrahams and Ullrich Köthe 2000. - Permission to copy, use, modify, sell and distribute this document is - granted provided this copyright notice appears in all copies. This - document is provided "as is" without express or implied warranty, and - with no claim as to its suitability for any purpose. + © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability + for any purpose.

    - Updated: Nov 21, 2000 + Updated: Oct 19, 2000

diff --git a/subclass.cpp b/subclass.cpp index ee28fd72..3598cb61 100644 --- a/subclass.cpp +++ b/subclass.cpp @@ -67,7 +67,7 @@ namespace { ref global_class_reduce() { - static ref result(detail::new_wrapped_function(class_reduce)); + static ref result(detail::new_wrapped_function(class_reduce, "__reduce__")); return result; } @@ -111,7 +111,7 @@ namespace { ref global_instance_reduce() { - static ref result(detail::new_wrapped_function(instance_reduce)); + static ref result(detail::new_wrapped_function(instance_reduce, "__reduce__")); return result; } } @@ -225,14 +225,21 @@ namespace detail { // Mostly copied wholesale from Python's classobject.c PyObject* class_base::repr() const + { + unsigned long address = reinterpret_cast(this); + string result = string("") % tuple(complete_class_name(), address); + return result.reference().release(); + } + + + // Mostly copied wholesale from Python's classobject.c + string class_base::complete_class_name() const { PyObject *mod = PyDict_GetItemString( m_name_space.get(), const_cast("__module__")); - unsigned long address = reinterpret_cast(this); - string result = (mod == NULL || !PyString_Check(mod)) - ? string("") % tuple(m_name, address) - : string("") % tuple(ref(mod, ref::increment_count), m_name, address); - return result.reference().release(); + return (mod == NULL || !PyString_Check(mod)) + ? m_name + : string("%s.%s") % tuple(ref(mod, ref::increment_count), m_name); } diff --git a/subclass.h b/subclass.h index a7679a95..714f0c5a 100644 --- a/subclass.h +++ b/subclass.h @@ -97,6 +97,9 @@ namespace detail { int setattr(const char* name, PyObject* value); PyObject* repr() const; void add_base(ref base); + + // get the complete class name (i.e. "module.class") + virtual string complete_class_name() const; protected: bool initialize_instance(instance* obj, PyObject* args, PyObject* keywords); diff --git a/test_extclass.py b/test_extclass.py index 578197f1..c321ac36 100644 --- a/test_extclass.py +++ b/test_extclass.py @@ -10,15 +10,18 @@ r''' Automatic checking of the number and type of arguments. Foo's constructor takes a single long parameter. - >>> ext = Foo() - Traceback (innermost last): - File "", line 1, in ? - TypeError: function requires exactly 1 argument; 0 given + >>> try: ext = Foo() + ... except TypeError, err: + ... assert re.match( + ... "'demo.Foo.__init__' expected argument\(s\) \(int\),\n" + ... "but got \(\) instead.", str(err)) + ... else: print 'no exception' >>> try: ext = Foo('foo') ... except TypeError, err: ... assert re.match( - ... '(illegal argument type for built-in operation)|(an integer is required)', str(err)) + ... "'demo.Foo.__init__' expected argument\(s\) \(int\),\n" + ... "but got \(string\) instead.", str(err)) ... else: print 'no exception' >>> ext = Foo(1) @@ -160,10 +163,16 @@ a Bar parameter: But objects not derived from Bar cannot: - >>> baz.pass_bar(baz) - Traceback (innermost last): - ... - TypeError: extension class 'Baz' is not convertible into 'Bar'. + >>> try: baz.pass_bar(baz) + ... except TypeError, err: + ... assert re.match( + ... "'pass_bar' expected argument\(s\) \(demo.Baz, demo.Bar\),\n" + ... "but got \(demo.Baz, demo.Baz\) instead.", str(err)) + ... else: print 'no exception' + +(this error was: +TypeError: extension class 'Baz' is not convertible into 'Bar'. +) The clone function on Baz returns a smart pointer; we wrap it into an extension_instance and make it look just like any other Baz obj. @@ -354,7 +363,11 @@ Some simple overloading tests: >>> try: r = Range('yikes') ... except TypeError, e: ... assert re.match( - ... 'No overloaded functions match [(]Range, string[)]\. Candidates are:\n.*\n.*', + ... "No variant of overloaded function 'demo.Range.__init__' matches argument\(s\):\n" + ... "\(string\)\n" + ... "Candidates are:\n" + ... "\(int\)\n" + ... "\(int, int\)", ... str(e)) ... else: print 'no exception' @@ -564,7 +577,17 @@ Testing overloaded free functions 15 >>> try: overloaded(1, 'foo') ... except TypeError, err: - ... assert re.match("No overloaded functions match \(int, string\)\. Candidates are:", + ... assert re.match( + ... "No variant of overloaded function 'overloaded' matches argument\(s\):\n" + ... "\(int, string\)\n" + ... "Candidates are:\n" + ... "\(\)\n" + ... "\(int\)\n" + ... "\(string\)\n" + ... "\(int, int\)\n" + ... "\(int, int, int\)\n" + ... "\(int, int, int, int\)\n" + ... "\(int, int, int, int, int\)", ... str(err)) ... else: ... print 'no exception' @@ -594,7 +617,17 @@ Testing overloaded constructors 5 >>> try: over = OverloadTest(1, 'foo') ... except TypeError, err: - ... assert re.match("No overloaded functions match \(OverloadTest, int, string\)\. Candidates are:", + ... assert re.match( + ... "No variant of overloaded function 'demo.OverloadTest.__init__' matches argument\(s\):\n" + ... "\(int, string\)\n" + ... "Candidates are:\n" + ... "\(\)\n" + ... "\(demo.OverloadTest\)\n" + ... "\(int\)\n" + ... "\(int, int\)\n" + ... "\(int, int, int\)\n" + ... "\(int, int, int, int\)\n" + ... "\(int, int, int, int, int\)", ... str(err)) ... else: ... print 'no exception' @@ -616,16 +649,35 @@ Testing overloaded methods 5 >>> try: over.overloaded(1,'foo') ... except TypeError, err: - ... assert re.match("No overloaded functions match \(OverloadTest, int, string\)\. Candidates are:", + ... assert re.match( + ... "No variant of overloaded function 'overloaded' matches argument\(s\):\n" + ... "\(demo.OverloadTest, int, string\)\n" + ... "Candidates are:\n" + ... "\(demo.OverloadTest\)\n" + ... "\(demo.OverloadTest, int\)\n" + ... "\(demo.OverloadTest, int, int\)\n" + ... "\(demo.OverloadTest, int, int, int\)\n" + ... "\(demo.OverloadTest, int, int, int, int\)\n" + ... "\(demo.OverloadTest, int, int, int, int, int\)", ... str(err)) ... else: ... print 'no exception' Testing base class conversions - >>> testUpcast(over) - Traceback (innermost last): - TypeError: extension class 'OverloadTest' is not convertible into 'Base'. + >>> try: testUpcast(over) + ... except TypeError, err: + ... assert re.match( + ... "'testUpcast' expected argument\(s\) \(demo.Base\),\n" + ... "but got \(demo.OverloadTest\) instead.", + ... str(err)) + ... else: + ... print 'no exception' + +(this error was: +TypeError: extension class 'OverloadTest' is not convertible into 'Base'. +) + >>> der1 = Derived1(333) >>> der1.x() 333 @@ -634,18 +686,37 @@ Testing base class conversions >>> der1 = derived1Factory(1000) >>> testDowncast1(der1) 1000 - >>> testDowncast2(der1) - Traceback (innermost last): + >>> try: testDowncast2(der1) + ... except TypeError, err: + ... assert re.match( + ... "'testDowncast2' expected argument\(s\) \(demo.Derived2\),\n" + ... "but got \(demo.Base\) instead.", + ... str(err)) + ... else: + ... print 'no exception' + +(this error was: TypeError: extension class 'Base' is not convertible into 'Derived2'. +) + >>> der2 = Derived2(444) >>> der2.x() 444 >>> testUpcast(der2) 444 >>> der2 = derived2Factory(1111) - >>> testDowncast2(der2) - Traceback (innermost last): + >>> try: testDowncast2(der2) + ... except TypeError, err: + ... assert re.match( + ... "'testDowncast2' expected argument\(s\) \(demo.Derived2\),\n" + ... "but got \(demo.Base\) instead.", + ... str(err)) + ... else: + ... print 'no exception' + +(this error was: TypeError: extension class 'Base' is not convertible into 'Derived2'. +) Testing interaction between callbacks, base declarations, and overloading - testCallback() calls callback() (within C++) @@ -656,10 +727,14 @@ Testing interaction between callbacks, base declarations, and overloading >>> c = CallbackTest() >>> c.testCallback(1) 2 - >>> c.testCallback('foo') - Traceback (innermost last): - File "", line 1, in ? - TypeError: illegal argument type for built-in operation + >>> try: c.testCallback('foo') + ... except TypeError, err: + ... assert re.match( + ... "'testCallback' expected argument\(s\) \(demo.CallbackTestBase, int\),\n" + ... "but got \(demo.CallbackTest, string\) instead.", + ... str(err)) + ... else: + ... print 'no exception' >>> c.callback(1) 2 >>> c.callback('foo') @@ -678,10 +753,14 @@ Testing interaction between callbacks, base declarations, and overloading -1 >>> r.callback('foo') 'foo 1' - >>> r.testCallback('foo') - Traceback (innermost last): - File "", line 1, in ? - TypeError: illegal argument type for built-in operation + >>> try: r.testCallback('foo') + ... except TypeError, err: + ... assert re.match( + ... "'testCallback' expected argument\(s\) \(demo.CallbackTestBase, int\),\n" + ... "but got \(demo.RedefineCallback, string\) instead.", + ... str(err)) + ... else: + ... print 'no exception' >>> r.testCallback(1) -1 >>> testCallback(r, 1) @@ -969,15 +1048,33 @@ test inheritB2 >>> j = pow(i, 5) >>> j.i() 32 - >>> j = pow(i, 5, k) - Traceback (innermost last): - TypeError: bad operand type(s) for pow() - >>> j = pow(i, 5, 5) - Traceback (innermost last): - TypeError: bad operand type(s) for pow() + >>> try: j = pow(i, 5, k) + ... except TypeError, err: + ... assert re.match( + ... "No variant of overloaded function '__pow__' matches argument\(s\):\n" + ... "\(demo.Int, int, demo.Int\)\n" + ... "Candidates are:\n" + ... "\(demo.Int, demo.Int\)\n" + ... "\(demo.Int, demo.Int, demo.Int\)\n" + ... "\(demo.Int, int\)", + ... str(err)) + ... else: + ... print 'no exception' + >>> try: j = pow(i, 5, 5) + ... except TypeError, err: + ... assert re.match( + ... "No variant of overloaded function '__pow__' matches argument\(s\):\n" + ... "\(demo.Int, int, int\)\n" + ... "Candidates are:\n" + ... "\(demo.Int, demo.Int\)\n" + ... "\(demo.Int, demo.Int, demo.Int\)\n" + ... "\(demo.Int, int\)", + ... str(err)) + ... else: + ... print 'no exception' >>> j = i/1 Traceback (innermost last): - TypeError: bad operand type(s) for / + TypeError: __div__(demo.Int, int) undefined. >>> j = 1+i >>> j.i() 3 @@ -993,10 +1090,10 @@ test inheritB2 -1 >>> j = 1/i Traceback (innermost last): - TypeError: bad operand type(s) for / + TypeError: __rdiv__(demo.Int, int) undefined. >>> pow(1,i) Traceback (innermost last): - TypeError: bad operand type(s) for pow() + TypeError: __rpow__(demo.Int, int) undefined. Test operator export to a subclass