Skip to content

Commit 96a7bce

Browse files
committed
Give feedback about the name and namespace of functions in error messages.
[SVN r19280]
1 parent c1e1ea6 commit 96a7bce

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

include/boost/python/object/function.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct BOOST_PYTHON_DECL function : PyObject
4848
py_function m_fn;
4949
handle<function> m_overloads;
5050
object m_name;
51+
object m_namespace;
5152
object m_doc;
5253
object m_arg_names;
5354
};

src/object/function.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <algorithm>
2525
#include <cstring>
2626

27+
#include <stdio.h>
28+
2729
namespace boost { namespace python { namespace objects {
2830

2931
py_function_impl_base::~py_function_impl_base()
@@ -177,8 +179,10 @@ void function::argument_error(PyObject* args, PyObject* keywords) const
177179
{
178180
static handle<> exception(
179181
PyErr_NewException("Boost.Python.ArgumentError", PyExc_TypeError, 0));
182+
183+
object message = "Python argument types in\n %s.%s("
184+
% make_tuple(this->m_namespace, this->m_name);
180185

181-
str message("Python argument types\n (");
182186
list actual;
183187
for (int i = 0; i < PyTuple_Size(args); ++i)
184188
{
@@ -214,12 +218,13 @@ void function::argument_error(PyObject* args, PyObject* keywords) const
214218
}
215219

216220
signatures.append(
217-
"(%s) -> %s" % make_tuple(str(", ").join(formal), s[0].basename)
221+
"%s(%s) -> %s" % make_tuple(f->m_name, str(", ").join(formal), s[0].basename)
218222
);
219223
}
220224

221225
message += str("\n ").join(signatures);
222226

227+
printf("\n--------\n%s\n--------\n", extract<const char*>(message)());
223228
PyErr_SetObject(exception.get(), message.ptr());
224229
throw_error_already_set();
225230
}
@@ -338,17 +343,19 @@ void function::add_to_namespace(
338343
if (dict == 0)
339344
throw_error_already_set();
340345

341-
// This isn't quite typesafe. We'll shoot first by assuming
342-
// the thing is a function*, then ask questions later. The code works nicer that way.
343-
handle<function> existing(
344-
allow_null(downcast<function>(::PyObject_GetItem(dict, name.ptr())))
345-
);
346+
handle<> existing(allow_null(::PyObject_GetItem(dict, name.ptr())));
346347

347348
if (existing)
348349
{
349350
if (existing->ob_type == &function_type)
350351
{
351-
new_func->add_overload(existing);
352+
new_func->add_overload(
353+
handle<function>(
354+
borrowed(
355+
downcast<function>(existing.get())
356+
)
357+
)
358+
);
352359
}
353360
else if (existing->ob_type == &PyStaticMethod_Type)
354361
{
@@ -376,9 +383,16 @@ void function::add_to_namespace(
376383
// A function is named the first time it is added to a namespace.
377384
if (new_func->name().ptr() == Py_None)
378385
new_func->m_name = name;
386+
387+
handle<> name_space_name(
388+
allow_null(::PyObject_GetAttrString(name_space.ptr(), "__name__")));
389+
390+
if (name_space_name)
391+
new_func->m_namespace = object(name_space_name);
379392
}
380393

381-
// The PyObject_GetAttrString() call above left an active error
394+
// The PyObject_GetAttrString() or PyObject_GetItem calls above may
395+
// have left an active error
382396
PyErr_Clear();
383397
if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0)
384398
throw_error_already_set();
@@ -489,7 +503,9 @@ extern "C"
489503

490504
static PyGetSetDef function_getsetlist[] = {
491505
{"__name__", (getter)function_get_name, 0 },
506+
{"func_name", (getter)function_get_name, 0 },
492507
{"__doc__", (getter)function_get_doc, (setter)function_set_doc},
508+
{"func_doc", (getter)function_get_doc, (setter)function_set_doc},
493509
{NULL} /* Sentinel */
494510
};
495511

0 commit comments

Comments
 (0)