'How to show console output in HTML body
I'm making an online Python editor. And when I'm trying to print the console's output to the HTML body using document.write(), it is showing undefined
Code :
var py
async function ld() {
py = await loadPyodide({
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.19.1/full/"
})
}
ld()
function run() {
document.write(py.runPython(document.getElementById("c").value))
}
/*no styles*/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WIDLE - Web IDLE</title>
<script src="https://cdn.jsdelivr.net/pyodide/v0.19.1/full/pyodide.js"></script>
</head>
<body>
<textarea id="c" ></textarea>
<button onclick="run()">run</button>
</body>
</html>
By the way, what I want is, to show the console output in HTML as the StackSnippets do.
Solution 1:[1]
As per @Andreas' comment-reply, you'll need to use the config parameter of loadPyodide to set a callback function for config.stdout (and also config.stderr).
Pyodide's online documentation doesn't show the exact signature of the stdout callback, but fortunately they do have a TypeScript-annotated file in their github repo which shows that both stdout and stderr are (string) => void.
So you can do something like this:
Disclaimers:
- I don't have any prior experience with Pyodide.
- My personal style preference is to use named functions, including global-scoped functions, though I know some people are now quite religious about not doing that, eh, whatever floats yer boat...
- I added
deferto the<script>. - The jsDelivr-hosted
pyodide/v0.19.1script does not load for me and I get a HTTP 403 error. Other people are reporting issues too.- I cannot recommend that anyone use jsDelivr or any other JS hosting service that doesn't have a plausible business model and/or actual relationship with the scripts they're hosting or the sites that are using them. And more reasons.
- Even if there's nothing dodgy going on at jsDelivr, and if also even if you're using
<script integrity="">correctly, no CDN website will be around forever, after which your site will just break. Just host scripts yourself or use your own CDN account that you are responsible for.
- Even if there's nothing dodgy going on at jsDelivr, and if also even if you're using
- I cannot recommend that anyone use jsDelivr or any other JS hosting service that doesn't have a plausible business model and/or actual relationship with the scripts they're hosting or the sites that are using them. And more reasons.
// Using `var` promotes these variables to window properties which makes it easier to access them in certain situations.
var py = null;
var pythonOutputUL = null;
// The pyodide.js <script> is marked with `defer` so it won't block the page load, which also means it can't be used until the DOMContentLoaded event.
function pythonConsoleStdOut( text ) {
console.log( "Python stdout: %o", text );
appendPythonOutputMessage( 'stdout', text );
}
function pythonConsoleStdErr( text ) {
console.error( "Python stderr: %o", text );
appendPythonOutputMessage( 'stderr', text );
}
function appendPythonOutputMessage( className, text ) {
const messageLI = document.createElement('li');
messageLI.classList.add( className );
messageLI.dataset['dt'] = new Date().toString();
messageLI.textContent = text;
window.pythonOutputUL.appendChild( messageLI );
}
window.addEventListener( 'DOMContentLoaded', loadPython );
const pyodideConfig = {
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.19.1/full/",
stdout : pythonConsoleStdOut,
stderr : pythonConsoleStdErr
};
async function loadPython() {
window.pythonOutputUL = document.getElementById( 'pythonOutputUL' );
try {
window.py = await loadPyodide( pyodideConfig );
}
catch( err ) {
debugger;
console.error( "Pyodide's loadPyodide threw an error: %o", err );
appendPythonOutputMessage( "Failed to load Pyodide: " + ( err || '' ).toString() );
return;
}
document.getElementById( 'loadingMessage' ).hidden = true;
document.getElementById( 'codeTextArea' ).disabled = false;
document.getElementById( 'runButton' ).disabled = false;
}
async function run( e ) {
if( !window.py ) throw new Error( "Pyodide isn't loaded yet." );
const pythonScript = document.getElementById( "codeTextArea" ).value;
const button = e.currentTarget;
button.disabled = true;
button.textContent = "Running...";
try {
await window.py.runPythonAsync( /*code:*/ pythonScript, /*globals:*/ { } );
button.textContent = "Run";
}
catch( err ) {
// debugger; // Uncomment at your discretion.
console.error( err );
button.textContent = "Error. See browser console.";
}
finally {
button.disabled = false;
}
}
function onPyodideScriptLoadError( event ) {
debugger;
console.error( "Failed to load Pyodide.js: %o", event );
appendPythonOutputMessage( "Failed to load Pyodide.js. See browser console." );
}
#pythonOutputUL {
font-family: monospace;
}
#pythonOutputUL > li[data-dt]::before {
content: "[" attr(data-dt) "] ";
display: inline;
}
#pythonOutputUL > li.stdout {
border-top: 1px solid #ccc;
}
#pythonOutputUL > li.stderr {
border-top: 1px solid #red;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WIDLE - Web IDLE</title>
<script src="https://cdn.jsdelivr.net/pyodide/v0.19.1/full/pyodide.js" defer onerror="onPyodideScriptLoadError(event)"></script>
</head>
<body>
<noscript>Please enable JS to run</noscript>
<p id="loadingMessage">Loading, please wait...</p>
<textarea id="codeTextArea" disabled></textarea>
<button id="runButton" onclick="run(event)" disabled>Run</button>
<ul id="pythonOutputUL">
</ul>
</body>
</html>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
