2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-21 17:12:22 +00:00

Tons of changes to improve error reporting

Added attributes function.__name__ and function.__signature__ and dir(function) feature


[SVN r8311]
This commit is contained in:
Ullrich Köthe
2000-11-23 22:48:51 +00:00
parent 4d7b6fe92a
commit ec4bc0382f
18 changed files with 1153 additions and 1134 deletions

1002
caller.h

File diff suppressed because it is too large Load Diff

View File

@@ -329,9 +329,9 @@ PyObject* read_only_setattr_function::do_call(PyObject* /*args*/, PyObject* /*ke
return 0;
}
const char* read_only_setattr_function::description() const
PyObject* read_only_setattr_function::description() const
{
return "uncallable";
return BOOST_PYTHON_CONVERSION::to_python("uncallable");
}
extension_class_base::extension_class_base(const char* name)
@@ -469,6 +469,19 @@ operator_dispatcher::create(const ref& object, const ref& self)
return result;
}
namespace {
void set_attribute_error(const char* oper, tuple args)
{
PyErr_Clear();
string message(oper);
message += argument_tuple_as_string(args);
message += " undefined.";
PyErr_SetObject(PyExc_TypeError, message.get());
}
} // anonymous namespace
extern "C"
{
@@ -498,7 +511,7 @@ int operator_dispatcher_coerce(PyObject** l, PyObject** r)
#define PY_DEFINE_OPERATOR(id, symbol) \
PyObject* operator_dispatcher_call_##id(PyObject* left, PyObject* right) \
PyObject* operator_dispatcher_call_##id(PyObject* left, PyObject* right) \
{ \
/* unwrap the arguments from their OperatorDispatcher */ \
PyObject* self; \
@@ -506,17 +519,20 @@ int operator_dispatcher_coerce(PyObject** l, PyObject** r)
int reverse = unwrap_args(left, right, self, other); \
if (reverse == unwrap_exception_code) \
return 0; \
const char * oper = reverse \
? "__r" #id "__" \
: "__" #id "__"; \
\
/* call the function */ \
PyObject* result = \
PyEval_CallMethod(self, \
const_cast<char*>(reverse ? "__r" #id "__" : "__" #id "__"), \
const_cast<char*>(oper), \
const_cast<char*>("(O)"), \
other); \
if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) \
{ \
PyErr_Clear(); \
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for " #symbol); \
tuple args(ref(self, ref::increment_count), ref(other, ref::increment_count)); \
set_attribute_error(oper , args); \
} \
return result; \
}
@@ -562,24 +578,34 @@ PyObject* operator_dispatcher_call_pow(PyObject* left, PyObject* right, PyObject
if (reverse == unwrap_exception_code)
return 0;
const char * oper = (reverse == 0)
? "__pow__"
: (reverse == 1)
? "__rpow__"
: "__rrpow__";
// call the function
PyObject* result =
PyEval_CallMethod(self,
const_cast<char*>((reverse == 0)
? "__pow__"
: (reverse == 1)
? "__rpow__"
: "__rrpow__"),
const_cast<char*>(oper),
const_cast<char*>("(OO)"),
first, second);
if (result == 0 &&
(PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError) ||
PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)))
{
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()");
}
if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError))
{
if(m == Py_None)
{
tuple args(ref(self, ref::increment_count), ref(first, ref::increment_count));
set_attribute_error(oper , args);
}
else
{
tuple args(ref(self, ref::increment_count),
ref(first, ref::increment_count),
ref(second, ref::increment_count));
set_attribute_error(oper , args);
}
}
return result;
}
@@ -592,16 +618,23 @@ int operator_dispatcher_call_cmp(PyObject* left, PyObject* right)
if (reverse == unwrap_exception_code)
return -1;
const char * oper = reverse
? "__rcmp__"
: "__cmp__";
// call the function
PyObject* result =
PyEval_CallMethod(self,
const_cast<char*>(reverse ? "__rcmp__" : "__cmp__"),
const_cast<char*>(oper),
const_cast<char*>("(O)"),
other);
if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError))
{
tuple args(ref(self, ref::increment_count), ref(other, ref::increment_count));
set_attribute_error(oper , args);
}
if (result == 0)
{
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for cmp() or <");
return -1;
}
else

View File

@@ -133,6 +133,39 @@ class class_registry
static std::vector<derived_class_info> static_derived_class_info;
};
template <class T, class H>
no_t* is_plain_aux(type<instance_value_holder<T, H> >);
template <class T, class H>
string forward_python_type_name(python::type<instance_value_holder<T, H> >)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T, class H>
no_t* is_plain_aux(type<instance_ptr_holder<T, H> >);
template <class T, class H>
string forward_python_type_name(python::type<instance_ptr_holder<T, H> >)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T>
string python_type_name(type<T>)
{
if(class_registry<T>::class_object() == 0)
{
return string("UnknownType");
}
else
{
return class_registry<T>::class_object()->complete_class_name();
}
}
}} // namespace python::detail
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
@@ -314,7 +347,9 @@ class read_only_setattr_function : public function
public:
read_only_setattr_function(const char* name);
PyObject* do_call(PyObject* args, PyObject* keywords) const;
const char* description() const;
PyObject* description() const;
string function_name() const
{ return m_name; }
private:
string m_name;
};
@@ -428,7 +463,7 @@ class extension_class
template <class Fn>
inline void def_raw(Fn fn, const char* name)
{
this->add_method(new_raw_arguments_function(fn), name);
this->add_method(new_raw_arguments_function(fn, name), name);
}
// define member functions. In fact this works for free functions, too -
@@ -438,7 +473,7 @@ class extension_class
template <class Fn>
inline void def(Fn fn, const char* name)
{
this->add_method(new_wrapped_function(fn), name);
this->add_method(new_wrapped_function(fn, name), name);
}
// Define a virtual member function with a default implementation.
@@ -447,7 +482,7 @@ class extension_class
template <class Fn, class DefaultFn>
inline void def(Fn fn, const char* name, DefaultFn default_fn)
{
this->add_method(new_virtual_function(type<T>(), fn, default_fn), name);
this->add_method(new_virtual_function(type<T>(), fn, default_fn, name), name);
}
// Provide a function which implements x.<name>, reading from the given
@@ -455,7 +490,7 @@ class extension_class
template <class MemberType>
inline void def_getter(MemberType T::*pm, const char* name)
{
this->add_getter_method(new getter_function<T, MemberType>(pm), name);
this->add_getter_method(new getter_function<T, MemberType>(pm, name), name);
}
// Provide a function which implements assignment to x.<name>, writing to
@@ -463,7 +498,7 @@ class extension_class
template <class MemberType>
inline void def_setter(MemberType T::*pm, const char* name)
{
this->add_setter_method(new setter_function<T, MemberType>(pm), name);
this->add_setter_method(new setter_function<T, MemberType>(pm, name), name);
}
// Expose the given member (pm) of the T obj as a read-only attribute

