Skip to content

Commit af53ae8

Browse files
committed
Implemented better error reporting for argument match errors.
[SVN r19271]
1 parent 8f76b88 commit af53ae8

File tree

6 files changed

+104
-49
lines changed

6 files changed

+104
-49
lines changed

include/boost/python/detail/caller.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ struct caller_arity<N>
172172

173173
static unsigned min_arity() { return N; }
174174

175-
static char const*const* type_names()
175+
static signature_element const* signature()
176176
{
177-
return signature<Sig>::type_names();
177+
return detail::signature<Sig>::elements();
178178
}
179179

180180
private:

include/boost/python/object/class.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
# include <boost/python/detail/prefix.hpp>
1010
# include <boost/utility.hpp>
11-
# include <boost/python/instance_holder.hpp>
1211
# include <boost/python/object_core.hpp>
1312
# include <boost/python/type_id.hpp>
1413
# include <cstddef>

include/boost/python/object/py_function.hpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct BOOST_PYTHON_DECL py_function_impl_base
2424
virtual PyObject* operator()(PyObject*, PyObject*) = 0;
2525
virtual unsigned min_arity() const = 0;
2626
virtual unsigned max_arity() const;
27-
virtual char const* const* type_names() const = 0;
27+
virtual python::detail::signature_element const* signature() const = 0;
2828
};
2929

3030
template <class Caller>
@@ -44,9 +44,9 @@ struct caller_py_function_impl : py_function_impl_base
4444
return m_caller.min_arity();
4545
}
4646

47-
virtual char const* const* type_names() const
47+
virtual python::detail::signature_element const* signature() const
4848
{
49-
return m_caller.type_names();
49+
return m_caller.signature();
5050
}
5151

5252
private:
@@ -70,9 +70,9 @@ struct signature_py_function_impl : py_function_impl_base
7070
return mpl::size<Sig>::value - 1;
7171
}
7272

73-
virtual char const* const* type_names() const
73+
virtual python::detail::signature_element const* signature() const
7474
{
75-
return python::detail::signature<Sig>::type_names();
75+
return python::detail::signature<Sig>::elements();
7676
}
7777

7878
private:
@@ -103,9 +103,9 @@ struct full_py_function_impl : py_function_impl_base
103103
return m_max_arity;
104104
}
105105

106-
virtual char const* const* type_names() const
106+
virtual python::detail::signature_element const* signature() const
107107
{
108-
return python::detail::signature<Sig>::type_names();
108+
return python::detail::signature<Sig>::elements();
109109
}
110110

111111
private:
@@ -150,6 +150,11 @@ struct py_function
150150
return m_impl->max_arity();
151151
}
152152

153+
python::detail::signature_element const* signature() const
154+
{
155+
return m_impl->signature();
156+
}
157+
153158
private:
154159
mutable std::auto_ptr<py_function_impl_base> m_impl;
155160
};

src/object/function.cpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <boost/python/args.hpp>
1414
#include <boost/python/refcount.hpp>
1515
#include <boost/python/extract.hpp>
16+
#include <boost/python/tuple.hpp>
17+
#include <boost/python/list.hpp>
1618

1719
#include <boost/python/detail/signature.hpp>
1820
#include <boost/mpl/vector/vector10.hpp>
@@ -173,8 +175,53 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
173175

174176
void function::argument_error(PyObject* args, PyObject* keywords) const
175177
{
176-
// This function needs to be improved to do better error reporting.
177-
PyErr_BadArgument();
178+
static handle<> exception(
179+
PyErr_NewException("Boost.Python.ArgumentError", PyExc_TypeError, 0));
180+
181+
str message("Python argument types\n (");
182+
list actual;
183+
for (int i = 0; i < PyTuple_Size(args); ++i)
184+
{
185+
char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name;
186+
actual.append(str(name));
187+
}
188+
message += str(", ").join(actual);
189+
message += ")\ndid not match C++ signature:\n ";
190+
191+
list signatures;
192+
for (function const* f = this; f; f = f->m_overloads.get())
193+
{
194+
py_function const& impl = f->m_fn;
195+
196+
python::detail::signature_element const* s
197+
= impl.signature();
198+
199+
list formal;
200+
if (impl.max_arity() == 0)
201+
formal.append("void");
202+
203+
for (unsigned n = 1; n <= impl.max_arity(); ++n)
204+
{
205+
if (s[n].basename == 0)
206+
{
207+
formal.append("...");
208+
break;
209+
}
210+
211+
formal.append(
212+
str(s[n].basename) + (s[n].lvalue ? " {lvalue}" : "")
213+
);
214+
}
215+
216+
signatures.append(
217+
"(%s) -> %s" % make_tuple(str(", ").join(formal), s[0].basename)
218+
);
219+
}
220+
221+
message += str("\n ").join(signatures);
222+
223+
PyErr_SetObject(exception.get(), message.ptr());
224+
throw_error_already_set();
178225
}
179226

