Executing dynamically created <pyscript>

I am trying to create a div containing a new pyscript and output section. But What do I need to call tun run the new pyscript code? Or at least a declared function within it?

let outputID = "blah"
let div = document.createElement("div");
let html = `
            <py-script output="${outputID}">
               ... python goes here ...
            </py-script>
            <div id="${outputID}">
            </div>
            `;
div.innerHTML = html;

// and yes this div gets added to the body after here

Thanks in advance

I see that it constructs and augments the py-script tag correctly. Some processing must be happening. But no output ever shows up in the output div.

Ah never mind I figured it out. Need to call “evaluate()” on the script tag DOM object.

Can you clarify your answer please? How did you call evaluate() on the script tag DOM object?

1 Like

This is typescript. A method execute of some object executes “text” as python. The object has a member variable output which is an HTMLDivElement (DOM div element), and a member variable pyScript in which is the script tag (first element child of an artificial div we create). We also use this to no add the tag repeatedly, but remove it before next time. I guess we could also remove it right after the execution. HTH.

    execute(text: string) {
        // prepare objects exposed to Python
        (window as any).blah= ...

        // pyscript
        let div = document.createElement("div");
        let html = `
            <py-script output="${this.output.id}">
from js import blah
${text}
            </py-script>
            `;
        div.innerHTML = html;

        // if we did this before, remove the script from the body
        if (this.pyScript) {
            this.pyScript.remove();
        }
        // now remember the new script
        this.pyScript = div.firstElementChild;
        try {
             // add it to the body - this will already augment the tag in certain ways
            document.body.appendChild(this.pyScript);
            // execute the code / evaluate the expression
            (this.pyScript as any).evaluate();
        } catch (error) {
            console.error("Python error:");
            console.error(error);
        }

    }

I plain JavaScript it would look more like this:

var myPyScript; // where I remember my pyscript object
var output = document.createElement("div"); // the div object where the output goes
output.id = "myPyScriptOutput";
document.body.appendChild(output);

function execute(text) {
        // prepare objects exposed to Python
        window.myCustomObject = ... ; // purely optional

        // pyscript
        let div = document.createElement("div");
        let html = `
            <py-script output="${output.id}">
from js import myCustomObject; # this is purely optional of course
${text}
            </py-script>
            `;
        div.innerHTML = html;

        // if we did this before, remove the script from the body
        if (myPyScript) {
            myPyScript.remove();
        }
        // now remember the new script
        myPyScript = div.firstElementChild;
        try {
             // add it to the body - this will already augment the tag in certain ways
            document.body.appendChild(myPyScript);
            // execute the code / evaluate the expression
            myPyScript.evaluate();
        } catch (error) {
            console.error("Python error:");
            console.error(error);
        }

    }

Not impossible, but also not do-able out of the box. The web components like need to participate in both the page load sequence and the Svelte Store messaging.

I just posted a video which shows how to work in the source (look for the post.) You could make a new web component which, when connectedCallback ran, would grab the child nodes of another div and execute it. Possibly passing the current node if needed.