]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
45 | py_function_impl_base::~py_function_impl_base() | |
46 | { | |
47 | } | |
48 | ||
49 | unsigned py_function_impl_base::max_arity() const | |
50 | { | |
51 | return this->min_arity(); | |
52 | } | |
53 | ||
54 | extern PyTypeObject function_type; | |
55 | ||
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 | { | |
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 | ||
119 | function::~function() | |
120 | { | |
121 | } | |
122 | ||
123 | 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 | } | |
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 | ||
240 | object 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 | ||
283 | object 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 | ||
292 | void 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 | ||
317 | void 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 | ||
331 | namespace | |
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(¬_implemented, mpl::vector1<void>(), 2) | |
404 | , python::detail::keyword_range()) | |
405 | ); | |
406 | return handle<function>(borrowed(downcast<function>(keeper.ptr()))); | |
407 | } | |
408 | } | |
409 | ||
410 | void 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 | ||
416 | namespace detail | |
417 | { | |
418 | extern char py_signature_tag[]; | |
419 | extern char cpp_signature_tag[]; | |
420 | } | |
421 | ||
422 | void 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 | ||
555 | BOOST_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 | ||
561 | BOOST_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 | ||
568 | namespace | |
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 | ||
592 | extern "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 | ||
684 | static 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 | ||
695 | PyTypeObject 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 | ||
746 | object 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 | ||
756 | object function_object(py_function const& f) | |
757 | { | |
758 | return function_object(f, python::detail::keyword_range()); | |
759 | } | |
760 | ||
761 | ||
762 | handle<> 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 | ||
771 | namespace 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 |