Skip to content

Commit bd0257c

Browse files
committed
Full docstring support
[SVN r14734]
1 parent 56e7b2a commit bd0257c

11 files changed

Lines changed: 211 additions & 45 deletions

File tree

include/boost/python/class.hpp

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
# include <boost/python/object/pickle_support.hpp>
2828
# include <boost/python/make_function.hpp>
2929
# include <boost/python/object/add_to_namespace.hpp>
30+
# include <boost/python/detail/def_helper.hpp>
3031

3132
namespace boost { namespace python {
3233

@@ -57,7 +58,7 @@ namespace detail
5758
template <class T, class Holder>
5859
static inline void register_copy_constructor(mpl::bool_t<false> const&, Holder*, object const&, T* = 0)
5960
{
60-
}
61+
}
6162
}
6263

6364
//
@@ -93,7 +94,7 @@ class class_ : public objects::class_base
9394
// Construct with the class name. [ Would have used a default
9495
// argument but gcc-2.95.2 choked on typeid(T).name() as a default
9596
// parameter value]
96-
class_(char const* name);
97+
class_(char const* name, char const* doc = 0);
9798

9899

99100
// Wrap a member function or a non-member function which can take
@@ -102,27 +103,25 @@ class class_ : public objects::class_base
102103
template <class F>
103104
self& def(char const* name, F f)
104105
{
105-
this->def_impl(name, f, 0, &f);
106+
this->def_impl(name, f, default_call_policies(), 0, &f);
106107
return *this;
107108
}
108109

109-
template <class Fn, class CallPolicy>
110-
self& def(char const* name, Fn fn, CallPolicy policy)
110+
template <class Fn, class CallPolicyOrDoc>
111+
self& def(char const* name, Fn fn, CallPolicyOrDoc const& policy_or_doc, char const* doc = 0)
111112
{
112-
return this->def(name
113-
, boost::python::make_function(
114-
// This bit of nastiness casts F to a member function of T if possible.
115-
detail::member_function_cast<T,Fn>::stage1(fn).stage2((T*)0).stage3(fn)
116-
, policy)
117-
);
113+
typedef detail::def_helper<CallPolicyOrDoc> helper;
114+
115+
this->def_impl(
116+
name, fn, helper::get_policy(policy_or_doc), helper::get_doc(policy_or_doc, doc), &fn);
117+
118+
return *this;
118119
}
119120

120121
template <detail::operator_id id, class L, class R>
121122
self& def(detail::operator_<id,L,R> const& op)
122123
{
123124
typedef detail::operator_<id,L,R> op_t;
124-
// Use function::add_to_namespace to achieve overloading if
125-
// appropriate.
126125
return this->def(op.name(), &op_t::template apply<T>::execute);
127126
}
128127

@@ -139,15 +138,19 @@ class class_ : public objects::class_base
139138
);
140139
}
141140

142-
template <class Args, class CallPolicy>
143-
self& def_init(Args const&, CallPolicy policy)
141+
template <class Args, class CallPolicyOrDoc>
142+
self& def_init(Args const&, CallPolicyOrDoc const& policy_or_doc, char const* doc = 0)
144143
{
145-
return this->def("__init__",
144+
typedef detail::def_helper<CallPolicyOrDoc> helper;
145+
146+
return this->def(
147+
"__init__",
146148
python::make_constructor<Args>(
147-
policy
149+
helper::get_policy(policy_or_doc)
148150
// Using runtime type selection works around a CWPro7 bug.
149151
, objects::select_holder<T,held_type>((held_type*)0).get()
150152
)
153+
, helper::get_doc(policy_or_doc, doc)
151154
);
152155
}
153156

@@ -201,22 +204,26 @@ class class_ : public objects::class_base
201204

202205
private: // helper functions
203206

204-
template <class F>
205-
inline void def_impl(char const* name, F const& f, char const* doc, ...)
207+
template <class Fn, class Policies>
208+
inline void def_impl(char const* name, Fn fn, Policies const& policies
209+
, char const* doc, ...)
206210
{
207211
objects::add_to_namespace(
208-
*this, name, make_function(
212+
*this, name,
213+
make_function(
209214
// This bit of nastiness casts F to a member function of T if possible.
210-
detail::member_function_cast<T,F>::stage1(f).stage2((T*)0).stage3(f))
215+
detail::member_function_cast<T,Fn>::stage1(fn).stage2((T*)0).stage3(fn)
216+
, policies)
211217
, doc);
212218
}
213219

214220
template <class F>
215-
inline void def_impl(char const* name, F const& f, char const* doc, object const volatile*)
221+
inline void def_impl(char const* name, F f, default_call_policies const&
222+
, char const* doc, object const*)
216223
{
217224
objects::add_to_namespace(*this, name, f, doc);
218225
}
219-
226+
220227
private: // types
221228
typedef objects::class_id class_id;
222229

@@ -266,8 +273,8 @@ inline class_<T,X1,X2,X3>::class_()
266273
}
267274

