From af53ae83297deaf607505bfd5a57529a92d9ffce Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 23 Jul 2003 01:31:34 +0000 Subject: [PATCH] Implemented better error reporting for argument match errors. [SVN r19271] --- include/boost/python/detail/caller.hpp | 4 +- include/boost/python/object/class.hpp | 1 - include/boost/python/object/py_function.hpp | 19 ++++-- src/object/function.cpp | 51 +++++++++++++- test/opaque.cpp | 2 + test/opaque.py | 76 +++++++++++---------- 6 files changed, 104 insertions(+), 49 deletions(-) diff --git a/include/boost/python/detail/caller.hpp b/include/boost/python/detail/caller.hpp index 392c0bee..14fe9c57 100644 --- a/include/boost/python/detail/caller.hpp +++ b/include/boost/python/detail/caller.hpp @@ -172,9 +172,9 @@ struct caller_arity static unsigned min_arity() { return N; } - static char const*const* type_names() + static signature_element const* signature() { - return signature::type_names(); + return detail::signature::elements(); } private: diff --git a/include/boost/python/object/class.hpp b/include/boost/python/object/class.hpp index 6584b9d6..2417ed4a 100644 --- a/include/boost/python/object/class.hpp +++ b/include/boost/python/object/class.hpp @@ -8,7 +8,6 @@ # include # include -# include # include # include # include diff --git a/include/boost/python/object/py_function.hpp b/include/boost/python/object/py_function.hpp index 610f5b30..fe3bde37 100644 --- a/include/boost/python/object/py_function.hpp +++ b/include/boost/python/object/py_function.hpp @@ -24,7 +24,7 @@ struct BOOST_PYTHON_DECL py_function_impl_base virtual PyObject* operator()(PyObject*, PyObject*) = 0; virtual unsigned min_arity() const = 0; virtual unsigned max_arity() const; - virtual char const* const* type_names() const = 0; + virtual python::detail::signature_element const* signature() const = 0; }; template @@ -44,9 +44,9 @@ struct caller_py_function_impl : py_function_impl_base return m_caller.min_arity(); } - virtual char const* const* type_names() const + virtual python::detail::signature_element const* signature() const { - return m_caller.type_names(); + return m_caller.signature(); } private: @@ -70,9 +70,9 @@ struct signature_py_function_impl : py_function_impl_base return mpl::size::value - 1; } - virtual char const* const* type_names() const + virtual python::detail::signature_element const* signature() const { - return python::detail::signature::type_names(); + return python::detail::signature::elements(); } private: @@ -103,9 +103,9 @@ struct full_py_function_impl : py_function_impl_base return m_max_arity; } - virtual char const* const* type_names() const + virtual python::detail::signature_element const* signature() const { - return python::detail::signature::type_names(); + return python::detail::signature::elements(); } private: @@ -150,6 +150,11 @@ struct py_function return m_impl->max_arity(); } + python::detail::signature_element const* signature() const + { + return m_impl->signature(); + } + private: mutable std::auto_ptr m_impl; }; diff --git a/src/object/function.cpp b/src/object/function.cpp index d9f333a8..a5eb1c3a 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -173,8 +175,53 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const void function::argument_error(PyObject* args, PyObject* keywords) const { - // This function needs to be improved to do better error reporting. - PyErr_BadArgument(); + static handle<> exception( + PyErr_NewException("Boost.Python.ArgumentError", PyExc_TypeError, 0)); + + str message("Python argument types\n ("); + list actual; + for (int i = 0; i < PyTuple_Size(args); ++i) + { + char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name; + actual.append(str(name)); + } + message += str(", ").join(actual); + message += ")\ndid not match C++ signature:\n "; + + list signatures; + for (function const* f = this; f; f = f->m_overloads.get()) + { + py_function const& impl = f->m_fn; + + python::detail::signature_element const* s + = impl.signature(); + + list formal; + if (impl.max_arity() == 0) + formal.append("void"); + + for (unsigned n = 1; n <= impl.max_arity(); ++n) + { + if (s[n].basename == 0) + { + formal.append("..."); + break; + } + + formal.append( + str(s[n].basename) + (s[n].lvalue ? " {lvalue}" : "") + ); + } + + signatures.append( + "(%s) -> %s" % make_tuple(str(", ").join(formal), s[0].basename) + ); + } + + message += str("\n ").join(signatures); + + PyErr_SetObject(exception.get(), message.ptr()); + throw_error_already_set(); } void function::add_overload(handle const& overload_) diff --git a/test/opaque.cpp b/test/opaque.cpp index d5de0a21..cb92e9cd 100644 --- a/test/opaque.cpp +++ b/test/opaque.cpp @@ -73,3 +73,5 @@ BOOST_PYTHON_MODULE(opaque_ext) bpl::def ("use2", &::use2); bpl::def ("failuse2", &::failuse2); } + +# include "module_tail.cpp" diff --git a/test/opaque.py b/test/opaque.py index a8073669..96d23d8a 100644 --- a/test/opaque.py +++ b/test/opaque.py @@ -7,18 +7,22 @@ """ >>> from opaque_ext import * ->>> # ->>> # Check for correct conversion + + + Check for correct conversion + >>> use(get()) -# Check that None is converted to a NULL opaque pointer + Check that None is converted to a NULL opaque pointer + >>> useany(get()) 1 >>> useany(None) 0 -# check that we don't lose type information by converting NULL opaque -# pointers to None + Check that we don't lose type information by converting NULL + opaque pointers to None + >>> assert getnull() is None >>> useany(getnull()) 0 @@ -27,43 +31,41 @@ Traceback (most recent call last): ... RuntimeError: success ->>> # ->>> # Check that there is no conversion from integers ... ->>> use(0) -Traceback (most recent call last): - ... -TypeError: bad argument type for built-in operation ->>> # ->>> # ... and from strings to opaque objects ->>> use("") -Traceback (most recent call last): - ... -TypeError: bad argument type for built-in operation ->>> # ->>> # Now check the same for another opaque pointer type + + Check that there is no conversion from integers ... + +>>> try: use(0) +... except TypeError: pass +... else: print 'expected a TypeError' + + ... and from strings to opaque objects + +>>> try: use("") +... except TypeError: pass +... else: print 'expected a TypeError' + + Now check the same for another opaque pointer type + >>> use2(get2()) >>> failuse2(get2()) Traceback (most recent call last): ... RuntimeError: success ->>> use2(0) -Traceback (most recent call last): - ... -TypeError: bad argument type for built-in operation ->>> use2("") -Traceback (most recent call last): - ... -TypeError: bad argument type for built-in operation ->>> # ->>> # Check that opaque types are distinct ->>> use(get2()) -Traceback (most recent call last): - ... -TypeError: bad argument type for built-in operation ->>> use2(get()) -Traceback (most recent call last): - ... -TypeError: bad argument type for built-in operation +>>> try: use2(0) +... except TypeError: pass +... else: print 'expected a TypeError' +>>> try: use2("") +... except TypeError: pass +... else: print 'expected a TypeError' + + Check that opaque types are distinct + +>>> try: use(get2()) +... except TypeError: pass +... else: print 'expected a TypeError' +>>> try: use2(get()) +... except TypeError: pass +... else: print 'expected a TypeError' """ def run(args = None): import sys