PyScript Dependency Declarations: Why Your Imports Fail and How to Fix Them
PyScript imports fail when packages are missing from py-config. Learn how the packages list controls both correctness and page load cost, with a minimal example and verification steps.
18 Oct 2025, 23:11 UTC

The import that never resolves
You drop a <py-script> tag into an HTML file, write import numpy as np, and get a ModuleNotFoundError in the browser console. The Python code is correct, but the page has no idea that numpy needs to be downloaded. In PyScript, dependency declaration is not optional metadata; it is the contract that tells the browser which wheels to fetch before your code runs.
Why <py-config> is the contract, not a comment
PyScript runs Python through Pyodide, a WebAssembly build of CPython. When the page loads, the browser downloads the Pyodide runtime and any Python packages you declare. The <py-script> tag executes only after those dependencies are ready. If a package is missing from <py-config>, the import fails at runtime because PyScript does not search PyPI on demand; it only preloads what you list. This is a deliberate design trade-off: it keeps the download deterministic, but it means your HTML must declare every third-party import explicitly.
A minimal working pattern
Here is the smallest useful structure. Replace the script source with the PyScript CDN URL documented for the release you are using.
<!-- Replace with the PyScript CDN URL for your target release -->
<script src="PYSCRIPT_CDN_URL"></script>
<py-config>
packages = ["numpy"]
</py-config>
<py-script>
import numpy as np
print(np.arange(5))
</py-script>
In this pattern, <py-config> carries a packages list. The <py-script> tag contains standard Python. You can also point to an external file with <py-script src="app.py">, which keeps configuration in one place and logic in another.
The hidden cost of a long packages list
Every entry in packages is a separate network request and a block of bytes the browser must decode. Adding pandas or scipy can add tens of megabytes to the initial payload. On a fast connection this is an annoyance; on a throttled mobile connection it can mean several seconds of blank screen. The same list also affects memory: Pyodide unpacks wheels into the browser's memory space before your first line runs.
A second limitation is threading. PyScript executes on the main browser thread by default. A long-running computation in <py-script> will freeze the UI, block event handlers, and make the page feel broken. If your Python does heavy work, you need to either break it into smaller async steps or move it to a Web Worker, which requires additional configuration beyond the basic two-tag setup.
Verify before you ship
Do not assume a package is available. Not every PyPI package with C extensions compiles cleanly to WebAssembly. Before relying on a dependency, check the Pyodide package list for your target version.
To verify a page locally:
- Save the HTML file and open it in a browser.
- Open DevTools and switch to the Network panel.
- Reload the page and filter for
.whlorwasmrequests. - Confirm that each package in your
packageslist appears as a successful download. - Check the Console for
ModuleNotFoundErroror fetch failures.
If a wheel is missing or the import fails, the package either is not in the Pyodide distribution or is listed under a different name.
Trade-offs and an actionable next step
The <py-config> approach gives you reproducibility at the cost of verbosity. You must know your dependencies ahead of time, and you pay for all of them upfront. For small utility libraries this is fine. For data-science stacks, consider whether the page truly needs the full library or whether a lighter pure-Python alternative would meet the requirement.
Start with an empty packages list. Add one dependency at a time, reload, and watch the Network panel. That habit keeps your page lean and your imports honest. When you are ready to move beyond inline scripts, keep the configuration in <py-config> and the logic in an external .py file referenced by <py-script src>. And before you copy a CDN URL from an old tutorial, confirm it against the release notes for the PyScript version you are actually using.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.