diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 569c5415d..65dad5a57 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -129,7 +129,7 @@ extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyOb // 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop` // 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment const auto static_prop = (PyObject *) get_internals().static_property_type; - const auto call_descr_set = descr && PyObject_IsInstance(descr, static_prop) + const auto call_descr_set = descr && value && PyObject_IsInstance(descr, static_prop) && !PyObject_IsInstance(value, static_prop); if (call_descr_set) { // Call `static_property.__set__()` instead of replacing the `static_property`. diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py index db135ccec..2aaf9331f 100644 --- a/tests/test_methods_and_attributes.py +++ b/tests/test_methods_and_attributes.py @@ -171,6 +171,19 @@ def test_static_properties(): assert m.TestPropertiesOverride().def_readonly == 99 assert m.TestPropertiesOverride.def_readonly_static == 99 + # Only static attributes can be deleted + del m.TestPropertiesOverride.def_readonly_static + assert ( + hasattr(m.TestPropertiesOverride, "def_readonly_static") + and m.TestPropertiesOverride.def_readonly_static + is m.TestProperties.def_readonly_static + ) + assert "def_readonly_static" not in m.TestPropertiesOverride.__dict__ + properties_override = m.TestPropertiesOverride() + with pytest.raises(AttributeError) as excinfo: + del properties_override.def_readonly + assert "can't delete attribute" in str(excinfo.value) + def test_static_cls(): """Static property getter and setters expect the type object as the their only argument"""