mirror of
https://github.com/boostorg/python.git
synced 2026-01-27 19:12:16 +00:00
Patches by Nikolay Mladenov (nickm at sitius com): new pythonic signatures; docstring support for enums; fix unrelated Visual C++ 6 problem
[SVN r39191]
This commit is contained in:
314
src/object/function_doc_signature.cpp
Executable file
314
src/object/function_doc_signature.cpp
Executable file
@@ -0,0 +1,314 @@
|
||||
// Copyright Nikolay Mladenov 2007.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
#include <boost/python/object/function_doc_signature.hpp>
|
||||
#include <boost/python/errors.hpp>
|
||||
#include <boost/python/str.hpp>
|
||||
#include <boost/python/args.hpp>
|
||||
#include <boost/python/tuple.hpp>
|
||||
|
||||
#include <boost/python/detail/signature.hpp>
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace python { namespace objects {
|
||||
|
||||
bool function_doc_signature_generator::arity_cmp( function const *f1, function const *f2 )
|
||||
{
|
||||
return f1->m_fn.max_arity() < f2->m_fn.max_arity();
|
||||
}
|
||||
|
||||
bool function_doc_signature_generator::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();
|
||||
|
||||
unsigned size = impl1.max_arity()+1;
|
||||
|
||||
for (unsigned 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
|
||||
bool f1_has_names = bool(f1->m_arg_names);
|
||||
bool f2_has_names = bool(f2->m_arg_names);
|
||||
if ( f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1]
|
||||
|| f1_has_names && !f2_has_names
|
||||
|| !f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=python::object()
|
||||
)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<function const*> function_doc_signature_generator::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->m_overloads.get();
|
||||
}
|
||||
|
||||
//std::sort(res.begin(),res.end(), &arity_cmp);
|
||||
|
||||
return res;
|
||||
}
|
||||
std::vector<function const*> function_doc_signature_generator::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;
|
||||
}
|
||||
|
||||
str function_doc_signature_generator::raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types )
|
||||
{
|
||||
str res("object");
|
||||
|
||||
res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const char * function_doc_signature_generator::py_type_str(const python::detail::signature_element &s)
|
||||
{
|
||||
if (s.basename==std::string("void")){
|
||||
static const char * none = "None";
|
||||
return none;
|
||||
}
|
||||
|
||||
PyTypeObject const * py_type = s.pytype_f?s.pytype_f():0;
|
||||
if ( py_type )
|
||||
return py_type->tp_name;
|
||||
else{
|
||||
static const char * object = "object";
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types)
|
||||
{
|
||||
str param;
|
||||
|
||||
python::detail::signature_element const * s = f.signature();
|
||||
if (cpp_types)
|
||||
{
|
||||
if(!n)
|
||||
s = &f.get_return_type();
|
||||
if (s[n].basename == 0)
|
||||
{
|
||||
return str("...");
|
||||
}
|
||||
|
||||
param = str(s[n].basename);
|
||||
|
||||
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
|
||||
param = py_type_str(f.get_return_type());
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
str function_doc_signature_generator::pretty_signature(function const *f, size_t n_overloads, bool cpp_types )
|
||||
{
|
||||
py_function
|
||||
const& impl = f->m_fn;
|
||||
;
|
||||
|
||||
|
||||
unsigned arity = impl.max_arity();
|
||||
|
||||
if(arity == unsigned(-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(impl, 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;
|
||||
}
|
||||
}
|
||||
|
||||
n_overloads+=n_extra_default_args;
|
||||
|
||||
if (!arity && cpp_types)
|
||||
formal_params.append("void");
|
||||
|
||||
str ret_type (formal_params.pop(0));
|
||||
if (cpp_types )
|
||||
{
|
||||
return str(
|
||||
"%s %s(%s%s%s%s)"
|
||||
% make_tuple
|
||||
( ret_type
|
||||
, 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,']')
|
||||
));
|
||||
}else{
|
||||
return str(
|
||||
"%s(%s%s%s%s) -> %s"
|
||||
% make_tuple
|
||||
( 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,']')
|
||||
, ret_type
|
||||
));
|
||||
}
|
||||
|
||||
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
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
char py_signature_tag[] = "PY signature : ";
|
||||
char cpp_signature_tag[] = "C++ signature:";
|
||||
}
|
||||
|
||||
list function_doc_signature_generator::function_doc_signatures( function const * f)
|
||||
{
|
||||
list signatures;
|
||||
std::vector<function const*> funcs = flatten( f);
|
||||
std::vector<function const*> split_funcs = split_seq_overloads( funcs, true);
|
||||
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){
|
||||
if((*fi)->doc()){
|
||||
str func_doc = str((*fi)->doc());
|
||||
int doc_len = len(func_doc);
|
||||
bool show_py_signature = doc_len >=int(sizeof(detail::py_signature_tag)/sizeof(char)-1)
|
||||
&& str(detail::py_signature_tag)==func_doc.slice(0, int(sizeof(detail::py_signature_tag)/sizeof(char))-1);
|
||||
bool show_cpp_signature = doc_len >=int(sizeof(detail::cpp_signature_tag)/sizeof(char))
|
||||
&& str(detail::cpp_signature_tag)==func_doc.slice(- int(sizeof(detail::cpp_signature_tag)/sizeof(char))+1, _);
|
||||
|
||||
str res;
|
||||
if(show_py_signature)
|
||||
{
|
||||
str sig = pretty_signature(*fi, n_overloads,false);
|
||||
res+=sig;
|
||||
if(doc_len > int(sizeof(detail::py_signature_tag)/sizeof(char))-1 )
|
||||
res+=" : "+func_doc.slice(int(sizeof(detail::py_signature_tag)/sizeof(char))-1,_);
|
||||
}else
|
||||
res+=func_doc;
|
||||
|
||||
if( show_cpp_signature)
|
||||
res+=str("\n ")+pretty_signature(*fi, n_overloads,true);
|
||||
|
||||
signatures.append(res);
|
||||
}
|
||||
++sfi;
|
||||
n_overloads = 0;
|
||||
}else
|
||||
++n_overloads ;
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
Reference in New Issue
Block a user