Compare commits

...

5 Commits

Author SHA1 Message Date
Aaron Gokaslan f2a7cac141
Merge 7eb5414a36 into c2291e597f 2024-08-23 16:38:41 +08:00
Aaron Gokaslan 7eb5414a36
Merge branch 'master' into skylion007/classmethod 2022-11-08 12:27:42 -05:00
Aaron Gokaslan 511df01562 Merge branch 'master' of https://github.com/pybind/pybind11 into skylion007/classmethod 2022-10-11 11:44:32 -07:00
Aaron Gokaslan 2e3d29de45 Update classmethod with reviewer comments 2022-10-11 11:30:09 -07:00
Aaron Gokaslan e5f866626e Implement classmethod pytype 2022-08-24 10:07:25 -04:00
4 changed files with 34 additions and 1 deletions

View File

@ -1689,6 +1689,18 @@ public:
return *this; return *this;
} }
template <typename Func, typename... Extra>
class_ &def_classmethod(const char *name_, Func &&f, const Extra &...extra) {
cpp_function cf(std::forward<Func>(f),
name(name_),
is_method(*this),
sibling(getattr(*this, name_, none())),
extra...);
auto cf_name = cf.name();
attr(std::move(cf_name)) = classmethod(std::move(cf));
return *this;
}
template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0> template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0>
class_ &def(const T &op, const Extra &...extra) { class_ &def(const T &op, const Extra &...extra) {
op.execute(*this, extra...); op.execute(*this, extra...);

View File

@ -1357,6 +1357,7 @@ inline bool PyUnicode_Check_Permissive(PyObject *o) {
#endif #endif
inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; } inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; }
inline bool PyClassMethod_Check(PyObject *o) { return o->ob_type == &PyClassMethod_Type; }
class kwargs_proxy : public handle { class kwargs_proxy : public handle {
public: public:
@ -2269,6 +2270,11 @@ public:
PYBIND11_OBJECT_CVT(staticmethod, object, detail::PyStaticMethod_Check, PyStaticMethod_New) PYBIND11_OBJECT_CVT(staticmethod, object, detail::PyStaticMethod_Check, PyStaticMethod_New)
}; };
class classmethod : public object {
public:
PYBIND11_OBJECT_CVT(classmethod, object, detail::PyClassMethod_Check, PyClassMethod_New)
};
class buffer : public object { class buffer : public object {
public: public:
PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer) PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer)

View File

@ -82,7 +82,15 @@ TEST_SUBMODULE(class_, m) {
}; };
py::class_<NoConstructor>(m, "NoConstructor") py::class_<NoConstructor>(m, "NoConstructor")
.def_static("new_instance", &NoConstructor::new_instance, "Return an instance"); .def_static("new_instance", &NoConstructor::new_instance, "Return an instance")
.def_classmethod(
"new_instance_seq_id",
[](py::type &cls) {
py::int_ seq_id = getattr(cls, "seq_id", py::int_(0));
cls.attr("seq_id") = seq_id + py::int_(1);
return NoConstructorNew::new_instance();
},
"Returns a new instance and then increment the seq_id");
py::class_<NoConstructorNew>(m, "NoConstructorNew") py::class_<NoConstructorNew>(m, "NoConstructorNew")
.def(py::init([]() { return nullptr; })) // Need a NOOP __init__ .def(py::init([]() { return nullptr; })) // Need a NOOP __init__

View File

@ -41,6 +41,13 @@ def test_instance_new():
assert cstats.alive() == 0 assert cstats.alive() == 0
def test_classmethod(num_instances=10):
assert not hasattr(m.NoConstructor, "seq_id")
for i in range(num_instances):
m.NoConstructor.new_instance_seq_id()
assert m.NoConstructor.seq_id == i + 1
def test_type(): def test_type():
assert m.check_type(1) == m.DerivedClass1 assert m.check_type(1) == m.DerivedClass1
with pytest.raises(RuntimeError) as execinfo: with pytest.raises(RuntimeError) as execinfo: