fix(code-runtime-python): stop the program's compile from inheriting the module's future annotations

bootstrap.py imports from __future__ import annotations; compile(wrapped) was
inheriting that PEP 563 flag, stringifying the program's type annotations and
changing the semantics of a legal program that reads f.__annotations__ at
runtime. compile(..., dont_inherit=True) stops the leak; a regression test
defines an annotated function and asserts the annotation is the live int class,
verified fail-before by removing dont_inherit (the test turns red).
This commit is contained in:
Chinesezjc
2026-08-31 14:49:54 +08:00
committed by Tianyi Cui
parent 6a659df999
commit 44205c4949
2 changed files with 23 additions and 1 deletions
@@ -2689,6 +2689,24 @@ describe('PythonCodeRuntime — budgets, termination, disposal', () => {
expect(result.value).toBe("read: ''")
}, 15_000)
it('keeps runtime type annotations unevaluated-as-strings when the program reads them', async () => {
// bootstrap.py imports `from __future__ import annotations`; without
// dont_inherit=True on compile(), that PEP 563 flag leaks into the program's
// compiled code and stringifies its type annotations, changing the semantics
// of a legal program that reads `f.__annotations__` at runtime.
const { runtime } = await setup()
const result = await runtime.run({
program: [
'def f(x: int) -> int:',
' return x',
'return f.__annotations__["x"].__name__',
].join('\n'),
bindings: [],
})
expect(result.error).toBeUndefined()
expect(result.value).toBe('int')
}, 15_000)
it('reaps a same-group child that ignores SIGTERM and releases the pipes before close', async () => {
// The same-group counterpart to the setsid-orphan case above. A descendant
// left in the child's OWN process group (no setsid, so `kill(-pid)` reaches