


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<py-script src="bug.py"></py-script>
</head>
<body>
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-2">
<input id="next1" type="submit" class="p-4 btn btn-primary" value="click me" py-onclick="test()">
</div>
</div>
</div>
</body>
import js
from js import document
def test():
button = document.getElementById("next1")
console.log("this is test 1")
console.log(button.getAttributeNames())
console.log(button.getAttribute("py-onclick"))
button.removeAttribute("py-onclick")
console.log(button.getAttributeNames())
console.log(button.getAttribute("py-onclick"))
button.setAttribute("py-onclick", "test2()")
console.log(button.getAttributeNames())
console.log(button.getAttribute("py-onclick"))
def test2():
console.log("success! this is test 2")
document.getElementById("next1").setAttribute("py-onclick", "test()")
so, the attribute value does get changed to reference the second function, but when clicking the button, it only performs the initial function it originally had.
console log shows two clicks of the button (edited)
py-onclick and py-click have event listeners attached to them when the app starts, I don't think simply removing the attribute and adding it again will achieve what you want.
If you want to have a different behaviou on different clicks, perhaps you could add a variable with a click count, then depending on the count your test() function would trigger one or the other flow







<py-config type="json">
{ "terminal": false, "packages": ["altair","bokeh" , "numpy", "pandas",
"scikit-learn", "panel==0.13.1"] }
</py-config>
exceptions.ts:52 (PY1001): Unable to install package(s) 'altair,bokeh,numpy,pandas,scikit-learn,panel==0.13.1'. Reason: Can't find a pure Python 3 Wheel for package(s) 'altair,bokeh,numpy,pandas,scikit-learn,panel==0.13.1'. See: https://pyodide.org/en/stable/usage/faq.html#micropip-can-t-find-a-pure-python-wheel for more information.


2022.12.1 i.e. <script defer src="https://pyscript.net/releases/2022.12.1/pyscript.js"></script>
ValueError: Can't find a pure Python 3 wheel for 'tornado>=5.1'.
The version of Bokeh distributed with Pyodide has all the webserver stuff removed, including the tornado dependency. So no other version can be used. Pyodide 0.22 comes with Bokeh v3.0.3, but Panel < 1.0 has a version cap for Bokeh < 2.5.0 and the Panel 1.0.0 alpha releases have a version cap for Bokeh > 3.1.0. So no version of Panel can be used in Pyodide 0.22 unless you get a custom version of Bokeh



















import js
from random import random
random.seed(js.Math.random()*2**16)
Or something similar



Object.defineProperty(globalThis, 'seed', {get() {
const random_val = new Uint8Array(1);
crypto.getRandomValues(random_val);
return random_val[0];
}});
and then
import js
from random import random
random.seed(js.seed)
random.seed(js.Date.now()) as that basically represent the default None in Python where the seed is based on system time ... that should work too, without bothering the crypto namespace.




random.seed(n=None, /)
Initialise the random number generator module with the seed n which should be an integer. When no argument (or None) is passed in it will (if supported by the port) initialise the PRNG with a true random number (usually a hardware generated random number).
The None case only works if MICROPY_PY_RANDOM_SEED_INIT_FUNC is enabled by the port, otherwise it raises ValueError.
As no ValueError is raised, it seems its not supported (yet) in Pyscript


random.seed(n=None, /)
Initialise the random number generator module with the seed n which should be an integer. When no argument (or None) is passed in it will (if supported by the port) initialise the PRNG with a true random number (usually a hardware generated random number).
The None case only works if MICROPY_PY_RANDOM_SEED_INIT_FUNC is enabled by the port, otherwise it raises ValueError.
As no ValueError is raised, it seems its not supported (yet) in Pyscript























print(dir(lib)) for both) I'm not seeing the memory usage grow at all after 10 reloads.







WebAssembly.Memory error again today. This time, I isolated it to PyOdide, as I only use PyOdide for the main thread and my one worker. I see nothing extraordinary in the memory reported by the Activity Monitor. Still not reproducible, other than following the script: "Have Chris iterate on his app for a day" 


create_callback_once and create_proxy to attach functions around? If the answer is yes, would you mind to be so kind to test the experimental_create_proxy = "auto" flag in your config.toml (or py-config) after removing those wrappers around and see if you can reproduce the error again? That might help us A LOT to convince Pyodide team that manual orchestration of proxies from users-side is actually failing while automatic usage of the GC internals help 

create_callback_once and create_proxy to attach functions around? If the answer is yes, would you mind to be so kind to test the experimental_create_proxy = "auto" flag in your config.toml (or py-config) after removing those wrappers around and see if you can reproduce the error again? That might help us A LOT to convince Pyodide team that manual orchestration of proxies from users-side is actually failing while automatic usage of the GC internals help 

