I am a React and Pyodide newbie. I am trying to get the following code to work in a way that I can utilize some OpenCV functionality. The code below works and I can use numpy, etc in the calculations. However, OpenCV is not available in Pyodide v0.18.1. It is available in all the subsequent versions (in one way or another). However, when I change the version number to anything above 0.18.1, I get an error in loadPyodide().
import React, { useState } from 'react';
let pyodidePromise = null;
let pyodideLoading = false;
const loadPyodide = async () => {
if (!pyodidePromise && !pyodideLoading) {
pyodideLoading = true;
pyodidePromise = window.loadPyodide({
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.18.1/full/"
});
const pyodide = await pyodidePromise;
await pyodide . loadPackage(['numpy']); //, 'opencv-python']);
pyodideLoading = false;
}
return pyodidePromise;
};
const runPythonScript = async (code) => {
const pyodide = await loadPyodide();
return await pyodide.runPythonAsync(code);
};
const ImageUploader = () => {
...
const callPython = async () => {
...
const scriptText = await (await fetch(script)).text();
const out = await runPythonScript(`${scriptText}\nmain(${JSON.stringify(args)})`);
...
};
...
For example when I change to v0.22.1, I get the following error (which may be the same error in all versions above v0.18.1).
load-pyodide.js:23
GET https://cdn.jsdelivr.net/pyodide/v0.21.1/full/packages.json 404
initializePackageIndex @ load-pyodide.js:23
loadPyodide @ pyodide.js:215
loadPyodide @ App.js:12
runPythonScript @ App.js:24
callPython @ App.js:59
await in callPython (async)
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26140
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
VM60:1
Uncaught (in promise) SyntaxError: Unexpected token '<', "<html>
<he"... is not valid JSON
await (async)
loadPyodide @ pyodide.js:215
loadPyodide @ App.js:12
runPythonScript @ App.js:24
callPython @ App.js:59
await in callPython (async)
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26140
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
pyodide.asm.js:10
Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'tests')
at pyodide.asm.js:10:114344
at loadPyodide (pyodide.js:227:9)
at async loadPyodide (App.js:16:1)
at async runPythonScript (App.js:24:1)
at async callPython (App.js:59:1)
What am I doing wrong? (This is my fourth day trying to understand this.)
edit
I incorporated it into my code based on the example below from @TachyonicBytes. It is simpler than what I previously had and works!!!
I am including a version of the simplified example from TachyonicBytes, but with imports of numpy and openCV. A simple example like this is what I have been looking for on the net for a week and could not find.
import React, { useEffect, useRef, useState } from "react";
import {useScript} from 'usehooks-ts'
const App = () => {
const pyodideStatus = useScript("https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js", {
removeOnUnmount: false,
})
const [pyodide, setPyodide] = useState(null);
const [pyodideLoaded, setPyodideLoaded] = useState(false);
useEffect(() => {
if (pyodideStatus === "ready") {
setTimeout(()=>{
(async function () {
const indexUrl = `https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js`
const pyodide = await globalThis.loadPyodide({indexUrl});
setPyodide(pyodide);
await pyodide.loadPackage(["numpy","opencv-python"]);
setPyodideLoaded(true);
})();
}, 1000)
}
}, [pyodideStatus]); // evaluate python code with pyodide and set output
async function callThis() {
const myPython = `
import numpy as np
import cv2
def func():
return np.array2string(5*np.array((1,2,3)))+" | numpy version: "+np.__version__+" | opecv version: "+cv2.__version__
func() `;
if (pyodideLoaded) {
console.log(pyodide);
let element = document.getElementById("replace");
element.innerHTML = pyodide.runPython(myPython);
console.log(element.innerHTML)
} else {
console.log("Pyodide not loaded yet");
}
}
return (
<div>
<div id="replace">Replace this</div>
<button onClick={callThis}>
Execute Python
</button>
</div> );
};
export default App;