Skip to content

Commit

Permalink
fix: add signature to callbacks (#67)
Browse files Browse the repository at this point in the history
Co-authored-by: Elias Sjögreen <[email protected]>
  • Loading branch information
sigmaSd and eliassjogreen authored Aug 14, 2024
1 parent 1e2e1ad commit 22ef420
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
18 changes: 14 additions & 4 deletions src/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,9 +458,9 @@ export class PyObject {
const view = new DataView(pyMethodDef.buffer);
const LE =
new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] !== 0x7;
const nameBuf = new TextEncoder().encode(
"JSCallback:" + (v.callback.name || "anonymous") + "\0",
);

const name = "JSCallback:" + (v.callback.name || "anonymous");
const nameBuf = new TextEncoder().encode(`${name}\0`);
view.setBigUint64(
0,
BigInt(Deno.UnsafePointer.value(Deno.UnsafePointer.of(nameBuf)!)),
Expand All @@ -472,9 +472,19 @@ export class PyObject {
LE,
);
view.setInt32(16, 0x1 | 0x2, LE);
// https://github.com/python/cpython/blob/f27593a87c344f3774ca73644a11cbd5614007ef/Objects/typeobject.c#L688
const SIGNATURE_END_MARKER = ")\n--\n\n";
// We're not using the correct arguments name, but just using dummy ones (because they're not accessible in js)
const fnArgs = [...Array(v.callback.length).keys()]
.map((_, i) => String.fromCharCode(97 + i)).join(",");
const docBuf = `${name}(${fnArgs}${SIGNATURE_END_MARKER}\0`;
view.setBigUint64(
24,
BigInt(Deno.UnsafePointer.value(Deno.UnsafePointer.of(nameBuf)!)),
BigInt(
Deno.UnsafePointer.value(
Deno.UnsafePointer.of(new TextEncoder().encode(docBuf))!,
),
),
LE,
);
const fn = py.PyCFunction_NewEx(
Expand Down
16 changes: 16 additions & 0 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,19 @@ Deno.test("exceptions", async (t) => {
assertThrows(() => array.shape = [3, 6]);
});
});

Deno.test("callbacks have signature", async (t) => {
const inspect = python.import("inspect");

await t.step("empty arguments", () => {
const fn = python.callback(() => {});
assertEquals(inspect.signature(fn).toString(), "()");
fn.destroy();
});

await t.step("with no arguments", () => {
const fn = python.callback((_f, _b, _c) => {});
assertEquals(inspect.signature(fn).toString(), "(a, b, c)");
fn.destroy();
});
});

0 comments on commit 22ef420

Please sign in to comment.