]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/python/src/object/function.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / python / src / object / function.cpp
CommitLineData
7c673cae
FG
1// Copyright David Abrahams 2001.
2// Distributed under the Boost Software License, Version 1.0. (See
3// accompanying file LICENSE_1_0.txt or copy at
4// http://www.boost.org/LICENSE_1_0.txt)
5
6#include <boost/python/docstring_options.hpp>
7#include <boost/python/object/function_object.hpp>
8#include <boost/python/object/function_handle.hpp>
9#include <boost/python/object/function_doc_signature.hpp>
10#include <boost/python/errors.hpp>
11#include <boost/python/str.hpp>
12#include <boost/python/object_attributes.hpp>
13#include <boost/python/args.hpp>
14#include <boost/python/refcount.hpp>
15#include <boost/python/extract.hpp>
16#include <boost/python/tuple.hpp>
17#include <boost/python/list.hpp>
18#include <boost/python/ssize_t.hpp>
19
20#include <boost/python/detail/signature.hpp>
21#include <boost/python/detail/none.hpp>
22#include <boost/mpl/vector/vector10.hpp>
23
1e59de90 24#include <boost/bind/bind.hpp>
7c673cae
FG
25
26#include <algorithm>
27#include <cstring>
28
29#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES
30# include <cstdio>
31#endif
32
33namespace boost { namespace python {
34 volatile bool docstring_options::show_user_defined_ = true;
35 volatile bool docstring_options::show_cpp_signatures_ = true;
36#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
37 volatile bool docstring_options::show_py_signatures_ = true;
38#else
39 volatile bool docstring_options::show_py_signatures_ = false;
40#endif
41}}
42
43namespace boost { namespace python { namespace objects {
44
45py_function_impl_base::~py_function_impl_base()
46{
47}
48
49unsigned py_function_impl_base::max_arity() const
50{
51 return this->min_arity();
52}
53
54extern PyTypeObject function_type;
55
56function::function(
57 py_function const& implementation
58#if BOOST_WORKAROUND(__EDG_VERSION__, == 245)
59 , python::detail::keyword const* names_and_defaults
60#else
61 , python::detail::keyword const* const names_and_defaults
62#endif
63 , unsigned num_keywords
64 )
65 : m_fn(implementation)
66 , m_nkeyword_values(0)
67{
68 if (names_and_defaults != 0)
69 {
70 unsigned int max_arity = m_fn.max_arity();
71 unsigned int keyword_offset
72 = max_arity > num_keywords ? max_arity - num_keywords : 0;
73
74
75 ssize_t tuple_size = num_keywords ? max_arity : 0;
76 m_arg_names = object(handle<>(PyTuple_New(tuple_size)));
77
78 if (num_keywords != 0)
79 {
80 for (unsigned j = 0; j < keyword_offset; ++j)
81 PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None));
82 }
83
84 for (unsigned i = 0; i < num_keywords; ++i)
85 {
86 tuple kv;
87
88 python::detail::keyword const* const p = names_and_defaults + i;
89 if (p->default_value)
90 {
91 kv = make_tuple(p->name, p->default_value);
92 ++m_nkeyword_values;
93 }
94 else
95 {
96 kv = make_tuple(p->name);
97 }
98
99 PyTuple_SET_ITEM(
100 m_arg_names.ptr()
101 , i + keyword_offset
102 , incref(kv.ptr())
103 );
104 }
105 }
106
107 PyObject* p = this;
108 if (Py_TYPE(&function_type) == 0)
109 {
1e59de90 110 Py_SET_TYPE(&function_type, &PyType_Type);
7c673cae
FG
111 ::PyType_Ready(&function_type);
112 }
113
114 (void)( // warning suppression for GCC
115 PyObject_INIT(p, &function_type)
116 );
117}
118
119function::~function()
120{
121}
122
123PyObject* function::call(PyObject* args, PyObject* keywords) const
124{
125 std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args);
126 std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0;
127 std::size_t n_actual = n_unnamed_actual + n_keyword_actual;
128
129 function const* f = this;
130
131 // Try overloads looking for a match
132 do
133 {
134 // Check for a plausible number of arguments
135 unsigned min_arity = f->m_fn.min_arity();
136 unsigned max_arity = f->m_fn.max_arity();
137
138 if (n_actual + f->m_nkeyword_values >= min_arity
139 && n_actual <= max_arity)
140 {
141 // This will be the args that actually get passed
142 handle<>inner_args(allow_null(borrowed(args)));
143
144 if (n_keyword_actual > 0 // Keyword arguments were supplied
145 || n_actual < min_arity) // or default keyword values are needed
146 {
147 if (f->m_arg_names.is_none())
148 {
149 // this overload doesn't accept keywords
150 inner_args = handle<>();
151 }
152 else
153 {
154 // "all keywords are none" is a special case
155 // indicating we will accept any number of keyword
156 // arguments
157 if (PyTuple_Size(f->m_arg_names.ptr()) == 0)
158 {
159 // no argument preprocessing
160 }
7c673cae
FG
161 else
162 {
163 // build a new arg tuple, will adjust its size later
164 assert(max_arity <= static_cast<std::size_t>(ssize_t_max));
165 inner_args = handle<>(
166 PyTuple_New(static_cast<ssize_t>(max_arity)));
167
168 // Fill in the positional arguments
169 for (std::size_t i = 0; i < n_unnamed_actual; ++i)
170 PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i)));
171
172 // Grab remaining arguments by name from the keyword dictionary
173 std::size_t n_actual_processed = n_unnamed_actual;
174
175 for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos)
176 {
177 // Get the keyword[, value pair] corresponding
178 PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos);
179
180 // If there were any keyword arguments,
181 // look up the one we need for this
182 // argument position
183 PyObject* value = n_keyword_actual
184 ? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0))
185 : 0;
186
187 if (!value)
188 {
189 // Not found; check if there's a default value
190 if (PyTuple_GET_SIZE(kv) > 1)
191 value = PyTuple_GET_ITEM(kv, 1);
192
193 if (!value)
194 {
195 // still not found; matching fails
196 PyErr_Clear();
197 inner_args = handle<>();
198 break;
199 }
200 }
201 else
202 {
203 ++n_actual_processed;
204 }
205
206 PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value));
207 }
208
209 if (inner_args.get())
210 {
211 //check if we proccessed all the arguments
212 if(n_actual_processed < n_actual)
213 inner_args = handle<>();
214 }
215 }
216 }
217 }
218
219 // Call the function. Pass keywords in case it's a
220 // function accepting any number of keywords
221 PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0;
222
223 // If the result is NULL but no error was set, m_fn failed
224 // the argument-matching test.
225
226 // This assumes that all other error-reporters are
227 // well-behaved and never return NULL to python without
228 // setting an error.
229 if (result != 0 || PyErr_Occurred())
230 return result;
231 }
232 f = f->m_overloads.get();
233 }
234 while (f);
235 // None of the overloads matched; time to generate the error message
236 argument_error(args, keywords);
237 return 0;
238}
239
240object function::signature(bool show_return_type) const
241{
242 py_function const& impl = m_fn;
243
244 python::detail::signature_element const* return_type = impl.signature();
245 python::detail::signature_element const* s = return_type + 1;
246
247 list formal_params;
248 if (impl.max_arity() == 0)
249 formal_params.append("void");
250
251 for (unsigned n = 0; n < impl.max_arity(); ++n)
252 {
253 if (s[n].basename == 0)
254 {
255 formal_params.append("...");
256 break;
257 }
258
259 str param(s[n].basename);
260 if (s[n].lvalue)
261 param += " {lvalue}";
262
263 if (m_arg_names) // None or empty tuple will test false
264 {
265 object kv(m_arg_names[n]);
266 if (kv)
267 {
268 char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s";
269 param += fmt % kv;
270 }
271 }
272
273 formal_params.append(param);
274 }
275
276 if (show_return_type)
277 return "%s(%s) -> %s" % make_tuple(
278 m_name, str(", ").join(formal_params), return_type->basename);
279 return "%s(%s)" % make_tuple(
280 m_name, str(", ").join(formal_params));
281}
282
283object function::signatures(bool show_return_type) const
284{
285 list result;
286 for (function const* f = this; f; f = f->m_overloads.get()) {
287 result.append(f->signature(show_return_type));
288 }
289 return result;
290}
291
292void function::argument_error(PyObject* args, PyObject* /*keywords*/) const
293{
294 static handle<> exception(
295 PyErr_NewException(const_cast<char*>("Boost.Python.ArgumentError"), PyExc_TypeError, 0));
296
297 object message = "Python argument types in\n %s.%s("
298 % make_tuple(this->m_namespace, this->m_name);
299
300 list actual_args;
301 for (ssize_t i = 0; i < PyTuple_Size(args); ++i)
302 {
303 char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name;
304 actual_args.append(str(name));
305 }
306 message += str(", ").join(actual_args);
307 message += ")\ndid not match C++ signature:\n ";
308 message += str("\n ").join(signatures());
309
310#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES
311 std::printf("\n--------\n%s\n--------\n", extract<const char*>(message)());
312#endif
313 PyErr_SetObject(exception.get(), message.ptr());
314 throw_error_already_set();
315}
316
317void function::add_overload(handle<function> const& overload_)
318{
319 function* parent = this;
320
321 while (parent->m_overloads)
322 parent = parent->m_overloads.get();
323
324 parent->m_overloads = overload_;
325
326 // If we have no documentation, get the docs from the overload
327 if (!m_doc)
328 m_doc = overload_->m_doc;
329}
330
331namespace
332{
333 char const* const binary_operator_names[] =
334 {
335 "add__",
336 "and__",
337 "div__",
338 "divmod__",
339 "eq__",
340 "floordiv__",
341 "ge__",
342 "gt__",
343 "le__",
344 "lshift__",
345 "lt__",
346 "mod__",
347 "mul__",
348 "ne__",
349 "or__",
350 "pow__",
351 "radd__",
352 "rand__",
353 "rdiv__",
354 "rdivmod__",
355 "rfloordiv__",
356 "rlshift__",
357 "rmod__",
358 "rmul__",
359 "ror__",
360 "rpow__",
361 "rrshift__",
362 "rshift__",
363 "rsub__",
364 "rtruediv__",
365 "rxor__",
366 "sub__",
367 "truediv__",
368 "xor__"
369 };
370
371 struct less_cstring
372 {
373 bool operator()(char const* x, char const* y) const
374 {
375 return BOOST_CSTD_::strcmp(x,y) < 0;
376 }
377 };
378
379 inline bool is_binary_operator(char const* name)
380 {
381 return name[0] == '_'
382 && name[1] == '_'
383 && std::binary_search(
384 &binary_operator_names[0]
385 , binary_operator_names + sizeof(binary_operator_names)/sizeof(*binary_operator_names)
386 , name + 2
387 , less_cstring()
388 );
389 }
390
391 // Something for the end of the chain of binary operators
392 PyObject* not_implemented(PyObject*, PyObject*)
393 {
394 Py_INCREF(Py_NotImplemented);
395 return Py_NotImplemented;
396 }
397
398 handle<function> not_implemented_function()
399 {
400
401 static object keeper(
402 function_object(
403 py_function(&not_implemented, mpl::vector1<void>(), 2)
404 , python::detail::keyword_range())
405 );
406 return handle<function>(borrowed(downcast<function>(keeper.ptr())));
407 }
408}
409
410void function::add_to_namespace(
411 object const& name_space, char const* name_, object const& attribute)
412{
413 add_to_namespace(name_space, name_, attribute, 0);
414}
415
416namespace detail
417{
418 extern char py_signature_tag[];
419 extern char cpp_signature_tag[];
420}
421
422void function::add_to_namespace(
423 object const& name_space, char const* name_, object const& attribute, char const* doc)
424{
425 str const name(name_);
426 PyObject* const ns = name_space.ptr();
427
428 if (attribute.ptr()->ob_type == &function_type)
429 {
430 function* new_func = downcast<function>(attribute.ptr());
431 handle<> dict;
432
433#if PY_VERSION_HEX < 0x03000000
434 // Old-style class gone in Python 3
435 if (PyClass_Check(ns))
436 dict = handle<>(borrowed(((PyClassObject*)ns)->cl_dict));
437 else
438#endif
439 if (PyType_Check(ns))
440 dict = handle<>(borrowed(((PyTypeObject*)ns)->tp_dict));
441 else
442 dict = handle<>(PyObject_GetAttrString(ns, const_cast<char*>("__dict__")));
443
444 if (dict == 0)
445 throw_error_already_set();
446
92f5a8d4 447 assert(!PyErr_Occurred());
7c673cae 448 handle<> existing(allow_null(::PyObject_GetItem(dict.get(), name.ptr())));
92f5a8d4 449 PyErr_Clear();
7c673cae
FG
450
451 if (existing)
452 {
453 if (existing->ob_type == &function_type)
454 {
455 new_func->add_overload(
456 handle<function>(
457 borrowed(
458 downcast<function>(existing.get())
459 )
460 )
461 );
462 }
463 else if (existing->ob_type == &PyStaticMethod_Type)
464 {
465 char const* name_space_name = extract<char const*>(name_space.attr("__name__"));
466
467 ::PyErr_Format(
468 PyExc_RuntimeError
469 , "Boost.Python - All overloads must be exported "
470 "before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'"
471 , name_space_name
472 , name_
473 );
474 throw_error_already_set();
475 }
476 }
477 else if (is_binary_operator(name_))
478 {
479 // Binary operators need an additional overload which
480 // returns NotImplemented, so that Python will try the
481 // __rxxx__ functions on the other operand. We add this
482 // when no overloads for the operator already exist.
483 new_func->add_overload(not_implemented_function());
484 }
485
486 // A function is named the first time it is added to a namespace.
487 if (new_func->name().is_none())
488 new_func->m_name = name;
489
92f5a8d4 490 assert(!PyErr_Occurred());
7c673cae
FG
491 handle<> name_space_name(
492 allow_null(::PyObject_GetAttrString(name_space.ptr(), const_cast<char*>("__name__"))));
92f5a8d4 493 PyErr_Clear();
7c673cae
FG
494
495 if (name_space_name)
496 new_func->m_namespace = object(name_space_name);
497 }
498
7c673cae
FG
499 if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0)
500 throw_error_already_set();
501
502 object mutable_attribute(attribute);
503/*
504 if (doc != 0 && docstring_options::show_user_defined_)
505 {
506 // Accumulate documentation
507
508 if (
509 PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__")
510 && mutable_attribute.attr("__doc__"))
511 {
512 mutable_attribute.attr("__doc__") += "\n\n";
513 mutable_attribute.attr("__doc__") += doc;
514 }
515 else {
516 mutable_attribute.attr("__doc__") = doc;
517 }
518 }
519
520 if (docstring_options::show_signatures_)
521 {
522 if ( PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__")
523 && mutable_attribute.attr("__doc__")) {
524 mutable_attribute.attr("__doc__") += (
525 mutable_attribute.attr("__doc__")[-1] != "\n" ? "\n\n" : "\n");
526 }
527 else {
528 mutable_attribute.attr("__doc__") = "";
529 }
530 function* f = downcast<function>(attribute.ptr());
531 mutable_attribute.attr("__doc__") += str("\n ").join(make_tuple(
532 "C++ signature:", f->signature(true)));
533 }
534 */
535 str _doc;
536
537 if (docstring_options::show_py_signatures_)
538 {
539 _doc += str(const_cast<const char*>(detail::py_signature_tag));
540 }
541 if (doc != 0 && docstring_options::show_user_defined_)
542 _doc += doc;
543
544 if (docstring_options::show_cpp_signatures_)
545 {
546 _doc += str(const_cast<const char*>(detail::cpp_signature_tag));
547 }
548 if(_doc)
549 {
550 object mutable_attribute(attribute);
551 mutable_attribute.attr("__doc__")= _doc;
552 }
553}
554
555BOOST_PYTHON_DECL void add_to_namespace(
556 object const& name_space, char const* name, object const& attribute)
557{
558 function::add_to_namespace(name_space, name, attribute, 0);
559}
560
561BOOST_PYTHON_DECL void add_to_namespace(
562 object const& name_space, char const* name, object const& attribute, char const* doc)
563{
564 function::add_to_namespace(name_space, name, attribute, doc);
565}
566
567
568namespace
569{
570 struct bind_return
571 {
572 bind_return(PyObject*& result, function const* f, PyObject* args, PyObject* keywords)
573 : m_result(result)
574 , m_f(f)
575 , m_args(args)
576 , m_keywords(keywords)
577 {}
578
579 void operator()() const
580 {
581 m_result = m_f->call(m_args, m_keywords);
582 }
583
584 private:
585 PyObject*& m_result;
586 function const* m_f;
587 PyObject* m_args;
588 PyObject* m_keywords;
589 };
590}
591
592extern "C"
593{
594 // Stolen from Python's funcobject.c
595 static PyObject *
596 function_descr_get(PyObject *func, PyObject *obj, PyObject *type_)
597 {
598#if PY_VERSION_HEX >= 0x03000000
599 // The implement is different in Python 3 because of the removal of unbound method
600 if (obj == Py_None || obj == NULL) {
601 Py_INCREF(func);
602 return func;
603 }
604 return PyMethod_New(func, obj);
605#else
606 if (obj == Py_None)
607 obj = NULL;
608 return PyMethod_New(func, obj, type_);
609#endif
610 }
611
612 static void
613 function_dealloc(PyObject* p)
614 {
615 delete static_cast<function*>(p);
616 }
617
618 static PyObject *
619 function_call(PyObject *func, PyObject *args, PyObject *kw)
620 {
621 PyObject* result = 0;
622 handle_exception(bind_return(result, static_cast<function*>(func), args, kw));
623 return result;
624 }
625
626 //
627 // Here we're using the function's tp_getset rather than its
628 // tp_members to set up __doc__ and __name__, because tp_members
629 // really depends on having a POD object type (it relies on
630 // offsets). It might make sense to reformulate function as a POD
631 // at some point, but this is much more expedient.
632 //
633 static PyObject* function_get_doc(PyObject* op, void*)
634 {
635 function* f = downcast<function>(op);
636 list signatures = function_doc_signature_generator::function_doc_signatures(f);
637 if(!signatures) return python::detail::none();
638 signatures.reverse();
639 return python::incref( str("\n").join(signatures).ptr());
640 }
641
642 static int function_set_doc(PyObject* op, PyObject* doc, void*)
643 {
644 function* f = downcast<function>(op);
645 f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object());
646 return 0;
647 }
648
649 static PyObject* function_get_name(PyObject* op, void*)
650 {
651 function* f = downcast<function>(op);
652 if (f->name().is_none())
653#if PY_VERSION_HEX >= 0x03000000
654 return PyUnicode_InternFromString("<unnamed Boost.Python function>");
655#else
656 return PyString_InternFromString("<unnamed Boost.Python function>");
657#endif
658 else
659 return python::incref(f->name().ptr());
660 }
661
662 // We add a dummy __class__ attribute in order to fool PyDoc into
663 // treating these as built-in functions and scanning their
664 // documentation
665 static PyObject* function_get_class(PyObject* /*op*/, void*)
666 {
667 return python::incref(upcast<PyObject>(&PyCFunction_Type));
668 }
669
670 static PyObject* function_get_module(PyObject* op, void*)
671 {
672 function* f = downcast<function>(op);
673 object const& ns = f->get_namespace();
674 if (!ns.is_none()) {
675 return python::incref(ns.ptr());
676 }
677 PyErr_SetString(
678 PyExc_AttributeError, const_cast<char*>(
679 "Boost.Python function __module__ unknown."));
680 return 0;
681 }
682}
683
684static PyGetSetDef function_getsetlist[] = {
685 {const_cast<char*>("__name__"), (getter)function_get_name, 0, 0, 0 },
686 {const_cast<char*>("func_name"), (getter)function_get_name, 0, 0, 0 },
687 {const_cast<char*>("__module__"), (getter)function_get_module, 0, 0, 0 },
688 {const_cast<char*>("func_module"), (getter)function_get_module, 0, 0, 0 },
689 {const_cast<char*>("__class__"), (getter)function_get_class, 0, 0, 0 }, // see note above
690 {const_cast<char*>("__doc__"), (getter)function_get_doc, (setter)function_set_doc, 0, 0},
691 {const_cast<char*>("func_doc"), (getter)function_get_doc, (setter)function_set_doc, 0, 0},
692 {NULL, 0, 0, 0, 0} /* Sentinel */
693};
694
695PyTypeObject function_type = {
696 PyVarObject_HEAD_INIT(NULL, 0)
697 const_cast<char*>("Boost.Python.function"),
698 sizeof(function),
699 0,
700 (destructor)function_dealloc, /* tp_dealloc */
701 0, /* tp_print */
702 0, /* tp_getattr */
703 0, /* tp_setattr */
704 0, /* tp_compare */
705 0, //(reprfunc)func_repr, /* tp_repr */
706 0, /* tp_as_number */
707 0, /* tp_as_sequence */
708 0, /* tp_as_mapping */
709 0, /* tp_hash */
710 function_call, /* tp_call */
711 0, /* tp_str */
712 0, // PyObject_GenericGetAttr, /* tp_getattro */
713 0, // PyObject_GenericSetAttr, /* tp_setattro */
714 0, /* tp_as_buffer */
715 Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */
716 0, /* tp_doc */
717 0, // (traverseproc)func_traverse, /* tp_traverse */
718 0, /* tp_clear */
719 0, /* tp_richcompare */
720 0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
721 0, /* tp_iter */
722 0, /* tp_iternext */
723 0, /* tp_methods */
724 0, // func_memberlist, /* tp_members */
725 function_getsetlist, /* tp_getset */
726 0, /* tp_base */
727 0, /* tp_dict */
728 function_descr_get, /* tp_descr_get */
729 0, /* tp_descr_set */
730 0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */
731 0, /* tp_init */
732 0, /* tp_alloc */
733 0, /* tp_new */
734 0, /* tp_free */
735 0, /* tp_is_gc */
736 0, /* tp_bases */
737 0, /* tp_mro */
738 0, /* tp_cache */
739 0, /* tp_subclasses */
740 0, /* tp_weaklist */
741#if PYTHON_API_VERSION >= 1012
742 0 /* tp_del */
743#endif
744};
745
746object function_object(
747 py_function const& f
748 , python::detail::keyword_range const& keywords)
749{
750 return python::object(
751 python::detail::new_non_null_reference(
752 new function(
753 f, keywords.first, keywords.second - keywords.first)));
754}
755
756object function_object(py_function const& f)
757{
758 return function_object(f, python::detail::keyword_range());
759}
760
761
762handle<> function_handle_impl(py_function const& f)
763{
764 return python::handle<>(
765 allow_null(
766 new function(f, 0, 0)));
767}
768
769} // namespace objects
770
771namespace detail
772{
773 object BOOST_PYTHON_DECL make_raw_function(objects::py_function f)
774 {
775 static keyword k;
776
777 return objects::function_object(
778 f
779 , keyword_range(&k,&k));
780 }
781 void BOOST_PYTHON_DECL pure_virtual_called()
782 {
783 PyErr_SetString(
784 PyExc_RuntimeError, const_cast<char*>("Pure virtual function called"));
785 throw_error_already_set();
786 }
787}
788
789}} // namespace boost::python