From cf7a8a1368f6d774b466f62276533c4b31d1e639 Mon Sep 17 00:00:00 2001 From: Bedis Nbiba Date: Wed, 14 Aug 2024 20:28:31 +0100 Subject: [PATCH] feat: add instanceMethod (#68) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Elias Sjögreen --- src/python.ts | 28 ++++++++++++++++++++++++++++ src/symbols.ts | 5 +++++ test/test.ts | 20 ++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/src/python.ts b/src/python.ts index 3ccd23a..15af63d 100644 --- a/src/python.ts +++ b/src/python.ts @@ -975,6 +975,34 @@ export class Python { callback(cb: PythonJSCallback): Callback { return new Callback(cb); } + + /** + * Creates a Python instance method from a JavaScript callback. + * + * @description + * This method takes a JavaScript callback function and creates a Python instance method. + * + * The method returns both the created Python instance method and the Callback object. + * The Callback object is returned to allow the user to explicitly call its `destroy` + * method when it's no longer needed, ensuring proper resource management and + * freeing of memory. + * + * @example + * const [pyMethod, callback] = instanceMethod(myJSFunction); + * // Use pyMethod as needed + * // ... + * // When done, explicitly free the callback + * callback.destroy(); + */ + instanceMethod(cb: PythonJSCallback): [PyObject, Callback] { + const pythonCb = python.callback(cb); + const method = new PyObject( + py.PyInstanceMethod_New( + PyObject.from(pythonCb).handle, + ), + ); + return [method, pythonCb]; + } } /** diff --git a/src/symbols.ts b/src/symbols.ts index 4e84320..1bd0def 100644 --- a/src/symbols.ts +++ b/src/symbols.ts @@ -249,4 +249,9 @@ export const SYMBOLS = { parameters: ["buffer", "pointer", "pointer"], result: "pointer", }, + + PyInstanceMethod_New: { + parameters: ["pointer"], + result: "pointer", + }, } as const; diff --git a/test/test.ts b/test/test.ts index 785cb66..bed7018 100644 --- a/test/test.ts +++ b/test/test.ts @@ -325,6 +325,26 @@ Deno.test("exceptions", async (t) => { }); }); +Deno.test("instance method", () => { + const { A } = python.runModule( + ` +class A: + def b(self): + return 4 + `, + "cb_test.py", + ); + + const [m, cb] = python.instanceMethod((_args, self) => { + return self.b(); + }); + // Modifying PyObject modifes A + PyObject.from(A).setAttr("a", m); + + assertEquals(new A().a.call().valueOf(), 4); + cb.destroy(); +}); + Deno.test("callbacks have signature", async (t) => { const inspect = python.import("inspect");