Skip to content

Commit

Permalink
clarification regarding issue #750
Browse files Browse the repository at this point in the history
  • Loading branch information
wjakob committed Oct 8, 2024
1 parent 5ead8f0 commit bbbd022
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 0 deletions.
30 changes: 30 additions & 0 deletions tests/test_classes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,4 +657,34 @@ NB_MODULE(test_classes_ext, m) {
}), "s"_a)
.def("value", &UniqueInt::value)
.def("lookups", &UniqueInt::lookups);

// issue #750
PyCFunctionWithKeywords dummy_init = [](PyObject *, PyObject *,
PyObject *) -> PyObject * {
PyErr_SetString(PyExc_RuntimeError, "This should never be called!");
return nullptr;
};

PyType_Slot init_slots[] {
// the presence of this slot enables normal object construction via __init__ and __new__
// instead of an optimized codepath within nanobind that skips these. That in turn
// makes it possible to intercept calls and implement custom logic.
{ Py_tp_init, (void *) dummy_init },
{ 0, nullptr }
};

struct MonkeyPatchable {
int value = 123;
};

nb::class_<MonkeyPatchable>(m, "MonkeyPatchable", nb::type_slots(init_slots))
.def(nb::init<>())
.def_static("custom_init", [](nb::handle_t<MonkeyPatchable> h) {
if (nb::inst_ready(h))
nb::raise_type_error("Input is already initialized!");
MonkeyPatchable *p = nb::inst_ptr<MonkeyPatchable>(h);
new (p) MonkeyPatchable{456};
nb::inst_mark_ready(h);
})
.def_rw("value", &MonkeyPatchable::value);
}
12 changes: 12 additions & 0 deletions tests/test_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -891,3 +891,15 @@ def test46_custom_new():
def test47_inconstructible():
with pytest.raises(TypeError, match="no constructor defined"):
t.Foo()

def test48_monekypatchable():
# issue 750: how to monkeypatch __init__
q = t.MonkeyPatchable()
assert q.value == 123

def my_init(self):
t.MonkeyPatchable.custom_init(self)

t.MonkeyPatchable.__init__ = my_init
q = t.MonkeyPatchable()
assert q.value == 456
12 changes: 12 additions & 0 deletions tests/test_classes_ext.pyi.ref
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ class Int:

def __repr__(self) -> str: ...

class MonkeyPatchable:
def __init__(self) -> None: ...

@staticmethod
def custom_init(arg: MonkeyPatchable, /) -> None: ...

@property
def value(self) -> int: ...

@value.setter
def value(self, arg: int, /) -> None: ...

class MyClass:
def __init__(self) -> None: ...

Expand Down
1 change: 1 addition & 0 deletions tests/test_ndarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def needs_torch(x):

try:
import tensorflow as tf
import tensorflow.config
def needs_tensorflow(x):
return x
except:
Expand Down

0 comments on commit bbbd022

Please sign in to comment.