View File

@@ -11,13 +11,35 @@
#include "singleton.h"
#include "objects.h"
#include "errors.h"
#include "extclass.h"
namespace python { namespace detail {
struct function::type_object :
singleton<function::type_object, callable<python::detail::type_object<function> > >
string argument_tuple_as_string(tuple arguments)
{
type_object() : singleton_base(&PyType_Type) {}
string result("(");
for (std::size_t i = 0; i < arguments.size(); ++i)
{
if (i != 0)
result += ", ";
if(arguments[i]->ob_type->ob_type == extension_meta_class())
{
result += downcast<class_base>(arguments[i]->ob_type).get()->complete_class_name();
}
else
{
result += arguments[i]->ob_type->tp_name;
}
}
result += ")";
return result;
}
struct function::type_object :
singleton<function::type_object, getattrable<callable<python::detail::type_object<function> > > >
{
type_object() : singleton_base(&PyType_Type)
{}
};
@@ -56,6 +78,38 @@ function::function()
{
}
PyObject* function::getattr(const char * name) const
{
if(strcmp(name, "__signatures__") == 0)
{
list signatures;
for (const function* f = this; f != 0; f = f->m_overloads.get())
{
signatures.push_back(f->description());
}
return signatures.reference().release();
}
else if(strcmp(name, "__name__") == 0)
{
return function_name().reference().release();
}
else if(strcmp(name, "__dict__") == 0)
{
dictionary items;
items.set_item(string("__name__"), detail::none());
items.set_item(string("__signatures__"), detail::none());
return items.reference().release();
}
else
{
PyErr_SetString(PyExc_AttributeError, name);
return 0;
}
}
PyObject* function::call(PyObject* args, PyObject* keywords) const
{
for (const function* f = this; f != 0; f = f->m_overloads.get())
@@ -69,6 +123,26 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
}
catch(const argument_error&)
{
if(m_overloads.get() == 0 && rephrase_argument_error() &&
PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError))
{
PyErr_Clear();
string message("");
string name(this->function_name());
if(name.size() != 0)
{
message += "'";
message += name;
message += "' ";
}
message += "expected argument(s) ";
message += description_as_string();
message += ",\nbut got ";
tuple arguments(ref(args, ref::increment_count));
message += argument_types_as_string(arguments);
message += " instead.";
PyErr_SetObject(PyExc_TypeError, message.get());
}
}
}
@@ -76,27 +150,52 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
return 0;
PyErr_Clear();
string message("No overloaded functions match (");
tuple arguments(ref(args, ref::increment_count));
for (std::size_t i = 0; i < arguments.size(); ++i)
string message("No variant of overloaded function");
string name(this->function_name());
if(name.size() != 0)
{
if (i != 0)
message += ", ";
message += arguments[i]->ob_type->tp_name;
message += " '";
message += name;
message += "'";
}
message += " matches argument(s):\n";
tuple arguments(ref(args, ref::increment_count));
message += argument_types_as_string(arguments);
message += "). Candidates are:\n";
message += "\nCandidates are:\n";
for (const function* f1 = this; f1 != 0; f1 = f1->m_overloads.get())
{
if (f1 != this)
message += "\n";
message += f1->description();
message += f1->description_as_string();
}
PyErr_SetObject(PyExc_TypeError, message.get());
return 0;
}
string function::description_as_string() const
{
string result("(");
tuple arguments(ref(this->description()));
for (std::size_t i = 0; i < arguments.size(); ++i)
{
if (i != 0)
result += ", ";
result += string(arguments[i]);
}
result += ")";
return result;
}
string function::argument_types_as_string(tuple arguments) const
{
return argument_tuple_as_string(arguments);
}
bound_function* bound_function::create(const ref& target, const ref& fn)
{
bound_function* const result = free_list;

View File

@@ -25,6 +25,8 @@ namespace python { namespace detail {
// forward declaration
class extension_instance;
string argument_tuple_as_string(tuple args);
// function --
// the common base class for all overloadable function and method objects
@@ -38,17 +40,36 @@ class function : public python_object
virtual ~function() {}
PyObject* call(PyObject* args, PyObject* keywords) const;
PyObject* getattr(const char * name) const;
static void add_to_namespace(reference<function> f, const char* name, PyObject* dict);
protected:
virtual PyObject* description() const = 0;
private:
virtual PyObject* do_call(PyObject* args, PyObject* keywords) const = 0;
virtual const char* description() const = 0;
virtual string description_as_string() const;
virtual string argument_types_as_string(tuple args) const;
virtual string function_name() const = 0;
virtual bool rephrase_argument_error() const
{ return true; }
private:
struct type_object;
private:
reference<function> m_overloads;
};
struct named_function : function
{
named_function(const char * name)
: m_name(name)
{}
string function_name() const
{ return m_name; }
string m_name;
};
// wrapped_function_pointer<> --
// A single function or member function pointer wrapped and presented to
// Python as a callable object.
@@ -57,19 +78,19 @@ class function : public python_object
// R - the return type of the function pointer
// F - the complete type of the wrapped function pointer
template <class R, class F>
struct wrapped_function_pointer : function
struct wrapped_function_pointer : named_function
{
typedef F ptr_fun; // pointer-to--function or pointer-to-member-function
wrapped_function_pointer(ptr_fun pf)
: m_pf(pf) {}
wrapped_function_pointer(ptr_fun pf, const char * name)
: named_function(name), m_pf(pf) {}
private:
PyObject* do_call(PyObject* args, PyObject* keywords) const
{ return caller<R>::call(m_pf, args, keywords); }
const char* description() const
{ return typeid(F).name(); }
PyObject* description() const
{ return function_signature(m_pf); }
private:
const ptr_fun m_pf;
@@ -80,15 +101,15 @@ struct wrapped_function_pointer : function
// verbatim to C++ (useful for customized argument parsing and variable
// argument lists)
template <class Ret, class Args, class Keywords>
struct raw_arguments_function : function
struct raw_arguments_function : named_function
{
typedef Ret (*ptr_fun)(Args, Keywords);
raw_arguments_function(ptr_fun pf)
: m_pf(pf) {}
raw_arguments_function(ptr_fun pf, const char * name)
: named_function(name), m_pf(pf) {}
private:
PyObject* do_call(PyObject* args, PyObject* keywords) const
PyObject* do_call(PyObject* args, PyObject* keywords) const
{
ref dict(keywords ?
ref(keywords, ref::increment_count) :
@@ -99,9 +120,17 @@ struct raw_arguments_function : function
from_python(dict.get(), python::type<Keywords>())));
}
const char* description() const
{ return typeid(ptr_fun).name(); }
PyObject* description() const
{
tuple result(1);
result.set_item(0, string("..."));
return result.reference().release();
}
virtual bool rephrase_argument_error() const
{ return false; }
private:
const ptr_fun m_pf;
};
@@ -119,19 +148,20 @@ struct raw_arguments_function : function
// parameter and calls T::f on it /non-virtually/, where V
// approximates &T::f.
template <class T, class R, class V, class D>
class virtual_function : public function
class virtual_function : public named_function
{
public:
virtual_function(V virtual_function_ptr, D default_implementation)
: m_virtual_function_ptr(virtual_function_ptr),
virtual_function(V virtual_function_ptr, D default_implementation, const char * name)
: named_function(name),
m_virtual_function_ptr(virtual_function_ptr),
m_default_implementation(default_implementation)
{}
private:
PyObject* do_call(PyObject* args, PyObject* keywords) const;
const char* description() const
{ return typeid(V).name(); }
PyObject* description() const
{ return function_signature(m_virtual_function_ptr); }
private:
const V m_virtual_function_ptr;
@@ -142,26 +172,26 @@ class virtual_function : public function
// functionality once the return type has already been deduced. R is expected to
// be type<X>, where X is the actual return type of pmf.
template <class F, class R>
function* new_wrapped_function_aux(R, F pmf)
function* new_wrapped_function_aux(R, F pmf, const char * name)
{
// We can't just use "typename R::Type" below because MSVC (incorrectly) pukes.
typedef typename R::type return_type;
return new wrapped_function_pointer<return_type, F>(pmf);
return new wrapped_function_pointer<return_type, F>(pmf, name);
}
// Create and return a new member function object wrapping the given
// pointer-to-member function
template <class F>
inline function* new_wrapped_function(F pmf)
inline function* new_wrapped_function(F pmf, const char * name)
{
// Deduce the return type and pass it off to the helper function above
return new_wrapped_function_aux(return_value(pmf), pmf);
return new_wrapped_function_aux(return_value(pmf), pmf, name);
}
template <class R, class Args, class keywords>
function* new_raw_arguments_function(R (*pmf)(Args, keywords))
function* new_raw_arguments_function(R (*pmf)(Args, keywords), const char * name)
{
return new raw_arguments_function<R, Args, keywords>(pmf);
return new raw_arguments_function<R, Args, keywords>(pmf, name);
}
@@ -170,26 +200,26 @@ function* new_raw_arguments_function(R (*pmf)(Args, keywords))
// be type<X>, where X is the actual return type of V.
template <class T, class R, class V, class D>
inline function* new_virtual_function_aux(
type<T>, R, V virtual_function_ptr, D default_implementation
)
type<T>, R, V virtual_function_ptr, D default_implementation,
const char * name)
{
// We can't just use "typename R::Type" below because MSVC (incorrectly) pukes.
typedef typename R::type return_type;
return new virtual_function<T, return_type, V, D>(
virtual_function_ptr, default_implementation);
virtual_function_ptr, default_implementation, name);
}
// Create and return a new virtual_function object wrapping the given
// virtual_function_ptr and default_implementation
template <class T, class V, class D>
inline function* new_virtual_function(
type<T>, V virtual_function_ptr, D default_implementation
)
type<T>, V virtual_function_ptr, D default_implementation,
const char * name)
{
// Deduce the return type and pass it off to the helper function above
return new_virtual_function_aux(
type<T>(), return_value(virtual_function_ptr),
virtual_function_ptr, default_implementation);
virtual_function_ptr, default_implementation, name);
}
// A function with a bundled "bound target" object. This is what is produced by
@@ -220,37 +250,37 @@ class bound_function : public python_object
// Special functions designed to access data members of a wrapped C++ object.
template <class ClassType, class MemberType>
class getter_function : public function
class getter_function : public named_function
{
public:
typedef MemberType ClassType::* pointer_to_member;
getter_function(pointer_to_member pm)
: m_pm(pm) {}
getter_function(pointer_to_member pm, const char * name)
: named_function(name), m_pm(pm) {}
private:
PyObject* do_call(PyObject* args, PyObject* keywords) const;
const char* description() const
{ return typeid(MemberType (*)(const ClassType&)).name(); }
PyObject* description() const
{ return function_signature((MemberType (*)(const ClassType&))0); }
private:
pointer_to_member m_pm;
};
template <class ClassType, class MemberType>
class setter_function : public function
class setter_function : public named_function
{
public:
typedef MemberType ClassType::* pointer_to_member;
setter_function(pointer_to_member pm)
: m_pm(pm) {}
setter_function(pointer_to_member pm, const char * name)
: named_function(name), m_pm(pm) {}
private:
PyObject* do_call(PyObject* args, PyObject* keywords) const;
const char* description() const
{ return typeid(void (*)(const ClassType&, const MemberType&)).name(); }
PyObject* description() const
{ return function_signature((void (*)(const ClassType&, const MemberType&))0); }
private:
pointer_to_member m_pm;
};

