mirror of
https://github.com/boostorg/python.git
synced 2026-01-24 18:12:43 +00:00
first attempt to implement docstrings with nice signatures
[SVN r22675]
This commit is contained in:
39
include/boost/python/converter/python_type.hpp
Executable file
39
include/boost/python/converter/python_type.hpp
Executable file
@@ -0,0 +1,39 @@
|
||||
#ifndef BOOST_PYTHON_OBJECT_PYTHON_TYPE_H
|
||||
#define BOOST_PYTHON_OBJECT_PYTHON_TYPE_H
|
||||
|
||||
#include <boost/python/converter/registered.hpp>
|
||||
|
||||
namespace boost {namespace python {namespace converter{
|
||||
namespace detail{
|
||||
inline void * identity (PyObject *p){return p;}
|
||||
namespace strip_type_info{
|
||||
BOOST_PYTHON_DECL void insert(boost::python::type_info, boost::python::type_info);
|
||||
BOOST_PYTHON_DECL type_info query(boost::python::type_info);
|
||||
}
|
||||
|
||||
}// namespace converter::detail
|
||||
|
||||
|
||||
template <class T> struct python_class : PyObject
|
||||
{
|
||||
typedef python_class<T> this_type;
|
||||
typedef T type;
|
||||
static void register_()
|
||||
{
|
||||
static bool first_time = true;
|
||||
|
||||
if ( !first_time ) return;
|
||||
first_time = false;
|
||||
converter::registry::insert(&detail::identity, boost::python::type_id<this_type>());
|
||||
converter::detail::strip_type_info::insert(boost::python::type_id<type>(), boost::python::type_id<type*>());
|
||||
converter::detail::strip_type_info::insert(boost::python::type_id<type>(), boost::python::type_id<type const *>());
|
||||
converter::detail::strip_type_info::insert(boost::python::type_id<type>(), boost::python::type_id<this_type*>());
|
||||
}
|
||||
private:
|
||||
python_class();
|
||||
};
|
||||
|
||||
|
||||
}}} //namespace boost :: python :: converter
|
||||
|
||||
#endif //BOOST_PYTHON_OBJECT_PYTHON_TYPE_H
|
||||
@@ -58,6 +58,7 @@ namespace
|
||||
, &slot_rvalue_from_python<T,SlotPolicy>::construct
|
||||
, type_id<T>()
|
||||
);
|
||||
const_cast<registration*>(registry::query(type_id<T>()))->m_class_object = SlotPolicy::get_class_object();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -94,6 +95,7 @@ namespace
|
||||
return (PyInt_Check(obj) || PyLong_Check(obj))
|
||||
? &number_methods->nb_int : 0;
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -129,6 +131,7 @@ namespace
|
||||
return (PyInt_Check(obj) || PyLong_Check(obj))
|
||||
? &py_object_identity : 0;
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -167,6 +170,7 @@ namespace
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
struct long_long_rvalue_from_python : long_long_rvalue_from_python_base
|
||||
@@ -222,6 +226,7 @@ namespace
|
||||
{
|
||||
return PyObject_IsTrue(intermediate);
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
// A SlotPolicy for extracting floating types from Python objects.
|
||||
@@ -253,6 +258,7 @@ namespace
|
||||
return PyFloat_AS_DOUBLE(intermediate);
|
||||
}
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyFloat_Type;}
|
||||
};
|
||||
|
||||
// A SlotPolicy for extracting C++ strings from Python objects.
|
||||
@@ -270,6 +276,7 @@ namespace
|
||||
{
|
||||
return std::string(PyString_AsString(intermediate),PyString_Size(intermediate));
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyString_Type;}
|
||||
};
|
||||
|
||||
// encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc
|
||||
@@ -308,6 +315,8 @@ namespace
|
||||
throw_error_already_set();
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyTypeObject * get_class_object() { return &PyUnicode_Type;}
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -404,6 +413,7 @@ void initialize_builtin_converters()
|
||||
|
||||
// Add an lvalue converter for char which gets us char const*
|
||||
registry::insert(convert_to_cstring,type_id<char>());
|
||||
const_cast<registration&>(registry::lookup(type_id<char const*>())).m_class_object = &PyString_Type;
|
||||
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
// Register by-value converters to std::string, std::wstring
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
#include <boost/python/converter/registry.hpp>
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
#include <boost/python/converter/builtin_converters.hpp>
|
||||
#include <boost/python/converter/python_type.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
@@ -243,4 +245,74 @@ namespace registry
|
||||
}
|
||||
} // namespace registry
|
||||
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace strip_type_info{
|
||||
struct type_info_map : std::map<boost::python::type_info, boost::python::type_info>
|
||||
{
|
||||
type_info_map(){
|
||||
(*this)[boost::python::type_id<bool*>()] = boost::python::type_id<bool>();
|
||||
(*this)[boost::python::type_id<bool const*>()] = boost::python::type_id<bool>();
|
||||
|
||||
(*this)[boost::python::type_id<char*>()] = boost::python::type_id<char>();
|
||||
(*this)[boost::python::type_id<unsigned char*>()] = boost::python::type_id<unsigned char>();
|
||||
|
||||
(*this)[boost::python::type_id<short*>()] = boost::python::type_id<short>();
|
||||
(*this)[boost::python::type_id<short const*>()] = boost::python::type_id<short>();
|
||||
(*this)[boost::python::type_id<unsigned short*>()] = boost::python::type_id<unsigned short>();
|
||||
(*this)[boost::python::type_id<unsigned short const*>()] = boost::python::type_id<unsigned short>();
|
||||
|
||||
(*this)[boost::python::type_id<int*>()] = boost::python::type_id<int>();
|
||||
(*this)[boost::python::type_id<int const*>()] = boost::python::type_id<int>();
|
||||
(*this)[boost::python::type_id<unsigned int*>()] = boost::python::type_id<unsigned int>();
|
||||
(*this)[boost::python::type_id<unsigned int const*>()] = boost::python::type_id<unsigned int>();
|
||||
|
||||
(*this)[boost::python::type_id<long*>()] = boost::python::type_id<long>();
|
||||
(*this)[boost::python::type_id<long const*>()] = boost::python::type_id<long>();
|
||||
(*this)[boost::python::type_id<unsigned long*>()] = boost::python::type_id<unsigned long>();
|
||||
(*this)[boost::python::type_id<unsigned long const*>()] = boost::python::type_id<unsigned long>();
|
||||
|
||||
(*this)[boost::python::type_id<long double*>()] = boost::python::type_id<long double>();
|
||||
(*this)[boost::python::type_id<long double const*>()] = boost::python::type_id<long double>();
|
||||
|
||||
(*this)[boost::python::type_id<double*>()] = boost::python::type_id<double>();
|
||||
(*this)[boost::python::type_id<double const*>()] = boost::python::type_id<double>();
|
||||
|
||||
(*this)[boost::python::type_id<float*>()] = boost::python::type_id<float>();
|
||||
(*this)[boost::python::type_id<float const*>()] = boost::python::type_id<float>();
|
||||
|
||||
(*this)[boost::python::type_id<std::string*>()] = boost::python::type_id<std::string>();
|
||||
(*this)[boost::python::type_id<std::string const*>()] = boost::python::type_id<std::string>();
|
||||
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
(*this)[boost::python::type_id<std::wstring*>()] = boost::python::type_id<std::wstring>();
|
||||
(*this)[boost::python::type_id<std::wstring const*>()] = boost::python::type_id<std::wstring>();
|
||||
# endif
|
||||
}
|
||||
};
|
||||
|
||||
static std::map<boost::python::type_info, boost::python::type_info> &type_info_remap_registry()
|
||||
{
|
||||
static type_info_map res;
|
||||
return res;
|
||||
}
|
||||
BOOST_PYTHON_DECL void insert(boost::python::type_info t, boost::python::type_info pt)
|
||||
{
|
||||
if(t==pt)
|
||||
return;
|
||||
type_info_remap_registry()[pt] = t;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL type_info query(boost::python::type_info pt)
|
||||
{
|
||||
std::map<boost::python::type_info, boost::python::type_info> :: iterator i
|
||||
= type_info_remap_registry().find(pt);
|
||||
return i == type_info_remap_registry().end()? pt : (*i).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::python::converter
|
||||
|
||||
@@ -167,5 +167,14 @@ list dict_base::values() const
|
||||
return assume_list(this->attr("values")());
|
||||
}
|
||||
}
|
||||
static struct register_dict_pytype_ptr
|
||||
{
|
||||
register_dict_pytype_ptr()
|
||||
{
|
||||
const_cast<converter::registration &>(
|
||||
converter::registry::lookup(boost::python::type_id<boost::python::dict>())
|
||||
).m_class_object = &PyDict_Type;
|
||||
}
|
||||
}register_dict_pytype_ptr_;
|
||||
|
||||
}}} // namespace boost::python
|
||||
|
||||
12
src/list.cpp
12
src/list.cpp
@@ -4,6 +4,8 @@
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
#include <boost/python/list.hpp>
|
||||
#include <boost/python/converter/registry.hpp>
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
|
||||
@@ -136,5 +138,13 @@ long list_base::count(object_cref value) const
|
||||
throw_error_already_set();
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct register_list_pytype_ptr
|
||||
{
|
||||
register_list_pytype_ptr()
|
||||
{
|
||||
const_cast<converter::registration &>(
|
||||
converter::registry::lookup(boost::python::type_id<boost::python::list>())
|
||||
).m_class_object = &PyList_Type;
|
||||
}
|
||||
}register_list_pytype_ptr_;
|
||||
}}} // namespace boost::python
|
||||
|
||||
@@ -613,14 +613,15 @@ namespace objects
|
||||
|
||||
namespace
|
||||
{
|
||||
PyObject* callable_check(PyObject* callable)
|
||||
PyObject* callable_check(PyObject* callable, const char *name)
|
||||
{
|
||||
if (PyCallable_Check(expect_non_null(callable)))
|
||||
return callable;
|
||||
|
||||
::PyErr_Format(
|
||||
PyExc_TypeError
|
||||
, "staticmethod expects callable object; got an object of type %s, which is not callable"
|
||||
, "staticmethod expects callable object; got an object \"%s\" of type %s, which is not callable"
|
||||
, name
|
||||
, callable->ob_type->tp_name
|
||||
);
|
||||
|
||||
@@ -638,7 +639,7 @@ namespace objects
|
||||
|
||||
this->attr(method_name) = object(
|
||||
handle<>(
|
||||
PyStaticMethod_New((callable_check)(method.ptr()) )
|
||||
PyStaticMethod_New((callable_check)(method.ptr(), method_name) )
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <boost/python/tuple.hpp>
|
||||
#include <boost/python/list.hpp>
|
||||
|
||||
#include <boost/python/converter/python_type.hpp>
|
||||
|
||||
#include <boost/python/detail/api_placeholder.hpp>
|
||||
#include <boost/python/detail/signature.hpp>
|
||||
#include <boost/mpl/vector/vector10.hpp>
|
||||
@@ -24,6 +26,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES
|
||||
# include <cstdio>
|
||||
@@ -226,6 +229,269 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline function const * function::overloads() const
|
||||
{
|
||||
return this->m_overloads.get();
|
||||
}
|
||||
|
||||
|
||||
class function_signature_generator{
|
||||
public:
|
||||
static bool arity_cmp( function const *f1, function const *f2 )
|
||||
{
|
||||
return f1->m_fn.max_arity() < f2->m_fn.max_arity();
|
||||
}
|
||||
|
||||
static bool are_seq_overloads( function const *f1, function const *f2 , bool check_docs)
|
||||
{
|
||||
py_function const & impl1 = f1->m_fn;
|
||||
py_function const & impl2 = f2->m_fn;
|
||||
|
||||
//the number of parameters differs by 1
|
||||
if (impl2.max_arity()-impl1.max_arity() != 1)
|
||||
return false;
|
||||
|
||||
// if check docs then f1 shold not have docstring or have the same docstring as f2
|
||||
if (check_docs && f2->doc() != f1->doc() && f1->doc())
|
||||
return false;
|
||||
|
||||
python::detail::signature_element const* s1 = impl1.signature();
|
||||
python::detail::signature_element const* s2 = impl2.signature();
|
||||
|
||||
size_t size = impl1.max_arity();
|
||||
|
||||
for (size_t i = 0; i != size; ++i)
|
||||
{
|
||||
//check if the argument types are the same
|
||||
if (s1[i].basename() != s2[i].basename())
|
||||
return false;
|
||||
|
||||
//return type
|
||||
if (!i) continue;
|
||||
|
||||
//check if the argument default values are the same
|
||||
if (f1->m_arg_names && f2->m_arg_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1]
|
||||
|| bool( f1->m_arg_names ) != bool( f2->m_arg_names
|
||||
))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<function const*> flatten(function const *f)
|
||||
{
|
||||
object name = f->name();
|
||||
|
||||
std::vector<function const*> res;
|
||||
|
||||
while (f) {
|
||||
|
||||
//this if takes out the not_implemented_function
|
||||
if (f->name() == name)
|
||||
res.push_back(f);
|
||||
|
||||
f=f->overloads();
|
||||
}
|
||||
|
||||
std::sort(res.begin(),res.end(), &arity_cmp);
|
||||
|
||||
return res;
|
||||
}
|
||||
static std::vector<function const*> split_seq_overloads( const std::vector<function const *> &funcs, bool split_on_doc_change)
|
||||
{
|
||||
std::vector<function const*> res;
|
||||
|
||||
std::vector<function const*>::const_iterator fi = funcs.begin();
|
||||
|
||||
function const * last = *fi;
|
||||
|
||||
while (++fi != funcs.end()){
|
||||
|
||||
//check if fi starts a new chain of overloads
|
||||
if (!are_seq_overloads( last, *fi, split_on_doc_change ))
|
||||
res.push_back(last);
|
||||
|
||||
last = *fi;
|
||||
}
|
||||
|
||||
if (last)
|
||||
res.push_back(last);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static object raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types = false)
|
||||
{
|
||||
str res("object");
|
||||
|
||||
res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char * py_type_str(const python::detail::signature_element &s)
|
||||
{
|
||||
if (s.basename()==std::string("void")){
|
||||
static const char * none = "None";
|
||||
return none;
|
||||
}
|
||||
const converter::registration *r=0;
|
||||
|
||||
if ( (r = converter::registry::query(s.tid) ) && r->m_class_object)
|
||||
return r->m_class_object->tp_name;
|
||||
else if ( (r = converter::registry::query(converter::detail::strip_type_info::query(s.tid) ) ) && r->m_class_object )
|
||||
return r->m_class_object->tp_name;
|
||||
else{
|
||||
static const char * object = "object";
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static object parameter_string(const python::detail::signature_element *s, size_t n, object arg_names, bool cpp_types)
|
||||
{
|
||||
str param;
|
||||
|
||||
if (cpp_types)
|
||||
{
|
||||
if (s[n].basename() == 0)
|
||||
{
|
||||
return str("...");
|
||||
}
|
||||
|
||||
param = str(s[n].tid.name());
|
||||
|
||||
if (s[n].lvalue)
|
||||
param += " {lvalue}";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n) //we are processing an argument and trying to come up with a name for it
|
||||
{
|
||||
object kv;
|
||||
if ( arg_names && (kv = arg_names[n-1]) )
|
||||
param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) );
|
||||
else
|
||||
param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) );
|
||||
}
|
||||
else //we are processing the return type - how should we handle it???
|
||||
param = py_type_str(s[n]);
|
||||
}
|
||||
|
||||
//an argument - check for default value and append it
|
||||
if(n && arg_names)
|
||||
{
|
||||
object kv(arg_names[n-1]);
|
||||
if (kv && len(kv) == 2)
|
||||
{
|
||||
param = str("%s=%r" % make_tuple(param, kv[1]));
|
||||
}
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
static object pretty_signature(function const *f, size_t n_overloads, bool cpp_types = false)
|
||||
{
|
||||
py_function
|
||||
const& impl = f->m_fn;
|
||||
;
|
||||
|
||||
python::detail::signature_element
|
||||
const* s = impl.signature()
|
||||
;
|
||||
|
||||
size_t arity = impl.max_arity();
|
||||
|
||||
if(arity == size_t(-1))// is this the proper raw function test?
|
||||
{
|
||||
return raw_function_pretty_signature(f,n_overloads,cpp_types);
|
||||
}
|
||||
|
||||
list formal_params;
|
||||
|
||||
size_t n_extra_default_args=0;
|
||||
|
||||
for (unsigned n = 0; n <= arity; ++n)
|
||||
{
|
||||
str param;
|
||||
|
||||
formal_params.append(
|
||||
parameter_string(s, n, f->m_arg_names, cpp_types)
|
||||
);
|
||||
|
||||
// find all the arguments with default values preceeding the arity-n_overloads
|
||||
if (n && f->m_arg_names)
|
||||
{
|
||||
object kv(f->m_arg_names[n-1]);
|
||||
|
||||
if (kv && len(kv) == 2)
|
||||
{
|
||||
//default argument preceeding the arity-n_overloads
|
||||
if( n <= arity-n_overloads)
|
||||
++n_extra_default_args;
|
||||
}
|
||||
else
|
||||
//argument without default, preceeding the arity-n_overloads
|
||||
if( n <= arity-n_overloads)
|
||||
n_extra_default_args = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arity && cpp_types)
|
||||
formal_params.append("void");
|
||||
|
||||
str ret_type (formal_params.pop(0));
|
||||
if ( !cpp_types )
|
||||
ret_type = str("-> "+ret_type);
|
||||
|
||||
n_overloads+=n_extra_default_args;
|
||||
|
||||
return str(
|
||||
"%s %s(%s%s%s%s) %s"
|
||||
% make_tuple
|
||||
( cpp_types?ret_type:str("")
|
||||
, f->m_name
|
||||
, str(",").join(formal_params.slice(0,arity-n_overloads))
|
||||
, n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str()
|
||||
, str(" [,").join(formal_params.slice(arity-n_overloads,arity))
|
||||
, std::string(n_overloads,']')
|
||||
, cpp_types?str(""):ret_type
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
static list function_signatures( function const * f, bool cpp_types, bool docs)
|
||||
{
|
||||
list signatures;
|
||||
std::vector<function const*> funcs = function_signature_generator::flatten( f);
|
||||
std::vector<function const*> split_funcs = function_signature_generator::split_seq_overloads( funcs, docs);
|
||||
std::vector<function const*>::const_iterator sfi=split_funcs.begin(), fi;
|
||||
size_t n_overloads=0;
|
||||
for (fi=funcs.begin(); fi!=funcs.end(); ++fi)
|
||||
{
|
||||
if(*sfi == *fi){
|
||||
signatures.append(
|
||||
(*fi)->doc() && docs
|
||||
? function_signature_generator::pretty_signature(*fi, n_overloads,cpp_types)+ " : " +(*fi)->doc()
|
||||
: function_signature_generator::pretty_signature(*fi, n_overloads,cpp_types)
|
||||
);
|
||||
++sfi;
|
||||
n_overloads = 0;
|
||||
}else
|
||||
++n_overloads ;
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
object function::pretty_signature(bool cpp_types, size_t n_optional_trailing_args )const
|
||||
{
|
||||
function const *f = this;
|
||||
return function_signature_generator::pretty_signature(this, n_optional_trailing_args, cpp_types);
|
||||
|
||||
}
|
||||
|
||||
void function::argument_error(PyObject* args, PyObject* keywords) const
|
||||
{
|
||||
static handle<> exception(
|
||||
@@ -243,47 +509,7 @@ void function::argument_error(PyObject* args, PyObject* keywords) const
|
||||
message += str(", ").join(actual_args);
|
||||
message += ")\ndid not match C++ signature:\n ";
|
||||
|
||||
list signatures;
|
||||
for (function const* f = this; f; f = f->m_overloads.get())
|
||||
{
|
||||
py_function const& impl = f->m_fn;
|
||||
|
||||
python::detail::signature_element const* s
|
||||
= impl.signature() + 1; // skip over return type
|
||||
|
||||
list formal_params;
|
||||
if (impl.max_arity() == 0)
|
||||
formal_params.append("void");
|
||||
|
||||
for (unsigned n = 0; n < impl.max_arity(); ++n)
|
||||
{
|
||||
if (s[n].basename == 0)
|
||||
{
|
||||
formal_params.append("...");
|
||||
break;
|
||||
}
|
||||
|
||||
str param(s[n].basename);
|
||||
if (s[n].lvalue)
|
||||
param += " {lvalue}";
|
||||
|
||||
if (f->m_arg_names) // None or empty tuple will test false
|
||||
{
|
||||
object kv(f->m_arg_names[n]);
|
||||
if (kv)
|
||||
{
|
||||
char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s";
|
||||
param += fmt % kv;
|
||||
}
|
||||
}
|
||||
|
||||
formal_params.append(param);
|
||||
}
|
||||
|
||||
signatures.append(
|
||||
"%s(%s)" % make_tuple(f->m_name, str(", ").join(formal_params))
|
||||
);
|
||||
}
|
||||
list signatures = function_signature_generator::function_signatures(this, true/*cpp types*/, false/*no docs*/);
|
||||
|
||||
message += str("\n ").join(signatures);
|
||||
|
||||
@@ -302,10 +528,6 @@ void function::add_overload(handle<function> const& overload_)
|
||||
parent = parent->m_overloads.get();
|
||||
|
||||
parent->m_overloads = overload_;
|
||||
|
||||
// If we have no documentation, get the docs from the overload
|
||||
if (!m_doc)
|
||||
m_doc = overload_->m_doc;
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -545,8 +767,11 @@ extern "C"
|
||||
//
|
||||
static PyObject* function_get_doc(PyObject* op, void*)
|
||||
{
|
||||
function* f = downcast<function>(op);
|
||||
return python::incref(f->doc().ptr());
|
||||
function const * f = downcast<function >(op);
|
||||
|
||||
list signatures = function_signature_generator::function_signatures(f, false/*pythonic args*/, true/*+docs*/);
|
||||
|
||||
return python::incref( str("\n ").join(signatures).ptr());
|
||||
}
|
||||
|
||||
static int function_set_doc(PyObject* op, PyObject* doc, void*)
|
||||
@@ -640,6 +865,7 @@ handle<> function_handle_impl(py_function const& f)
|
||||
new function(f, 0, 0)));
|
||||
}
|
||||
|
||||
|
||||
} // namespace objects
|
||||
|
||||
namespace detail
|
||||
|
||||
10
src/str.cpp
10
src/str.cpp
@@ -328,5 +328,15 @@ BOOST_PYTHON_DEFINE_STR_METHOD(title, 0)
|
||||
BOOST_PYTHON_DEFINE_STR_METHOD(translate, 1)
|
||||
BOOST_PYTHON_DEFINE_STR_METHOD(translate, 2)
|
||||
BOOST_PYTHON_DEFINE_STR_METHOD(upper, 0)
|
||||
|
||||
static struct register_str_pytype_ptr
|
||||
{
|
||||
register_str_pytype_ptr()
|
||||
{
|
||||
const_cast<converter::registration &>(
|
||||
converter::registry::lookup(boost::python::type_id<boost::python::str>())
|
||||
).m_class_object = &PyString_Type;
|
||||
}
|
||||
}register_str_pytype_ptr_;
|
||||
|
||||
}}} // namespace boost::python
|
||||
|
||||
@@ -17,4 +17,15 @@ tuple_base::tuple_base(object_cref sequence)
|
||||
: object(call(sequence))
|
||||
{}
|
||||
|
||||
static struct register_tuple_pytype_ptr
|
||||
{
|
||||
register_tuple_pytype_ptr()
|
||||
{
|
||||
const_cast<converter::registration &>(
|
||||
converter::registry::lookup(boost::python::type_id<boost::python::tuple>())
|
||||
).m_class_object = &PyTuple_Type;
|
||||
}
|
||||
}register_tuple_pytype_ptr_;
|
||||
|
||||
|
||||
}}} // namespace boost::python
|
||||
|
||||
Reference in New Issue
Block a user