create_once_callable in the mix, and you are usign raw DOM API, please never forget to pass {"once": true} as third argument of addEventListener, as I think there's a granted leak in that pyodide implementation too ... but never got a chance to demonstrate there is, thank you!

create_callback_once and create_proxy to attach functions around? If the answer is yes, would you mind to be so kind to test the experimental_create_proxy = "auto" flag in your config.toml (or py-config) after removing those wrappers around and see if you can reproduce the error again? That might help us A LOT to convince Pyodide team that manual orchestration of proxies from users-side is actually failing while automatic usage of the GC internals help experimental_create_proxy ? Right now I am getting Error: This borrowed proxy was automatically destroyed at the end of a function call. Try using create_proxy or create_once_callable.

experimental_create_proxy ? Right now I am getting Error: This borrowed proxy was automatically destroyed at the end of a function call. Try using create_proxy or create_once_callable. 

jquery (using LTK).pyodide.setDebug(true). Where and when should I do that?

jquery (using LTK). create_proxy callbacks in there, if ever?

create_callable_once utility? that's another potential leak to me as on WASM side it gets freed, on JS side not necessarily if that listener never gets removed ... I am just trying to understand your use-case stack though, where if tons of create_proxy is needed, I can already see how many ways that can fail at cleaning up the GC in the long run ... although a refresh should do, you seem to have issues on the same session (no new tab) though, so maybe I can start checking Pyodide to see if anything rings a bell





sessionStorage that might be "abused" on Pyodide to fast-path/bootstrap stuff on the same tab ... it's the only primitive I know that persists on same tab but would be new/clear on any new tab but I haven't investigated anough to see if that might be the root cause of your issues there.

navigator.storage which is a session related storage too ... and maybe, just maybe, we're into something here https://github.com/search?q=repo%3Apyodide%2Fpyodide%20mountNativeFS&type=codecreate_proxy itself.


worker attribute beside terminal? I see clicks logged/appended on the page.
create_proxy = "auto" flag but, most importantly, I'd love to understand your previous comment ... as the primitives behind that flag are all standards based and I am sure nobody specd' leaks in the FinalizationRegistry API.

create_proxy = "auto" flag but, most importantly, I'd love to understand your previous comment ... as the primitives behind that flag are all standards based and I am sure nobody specd' leaks in the FinalizationRegistry API. 




window.prompt blocks the main thread ... nothing will ever happen in there so if you block the main thread with a prompt you cannot expect much else happening in there ... use a timeout to ask for input and see it working.





new_div = pydom.create("div", classes=['test-class'])
then new_div.classes just returns an empty list. Doing the same thing w/ the Pyodide runtime works properly (returns ['test-class']).
Element.add_class() and .remove_class() work in both cases (I see the classes change in the browser's web inspector), but the results don't show up in .classes w/ MicroPython.
I'm using the 2024.6.1 release.MicroPython v1.23.0 on 2024-05-31; JS with Emscripten
Type "help()" for more information.
>>> from pyweb import pydom
>>> new_div = pydom.create("div", classes=['test-class'])
>>> new_div.classes
[]
>>> new_div.remove_class('test-class')
<Element object at 33b10>
>>> new_div.classes
[]
>>> new_div.add_class('test-class')
<Element object at 33b10>
>>> new_div.classes
[]
>>> 







await to import packages. Not quite sure what you're trying to do. Some example code and a use case would be helpful.

async attribute when you want top-level await, both in Python (in JS you need type="module" that enables it already) (edited)
async - I'm not sure why the default isn't / shouldn't be that.

async - I'm not sure why the default isn't / shouldn't be that. 













__setattr__, __getattr__ nor __getattribute__, and those are completely central for the proxy operation"
I wonder if you can help ? The github issue is here: https://github.com/kkinder/puepy/discussions/17#discussioncomment-10374441 (edited)

__setattr__, __getattr__ nor __getattribute__, and those are completely central for the proxy operation"
I wonder if you can help ? The github issue is here: https://github.com/kkinder/puepy/discussions/17#discussioncomment-10374441 (edited)

__setattr__, __getattr__ nor __getattribute__, and those are completely central for the proxy operation"
I wonder if you can help ? The github issue is here: https://github.com/kkinder/puepy/discussions/17#discussioncomment-10374441 (edited)__getattr__ in various places without issues











config attribute for what I could test ... so maybe having an <mpy-config> around could mitigate the issue



config attribute for what I could test ... so maybe having an <mpy-config> around could mitigate the issue













Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0 but on Chromium it's still Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Hacker News • 05/09/2024 15:24 





py-editor on https://christianlb.pyscriptapps.com/playground/v1/. On my PC browsers (Firefox, Brave, Chrome) the editor is able to successfully run the code and print the output just below, while on mobile (iPad and iPhone) the code execution hangs on the "loading wheel" in all mobile browsers I've tested with (Firefox Focus, Brave, Firefox, DuckDuckGo, Safari, Chrome) (edited)

















navigator.userAgent Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0 while in its about it's 130.0.2808.0 ... 













assign has disappeared from the js API.
E.g. js_array.assign(my_stream.getbuffer()) errors with no assign available
if I do a dir() I get: ['__class__', 'find', 'join', 'keys', 'map', 'reverse', 'set', 'sort', 'values', 'buffer', 'fill', 'filter', 'new', 'slice', 'reduce', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', 'length', 'toString'] (edited)
io.BytesIO doesn't give expected results and neither does Uint8Array Tricky to work out how to do this kind of thing in mpy - guess we need pyodide for more than I thought
io.BytesIO


io.BytesIO 








https://cdn.jsdelivr.net/npm/@pyscript/core@0.6.0/dist/core.js instead of the stable/official URL for PyScript and tell me how that went? I have just enabled Pyodide lockFileURL to avoid re-importing same packages all over the place every single time and I believe after your second run things should be predictably faster than before, thank you! (edited)numpy reduced bootstrap time by 1 second which is everything but irrelevant gain here addEventListener('py:progress', ({ detail }) => {
const [action, what] = detail.split(/\s+/);
if (action === 'Loading') console.time(what);
else console.timeEnd(what);
});
put this as a script before anything else and please let me know how it goes, thanks!

