Repository: pyscript/pyscript
File: pyscriptjs/src/remote_interpreter.ts (TypeScript)

Code before:
        this.pyscript_py = Synclink.proxy(this.interface.pyimport('pyscript')) as PyProxy & typeof this.pyscript_py;
        this.pyscript_py._install_pyscript_loop();

        if (config.packages) {
            logger.info('Found packages in configuration to install. Loading micropip...');
            await this.loadPackage('micropip');
        }
        logger.info('pyodide loaded and initialized');
        this.pyscript_py._run_pyscript('print("Python initialization complete")');
    }

    /**
     * delegates the registration of JS modules to
     * the underlying interface.
     * */
    registerJsModule(name: string, module: object): void {
        this.interface.registerJsModule(name, module);
    }

    /**
     * delegates the loading of packages to
     * the underlying interface.
     * */
    async loadPackage(names: string | string[]): Promise<void> {
        logger.info(`pyodide.loadPackage: ${names.toString()}`);
        // the new way in v0.22.1 and later is to pass it as a dict of options i.e.
        // { messageCallback: logger.info.bind(logger), errorCallback: logger.info.bind(logger) }
        // but one of our tests tries to use a locally downloaded older version of pyodide
        // for which the signature of `loadPackage` accepts the above params as args i.e.
        // the call uses `logger.info.bind(logger), logger.info.bind(logger)`.
        const messageCallback = logger.info.bind(logger) as typeof logger.info;
        if (Number(this.interpreter.version.split('.')[1]) >= 22) {
            await this.interface.loadPackage(names, {
                messageCallback,
                errorCallback: messageCallback,
            });
        } else {
            // @ts-expect-error Types don't include this deprecated call signature
            await this.interface.loadPackage(names, messageCallback, messageCallback);
        }
    }

    /**
     * delegates the installation of packages
     * (using a package manager, which can be specific to
     * the interface) to the underlying interface.
     *
     * For Pyodide, we use `micropip`
     * */
    async installPackage(package_name: string | string[]): Promise<void> {
        if (package_name.length > 0) {

Review comment (suggestion):
```suggestion
        // the new way in v0.22.0 and later is to pass it as a dict of options i.e.
```
makes it sound like we made this change in a patch release...

Code after:
            this.FS.mkdir('/home/pyodide/' + dir);
        }
        for (const [path, value] of python_package.files) {
            this.FS.writeFile('/home/pyodide/' + path, value);
        }
        //Refresh the module cache so Python consistently finds pyscript module
        this.invalidate_module_path_cache();

        this.globals = Synclink.proxy(this.interface.globals as PyProxyDict);
        logger.info('importing pyscript');
        this.pyscript_internal = Synclink.proxy(this.interface.pyimport('pyscript._internal')) as PyProxy &
            typeof this.pyscript_internal;
        this.pyscript_internal.set_version_info(version);
        this.pyscript_internal.install_pyscript_loop();

        if (config.packages) {
            logger.info('Found packages in configuration to install. Loading micropip...');
            await this.loadPackage('micropip');
        }
        // import some carefully selected names into the global namespace
        this.interface.runPython(`
        import js
        import pyscript
        from pyscript import Element, display, HTML
        `);

        logger.info('pyodide loaded and initialized');
    }

    /**
     * delegates the registration of JS modules to
     * the underlying interface.
     * */
    registerJsModule(name: string, module: object): void {
        this.interface.registerJsModule(name, module);
    }

    /**
     * delegates the loading of packages to
     * the underlying interface.
     * */
    async loadPackage(names: string | string[]): Promise<void> {
        logger.info(`pyodide.loadPackage: ${names.toString()}`);
        // The signature of `loadPackage` changed in Pyodide 0.22; while we generally
        // don't support older versions of Pyodide in any given release of PyScript, this
        // significant change is useful in some testing scenarios (for now)
        const messageCallback = logger.info.bind(logger) as typeof logger.info;
        // Comparing version as number to avoid issues with lexicographic comparison
        if (Number(this.interpreter.version.split('.')[1]) >= 22) {
            await this.interface.loadPackage(names, {
                messageCallback,