2
0
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:
Ullrich Köthe
2000-11-10 11:44:42 +00:00
parent f6e12ce904
commit 03dbf0387a
8 changed files with 130 additions and 16 deletions

View File

@@ -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

View File

@@ -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_

View File

@@ -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()

View File

@@ -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.

View File

@@ -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

View File

@@ -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 } };
}

View File

@@ -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)
{

View File

@@ -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