268275
template <class T, class X1, class X2, class X3>
269-
inline class_<T,X1,X2,X3>::class_(char const* name)
270-
: base(name, id_vector::size, id_vector().ids)
276+
inline class_<T,X1,X2,X3>::class_(char const* name, char const* doc)
277+
: base(name, id_vector::size, id_vector().ids, doc)
271278
{
272279
// register converters
273280
objects::register_class_from_python<T,bases>();

include/boost/python/detail/module_base.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class BOOST_PYTHON_DECL module_base
1515
{
1616
public:
1717
// Create a module. REQUIRES: only one module is created per module.
18-
module_base(const char* name);
18+
module_base(char const* name, char const* doc = 0);
1919
~module_base();
2020

2121
// Add elements to the module

include/boost/python/module.hpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# include <boost/python/detail/module_base.hpp>
1414
# include <boost/python/module_init.hpp>
1515
# include <boost/python/object_core.hpp>
16+
# include <boost/python/detail/def_helper.hpp>
1617

1718
namespace boost { namespace python {
1819

@@ -21,8 +22,8 @@ class module : public detail::module_base
2122
public:
2223
typedef detail::module_base base;
2324

24-
module(const char* name)
25-
: base(name) {}
25+
module(char const* name, char const* doc = 0)
26+
: base(name, doc) {}
2627

2728
// Add elements to the module
2829
template <class T>
@@ -42,17 +43,22 @@ class module : public detail::module_base
4243
}
4344

4445
template <class Fn>
45-
module& def(char const* name, Fn fn, char const* doc = 0)
46+
module& def(char const* name, Fn fn)
4647
{
47-
this->setattr_doc(name, boost::python::make_function(fn), doc);
48+
this->setattr_doc(
49+
name, boost::python::make_function(fn), 0);
50+
4851
return *this;
4952
}
50-
51-
52-
template <class Fn, class ResultHandler>
53-
module& def(char const* name, Fn fn, ResultHandler handler, char const* doc = 0)
53+
template <class Fn, class CallPolicyOrDoc>
54+
module& def(char const* name, Fn fn, CallPolicyOrDoc const& policy_or_doc, char const* doc = 0)
5455
{
55-
this->setattr_doc(name, boost::python::make_function(fn, handler), doc);
56+
typedef detail::def_helper<CallPolicyOrDoc> helper;
57+
58+
this->setattr_doc(
59+
name, boost::python::make_function(fn, helper::get_policy(policy_or_doc)),
60+
helper::get_doc(policy_or_doc, doc));
61+
5662
return *this;
5763
}
5864
};

include/boost/python/object/class.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct BOOST_PYTHON_DECL class_base : python::api::object
3333
, std::size_t num_types // A list of class_ids. The first is the type
3434
, class_id const*const types // this is wrapping. The rest are the types of
3535
// any bases.
36+
, char const* doc = 0 // Docstring, if any.
3637
);
3738

3839
// Retrieve the underlying object

include/boost/python/object/function.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ struct BOOST_PYTHON_DECL function : PyObject
3434
object const& doc() const;
3535
void doc(object const& x);
3636

37+
object const& name() const;
38+
3739
private: // helper functions
3840
void argument_error(PyObject* args, PyObject* keywords) const;
3941
void add_overload(handle<function> const&);
@@ -43,6 +45,7 @@ struct BOOST_PYTHON_DECL function : PyObject
4345
unsigned m_min_args;
4446
unsigned m_max_args;
4547
handle<function> m_overloads;
48+
object m_name;
4649
object m_doc;
4750
};
4851

@@ -59,6 +62,11 @@ inline void function::doc(object const& x)
5962
this->m_doc = x;
6063
}
6164

65+
inline object const& function::name() const
66+
{
67+
return this->m_name;
68+
}
69+
6270
}}} // namespace boost::python::objects
6371

6472
#endif // FUNCTION_DWA20011214_HPP

src/module.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616

