mirror of
https://github.com/boostorg/python.git
synced 2026-01-21 17:12:22 +00:00
added new feature: def_raw()
[SVN r8162]
This commit is contained in:
@@ -26,6 +26,13 @@ class ClassWrapper
|
||||
void def(const Signature& signature)
|
||||
{ m_class->def(signature); }
|
||||
|
||||
// define a function that passes Python arguments and keywords
|
||||
// to C++ verbatim (as a 'Tuple const &' and 'Dict const &'
|
||||
// respectively). This is useful for manual argument passing.
|
||||
// It's also the only possibility to pass keyword arguments to C++.
|
||||
void def_raw(RawArgumentsFunction::PtrFun fn, const char* name)
|
||||
{ m_class->def_raw(fn, name); }
|
||||
|
||||
// define member functions. In fact this works for free functions, too -
|
||||
// they act like static member functions, or if they start with the
|
||||
// appropriate self argument (as a pointer or reference), they can be used
|
||||
|
||||
33
extclass.h
33
extclass.h
@@ -74,9 +74,7 @@ class ExtensionClassBase : public Class<ExtensionInstance>
|
||||
{
|
||||
public:
|
||||
ExtensionClassBase(const char* name);
|
||||
void set_attribute(const char* name, PyObject* x);
|
||||
void set_attribute(const char* name, Ptr x);
|
||||
|
||||
|
||||
public:
|
||||
// the purpose of try_class_conversions() and its related functions
|
||||
// is explained in extclass.cpp
|
||||
@@ -84,6 +82,9 @@ class ExtensionClassBase : public Class<ExtensionInstance>
|
||||
void* try_base_class_conversions(InstanceHolderBase*) const;
|
||||
void* try_derived_class_conversions(InstanceHolderBase*) const;
|
||||
|
||||
void set_attribute(const char* name, PyObject* x_);
|
||||
void set_attribute(const char* name, Ptr x);
|
||||
|
||||
private:
|
||||
virtual void* extract_object_from_holder(InstanceHolderBase* v) const = 0;
|
||||
virtual std::vector<py::detail::BaseClassInfo> const& base_classes() const = 0;
|
||||
@@ -137,7 +138,7 @@ class PyExtensionClassConverters
|
||||
// Get an object which can be used to convert T to/from python. This is used
|
||||
// as a kind of concept check by the global template
|
||||
//
|
||||
// from_python(PyObject*, py::Type<const T&>)
|
||||
// PyObject* to_python(const T& x)
|
||||
//
|
||||
// below this class, to prevent the confusing messages that would otherwise
|
||||
// pop up. Now, if T hasn't been wrapped as an extension class, the user
|
||||
@@ -149,12 +150,12 @@ class PyExtensionClassConverters
|
||||
}
|
||||
|
||||
// This is a member function because in a conforming implementation, friend
|
||||
// functions defined inline in the class body are all instantiated as soon
|
||||
// funcitons defined inline in the class body are all instantiated as soon
|
||||
// as the enclosing class is instantiated. If T is not copyable, that causes
|
||||
// a compiler error. Instead, we access this function through the global
|
||||
// template
|
||||
//
|
||||
// from_python(PyObject*, py::Type<const T&>)
|
||||
// PyObject* to_python(const T& x)
|
||||
//
|
||||
// defined below this class. Since template functions are instantiated only
|
||||
// on demand, errors will be avoided unless T is noncopyable and the user
|
||||
@@ -233,15 +234,7 @@ class PyExtensionClassConverters
|
||||
friend const T* from_python(PyObject* p, py::Type<const T*>)
|
||||
{ return from_python(p, py::Type<T*>()); }
|
||||
|
||||
// Convert to const T* const&
|
||||
friend const T* from_python(PyObject* p, py::Type<const T *const&>)
|
||||
{ return from_python(p, py::Type<const T*>()); }
|
||||
|
||||
// Convert to T* const&
|
||||
friend T* from_python(PyObject* p, py::Type<T* const&>)
|
||||
{ return from_python(p, py::Type<T*>()); }
|
||||
|
||||
// Convert to T&
|
||||
// Convert to T&
|
||||
friend T& from_python(PyObject* p, py::Type<T&>)
|
||||
{ return *py::check_non_null(from_python(p, py::Type<T*>())); }
|
||||
|
||||
@@ -369,6 +362,15 @@ class ExtensionClass
|
||||
Signature0()))))));
|
||||
}
|
||||
|
||||
// define a function that passes Python arguments and keywords
|
||||
// to C++ verbatim (as a 'Tuple const &' and 'Dict const &'
|
||||
// respectively). This is useful for manual argument passing.
|
||||
// It's also the only possibility to pass keyword arguments to C++.
|
||||
void def_raw(RawArgumentsFunction::PtrFun fn, const char* name)
|
||||
{
|
||||
this->add_method(new RawArgumentsFunction(fn), name);
|
||||
}
|
||||
|
||||
// define member functions. In fact this works for free functions, too -
|
||||
// they act like static member functions, or if they start with the
|
||||
// appropriate self argument (as a pointer), they can be used just like
|
||||
@@ -683,3 +685,4 @@ std::vector<py::detail::DerivedClassInfo> ClassRegistry<T>::static_derived_class
|
||||
} // namespace py
|
||||
|
||||
#endif // EXTENSION_CLASS_DWA052000_H_
|
||||
|
||||
|
||||
@@ -549,6 +549,39 @@ struct A_callback : A1 {
|
||||
PyObject* m_self;
|
||||
};
|
||||
|
||||
/************************************************************/
|
||||
/* */
|
||||
/* RawTest */
|
||||
/* (test passing of raw arguments to C++) */
|
||||
/* */
|
||||
/************************************************************/
|
||||
|
||||
struct RawTest
|
||||
{
|
||||
RawTest(int i) : i_(i) {}
|
||||
|
||||
int i_;
|
||||
};
|
||||
|
||||
template class py::ExtensionClass<RawTest>;
|
||||
|
||||
PyObject * raw(py::Tuple const & args, py::Dict const & keywords)
|
||||
{
|
||||
if(args.size() != 2 || keywords.size() != 2)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "wrong number of arguments");
|
||||
throw py::ArgumentError();
|
||||
}
|
||||
|
||||
RawTest * first = from_python(args[0].get(), py::Type<RawTest *>());
|
||||
int second = from_python(args[1].get(), py::Type<int>());
|
||||
|
||||
int third = from_python(keywords[py::String("third")].get(), py::Type<int>());
|
||||
int fourth = from_python(keywords[py::String("fourth")].get(), py::Type<int>());
|
||||
|
||||
return to_python(first->i_ + second + third + fourth);
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
/* */
|
||||
/* Ratio */
|
||||
@@ -636,6 +669,8 @@ const Record* get_record()
|
||||
return &v;
|
||||
}
|
||||
|
||||
template class py::ExtensionClass<Record>; // explicitly instantiate
|
||||
|
||||
} // namespace extclass_demo
|
||||
|
||||
#ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
@@ -799,7 +834,7 @@ void init_module(py::Module& m)
|
||||
b2_class.def(py::Constructor<>());
|
||||
b2_class.def(&B2::overrideA1, "overrideA1");
|
||||
b2_class.def(&B2::inheritB2, "inheritB2");
|
||||
|
||||
|
||||
m.def(call_overrideA1, "call_overrideA1");
|
||||
m.def(call_overrideB1, "call_overrideB1");
|
||||
m.def(call_inheritA1, "call_inheritA1");
|
||||
@@ -812,6 +847,12 @@ void init_module(py::Module& m)
|
||||
m.def(factoryB1asA2, "factoryB1asA2");
|
||||
m.def(factoryB1asB1, "factoryB1asB1");
|
||||
m.def(factoryCasB1, "factoryCasB1");
|
||||
|
||||
py::ClassWrapper<RawTest> rawtest_class(m, "RawTest");
|
||||
rawtest_class.def(py::Constructor<int>());
|
||||
rawtest_class.def_raw(&raw, "raw");
|
||||
|
||||
m.def_raw(&raw, "raw");
|
||||
}
|
||||
|
||||
void init_module()
|
||||
|
||||
27
functions.h
27
functions.h
@@ -75,6 +75,33 @@ struct WrappedFunctionPointer : Function
|
||||
const PtrFun m_pf;
|
||||
};
|
||||
|
||||
// RawArgumentsFunction
|
||||
// A function that passes the Python argument tuple and keyword dictionary
|
||||
// verbatim to C++ (useful for customized argument parsing and variable
|
||||
// argument lists)
|
||||
struct RawArgumentsFunction : Function
|
||||
{
|
||||
typedef PyObject * (*PtrFun)(Tuple const &, Dict const &);
|
||||
|
||||
RawArgumentsFunction(PtrFun pf)
|
||||
: m_pf(pf) {}
|
||||
|
||||
private:
|
||||
PyObject* do_call(PyObject* args, PyObject* keywords) const
|
||||
{
|
||||
return (*m_pf)(Tuple(Ptr(args, Ptr::new_ref)),
|
||||
keywords ?
|
||||
Dict(Ptr(keywords, Ptr::new_ref)) :
|
||||
Dict());
|
||||
}
|
||||
|
||||
const char* description() const
|
||||
{ return typeid(PtrFun).name(); }
|
||||
|
||||
private:
|
||||
const PtrFun m_pf;
|
||||
};
|
||||
|
||||
// virtual_function<> --
|
||||
// A virtual function with a default implementation wrapped and presented
|
||||
// to Python as a callable object.
|
||||
|
||||
@@ -367,6 +367,15 @@ class ExtensionClass
|
||||
""", args)
|
||||
+
|
||||
"""
|
||||
// define a function that passes Python arguments and keywords
|
||||
// to C++ verbatim (as a 'Tuple const &' and 'Dict const &'
|
||||
// respectively). This is useful for manual argument passing.
|
||||
// It's also the only possibility to pass keyword arguments to C++.
|
||||
void def_raw(RawArgumentsFunction::PtrFun fn, const char* name)
|
||||
{
|
||||
this->add_method(new RawArgumentsFunction(fn), name);
|
||||
}
|
||||
|
||||
// define member functions. In fact this works for free functions, too -
|
||||
// they act like static member functions, or if they start with the
|
||||
// appropriate self argument (as a pointer), they can be used just like
|
||||
|
||||
@@ -34,6 +34,11 @@ void Module::add(PyTypeObject* x, const char* name /*= 0*/)
|
||||
name ? name : x->tp_name);
|
||||
}
|
||||
|
||||
void Module::def_raw(RawFunctionPtr fn, const char* name)
|
||||
{
|
||||
add(new RawArgumentsFunction(fn), name);
|
||||
}
|
||||
|
||||
PyMethodDef Module::initial_methods[] = { { 0, 0, 0, 0 } };
|
||||
|
||||
}
|
||||
|
||||
4
module.h
4
module.h
@@ -19,6 +19,8 @@ class ExtensionType;
|
||||
|
||||
class Module
|
||||
{
|
||||
typedef PyObject * (*RawFunctionPtr)(py::Tuple const &, py::Dict const &);
|
||||
|
||||
public:
|
||||
Module(const char* name);
|
||||
|
||||
@@ -28,6 +30,8 @@ public:
|
||||
|
||||
void add(Ptr x, const char*name);
|
||||
|
||||
void def_raw(RawFunctionPtr fn, const char* name);
|
||||
|
||||
template <class Fn>
|
||||
void def(Fn fn, const char* name)
|
||||
{
|
||||
|
||||
@@ -842,6 +842,24 @@ test inheritB2
|
||||
>>> db2.inheritB2()
|
||||
'B2::inheritB2'
|
||||
|
||||
========= test the new def_raw() feature ==========
|
||||
|
||||
>>> r = RawTest(1)
|
||||
>>> raw(r,1,third=1,fourth=1)
|
||||
4
|
||||
>>> r.raw(1,third=1,fourth=1)
|
||||
4
|
||||
>>> raw(r,1,third=1,f=1)
|
||||
Traceback (innermost last):
|
||||
KeyError: fourth
|
||||
>>> raw(r,1,third=1)
|
||||
Traceback (innermost last):
|
||||
TypeError: wrong number of arguments
|
||||
>>> raw(r,1)
|
||||
Traceback (innermost last):
|
||||
TypeError: wrong number of arguments
|
||||
|
||||
|
||||
========= Prove that the "phantom base class" issue is resolved ==========
|
||||
|
||||
>>> assert pa1_a1.__class__ == A1
|
||||
|
||||
Reference in New Issue
Block a user