Files
pyscript/pyscriptjs/src/pyexec.ts
2023-05-06 08:20:08 +02:00

74 lines
2.6 KiB
TypeScript

import { getLogger } from './logger';
import { ensureUniqueId } from './utils';
import { UserError, ErrorCode } from './exceptions';
import { InterpreterClient } from './interpreter_client';
import type { PyProxyCallable } from 'pyodide';
const logger = getLogger('pyexec');
export async function pyExec(
interpreter: InterpreterClient,
pysrc: string,
outElem: HTMLElement,
): Promise<{ result: any }> {
ensureUniqueId(outElem);
if (await interpreter._remote.pyscript_internal.uses_top_level_await(pysrc)) {
const err = new UserError(
ErrorCode.TOP_LEVEL_AWAIT,
'The use of top-level "await", "async for", and ' +
'"async with" has been removed.' +
'\nPlease write a coroutine containing ' +
'your code and schedule it using asyncio.ensure_future() or similar.' +
'\nSee https://docs.pyscript.net/latest/guides/asyncio.html for more information.',
);
displayPyException(err, outElem);
return { result: undefined };
}
try {
return await interpreter.run(pysrc, outElem.id);
} catch (e) {
const err = e as Error;
// XXX: currently we display exceptions in the same position as
// the output. But we probably need a better way to do that,
// e.g. allowing plugins to intercept exceptions and display them
// in a configurable way.
displayPyException(err, outElem);
return { result: undefined };
}
}
/**
* Javascript API to call the python display() function
*
* Expected usage:
* pyDisplay(interpreter, obj);
* pyDisplay(interpreter, obj, { target: targetID });
*/
export async function pyDisplay(interpreter: InterpreterClient, obj: any, kwargs: { [k: string]: any } = {}) {
const display = (await interpreter.globals.get('display')) as PyProxyCallable;
try {
await display.callKwargs(obj, kwargs);
} finally {
display.destroy();
}
}
export function displayPyException(err: Error, errElem: HTMLElement) {
const pre = document.createElement('pre');
pre.className = 'py-error';
if (err.name === 'PythonError') {
// err.message contains the python-level traceback (i.e. a string
// starting with: "Traceback (most recent call last) ..."
logger.error('Python exception:\n' + err.message);
pre.innerText = err.message;
} else {
// this is very likely a normal JS exception. The best we can do is to
// display it as is.
logger.error('Non-python exception:\n' + err.toString());
pre.innerText = err.toString();
}
errElem.appendChild(pre);
}