mirror of
https://github.com/boostorg/python.git
synced 2026-01-23 05:42:30 +00:00
Add staticmethod support from Nikolay Mladenov <nickm-at-sitius.com>
[SVN r16946]
This commit is contained in:
@@ -29,10 +29,16 @@
|
||||
<hr>
|
||||
|
||||
<dl class="page-index">
|
||||
<dt>19 January 2003</dt>
|
||||
|
||||
<dd>Integrated <code>staticmethod</code> support from <a href=
|
||||
"mailto:nickm-at-sitius.com">Nikolay Mladenov</a>. Thanks,
|
||||
Nikolay!</dd>
|
||||
|
||||
<dt>29 December 2002</dt>
|
||||
|
||||
<dd>Added Visual Studio project file and instructions from Brett
|
||||
Calcott.</dd>
|
||||
Calcott. Thanks, Brett!</dd>
|
||||
|
||||
<dt>20 December 2002</dt>
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
contributed and maintains the Visual Studio project files and
|
||||
documentation.</p>
|
||||
|
||||
<p><a href="mailto:nickm@sitius.com">Nikolay Mladenov</a> contributed
|
||||
<code>staticmethod</code> support.</p>
|
||||
|
||||
<p>Martin Casado solved some sticky problems which allow us to build the
|
||||
Boost.Python shared library for AIX's crazy dynamic linking model.</p>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
namespace boost { namespace python
|
||||
{
|
||||
template <class T
|
||||
<font color="#007F00"> , class Bases = bases<>
|
||||
<font color="#007F00"> , class Bases = bases<>
|
||||
, class HeldType = T
|
||||
, class NonCopyable = <i>unspecified</i>
|
||||
>
|
||||
@@ -242,6 +242,9 @@ namespace boost { namespace python
|
||||
template <class Fn, class A1, class A2, class A3>
|
||||
class_& def(char const* name, Fn fn, A1 const&, A2 const&, A3 const&);
|
||||
|
||||
// declaring method as static
|
||||
class_& staticmethod(char const* name);
|
||||
|
||||
// exposing operators
|
||||
template <<i>unspecified</i>>
|
||||
class_& def(<a href=
|
||||
@@ -344,10 +347,11 @@ class_& def(Init init_expr);
|
||||
generated constructs an object of <code>HeldType</code> according to
|
||||
the semantics described <a href="#HeldType">above</a>, using a copy of
|
||||
<code>init_expr</code>'s <a href="CallPolicies.html">call policies</a>.
|
||||
If the longest <a href="init.html#init-expressions">valid prefix</a> of <code>Init</code> contains <em>N</em>
|
||||
types and <code>init_expr</code> holds <em>M</em> keywords, an initial
|
||||
sequence of the keywords are used for all but the first
|
||||
<em>N</em> - <em>M</em> arguments of each overload.</dt>
|
||||
If the longest <a href="init.html#init-expressions">valid prefix</a> of
|
||||
<code>Init</code> contains <em>N</em> types and <code>init_expr</code>
|
||||
holds <em>M</em> keywords, an initial sequence of the keywords are used
|
||||
for all but the first <em>N</em> - <em>M</em> arguments of
|
||||
each overload.</dt>
|
||||
|
||||
<dt><b>Returns:</b> <code>*this</code></dt>
|
||||
|
||||
@@ -378,20 +382,20 @@ class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3
|
||||
<li>
|
||||
If <code>a1</code> is the result of an <a href=
|
||||
"overloads.html#overload-dispatch-expression"><em>overload-dispatch-expression</em></a>,
|
||||
only the second form is allowed and fn must be a pointer
|
||||
to function or pointer to member function whose <a
|
||||
href="definitions.html#arity">arity</a> is the same as A1's <a href=
|
||||
"overloads.html#overload-dispatch-expression"><em>maximum arity</em></a>.
|
||||
only the second form is allowed and fn must be a pointer to
|
||||
function or pointer to member function whose <a href=
|
||||
"definitions.html#arity">arity</a> is the same as A1's <a href=
|
||||
"overloads.html#overload-dispatch-expression"><em>maximum
|
||||
arity</em></a>.
|
||||
|
||||
<dl>
|
||||
<dt><b>Effects:</b> For each prefix <em>P</em> of
|
||||
<code>Fn</code>'s sequence of argument types, beginning
|
||||
with the one whose length is <code>A1</code>'s <a href=
|
||||
"overloads.html#overload-dispatch-expression"><em>minimum
|
||||
arity</em></a>, adds a
|
||||
<code><em>name</em>(</code>...<code>)</code> method
|
||||
overload to the extension class. Each overload generated
|
||||
invokes
|
||||
<code>Fn</code>'s sequence of argument types, beginning with
|
||||
the one whose length is <code>A1</code>'s <a href=
|
||||
"overloads.html#overload-dispatch-expression"><em>minimum
|
||||
arity</em></a>, adds a
|
||||
<code><em>name</em>(</code>...<code>)</code> method overload to
|
||||
the extension class. Each overload generated invokes
|
||||
<code>a1</code>'s call-expression with <em>P</em>, using a copy
|
||||
of <code>a1</code>'s <a href="CallPolicies.html">call
|
||||
policies</a>. If the longest valid prefix of <code>A1</code>
|
||||
@@ -477,6 +481,37 @@ class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3
|
||||
<dt><b>Returns:</b> <code>*this</code></dt>
|
||||
</dl>
|
||||
<pre>
|
||||
class_& staticmethod(char const* name);
|
||||
</pre>
|
||||
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> <code>name</code> is an <a href=
|
||||
"definitions.html#ntbs">ntbs</a> which conforms to Python's <a href=
|
||||
"http://www.python.org/doc/current/ref/identifiers.html">identifier
|
||||
naming rules</a>, and corresponds to a method whose overloads have all
|
||||
been defined.</dt>
|
||||
|
||||
<dt><b>Effects:</b> Replaces the existing named attribute <i>x</i> with
|
||||
the result of invoking <code>staticmethod(</code><i>x</i><code>)</code>
|
||||
in Python. Specifies that the corresponding method is static and
|
||||
therefore no object instance will be passed to it. This is equivalent
|
||||
to the Python statement:</dt>
|
||||
|
||||
<dd>
|
||||
<pre>
|
||||
setattr(self, name, staticmethod(getattr(self, name)))
|
||||
</pre>
|
||||
</dd>
|
||||
|
||||
<dt><b>Note:</b> Attempting to invoke <code>def(name,...)</code> after
|
||||
invoking <code>staticmethod(name)</code> will <a href=
|
||||
"definitions.html#raise">raise</a> a RuntimeError.</dt>
|
||||
|
||||
<dt><b>Returns:</b> <code>*this</code></dt>
|
||||
</dl>
|
||||
<br>
|
||||
|
||||
<pre>
|
||||
template <<i>unspecified</i>>
|
||||
class_& def(<a href=
|
||||
"operators.html#operator_-spec">detail::operator_</a><unspecified>);
|
||||
@@ -597,27 +632,21 @@ class_& def_pickle(PickleSuite const&);
|
||||
</pre>
|
||||
|
||||
<dl class="function-semantics">
|
||||
<dt><b>Requires:</b> PickleSuite must be publically derived from
|
||||
<a href="pickle.html"
|
||||
><code>pickle_suite</code></a>.</dt>
|
||||
<dt><b>Requires:</b> PickleSuite must be publically derived from <a
|
||||
href="pickle.html"><code>pickle_suite</code></a>.</dt>
|
||||
|
||||
<dt><b>Effects:</b> Defines a legal combination of the special
|
||||
attributes and methods:
|
||||
<code>__getinitargs__</code>,
|
||||
<code>__getstate__</code>,
|
||||
<code>__setstate__</code>,
|
||||
<code>__getstate_manages_dict__</code>,
|
||||
<code>__safe_for_unpickling__</code>,
|
||||
<code>__reduce__</code>
|
||||
</dt>
|
||||
attributes and methods: <code>__getinitargs__</code>,
|
||||
<code>__getstate__</code>, <code>__setstate__</code>,
|
||||
<code>__getstate_manages_dict__</code>,
|
||||
<code>__safe_for_unpickling__</code>, <code>__reduce__</code></dt>
|
||||
|
||||
<dt><b>Returns:</b> <code>*this</code></dt>
|
||||
|
||||
<dt><b>Rationale:</b> Provides an
|
||||
<a href="pickle.html"
|
||||
>easy to use high-level interface</a>
|
||||
for establishing complete pickle support for the wrapped class.
|
||||
The user is protected by compile-time consistency checks.</dt>
|
||||
<dt><b>Rationale:</b> Provides an <a href="pickle.html">easy to use
|
||||
high-level interface</a> for establishing complete pickle support for
|
||||
the wrapped class. The user is protected by compile-time consistency
|
||||
checks.</dt>
|
||||
</dl>
|
||||
<br>
|
||||
|
||||
@@ -685,8 +714,8 @@ class_<Derived, bases<Base> >("Derived");
|
||||
</pre>
|
||||
Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
||||
13 November, 2002
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
13 November, 2002
|
||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
||||
|
||||
|
||||
<p><i>© Copyright <a href=
|
||||
|
||||
@@ -352,6 +352,11 @@ class class_ : public objects::class_base
|
||||
return *this;
|
||||
}
|
||||
|
||||
self& staticmethod(char const* name)
|
||||
{
|
||||
this->make_method_static(name);
|
||||
return *this;
|
||||
}
|
||||
private: // helper functions
|
||||
|
||||
inline void register_() const;
|
||||
|
||||
@@ -31,6 +31,12 @@ struct BOOST_PYTHON_DECL class_base : python::api::object
|
||||
, char const* doc = 0 // Docstring, if any.
|
||||
);
|
||||
|
||||
|
||||
// Implementation detail. Hiding this in the private section would
|
||||
// require use of template friend declarations.
|
||||
void enable_pickling(bool getstate_manages_dict);
|
||||
|
||||
protected:
|
||||
// Retrieve the underlying object
|
||||
void add_property(char const* name, object const& fget);
|
||||
void add_property(char const* name, object const& fget, object const& fset);
|
||||
@@ -45,9 +51,9 @@ struct BOOST_PYTHON_DECL class_base : python::api::object
|
||||
// for abstract classes.
|
||||
void def_no_init();
|
||||
|
||||
// Implementation detail. Hiding this in the private section would
|
||||
// require use of template friend declarations.
|
||||
void enable_pickling(bool getstate_manages_dict);
|
||||
// Effects:
|
||||
// setattr(self, staticmethod(getattr(self, method_name)))
|
||||
void make_method_static(const char *method_name);
|
||||
};
|
||||
|
||||
}}} // namespace boost::python::objects
|
||||
|
||||
@@ -440,6 +440,37 @@ namespace objects
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
PyObject* callable_check(PyObject* callable)
|
||||
{
|
||||
if (PyCallable_Check(expect_non_null(callable)))
|
||||
return callable;
|
||||
|
||||
::PyErr_Format(
|
||||
PyExc_TypeError
|
||||
, "staticmethod expects callable object; got an object of type %s, which is not callable"
|
||||
, callable->ob_type->tp_name
|
||||
);
|
||||
|
||||
throw_error_already_set();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void class_base::make_method_static(const char * method_name)
|
||||
{
|
||||
PyTypeObject* self = downcast<PyTypeObject>(this->ptr());
|
||||
dict d((handle<>(borrowed(self->tp_dict))));
|
||||
|
||||
object method(d[method_name]);
|
||||
|
||||
this->attr(method_name) = object(
|
||||
handle<>(
|
||||
PyStaticMethod_New((callable_check)(method.ptr()) )
|
||||
));
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL type_handle registered_class_object(class_id id)
|
||||
{
|
||||
return query_class(id);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <boost/python/object_attributes.hpp>
|
||||
#include <boost/python/args.hpp>
|
||||
#include <boost/python/refcount.hpp>
|
||||
#include <boost/python/extract.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -261,7 +262,22 @@ void function::add_to_namespace(
|
||||
if (existing)
|
||||
{
|
||||
if (existing->ob_type == &function_type)
|
||||
{
|
||||
new_func->add_overload(existing);
|
||||
}
|
||||
else if (existing->ob_type == &PyStaticMethod_Type)
|
||||
{
|
||||
char const* name_space_name = extract<char const*>(name_space.attr("__name__"));
|
||||
|
||||
::PyErr_Format(
|
||||
PyExc_RuntimeError
|
||||
, "Boost.Python - All overloads must be exported "
|
||||
"before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'"
|
||||
, name_space_name
|
||||
, name_
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
}
|
||||
else if (is_binary_operator(name_))
|
||||
{
|
||||
|
||||
@@ -63,6 +63,7 @@ run ../test/embedding.cpp <dll>../build/boost_python
|
||||
<library-path>$(PYTHON_LIB_PATH)
|
||||
<find-library>$(PYTHON_EMBEDDED_LIBRARY) ;
|
||||
|
||||
bpl-test staticmethod ;
|
||||
bpl-test shared_ptr ;
|
||||
bpl-test polymorphism ;
|
||||
bpl-test auto_ptr ;
|
||||
|
||||
46
test/staticmethod.cpp
Normal file
46
test/staticmethod.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright David Abrahams 2002. Permission to copy, use,
|
||||
// modify, sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
#include <boost/python/class.hpp>
|
||||
#include <boost/python/module.hpp>
|
||||
#include <boost/python/def.hpp>
|
||||
#include <boost/python/call_method.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
struct X
|
||||
{
|
||||
explicit X(int x) : x(x), magic(7654321) { ++counter; }
|
||||
X(X const& rhs) : x(rhs.x), magic(7654321) { ++counter; }
|
||||
virtual ~X() { assert(magic == 7654321); magic = 6666666; x = 9999; --counter; }
|
||||
|
||||
void set(int x) { assert(magic == 7654321); this->x = x; }
|
||||
int value() const { assert(magic == 7654321); return x; }
|
||||
static int count() { return counter; }
|
||||
private:
|
||||
void operator=(X const&);
|
||||
private:
|
||||
int x;
|
||||
long magic;
|
||||
static int counter;
|
||||
};
|
||||
int X::counter;
|
||||
int getXmagic(){return 7654321;}
|
||||
|
||||
BOOST_PYTHON_MODULE(staticmethod_ext)
|
||||
{
|
||||
class_<X>("X", init<int>())
|
||||
.def("value", &X::value)
|
||||
.def("set", &X::set)
|
||||
.def("count", &X::count)
|
||||
.staticmethod("count")
|
||||
.def("magic", &getXmagic)
|
||||
.staticmethod("magic")
|
||||
;
|
||||
}
|
||||
|
||||
#include "module_tail.cpp"
|
||||
52
test/staticmethod.py
Normal file
52
test/staticmethod.py
Normal file
@@ -0,0 +1,52 @@
|
||||
'''
|
||||
>>> from staticmethod_ext import *
|
||||
|
||||
>>> class X1(X):
|
||||
... pass
|
||||
|
||||
|
||||
>>> x = X(16)
|
||||
>>> x1 = X1(17)
|
||||
|
||||
|
||||
|
||||
>>> x1.count()
|
||||
2
|
||||
|
||||
>>> x.count()
|
||||
2
|
||||
|
||||
>>> X1.count()
|
||||
2
|
||||
|
||||
>>> X.count()
|
||||
2
|
||||
|
||||
|
||||
>>> x1.magic()
|
||||
7654321
|
||||
|
||||
>>> x.magic()
|
||||
7654321
|
||||
|
||||
>>> X1.magic()
|
||||
7654321
|
||||
|
||||
>>> X.magic()
|
||||
7654321
|
||||
|
||||
|
||||
'''
|
||||
|
||||
def run(args = None):
|
||||
import sys
|
||||
import doctest
|
||||
|
||||
if args is not None:
|
||||
sys.argv = args
|
||||
return doctest.testmod(sys.modules.get(__name__))
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "running..."
|
||||
import sys
|
||||
sys.exit(run()[0])
|
||||
Reference in New Issue
Block a user