180227
void function::add_overload(handle<function> const& overload_)

test/opaque.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,5 @@ BOOST_PYTHON_MODULE(opaque_ext)
7373
bpl::def ("use2", &::use2);
7474
bpl::def ("failuse2", &::failuse2);
7575
}
76+
77+
# include "module_tail.cpp"

test/opaque.py

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@
77

88
"""
99
>>> from opaque_ext import *
10-
>>> #
11-
>>> # Check for correct conversion
10+
11+
12+
Check for correct conversion
13+
1214
>>> use(get())
1315
14-
# Check that None is converted to a NULL opaque pointer
16+
Check that None is converted to a NULL opaque pointer
17+
1518
>>> useany(get())
1619
1
1720
>>> useany(None)
1821
0
1922
20-
# check that we don't lose type information by converting NULL opaque
21-
# pointers to None
23+
Check that we don't lose type information by converting NULL
24+
opaque pointers to None
25+
2226
>>> assert getnull() is None
2327
>>> useany(getnull())
2428
0
@@ -27,43 +31,41 @@
2731
Traceback (most recent call last):
2832
...
2933
RuntimeError: success
30-
>>> #
31-
>>> # Check that there is no conversion from integers ...
32-
>>> use(0)
33-
Traceback (most recent call last):
34-
...
35-
TypeError: bad argument type for built-in operation
36-
>>> #
37-
>>> # ... and from strings to opaque objects
38-
>>> use("")
39-
Traceback (most recent call last):
40-
...
41-
TypeError: bad argument type for built-in operation
42-
>>> #
43-
>>> # Now check the same for another opaque pointer type
34+
35+
Check that there is no conversion from integers ...
36+
37+
>>> try: use(0)
38+
... except TypeError: pass
39+
... else: print 'expected a TypeError'
40+
41+
... and from strings to opaque objects
42+
43+
>>> try: use("")
44+
... except TypeError: pass
45+
... else: print 'expected a TypeError'
46+
47+
Now check the same for another opaque pointer type
48+
4449
>>> use2(get2())
4550
>>> failuse2(get2())
4651
Traceback (most recent call last):
4752
...
4853
RuntimeError: success
49-
>>> use2(0)
50-
Traceback (most recent call last):
51-
...
52-
TypeError: bad argument type for built-in operation
53-
>>> use2("")
54-
Traceback (most recent call last):
55-
...
56-
TypeError: bad argument type for built-in operation
57-
>>> #
58-
>>> # Check that opaque types are distinct
59-
>>> use(get2())
60-
Traceback (most recent call last):
61-
...
62-
TypeError: bad argument type for built-in operation
63-
>>> use2(get())
64-
Traceback (most recent call last):
65-
...
66-
TypeError: bad argument type for built-in operation
54+
>>> try: use2(0)
55+
... except TypeError: pass
56+
... else: print 'expected a TypeError'
57+
>>> try: use2("")
58+
... except TypeError: pass
59+
... else: print 'expected a TypeError'
60+
61+
Check that opaque types are distinct
62+
63+
>>> try: use(get2())
64+
... except TypeError: pass
65+
... else: print 'expected a TypeError'
66+
>>> try: use2(get())
67+
... except TypeError: pass
68+
... else: print 'expected a TypeError'
6769
"""
6870
def run(args = None):
6971
import sys

0 commit comments

Comments
 (0)