https://cdn.jsdelivr.net/npm/@pyscript/core@0.6.0/dist/core.js instead of the stable/official URL for PyScript and tell me how that went? I have just enabled Pyodide lockFileURL to avoid re-importing same packages all over the place every single time and I believe after your second run things should be predictably faster than before, thank you! (edited)

packages_cache = "never" and tell me, right after, what is the result, assuming you are with the same hardware and internet connection?

packages_cache = "never" ... when it's there, it bypasses the caching entirely, when it's not there, or it's not never, first time it re-does the thing then next time you should see the improvements.



packages_cache = "never" ?


lockFileURL story is just about resolving dependencies, although I got confirmed IndexedDB is not blob constrained so from a runtime URL it should attach itself to the origin site, the original page that created it. The never you added after switching to latest PyScript on npm also means it was working before, or it's working now, because if you don't have that, and you are using the PyScript I've suggested, it means it's working ... your first screenshot demonstrated it's working, now is there where you see improvements? I'll show two different scenarios in a bit (edited)lockFileURL story.








https://cdn.jsdelivr.net/npm/@pyscript/core@0.6.2/dist/core.js and let me know if anything is off (it should've fixed also random crashes, if delivered via Pyodide workers)

https://cdn.jsdelivr.net/npm/@pyscript/core@0.6.2/dist/core.js and let me know if anything is off (it should've fixed also random crashes, if delivered via Pyodide workers) 










https://cdn.jsdelivr.net/npm/@pyscript/core@0.6.33/dist/core.js as that whould at least guarantee iOS works again now.

https://cdn.jsdelivr.net/npm/@pyscript/core@0.6.33/dist/core.js as that whould at least guarantee iOS works again now. https://cdn.jsdelivr.net/npm/@pyscript/core@0.6.35/dist/core.js and https://cdn.jsdelivr.net/npm/@pyscript/core@0.6.35/dist/core.css I can confirm the issue around relative packages has been solved ... I've cloned the project and it looks good to me: https://pyscript.com/@agiammarchi/marching-squares-with-spy-copy-copy/latest?files=index.html
from pyscript.ffi import to_js
I get a Assertion failed: stringToUTF8Array expects a string (got symbol)
I think this is because its not a dict. Is there a way to pass a list ? (its an argument to a parameter that is currently being sent as a dict of true/false/numbers/strings at the moment.) I.e.
self.element.slider(to_js({
"min": min_value,
"max": max_value,
"range": "true",
"values": values,
"orientation": "horizontal" if horizontal else "vertical",
}))
where values is a list like [10,20], rest are ints. I think "true" instead of True is the right thing ?
set_value to get this to work.
So here's how to expand the ltk by adding a range (or minmax) slider: https://pyscript.com/@neon22/rangeslider-working/latest?files=main.py
showDirectoryPicker was available
if hasattr(ltk.window, "showDirectoryPicker"):
print("yeah, persistent directory handlers available!")
but it does not appear to be firing




showDirectoryPicker was available
if hasattr(ltk.window, "showDirectoryPicker"):
print("yeah, persistent directory handlers available!")
but it does not appear to be firing 



