If a1 is the result of an overload-dispatch-expression,
- only the second form is allowed and fn must be a pointer
- to function or pointer to member function whose arity is the same as A1's maximum arity.
+ only the second form is allowed and fn must be a pointer to
+ function or pointer to member function whose arity is the same as A1's maximum
+ arity.
- Effects: For each prefix P of
-
Fn's sequence of argument types, beginning
- with the one whose length is A1's minimum
- arity, adds a
- name(...) method
- overload to the extension class. Each overload generated
- invokes
+ Fn's sequence of argument types, beginning with
+ the one whose length is A1's minimum
+ arity, adds a
+ name(...) method overload to
+ the extension class. Each overload generated invokes
a1's call-expression with P, using a copy
of a1's call
policies. If the longest valid prefix of A1
@@ -477,6 +481,37 @@ class_& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3
- Returns:
*this
+class_& staticmethod(char const* name);
+
+
+
+ - Requires:
name is an ntbs which conforms to Python's identifier
+ naming rules, and corresponds to a method whose overloads have all
+ been defined.
+
+ - Effects: Replaces the existing named attribute x with
+ the result of invoking
staticmethod(x)
+ 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:
+
+ -
+
+setattr(self, name, staticmethod(getattr(self, name)))
+
+
+
+ - Note: Attempting to invoke
def(name,...) after
+ invoking staticmethod(name) will raise a RuntimeError.
+
+ - Returns:
*this
+
+
+
+
template <unspecified>
class_& def(detail::operator_<unspecified>);
@@ -597,27 +632,21 @@ class_& def_pickle(PickleSuite const&);
- - Requires: PickleSuite must be publically derived from
-
pickle_suite.
+ - Requires: PickleSuite must be publically derived from
pickle_suite.
- Effects: Defines a legal combination of the special
- attributes and methods:
-
__getinitargs__,
- __getstate__,
- __setstate__,
- __getstate_manages_dict__,
- __safe_for_unpickling__,
- __reduce__
-
+ attributes and methods: __getinitargs__,
+ __getstate__, __setstate__,
+ __getstate_manages_dict__,
+ __safe_for_unpickling__, __reduce__
- Returns:
*this
- - Rationale: Provides an
- easy to use high-level interface
- for establishing complete pickle support for the wrapped class.
- The user is protected by compile-time consistency checks.
+ - Rationale: Provides an easy to use
+ high-level interface for establishing complete pickle support for
+ the wrapped class. The user is protected by compile-time consistency
+ checks.
@@ -685,8 +714,8 @@ class_<Derived, bases<Base> >("Derived");
Revised
- 13 November, 2002
-
+ 13 November, 2002
+
© Copyright make_method_static(name);
+ return *this;
+ }
private: // helper functions
inline void register_() const;
diff --git a/include/boost/python/object/class.hpp b/include/boost/python/object/class.hpp
index f551c29c..78cf06b5 100644
--- a/include/boost/python/object/class.hpp
+++ b/include/boost/python/object/class.hpp
@@ -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
diff --git a/src/object/class.cpp b/src/object/class.cpp
index 3c261026..dc560fef 100644
--- a/src/object/class.cpp
+++ b/src/object/class.cpp
@@ -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(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);
diff --git a/src/object/function.cpp b/src/object/function.cpp
index 2a9f0121..bf6e8665 100644
--- a/src/object/function.cpp
+++ b/src/object/function.cpp
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#include
#include
@@ -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(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_))
{
diff --git a/test/Jamfile b/test/Jamfile
index 67c2c118..eb767745 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -63,6 +63,7 @@ run ../test/embedding.cpp ../build/boost_python
$(PYTHON_LIB_PATH)
$(PYTHON_EMBEDDED_LIBRARY) ;
+bpl-test staticmethod ;
bpl-test shared_ptr ;
bpl-test polymorphism ;
bpl-test auto_ptr ;
diff --git a/test/staticmethod.cpp b/test/staticmethod.cpp
new file mode 100644
index 00000000..a62f6275
--- /dev/null
+++ b/test/staticmethod.cpp
@@ -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
+#include
+#include
+#include
+#include
+#include
+
+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", init())
+ .def("value", &X::value)
+ .def("set", &X::set)
+ .def("count", &X::count)
+ .staticmethod("count")
+ .def("magic", &getXmagic)
+ .staticmethod("magic")
+ ;
+}
+
+#include "module_tail.cpp"
diff --git a/test/staticmethod.py b/test/staticmethod.py
new file mode 100644
index 00000000..7fcaae60
--- /dev/null
+++ b/test/staticmethod.py
@@ -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])