1717
namespace boost { namespace python { namespace detail {
1818

19-
module_base::module_base(const char* name)
19+
module_base::module_base(char const* name, char const* doc)
2020
: m_module(
2121
allow_null(python::borrowed(
2222
scope().ptr()
2323
)))
2424
{
25+
if (doc != 0)
26+
scope().attr("__doc__") = doc;
2527
}
2628

2729
module_base::~module_base()

src/object/class.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ namespace objects
279279
}
280280

281281
class_base::class_base(
282-
char const* name, std::size_t num_types, class_id const* const types)
282+
char const* name, std::size_t num_types, class_id const* const types, char const* doc)
283283
: object(new_class(name, num_types, types))
284284
{
285285
// Insert the new class object in the registry
@@ -288,6 +288,9 @@ namespace objects
288288

289289
// Class object is leaked, for now
290290
converters.class_object = (PyTypeObject*)incref(this->ptr());
291+
292+
if (doc)
293+
this->attr("__doc__") = doc;
291294
}
292295

293296
extern "C"

src/object/function.cpp

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ function::function(py_function const& implementation, unsigned min_args, unsigne
2424
, m_max_args(std::max(max_args,min_args))
2525
{
2626
PyObject* p = this;
27+
::PyType_Ready(&function_type);
2728
PyObject_INIT(p, &function_type);
2829
}
2930

@@ -162,6 +163,7 @@ void function::add_to_namespace(
162163

163164
if (attribute.ptr()->ob_type == &function_type)
164165
{
166+
function* new_func = downcast<function>(attribute.ptr());
165167
PyObject* dict = 0;
166168

167169
if (PyClass_Check(ns))
@@ -180,17 +182,24 @@ void function::add_to_namespace(
180182
allow_null(downcast<function>(::PyObject_GetItem(dict, name.ptr())))
181183
);
182184

183-
if (existing.get())
185+
if (existing)
184186
{
185187
if (existing->ob_type == &function_type)
186-
static_cast<function*>(attribute.ptr())->add_overload(existing);
188+
new_func->add_overload(existing);
187189
}
188-
// Binary operators need an additional overload which returns NotImplemented
189190
else if (is_binary_operator(name_))
190191
{
191-
static_cast<function*>(attribute.ptr())->add_overload(
192-
not_implemented_function());
192+
// Binary operators need an additional overload which
193+
// returns NotImplemented, so that Python will try the
194+
// lxxx functions on the other operand. We add this
195+
// overload already when no overloads for the operator
196+
// already exist.
197+
new_func->add_overload(not_implemented_function());
193198
}
199+
200+
// A function is named the first time it is added to a namespace.
201+
if (new_func->name().ptr() == Py_None)
202+
new_func->m_name = name;
194203
}
195204

196205
// The PyObject_GetAttrString() call above left an active error
@@ -259,21 +268,38 @@ extern "C"
259268
return result;
260269
}
261270

271+
//
272+
// Here we're using the function's tp_getset rather than its
273+
// tp_members to set up __doc__ and __name__, because tp_members
274+
// really depends on having a POD object type (it relies on
275+
// offsets). It might make sense to reformulate function as a POD
276+
// at some point, but this is much more expedient.
277+
//
262278
static PyObject* function_get_doc(PyObject* op, void*)
263279
{
264280
function* f = downcast<function>(op);
265-
return incref(f->doc().ptr());
281+
return python::incref(f->doc().ptr());
266282
}
267283

268-
static int function_set_doc(PyObject* op, PyObject* doc)
284+
static int function_set_doc(PyObject* op, PyObject* doc, void*)
269285
{
270286
function* f = downcast<function>(op);
271287
f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object());
272288
return 0;
273289
}
274290

291+
static PyObject* function_get_name(PyObject* op, void*)
292+
{
293+
function* f = downcast<function>(op);
294+
if (f->name().ptr() == Py_None)
295+
return PyString_InternFromString("<unnamed Boost.Python function>");
296+
else
297+
return python::incref(f->name().ptr());
298+
}
299+
275300
static PyGetSetDef function_getsetlist[] = {
276-
{"__doc__", function_get_doc, (setter)function_set_doc},
301+
{"__name__", function_get_name, 0 },
302+
{"__doc__", function_get_doc, function_set_doc},
277303
{NULL} /* Sentinel */
278304
};
279305
}

test/Jamfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ rule bpl-test ( name ? : files * )
5555
}
5656

5757
bpl-test minimal ;
58+
bpl-test docstring ;
5859
bpl-test pearu1 : test_cltree.py cltree.cpp ;
5960
bpl-test try : newtest.py m1.cpp m2.cpp ;
6061
bpl-test builtin_converters : test_builtin_converters.py test_builtin_converters.cpp ;

0 commit comments

Comments
 (0)