mirror of
https://github.com/boostorg/python.git
synced 2026-01-23 05:42:30 +00:00
Added the new arg class from
"nickm-at-sitius.com" (Nikolay Mladenov) which supplies the ability to wrap functions that can be called with ommitted arguments in the middle. [SVN r19441]
This commit is contained in:
134
doc/v2/args.html
134
doc/v2/args.html
@@ -3,7 +3,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="generator" content=
|
||||
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
|
||||
"HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<link rel="stylesheet" type="text/css" href="../boost.css">
|
||||
|
||||
@@ -35,7 +35,31 @@
|
||||
|
||||
<dt><a href="#keyword-expression"><i>keyword-expressions</i></a></dt>
|
||||
|
||||
<dt><a href="#functions">Functions</a></dt>
|
||||
<dt><a href="#classes">Classes</a></dt>
|
||||
|
||||
<dd>
|
||||
<dl class="page-index">
|
||||
<dt><a href="#arg-spec">class <code>arg</code></a></dt>
|
||||
|
||||
<dd>
|
||||
<dl class="page-index">
|
||||
<dt><a href="#arg-synopsis">class <code>arg</code>
|
||||
synopsis</a></dt>
|
||||
|
||||
<dt><a href="#arg-ctor">class <code>arg</code>
|
||||
constructor</a></dt>
|
||||
|
||||
<dt><a href="#arg-operator">class <code>arg</code> template
|
||||
<code>operator =</code></a></dt>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
|
||||
<dt><a href="#keyword-expression-operators"><i>Keyword-expression</i>
|
||||
operator <code>,</code></a></dt>
|
||||
|
||||
<dt><a href="#functions">Functions (deprecated)</a></dt>
|
||||
|
||||
<dd>
|
||||
<dl class="page-index">
|
||||
@@ -57,27 +81,95 @@
|
||||
|
||||
<p>A <b>keyword-expression</b> results in an object which holds a
|
||||
sequence of <a href="definitions.html#ntbs">ntbs</a>es, and whose type
|
||||
encodes the number of keywords specified.</p>
|
||||
encodes the number of keywords specified. The <b>keyword-expression</b>
|
||||
may contain default values for some or all of the keywords it holds</p>
|
||||
|
||||
<h2><a name="functions"></a>Functions</h2>
|
||||
<h2><a name="classes"></a>Classes</h2>
|
||||
|
||||
<h3><a name="args-spec"></a><code>args(</code>...<code>)</code></h3>
|
||||
<h3><a name="arg-spec"></a><code>class arg;</code></h3>
|
||||
|
||||
<p>The objects of class arg are keyword-expressions holding one keyword (
|
||||
size one )</p>
|
||||
|
||||
<h4><a name="arg-synopsis"></a>Class <code>arg</code> synopsis</h4>
|
||||
<pre>
|
||||
<i>unspecified1</i> args(char const*);
|
||||
<i>unspecified2</i> args(char const*, char const*);
|
||||
.
|
||||
.
|
||||
.
|
||||
<i>unspecifiedN</i> args(char const*, char const*, ... char const*);
|
||||
namespace boost { namespace python
|
||||
{
|
||||
struct arg
|
||||
{
|
||||
template <class T>
|
||||
arg &perator = (T const &value);
|
||||
explicit arg (char const *name){elements[0].name = name;}
|
||||
};
|
||||
|
||||
}}
|
||||
</pre>
|
||||
|
||||
<h4><a name="arg-ctor"></a>Class <code>arg</code> constructor</h4>
|
||||
<pre>
|
||||
arg(char const* name);
|
||||
</pre>
|
||||
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> Every argument must be a <a href=
|
||||
<dt><b>Requires:</b> The argument must be a <a href=
|
||||
"definitions.html#ntbs">ntbs</a>.</dt>
|
||||
|
||||
<dt><b>Returns:</b> an object representing a <a href=
|
||||
"#keyword-expression"><i>keyword-expression</i></a> encapsulating the
|
||||
arguments passed.</dt>
|
||||
<dt><b>Effects:</b> Constructs an <code>arg</code> object holding a
|
||||
keyword with name <code>name</code>.</dt>
|
||||
</dl>
|
||||
|
||||
<h4><a name="arg-operator"></a>Class <code>arg</code> operator =</h4>
|
||||
<pre>
|
||||
template <class T> arg &operator = (T const &value);
|
||||
</pre>
|
||||
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> The argument must convertible to python.</dt>
|
||||
|
||||
<dt><b>Effects:</b> Assigns default value for the keyword.</dt>
|
||||
|
||||
<dt><b>Returns:</b> Reference to <code>this</code>.</dt>
|
||||
</dl>
|
||||
|
||||
<h2><a name="keyword-expression-operators"><i>Keyword-expression</i>
|
||||
operator <code>,</code></a></h2>
|
||||
<pre>
|
||||
<i>keyword-expression</i> operator , (<i>keyword-expression</i>, const arg &kw) const
|
||||
<i>keyword-expression</i> operator , (<i>keyword-expression</i>, const char *name) const;
|
||||
</pre>
|
||||
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> The argument <code>name</code> must be a <a href=
|
||||
"definitions.html#ntbs">ntbs</a>.</dt>
|
||||
|
||||
<dt><b>Effects:</b> Extends the <i>keyword-expression</i> argument with
|
||||
one more keyword.</dt>
|
||||
|
||||
<dt><b>Returns:</b> The extended <i>keyword-expression</i>.</dt>
|
||||
</dl>
|
||||
|
||||
<h2><font color="#7F7F7F"><a name="functions"></a>Functions
|
||||
(deprecated)</font></h2>
|
||||
|
||||
<h3><a name="args-spec"></a><code><font color=
|
||||
"#7F7F7F">args</font>(</code>...<code>)</code></h3>
|
||||
<pre>
|
||||
<font color="#7F7F7F"> <i>unspecified1</i> args(char const*);
|
||||
<i>unspecified2</i> args(char const*, char const*);
|
||||
.
|
||||
.
|
||||
.
|
||||
<i>unspecifiedN</i> args(char const*, char const*, ... char const*);
|
||||
</font>
|
||||
</pre>
|
||||
|
||||
<dl class="function-semantics">
|
||||
<dt><font color="#7F7F7F"><b>Requires:</b> Every argument must be a <a
|
||||
href="definitions.html#ntbs">ntbs</a>.</font></dt>
|
||||
|
||||
<dt><font color="#7F7F7F"><b>Returns:</b> an object representing a <a
|
||||
href="#keyword-expression"><i>keyword-expression</i></a> encapsulating
|
||||
the arguments passed.</font></dt>
|
||||
</dl>
|
||||
|
||||
<h2><a name="examples"></a>Example</h2>
|
||||
@@ -85,19 +177,21 @@
|
||||
#include <boost/python/def.hpp>
|
||||
using namespace boost::python;
|
||||
|
||||
int f(int x, int y, int z);
|
||||
int f(double x, double y, double z=0.0, double w=1.0);
|
||||
|
||||
BOOST_PYTHON_MODULE(xxx)
|
||||
{
|
||||
def("f", f, args("x", "y", "z"));
|
||||
def("f", f
|
||||
, ( arg("x"), "y", arg("z")=0.0, arg("w")=1.0 )
|
||||
);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Revised 05 November, 2001</p>
|
||||
<p>Revised 01 August, 2003</p>
|
||||
|
||||
<p><i>© Copyright <a href=
|
||||
"../../../../people/dave_abrahams.htm">Dave Abrahams</a> 2002. All Rights
|
||||
Reserved.</i></p>
|
||||
"../../../../people/dave_abrahams.htm">Dave Abrahams</a> 2002-2003. All
|
||||
Rights Reserved.</i></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -23,11 +23,12 @@
|
||||
# include <boost/preprocessor/iteration/local.hpp>
|
||||
|
||||
# include <boost/python/detail/mpl_lambda.hpp>
|
||||
# include <boost/python/object_core.hpp>
|
||||
|
||||
# include <boost/mpl/bool.hpp>
|
||||
|
||||
# include <cstddef>
|
||||
|
||||
# include <algorithm>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
@@ -42,6 +43,16 @@ namespace detail
|
||||
{
|
||||
return keyword_range(elements, elements + nkeywords);
|
||||
}
|
||||
|
||||
keywords<nkeywords+1> operator,(const keywords<1> &k) const
|
||||
{
|
||||
python::detail::keywords<size+1> res;
|
||||
std::copy(elements, elements+size, res.elements);
|
||||
res.elements[size] = k.elements[0];
|
||||
return res;
|
||||
}
|
||||
|
||||
keywords<nkeywords+1> operator,(const char *name) const;
|
||||
|
||||
keyword elements[nkeywords];
|
||||
};
|
||||
@@ -97,6 +108,37 @@ namespace detail
|
||||
# endif
|
||||
}
|
||||
|
||||
struct arg : detail::keywords<1>
|
||||
{
|
||||
explicit arg(char const *name)
|
||||
{
|
||||
elements[0].name = name;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
arg& operator=(T const& value)
|
||||
{
|
||||
object z(value);
|
||||
elements[0].default_value = handle<>(python::borrowed(object(value).ptr()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator detail::keyword const&() const
|
||||
{
|
||||
return elements[0];
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <std::size_t nkeywords>
|
||||
inline keywords<nkeywords + 1>
|
||||
keywords<nkeywords>::operator,(const char *name) const
|
||||
{
|
||||
return this->operator,(arg(name));
|
||||
}
|
||||
}
|
||||
|
||||
# define BOOST_PYTHON_ASSIGN_NAME(z, n, _) result.elements[n].name = name##n;
|
||||
# define BOOST_PP_LOCAL_MACRO(n) \
|
||||
inline detail::keywords<n> args(BOOST_PP_ENUM_PARAMS_Z(1, n, char const* name)) \
|
||||
|
||||
@@ -19,6 +19,10 @@ namespace detail
|
||||
{
|
||||
struct keyword
|
||||
{
|
||||
keyword(char const* name_=0)
|
||||
: name(name_)
|
||||
{}
|
||||
|
||||
char const* name;
|
||||
handle<> default_value;
|
||||
};
|
||||
|
||||
@@ -51,6 +51,7 @@ struct BOOST_PYTHON_DECL function : PyObject
|
||||
object m_namespace;
|
||||
object m_doc;
|
||||
object m_arg_names;
|
||||
unsigned m_nkeyword_values;
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
@@ -43,10 +43,11 @@ extern PyTypeObject function_type;
|
||||
|
||||
function::function(
|
||||
py_function const& implementation
|
||||
, python::detail::keyword const* names_and_defaults
|
||||
, python::detail::keyword const* const names_and_defaults
|
||||
, unsigned num_keywords
|
||||
)
|
||||
: m_fn(implementation)
|
||||
, m_nkeyword_values(0)
|
||||
{
|
||||
if (names_and_defaults != 0)
|
||||
{
|
||||
@@ -66,12 +67,23 @@ function::function(
|
||||
|
||||
for (unsigned i = 0; i < num_keywords; ++i)
|
||||
{
|
||||
tuple kv;
|
||||
|
||||
python::detail::keyword const* const p = names_and_defaults + i;
|
||||
if (p->default_value)
|
||||
{
|
||||
kv = make_tuple(p->name, p->default_value);
|
||||
++m_nkeyword_values;
|
||||
}
|
||||
else
|
||||
{
|
||||
kv = make_tuple(p->name);
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(
|
||||
m_arg_names.ptr()
|
||||
, i + keyword_offset
|
||||
, expect_non_null(
|
||||
PyString_FromString(const_cast<char*>(names_and_defaults[i].name))
|
||||
)
|
||||
, incref(kv.ptr())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -91,9 +103,9 @@ function::~function()
|
||||
|
||||
PyObject* function::call(PyObject* args, PyObject* keywords) const
|
||||
{
|
||||
std::size_t nargs = PyTuple_GET_SIZE(args);
|
||||
std::size_t nkeywords = keywords ? PyDict_Size(keywords) : 0;
|
||||
std::size_t total_args = nargs + nkeywords;
|
||||
std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args);
|
||||
std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0;
|
||||
std::size_t n_actual = n_unnamed_actual + n_keyword_actual;
|
||||
|
||||
function const* f = this;
|
||||
|
||||
@@ -101,56 +113,88 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
|
||||
do
|
||||
{
|
||||
// Check for a plausible number of arguments
|
||||
if (total_args >= f->m_fn.min_arity()
|
||||
&& total_args <= f->m_fn.max_arity())
|
||||
unsigned min_arity = f->m_fn.min_arity();
|
||||
unsigned max_arity = f->m_fn.max_arity();
|
||||
|
||||
if (n_actual + f->m_nkeyword_values >= min_arity
|
||||
&& n_actual <= max_arity)
|
||||
{
|
||||
// This will be the args that actually get passed
|
||||
handle<> args2(allow_null(borrowed(args)));
|
||||
handle<>inner_args(allow_null(borrowed(args)));
|
||||
|
||||
if (nkeywords > 0) // Keyword arguments were supplied
|
||||
{
|
||||
if (f->m_arg_names.ptr() == Py_None) // this overload doesn't accept keywords
|
||||
if (n_keyword_actual > 0 // Keyword arguments were supplied
|
||||
|| n_actual < min_arity) // or default keyword values are needed
|
||||
{
|
||||
if (f->m_arg_names.ptr() == Py_None)
|
||||
{
|
||||
args2 = handle<>(); // signal failure
|
||||
// this overload doesn't accept keywords
|
||||
inner_args = handle<>();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::size_t max_args
|
||||
= static_cast<std::size_t>(PyTuple_Size(f->m_arg_names.ptr()));
|
||||
|
||||
// "all keywords are none" is a special case
|
||||
// indicating we will accept any number of keyword
|
||||
// arguments
|
||||
if (max_args == 0)
|
||||
if (PyTuple_Size(f->m_arg_names.ptr()) == 0)
|
||||
{
|
||||
// no argument preprocessing
|
||||
}
|
||||
else if (max_args < total_args)
|
||||
else if (n_actual > max_arity)
|
||||
{
|
||||
args2 = handle<>();
|
||||
// too many arguments
|
||||
inner_args = handle<>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// build a new arg tuple
|
||||
args2 = handle<>(PyTuple_New(total_args));
|
||||
// build a new arg tuple, will adjust its size later
|
||||
inner_args = handle<>(PyTuple_New(max_arity));
|
||||
|
||||
// Fill in the positional arguments
|
||||
for (std::size_t i = 0; i < nargs; ++i)
|
||||
PyTuple_SET_ITEM(args2.get(), i, incref(PyTuple_GET_ITEM(args, i)));
|
||||
for (std::size_t i = 0; i < n_unnamed_actual; ++i)
|
||||
PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i)));
|
||||
|
||||
// Grab remaining arguments by name from the keyword dictionary
|
||||
for (std::size_t j = nargs; j < total_args; ++j)
|
||||
std::size_t n_actual_processed = n_unnamed_actual;
|
||||
|
||||
for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos)
|
||||
{
|
||||
PyObject* value = PyDict_GetItem(
|
||||
keywords, PyTuple_GET_ITEM(f->m_arg_names.ptr(), j));
|
||||
|
||||
// Get the keyword[, value pair] corresponding
|
||||
PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos);
|
||||
|
||||
// If there were any keyword arguments,
|
||||
// look up the one we need for this
|
||||
// argument position
|
||||
PyObject* value = n_keyword_actual
|
||||
? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0))
|
||||
: 0;
|
||||
|
||||
if (!value)
|
||||
{
|
||||
PyErr_Clear();
|
||||
args2 = handle<>();
|
||||
break;
|
||||
// Not found; check if there's a default value
|
||||
if (PyTuple_GET_SIZE(kv) > 1)
|
||||
value = PyTuple_GET_ITEM(kv, 1);
|
||||
|
||||
if (!value)
|
||||
{
|
||||
// still not found; matching fails
|
||||
PyErr_Clear();
|
||||
inner_args = handle<>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
PyTuple_SET_ITEM(args2.get(), j, incref(value));
|
||||
else
|
||||
{
|
||||
++n_actual_processed;
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value));
|
||||
}
|
||||
|
||||
if (inner_args.get())
|
||||
{
|
||||
//check if we proccessed all the arguments
|
||||
if(n_actual_processed < n_actual)
|
||||
inner_args = handle<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,7 +202,7 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
|
||||
|
||||
// Call the function. Pass keywords in case it's a
|
||||
// function accepting any number of keywords
|
||||
PyObject* result = args2 ? f->m_fn(args2.get(), keywords) : 0;
|
||||
PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0;
|
||||
|
||||
// If the result is NULL but no error was set, m_fn failed
|
||||
// the argument-matching test.
|
||||
|
||||
@@ -84,6 +84,8 @@ bpl-test exception_translator ;
|
||||
bpl-test pearu1 : test_cltree.py cltree.cpp ;
|
||||
bpl-test try : newtest.py m1.cpp m2.cpp ;
|
||||
|
||||
bpl-test keywords : keywords.cpp keywords_test.py ;
|
||||
|
||||
extension builtin_converters : test_builtin_converters.cpp <dll>../build/boost_python ;
|
||||
boost-python-runtest builtin_converters : test_builtin_converters.py <pyd>builtin_converters ;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user