[js_modules.main] where you pass the data you want to render at requestAnimationFrame speed ... that works always on the main so the worker is free to interact ... in short: worker produces data, main renders data ... a custom module to do that should do, I will create an example soon.
runPythonAsync call to the interpreter, when code.interact() is invoked, that will never resolve, it's an infinite loop like most REPL use to handle input/output on the terminal.

code.interact() the worker is "forever waiting" for the next thing to read/write in the terminal and, if needed, I can add an example about how to workaround by delegating to the main thread the logic. (edited)


code.interact() remains blocking ... agreed ideally both should behave the same (where the same is what's MicroPython is doing).
code.interact() work.

code.interact() work. interpreter.replProcessChar(c) functionality that Pyodide AFAIK lacks https://github.com/pyscript/pyscript/blob/3223a9c7e9f49eadce9ac99d0b3967fccc58822d/core/src/plugins/py-terminal/mpy.js#L235-L253linebuffer: false ... maybe I can check again if we can do the same with Pyodide and override the code utility but that might lead to unexpected, less REPL-like, behaviors ... I'll try to give it a shot.

<script type="py"> element in .html pages. The weird thing is that these rerenders happen on iPad only. Pages work well on phones and desktop. Anyone else having this kind of behavior? Thanks to all and stay awesome.

<script type="py"> element in .html pages. The weird thing is that these rerenders happen on iPad only. Pages work well on phones and desktop. Anyone else having this kind of behavior? Thanks to all and stay awesome. 













mpy no issue whatsoever ... I have no idea why that would be the case though but I am at PyCon IT and I am not sure when/how I can debug this but I'll try.
worker attribute would just fix the thing ... if it doesn't, that's something that needs deep investigation as it's completely unexpected/isolated but it's only in latest iOS and iPad so I hope a regression they might fix before we land a patch

0.27.0 works but 0.27.1 breaks iPad on iOS 18 ... as the error is behind the Pyodide scene which is minified it's hard for me to tell what's going on but it seems to point always at the FS namespace for what I could tell ... maybe @hood is aware of such issue? I am on iPad Air 13 2025 with iOS 18 on Browser stack and as soon as pyodide bootstraps it redirects to itself and it makes it impossible to reach/use the page.

0.27.0 works but 0.27.1 breaks iPad on iOS 18 ... as the error is behind the Pyodide scene which is minified it's hard for me to tell what's going on but it seems to point always at the FS namespace for what I could tell ... maybe @hood is aware of such issue? I am on iPad Air 13 2025 with iOS 18 on Browser stack and as soon as pyodide bootstraps it redirects to itself and it makes it impossible to reach/use the page. 0.27.0 until the reason it fails after is found, you can use an explicit interpreter = "https://cdn.jsdelivr.net/pyodide/v0.27.0/full/pyodide.mjs" field in your config TOML or add explicitly a config TOML/JSON that uses such interpreter otherwise iPad on iOS18 fails ... to keep in mind it doesn't with iOS 16

0.27.0 until the reason it fails after is found, you can use an explicit interpreter = "https://cdn.jsdelivr.net/pyodide/v0.27.0/full/pyodide.mjs" field in your config TOML or add explicitly a config TOML/JSON that uses such interpreter otherwise iPad on iOS18 fails ... to keep in mind it doesn't with iOS 16 












<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/languages/python.min.js" integrity="sha512-/uCTceIDOniHf+VUKbCnP/x6GQSRrm4GwUtQYMgKa9yIZPGzlR04flSsD+2or7bPn44VY9inIHI4cwNCcZmJDw==" crossorigin="anonymous"></script> what are these for ?







BREAKING CHANGE The following packages are removed from the Pyodide distribution because of the build issues. We will try to fix them in the future: and then lists pygame-ce








input() fails in every online python runner i tested:
1. https://pydantic.runTraceback (most recent call last):
File "main.py", line 1, in <module>
input()
EOFError
2. https://play.ty.dev/Failed to run Python script: PythonError: Traceback (most recent call last):
File "/lib/python313.zip/_pyodide/_base.py", line 523, in eval_code
.run(globals, locals)
~~~^^^^^^^^^^^^^^^^^
File "/lib/python313.zip/_pyodide/_base.py", line 357, in run
coroutine = eval(self.code, globals, locals)
File "main.py", line 1, in <module>
input()
~~~~~^^
OSError: [Errno 29] I/O error
3. https://www.pykernel.com/Uncaught (in promise) TypeError: u is not iterable
at d.Tty.calculatePosition (xterm-readline.js:7:9081)
at new n.State (xterm-readline.js:7:5423)
at xterm-readline.js:7:12324
at new Promise (<anonymous>)
at o.Readline.read (xterm-readline.js:7:12272)
Observations:



