4

I would like to run an Python script on Browser when clicking a button (on a html file). Something close to this:

<!DOCTYPE html>
<html>

<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<py-env>
</py-env>
</head>

<body>

<button type="button" onclick="runPython()">run Python</button>

<script>
function runPython() { 

<py-script>
print("you clicked me")
</py-script>

}
</script>

</body>
</html>

3 Answers 3

11

To call Python code from JavaScript requires creating a proxy. This proxy handles type (data) translation to and from JavaScript.

To create a proxy:

from js import document 
from pyodide import create_proxy

function_proxy = create_proxy(runPython)

Change your HTML element declaration to declare an ID and remove the onClick:

<button type="button" id="button">run Python</button>

Assign the proxy to an event listener for the button:

e = document.getElementById("button")
e.addEventListener("click", function_proxy)

This style is very similar to how JavaScript also assigns event listeners.

Put this together:

<body>

<button type="button" id="button">run Python</button>

<py-script>
from js import document 
from pyodide import create_proxy

def runPython():
    print("you clicked me")

function_proxy = create_proxy(runPython)

document.getElementById("button").addEventListener("click", function_proxy)
</py-script>

</body>

I wrote several articles on JavaScript and Python:

Sign up to request clarification or add additional context in comments.

4 Comments

The new pys-onClick already creates a proxy and sends it as the first argument to the function
@IuriGuilherme - correct, but understanding what a proxy is and how to use one is important as there are many ways they are required. You cannot use pys-onClick for DOM elements that are created after a page loads. If you are modifying DOM elements dynamically, you will have memory leaks if the proxy handle is not freed. pys-onClick does not provide the proxy handle.
I agree with you but that's not what I see the folks currently at the pyscript committee talking about - they wish to make the language more "user friendly" which in turn seems to mean they're trying to hide technical details as much as possible. I'm not saying I agree with that point of view, I'm just assuming that's what's gonna happen in the near future
in the forums and in the dev forums. The main message is "programming for the 99%" so that affects a lot of alpha decisions into making it simpler for more people
4
<html>
    <head>
      <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
      <link rel = 'stylesheet' href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
      <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
    </head>

  <body>
    <button id = "show_output" class = "btn btn-primary" type = "submit" pys-onClick="show_output">Show Output</button>
    <div id="output_div" style="margin-top: 10px;margin-bottom: 10px;"></div>
   
    <py-script> 
             
             def show_output(*args, **kwargs):
                output = Element("output_div")
                output.write("You Clicked Me!")
    </py-script>
  </body>
</html>

3 Comments

This answer provides another good technique/solution. As the PyScript team develops the browser DOM framework, these types of improvements will increase. Currently, these improvements are in alpha, but I expect some beneficial DOM frameworks to be released by Anaconda.
This answer shows how to use two new features pys-onClick and Element(). Many more are expected to simplify Python development in the browser.
The pyscript module has a write function taking the id of the element as first argument and value to the next, optionally appending text instead of overwriting it, this saves you from referencing the element if possible: github.com/pyscript/pyscript/blob/…
3

You can do it without the javascript's <script> and function. You already have pyscript. Change the onClick property of the button to pys-onClick and add an id property to the button, which you will then use in the python function pyscript.write('element-id', 'element-value', append=False):

<!DOCTYPE html>
<html>

<head>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<py-env>
</py-env>
</head>

<body>

<button id="thebuttonid" type="button" pys-onClick="runPython">run Python</button>

<py-script>
def runPython(*args):
    pyscript.write("thebuttonid", "you clicked me")
</py-script>

</body>
</html>

This only works if the button with the pys-onClick has an id. The id provided to the pyscript.write function is the id of the element you want to write into. In this particular case it happened to be the same element you're calling the function from. The function needs to receive arguments (hence *args) because it is receiving a pyodide javascript proxy as argument. A full annotated version would be:

<py-script>
from pyodide import JsProxy
def runPython(proxy: JsProxy) -> None:
    """
    Writes 'you clicked me' in the html element with the id 'thebuttonid'.
    This function must be called from an element with the property pys-onClick='runPython'.
    """
    pyscript.write("thebuttonid", "you clicked me")
</py-script>

Now since you're using pyscript you can replace the regular html button with a py-button:

<py-button id="thebuttonid" label="run Python" type="button" pys-onClick="runPython"></py-button>

It'll get styled by tailwind css because you imported the css file at the header. Notice that you have to move the label to a property instead of using it as the value of the button.

1 Comment

tips: pys-onClick now is deprecated. Use py-click instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.