View File

@@ -31,6 +31,7 @@ body_sections = (
# include <boost/config.hpp>
# include "signatures.h"
# include "none.h"
# include "objects.h"
namespace python {
@@ -56,9 +57,25 @@ struct caller<void>
''',
'''};
}
namespace detail
{
// create signature tuples
inline''',
'''
// member functions
''',
'''
// const member functions
''',
'''
// free functions
''',
'''} // namespace detail
#endif
} // namespace python
#endif // CALLER_DWA05090_H_
''')
#'
@@ -87,6 +104,34 @@ free_function = '''%{ template <%(class A%n%:, %)>
'''
function_signature = '''%{template <%}%(class A%n%:, %)%{>%}
PyObject* function_signature(%(type<A%n>%:, %)) {
%( static const bool is_plain_A%n = BOOST_PYTHON_IS_PLAIN(A%n);
%) tuple result(%x);
%( result.set_item(%N, python_type_name_selector<is_plain_A%n>::get(type<A%n>()));
%)
return result.reference().release();
}
'''
member_function_signature = '''template <class R, class T%(, class A%n%)>
inline PyObject* function_signature(R (T::*pmf)(%(A%n%:, %))%1) {
return function_signature(
python::type<T>()%(,
python::type<A%n>()%));
}
'''
free_function_signature = '''template <class R%(, class A%n%)>
inline PyObject* function_signature(R (*f)(%(A%n%:, %))) {
return function_signature(%(
python::type<A%n>()%:,%));
}
'''
def gen_caller(member_function_args, free_function_args = None):
if free_function_args is None:
free_function_args = member_function_args + 1
@@ -118,6 +163,16 @@ def gen_caller(member_function_args, free_function_args = None):
+ gen_functions(free_function, free_function_args,
'void', '', return_none)
+ body_sections[6]
# create lists describing the function signatures
+ gen_functions(function_signature, free_function_args)
+ body_sections[7]
+ gen_functions(member_function_signature, member_function_args, '')
+ body_sections[8]
+ gen_functions(member_function_signature, member_function_args, ' const')
+ body_sections[9]
+ gen_functions(free_function_signature, free_function_args)
+ body_sections[10]
)
if __name__ == '__main__':

View File

@@ -138,6 +138,39 @@ class class_registry
static std::vector<derived_class_info> static_derived_class_info;
};
template <class T, class H>
no_t* is_plain_aux(type<instance_value_holder<T, H> >);
template <class T, class H>
string forward_python_type_name(python::type<instance_value_holder<T, H> >)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T, class H>
no_t* is_plain_aux(type<instance_ptr_holder<T, H> >);
template <class T, class H>
string forward_python_type_name(python::type<instance_ptr_holder<T, H> >)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T>
string python_type_name(type<T>)
{
if(class_registry<T>::class_object() == 0)
{
return string("UnknownType");
}
else
{
return class_registry<T>::class_object()->complete_class_name();
}
}
}} // namespace python::detail
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
@@ -319,7 +352,9 @@ class read_only_setattr_function : public function
public:
read_only_setattr_function(const char* name);
PyObject* do_call(PyObject* args, PyObject* keywords) const;
const char* description() const;
PyObject* description() const;
string function_name() const
{ return m_name; }
private:
string m_name;
};
@@ -433,7 +468,7 @@ class extension_class
template <class Fn>
inline void def_raw(Fn fn, const char* name)
{
this->add_method(new_raw_arguments_function(fn), name);
this->add_method(new_raw_arguments_function(fn, name), name);
}
// define member functions. In fact this works for free functions, too -
@@ -443,7 +478,7 @@ class extension_class
template <class Fn>
inline void def(Fn fn, const char* name)
{
this->add_method(new_wrapped_function(fn), name);
this->add_method(new_wrapped_function(fn, name), name);
}
// Define a virtual member function with a default implementation.
@@ -452,7 +487,7 @@ class extension_class
template <class Fn, class DefaultFn>
inline void def(Fn fn, const char* name, DefaultFn default_fn)
{
this->add_method(new_virtual_function(type<T>(), fn, default_fn), name);
this->add_method(new_virtual_function(type<T>(), fn, default_fn, name), name);
}
// Provide a function which implements x.<name>, reading from the given
@@ -460,7 +495,7 @@ class extension_class
template <class MemberType>
inline void def_getter(MemberType T::*pm, const char* name)
{
this->add_getter_method(new getter_function<T, MemberType>(pm), name);
this->add_getter_method(new getter_function<T, MemberType>(pm, name), name);
}
// Provide a function which implements assignment to x.<name>, writing to
@@ -468,7 +503,7 @@ class extension_class
template <class MemberType>
inline void def_setter(MemberType T::*pm, const char* name)
{
this->add_setter_method(new setter_function<T, MemberType>(pm), name);
this->add_setter_method(new setter_function<T, MemberType>(pm, name), name);
}
// Expose the given member (pm) of the T obj as a read-only attribute

View File

@@ -35,6 +35,8 @@ def _gen_arg(template, n, args, delimiter = '%'):
if key == 'n':
result = result + `n`
elif key == 'N':
result = result + `n-1`
else:
result = result + _gen_common_key(key, n, args)
@@ -55,8 +57,13 @@ def gen_function(template, n, *args, **keywords):
%n is transformed into the string representation of 1..n for each repetition
of n.
%x, where x is a digit, is transformed into the corresponding additional
%N is transformed into the string representation of 0..(n-1) for each repetition
of n.
%i, where i is a digit, is transformed into the corresponding additional
argument.
%x is transformed into the number of the current repetition
for example,

View File

@@ -130,6 +130,8 @@ private: // override function hook
PyObject* do_call(PyObject* args, PyObject* keywords) const;
private:
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0;
string description_as_string() const;
string argument_types_as_string(tuple args) const;
};
""" + gen_functions("""
@@ -145,8 +147,20 @@ struct init%x : init
python::detail::reference_parameter<A%n>(from_python(a%n, type<A%n>()))%)
);
}
const char* description() const
{ return typeid(void (*)(T&%(, A%n%%))).name(); }
PyObject* description() const
{
return function_signature(python::type<T>()%(,
python::type<A%n>()%));
}
string function_name() const
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
string result(python_type_name_selector<is_plain>::get(python::type<T>()));
result += ".__init__";
return result;
}
};""", args) + """
}} // namespace python::detail

View File

@@ -33,4 +33,24 @@ namespace python { namespace detail {
return none();
}
string init::description_as_string() const
{
tuple arguments(ref(this->description()));
string result("(");
for (std::size_t i = 1; i < arguments.size(); ++i)
{
if (i != 1)
result += ", ";
result += string(arguments[i]);
}
result += ")";
return result;
}
string init::argument_types_as_string(tuple arguments) const
{
return argument_tuple_as_string(arguments.slice(1,arguments.size()));
}
}} // namespace python::detail

View File

@@ -110,11 +110,6 @@ template <class T, class A1, class A2> struct init2;
template <class T, class A1, class A2, class A3> struct init3;
template <class T, class A1, class A2, class A3, class A4> struct init4;
template <class T, class A1, class A2, class A3, class A4, class A5> struct init5;
template <class T, class A1, class A2, class A3, class A4, class A5, class A6> struct Init6;
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7> struct Init7;
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> struct Init8;
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> struct Init9;
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10> struct Init10;
template <class T>
struct init_function
@@ -162,71 +157,6 @@ struct init_function
detail::parameter_traits<A4>::const_reference,
detail::parameter_traits<A5>::const_reference>;
}
template <class A1, class A2, class A3, class A4, class A5, class A6>
static init* create(signature6<A1, A2, A3, A4, A5, A6>) {
return new Init6<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference,
detail::parameter_traits<A3>::const_reference,
detail::parameter_traits<A4>::const_reference,
detail::parameter_traits<A5>::const_reference,
detail::parameter_traits<A6>::const_reference>;
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
static init* create(signature7<A1, A2, A3, A4, A5, A6, A7>) {
return new Init7<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference,
detail::parameter_traits<A3>::const_reference,
detail::parameter_traits<A4>::const_reference,
detail::parameter_traits<A5>::const_reference,
detail::parameter_traits<A6>::const_reference,
detail::parameter_traits<A7>::const_reference>;
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
static init* create(signature8<A1, A2, A3, A4, A5, A6, A7, A8>) {
return new Init8<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference,
detail::parameter_traits<A3>::const_reference,
detail::parameter_traits<A4>::const_reference,
detail::parameter_traits<A5>::const_reference,
detail::parameter_traits<A6>::const_reference,
detail::parameter_traits<A7>::const_reference,
detail::parameter_traits<A8>::const_reference>;
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
static init* create(signature9<A1, A2, A3, A4, A5, A6, A7, A8, A9>) {
return new Init9<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference,
detail::parameter_traits<A3>::const_reference,
detail::parameter_traits<A4>::const_reference,
detail::parameter_traits<A5>::const_reference,
detail::parameter_traits<A6>::const_reference,
detail::parameter_traits<A7>::const_reference,
detail::parameter_traits<A8>::const_reference,
detail::parameter_traits<A9>::const_reference>;
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
static init* create(signature10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>) {
return new Init10<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference,
detail::parameter_traits<A3>::const_reference,
detail::parameter_traits<A4>::const_reference,
detail::parameter_traits<A5>::const_reference,
detail::parameter_traits<A6>::const_reference,
detail::parameter_traits<A7>::const_reference,
detail::parameter_traits<A8>::const_reference,
detail::parameter_traits<A9>::const_reference,
detail::parameter_traits<A10>::const_reference>;
}
};
class init : public function
@@ -235,6 +165,8 @@ private: // override function hook
PyObject* do_call(PyObject* args, PyObject* keywords) const;
private:
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0;
string description_as_string() const;
string argument_types_as_string(tuple args) const;
};
@@ -248,8 +180,19 @@ struct init0 : init
return new T(self
);
}
const char* description() const
{ return typeid(void (*)(T&)).name(); }
PyObject* description() const
{
return function_signature(python::type<T>());
}
string function_name() const
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
string result(python_type_name_selector<is_plain>::get(python::type<T>()));
result += ".__init__";
return result;
}
};
template <class T, class A1>
@@ -264,8 +207,20 @@ struct init1 : init
python::detail::reference_parameter<A1>(from_python(a1, type<A1>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1)).name(); }
PyObject* description() const
{
return function_signature(python::type<T>(),
python::type<A1>());
}
string function_name() const
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
string result(python_type_name_selector<is_plain>::get(python::type<T>()));
result += ".__init__";
return result;
}
};
template <class T, class A1, class A2>
@@ -282,8 +237,21 @@ struct init2 : init
python::detail::reference_parameter<A2>(from_python(a2, type<A2>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2)).name(); }
PyObject* description() const
{
return function_signature(python::type<T>(),
python::type<A1>(),
python::type<A2>());
}
string function_name() const
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
string result(python_type_name_selector<is_plain>::get(python::type<T>()));
result += ".__init__";
return result;
}
};
template <class T, class A1, class A2, class A3>
@@ -302,8 +270,22 @@ struct init3 : init
python::detail::reference_parameter<A3>(from_python(a3, type<A3>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3)).name(); }
PyObject* description() const
{
return function_signature(python::type<T>(),
python::type<A1>(),
python::type<A2>(),
python::type<A3>());
}
string function_name() const
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
string result(python_type_name_selector<is_plain>::get(python::type<T>()));
result += ".__init__";
return result;
}
};
template <class T, class A1, class A2, class A3, class A4>
@@ -324,8 +306,23 @@ struct init4 : init
python::detail::reference_parameter<A4>(from_python(a4, type<A4>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4)).name(); }
PyObject* description() const
{
return function_signature(python::type<T>(),
python::type<A1>(),
python::type<A2>(),
python::type<A3>(),
python::type<A4>());
}
string function_name() const
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
string result(python_type_name_selector<is_plain>::get(python::type<T>()));
result += ".__init__";
return result;
}
};
template <class T, class A1, class A2, class A3, class A4, class A5>
@@ -348,160 +345,27 @@ struct init5 : init
python::detail::reference_parameter<A5>(from_python(a5, type<A5>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5)).name(); }
};
template <class T, class A1, class A2, class A3, class A4, class A5, class A6>
struct Init6 : init
{
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
{
PyObject* a1;
PyObject* a2;
PyObject* a3;
PyObject* a4;
PyObject* a5;
PyObject* a6;
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6))
throw argument_error();
return new T(self,
python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
python::detail::reference_parameter<A6>(from_python(a6, type<A6>()))
);
PyObject* description() const
{
return function_signature(python::type<T>(),
python::type<A1>(),
python::type<A2>(),
python::type<A3>(),
python::type<A4>(),
python::type<A5>());
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6)).name(); }
};
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
struct Init7 : init
{
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
{
PyObject* a1;
PyObject* a2;
PyObject* a3;
PyObject* a4;
PyObject* a5;
PyObject* a6;
PyObject* a7;
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7))
throw argument_error();
return new T(self,
python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
python::detail::reference_parameter<A6>(from_python(a6, type<A6>())),
python::detail::reference_parameter<A7>(from_python(a7, type<A7>()))
);
string function_name() const
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
string result(python_type_name_selector<is_plain>::get(python::type<T>()));
result += ".__init__";
return result;
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7)).name(); }
};
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
struct Init8 : init
{
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
{
PyObject* a1;
PyObject* a2;
PyObject* a3;
PyObject* a4;
PyObject* a5;
PyObject* a6;
PyObject* a7;
PyObject* a8;
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8))
throw argument_error();
return new T(self,
python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
python::detail::reference_parameter<A6>(from_python(a6, type<A6>())),
python::detail::reference_parameter<A7>(from_python(a7, type<A7>())),
python::detail::reference_parameter<A8>(from_python(a8, type<A8>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8)).name(); }
};
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
struct Init9 : init
{
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
{
PyObject* a1;
PyObject* a2;
PyObject* a3;
PyObject* a4;
PyObject* a5;
PyObject* a6;
PyObject* a7;
PyObject* a8;
PyObject* a9;
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9))
throw argument_error();
return new T(self,
python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
python::detail::reference_parameter<A6>(from_python(a6, type<A6>())),
python::detail::reference_parameter<A7>(from_python(a7, type<A7>())),
python::detail::reference_parameter<A8>(from_python(a8, type<A8>())),
python::detail::reference_parameter<A9>(from_python(a9, type<A9>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8, A9)).name(); }
};
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
struct Init10 : init
{
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
{
PyObject* a1;
PyObject* a2;
PyObject* a3;
PyObject* a4;
PyObject* a5;
PyObject* a6;
PyObject* a7;
PyObject* a8;
PyObject* a9;
PyObject* a10;
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10))
throw argument_error();
return new T(self,
python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
python::detail::reference_parameter<A6>(from_python(a6, type<A6>())),
python::detail::reference_parameter<A7>(from_python(a7, type<A7>())),
python::detail::reference_parameter<A8>(from_python(a8, type<A8>())),
python::detail::reference_parameter<A9>(from_python(a9, type<A9>())),
python::detail::reference_parameter<A10>(from_python(a10, type<A10>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)).name(); }
};
}} // namespace python::detail
#endif // INIT_FUNCTION_DWA052000_H_

View File

@@ -18,8 +18,6 @@ namespace python {
class module_builder
{
typedef PyObject * (*raw_function_ptr)(python::tuple const &, python::dictionary const &);
public:
// Create a module. REQUIRES: only one module_builder is created per module.
module_builder(const char* name);
@@ -32,13 +30,13 @@ class module_builder
template <class Fn>
void def_raw(Fn fn, const char* name)
{
add(detail::new_raw_arguments_function(fn), name);
add(detail::new_raw_arguments_function(fn, name), name);
}
template <class Fn>
void def(Fn fn, const char* name)
{
add(detail::new_wrapped_function(fn), name);
add(detail::new_wrapped_function(fn, name), name);
}
static string name();

146
objects.h
View File

@@ -293,6 +293,152 @@ struct list::slice_proxy
int m_low, m_high;
};
namespace detail
{
#define BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(T, name) \
inline string python_type_name(python::type<T >) \
{ return string(#name); }
#if 0
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(long, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned long, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(int, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned int, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(short, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned short, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(signed char, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned char, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(bool, types.IntType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(float, types.FloatType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(double, types.FloatType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(void, types.NoneType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(const char *, types.StringType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(std::string, types.StringType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(PyObject, AnyType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(reference<PyObject>, AnyType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(list, types.ListType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(tuple, types.TupleType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(dictionary, types.DictionaryType);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(string, types.StringType);
#endif /* #if 0 */
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(long, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned long, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(int, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned int, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(short, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned short, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(signed char, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(unsigned char, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(bool, int);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(float, float);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(double, float);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(void, None);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(const char *, string);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(std::string, string);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(PyObject, any);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(reference<PyObject>, any);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(list, list);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(tuple, tuple);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(dictionary, dictionary);
BOOST_PYTHON_OVERLOAD_TYPENAME_FUNCTION(string, string);
typedef char no_t[1];
typedef char yes_t[2];
yes_t* is_plain_aux(...);
template <class T>
no_t* is_plain_aux(type<T *>);
template <class T>
no_t* is_plain_aux(type<T const *>);
template <class T>
no_t* is_plain_aux(type<T &>);
template <class T>
no_t* is_plain_aux(type<T const &>);
template <class T>
no_t* is_plain_aux(type<std::auto_ptr<T> >);
template <class T>
no_t* is_plain_aux(type<boost::shared_ptr<T> >);
template <class T>
no_t* is_plain_aux(type<reference<T> >);
#define BOOST_PYTHON_IS_PLAIN(T) \
(sizeof(*python::detail::is_plain_aux(python::type<T>())) == \
sizeof(python::detail::yes_t))
template <bool is_plain>
struct python_type_name_selector
{
template <class T>
static string get(python::type<T> t)
{ return python_type_name(t); }
};
template <class T>
string forward_python_type_name(python::type<T&>)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T>
string forward_python_type_name(python::type<const T&>)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T>
string forward_python_type_name(python::type<T*>)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T>
string forward_python_type_name(python::type<const T*>)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T>
string forward_python_type_name(python::type<std::auto_ptr<T> >)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T>
string forward_python_type_name(python::type<boost::shared_ptr<T> >)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <class T>
string forward_python_type_name(python::type<reference<T> >)
{
static const bool is_plain = BOOST_PYTHON_IS_PLAIN(T);
return python_type_name_selector<is_plain>::get(python::type<T>());
}
template <>
struct python_type_name_selector<false>
{
template <class T>
static string get(python::type<T> t)
{ return forward_python_type_name(t); }
};
} // namespace detail
} // namespace python
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE

View File

@@ -197,8 +197,7 @@ namespace detail
};
};
// Fully specialize define_operator for all operators defined in operator_id above.
// Every specialization defines one function object for normal operator calls and one
// for operator calls with operands reversed ("__r*__" function variants).
@@ -214,15 +213,20 @@ namespace detail
{ \
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
{ \
tuple args(ref(arguments, ref::increment_count)); \
tuple args(ref(arguments, ref::increment_count)); \
\
return BOOST_PYTHON_CONVERSION::to_python( \
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), python::type<Left>()) oper \
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), python::type<Right>())); \
} \
\
const char* description() const \
{ return "__" #id "__"; } \
string function_name() const \
{ return string(name()); } \
\
PyObject* description() const \
{ \
return function_signature(python::type<Left>(), python::type<Right>()); \
} \
}; \
\
template <class Right, class Left> \
@@ -230,15 +234,20 @@ namespace detail
{ \
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
{ \
tuple args(ref(arguments, ref::increment_count)); \
tuple args(ref(arguments, ref::increment_count)); \
\
return BOOST_PYTHON_CONVERSION::to_python( \
return BOOST_PYTHON_CONVERSION::to_python( \
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), python::type<Left>()) oper \
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), python::type<Right>())); \
} \
\
const char* description() const \
{ return "__r" #id "__"; } \
string function_name() const \
{ return string(rname()); } \
\
PyObject* description() const \
{ \
return function_signature(python::type<Left>(), python::type<Right>()); \
} \
\
}; \
\
@@ -255,14 +264,19 @@ namespace detail
{ \
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
{ \
tuple args(ref(arguments, ref::increment_count)); \
tuple args(ref(arguments, ref::increment_count)); \
\
return BOOST_PYTHON_CONVERSION::to_python( \
return BOOST_PYTHON_CONVERSION::to_python( \
oper(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), python::type<operand>()))); \
} \
\
const char* description() const \
{ return "__" #id "__"; } \
string function_name() const \
{ return string(name()); } \
\
PyObject* description() const \
{ \
return function_signature(python::type<operand>()); \
} \
}; \
\
static const char * name() { return "__" #id "__"; } \
@@ -317,8 +331,13 @@ namespace detail
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), python::type<Right>())));
}
const char* description() const
{ return "__pow__"; }
string function_name() const
{ return string(name()); }
PyObject* description() const
{
return function_signature(python::type<Left>(), python::type<Right>());
}
};
@@ -331,7 +350,7 @@ namespace detail
if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type)
{
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()");
PyErr_SetString(PyExc_TypeError, "'__pow__' expected 2 arguments, got 3.");
throw argument_error();
}
@@ -340,8 +359,13 @@ namespace detail
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), python::type<Right>())));
}
const char* description() const
{ return "__rpow__"; }
string function_name() const
{ return string(rname()); }
PyObject* description() const
{
return function_signature(python::type<Left>(), python::type<Right>());
}
};
@@ -374,8 +398,13 @@ namespace detail
return res;
}
const char* description() const
{ return "__divmod__"; }
string function_name() const
{ return string(name()); }
PyObject* description() const
{
return function_signature(python::type<Left>(), python::type<Right>());
}
};
@@ -399,9 +428,13 @@ namespace detail
return res;
}
const char* description() const
{ return "__rdivmod__"; }
string function_name() const
{ return string(rname()); }
PyObject* description() const
{
return function_signature(python::type<Left>(), python::type<Right>());
}
};
static const char * name() { return "__divmod__"; }
@@ -430,8 +463,13 @@ namespace detail
0) ;
}
const char* description() const
{ return "__cmp__"; }
string function_name() const
{ return string(name()); }
PyObject* description() const
{
return function_signature(python::type<Left>(), python::type<Right>());
}
};
@@ -452,8 +490,13 @@ namespace detail
0) ;
}
const char* description() const
{ return "__rcmp__"; }
string function_name() const
{ return string(rname()); }
PyObject* description() const
{
return function_signature(python::type<Left>(), python::type<Right>());
}
};
@@ -488,8 +531,13 @@ namespace detail
#endif
}
const char* description() const
{ return "__str__"; }
string function_name() const
{ return string(name()); }
PyObject* description() const
{
return function_signature(python::type<operand>());
}
};

View File

@@ -18,7 +18,7 @@ namespace detail {
// A stand-in for the built-in void. This one can be passed to functions and
// (under MSVC, which has a bug, be used as a default template type parameter).
struct void_t {};
}
} // namespace detail
// An envelope in which type information can be delivered for the purposes
// of selecting an overloaded from_python() function. This is needed to work

View File

@@ -67,7 +67,7 @@ namespace {
ref global_class_reduce()
{
static ref result(detail::new_wrapped_function(class_reduce));
static ref result(detail::new_wrapped_function(class_reduce, "__reduce__"));
return result;
}
@@ -111,7 +111,7 @@ namespace {
ref global_instance_reduce()
{
static ref result(detail::new_wrapped_function(instance_reduce));
static ref result(detail::new_wrapped_function(instance_reduce, "__reduce__"));
return result;
}
}
@@ -225,14 +225,21 @@ namespace detail {
// Mostly copied wholesale from Python's classobject.c
PyObject* class_base::repr() const
{
unsigned long address = reinterpret_cast<unsigned long>(this);
string result = string("<extension class %s at %lx>") % tuple(complete_class_name(), address);
return result.reference().release();
}
// Mostly copied wholesale from Python's classobject.c
string class_base::complete_class_name() const
{
PyObject *mod = PyDict_GetItemString(
m_name_space.get(), const_cast<char*>("__module__"));
unsigned long address = reinterpret_cast<unsigned long>(this);
string result = (mod == NULL || !PyString_Check(mod))
? string("<extension class %s at %lx>") % tuple(m_name, address)
: string("<extension class %s.%s at %lx>") % tuple(ref(mod, ref::increment_count), m_name, address);
return result.reference().release();
return (mod == NULL || !PyString_Check(mod))
? m_name
: string("%s.%s") % tuple(ref(mod, ref::increment_count), m_name);
}

View File

@@ -97,6 +97,9 @@ namespace detail {
int setattr(const char* name, PyObject* value);
PyObject* repr() const;
void add_base(ref base);
// get the complete class name (i.e. "module.class")
virtual string complete_class_name() const;
protected:
bool initialize_instance(instance* obj, PyObject* args, PyObject* keywords);

View File

@@ -10,15 +10,18 @@ r'''
Automatic checking of the number and type of arguments. Foo's constructor takes
a single long parameter.
>>> ext = Foo()
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: function requires exactly 1 argument; 0 given
>>> try: ext = Foo()
... except TypeError, err:
... assert re.match(
... "'demo.Foo.__init__' expected argument\(s\) \(int\),\n"
... "but got \(\) instead.", str(err))
... else: print 'no exception'
>>> try: ext = Foo('foo')
... except TypeError, err:
... assert re.match(
... '(illegal argument type for built-in operation)|(an integer is required)', str(err))
... "'demo.Foo.__init__' expected argument\(s\) \(int\),\n"
... "but got \(string\) instead.", str(err))
... else: print 'no exception'
>>> ext = Foo(1)
@@ -160,10 +163,16 @@ a Bar parameter:
But objects not derived from Bar cannot:
>>> baz.pass_bar(baz)
Traceback (innermost last):
...
TypeError: extension class 'Baz' is not convertible into 'Bar'.
>>> try: baz.pass_bar(baz)
... except TypeError, err:
... assert re.match(
... "'pass_bar' expected argument\(s\) \(demo.Baz, demo.Bar\),\n"
... "but got \(demo.Baz, demo.Baz\) instead.", str(err))
... else: print 'no exception'
(this error was:
TypeError: extension class 'Baz' is not convertible into 'Bar'.
)
The clone function on Baz returns a smart pointer; we wrap it into an
extension_instance and make it look just like any other Baz obj.
@@ -354,7 +363,11 @@ Some simple overloading tests:
>>> try: r = Range('yikes')
... except TypeError, e:
... assert re.match(
... 'No overloaded functions match [(]Range, string[)]\. Candidates are:\n.*\n.*',
... "No variant of overloaded function 'demo.Range.__init__' matches argument\(s\):\n"
... "\(string\)\n"
... "Candidates are:\n"
... "\(int\)\n"
... "\(int, int\)",
... str(e))
... else: print 'no exception'
@@ -564,7 +577,17 @@ Testing overloaded free functions
15
>>> try: overloaded(1, 'foo')
... except TypeError, err:
... assert re.match("No overloaded functions match \(int, string\)\. Candidates are:",
... assert re.match(
... "No variant of overloaded function 'overloaded' matches argument\(s\):\n"
... "\(int, string\)\n"
... "Candidates are:\n"
... "\(\)\n"
... "\(int\)\n"
... "\(string\)\n"
... "\(int, int\)\n"
... "\(int, int, int\)\n"
... "\(int, int, int, int\)\n"
... "\(int, int, int, int, int\)",
... str(err))
... else:
... print 'no exception'
@@ -594,7 +617,17 @@ Testing overloaded constructors
5
>>> try: over = OverloadTest(1, 'foo')
... except TypeError, err:
... assert re.match("No overloaded functions match \(OverloadTest, int, string\)\. Candidates are:",
... assert re.match(
... "No variant of overloaded function 'demo.OverloadTest.__init__' matches argument\(s\):\n"
... "\(int, string\)\n"
... "Candidates are:\n"
... "\(\)\n"
... "\(demo.OverloadTest\)\n"
... "\(int\)\n"
... "\(int, int\)\n"
... "\(int, int, int\)\n"
... "\(int, int, int, int\)\n"
... "\(int, int, int, int, int\)",
... str(err))
... else:
... print 'no exception'
@@ -616,16 +649,35 @@ Testing overloaded methods
5
>>> try: over.overloaded(1,'foo')
... except TypeError, err:
... assert re.match("No overloaded functions match \(OverloadTest, int, string\)\. Candidates are:",
... assert re.match(
... "No variant of overloaded function 'overloaded' matches argument\(s\):\n"
... "\(demo.OverloadTest, int, string\)\n"
... "Candidates are:\n"
... "\(demo.OverloadTest\)\n"
... "\(demo.OverloadTest, int\)\n"
... "\(demo.OverloadTest, int, int\)\n"
... "\(demo.OverloadTest, int, int, int\)\n"
... "\(demo.OverloadTest, int, int, int, int\)\n"
... "\(demo.OverloadTest, int, int, int, int, int\)",
... str(err))
... else:
... print 'no exception'
Testing base class conversions
>>> testUpcast(over)
Traceback (innermost last):
TypeError: extension class 'OverloadTest' is not convertible into 'Base'.
>>> try: testUpcast(over)
... except TypeError, err:
... assert re.match(
... "'testUpcast' expected argument\(s\) \(demo.Base\),\n"
... "but got \(demo.OverloadTest\) instead.",
... str(err))
... else:
... print 'no exception'
(this error was:
TypeError: extension class 'OverloadTest' is not convertible into 'Base'.
)
>>> der1 = Derived1(333)
>>> der1.x()
333
@@ -634,18 +686,37 @@ Testing base class conversions
>>> der1 = derived1Factory(1000)
>>> testDowncast1(der1)
1000
>>> testDowncast2(der1)
Traceback (innermost last):
>>> try: testDowncast2(der1)
... except TypeError, err:
... assert re.match(
... "'testDowncast2' expected argument\(s\) \(demo.Derived2\),\n"
... "but got \(demo.Base\) instead.",
... str(err))
... else:
... print 'no exception'
(this error was:
TypeError: extension class 'Base' is not convertible into 'Derived2'.
)
>>> der2 = Derived2(444)
>>> der2.x()
444
>>> testUpcast(der2)
444
>>> der2 = derived2Factory(1111)
>>> testDowncast2(der2)
Traceback (innermost last):
>>> try: testDowncast2(der2)
... except TypeError, err:
... assert re.match(
... "'testDowncast2' expected argument\(s\) \(demo.Derived2\),\n"
... "but got \(demo.Base\) instead.",
... str(err))
... else:
... print 'no exception'
(this error was:
TypeError: extension class 'Base' is not convertible into 'Derived2'.
)
Testing interaction between callbacks, base declarations, and overloading
- testCallback() calls callback() (within C++)
@@ -656,10 +727,14 @@ Testing interaction between callbacks, base declarations, and overloading
>>> c = CallbackTest()
>>> c.testCallback(1)
2
>>> c.testCallback('foo')
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: illegal argument type for built-in operation
>>> try: c.testCallback('foo')
... except TypeError, err:
... assert re.match(
... "'testCallback' expected argument\(s\) \(demo.CallbackTestBase, int\),\n"
... "but got \(demo.CallbackTest, string\) instead.",
... str(err))
... else:
... print 'no exception'
>>> c.callback(1)
2
>>> c.callback('foo')
@@ -678,10 +753,14 @@ Testing interaction between callbacks, base declarations, and overloading
-1
>>> r.callback('foo')
'foo 1'
>>> r.testCallback('foo')
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: illegal argument type for built-in operation
>>> try: r.testCallback('foo')
... except TypeError, err:
... assert re.match(
... "'testCallback' expected argument\(s\) \(demo.CallbackTestBase, int\),\n"
... "but got \(demo.RedefineCallback, string\) instead.",
... str(err))
... else:
... print 'no exception'
>>> r.testCallback(1)
-1
>>> testCallback(r, 1)
@@ -969,15 +1048,33 @@ test inheritB2
>>> j = pow(i, 5)
>>> j.i()
32
>>> j = pow(i, 5, k)
Traceback (innermost last):
TypeError: bad operand type(s) for pow()
>>> j = pow(i, 5, 5)
Traceback (innermost last):
TypeError: bad operand type(s) for pow()
>>> try: j = pow(i, 5, k)
... except TypeError, err:
... assert re.match(
... "No variant of overloaded function '__pow__' matches argument\(s\):\n"
... "\(demo.Int, int, demo.Int\)\n"
... "Candidates are:\n"
... "\(demo.Int, demo.Int\)\n"
... "\(demo.Int, demo.Int, demo.Int\)\n"
... "\(demo.Int, int\)",
... str(err))
... else:
... print 'no exception'
>>> try: j = pow(i, 5, 5)
... except TypeError, err:
... assert re.match(
... "No variant of overloaded function '__pow__' matches argument\(s\):\n"
... "\(demo.Int, int, int\)\n"
... "Candidates are:\n"
... "\(demo.Int, demo.Int\)\n"
... "\(demo.Int, demo.Int, demo.Int\)\n"
... "\(demo.Int, int\)",
... str(err))
... else:
... print 'no exception'
>>> j = i/1
Traceback (innermost last):
TypeError: bad operand type(s) for /
TypeError: __div__(demo.Int, int) undefined.
>>> j = 1+i
>>> j.i()
3
@@ -993,10 +1090,10 @@ test inheritB2
-1
>>> j = 1/i
Traceback (innermost last):
TypeError: bad operand type(s) for /
TypeError: __rdiv__(demo.Int, int) undefined.
>>> pow(1,i)
Traceback (innermost last):
TypeError: bad operand type(s) for pow()
TypeError: __rpow__(demo.Int, int) undefined.
Test operator export to a subclass