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