import './styles/pyscript_base.css'; import { loadConfigFromElement } from './pyconfig'; import type { AppConfig } from './pyconfig'; import { InterpreterClient } from './interpreter_client'; import { version } from './version'; import { PluginManager, define_custom_element, Plugin, PythonPlugin } from './plugin'; import { make_PyScript, initHandlers, mountElements } from './components/pyscript'; import { getLogger } from './logger'; import { showWarning, globalExport, createLock } from './utils'; import { calculateFetchPaths } from './plugins/calculateFetchPaths'; import { createCustomElements } from './components/elements'; import { UserError, ErrorCode, _createAlertBanner } from './exceptions'; import { type Stdio, StdioMultiplexer, DEFAULT_STDIO } from './stdio'; import { PyTerminalPlugin } from './plugins/pyterminal'; import { SplashscreenPlugin } from './plugins/splashscreen'; import { ImportmapPlugin } from './plugins/importmap'; import { StdioDirector as StdioDirector } from './plugins/stdiodirector'; import { RemoteInterpreter } from './remote_interpreter'; import { robustFetch } from './fetch'; import * as Synclink from 'synclink'; const logger = getLogger('pyscript/main'); /** * Monkey patching the error transfer handler to preserve the `$$isUserError` * marker so as to detect `UserError` subclasses in the error handling code. */ const throwHandler = Synclink.transferHandlers.get('throw') as Synclink.TransferHandler< { value: unknown }, { value: { $$isUserError: boolean } } >; const old_error_transfer_handler = throwHandler.serialize.bind(throwHandler) as typeof throwHandler.serialize; function new_error_transfer_handler({ value }: { value: { $$isUserError: boolean } }) { const result = old_error_transfer_handler({ value }); result[0].value.$$isUserError = value.$$isUserError; return result; } throwHandler.serialize = new_error_transfer_handler; /* High-level overview of the lifecycle of a PyScript App: 1. pyscript.js is loaded by the browser. PyScriptApp().main() is called 2. loadConfig(): search for py-config and compute the config for the app 3. (it used to be "show the splashscreen", but now it's a plugin) 4. loadInterpreter(): start downloading the actual interpreter (e.g. pyodide.js) --- wait until (4) has finished --- 5. now the pyodide src is available. Initialize the engine 6. setup the environment, install packages 6.5: call the Plugin.afterSetup() hook 7. connect the py-script web component. This causes the execution of all the user scripts 8. initialize the rest of web components such as py-button, py-repl, etc. More concretely: - Points 1-4 are implemented sequentially in PyScriptApp.main(). - PyScriptApp.loadInterpreter adds a