Third-party libraries
Goal
Use libraries beyond Drafter (matplotlib, pandas, requests, and others) inside an app that runs in the browser.
Before you start
You should have read Python in the browser: the key fact is that your app runs in Pyodide, so a library must be installable there, not only on your computer. You also need the library installed locally (with pip or Thonny) so the first run on your own machine works.
Importing is usually all it takes
When your program runs in the browser, Drafter scans your code for imports and installs what it finds before running it. For most libraries there is nothing to configure:
from drafter import *
from dataclasses import dataclass
import matplotlib.pyplot as plt
@dataclass
class State:
pass
@route
def index(state: State) -> Page:
plt.plot([1, 4, 2, 8, 5])
plt.title("A chart from a third-party library")
return Page(state, [
Header("It works"),
MatPlotLibPlot()
])
start_server(State())
The first page load that needs a library pays a download cost: matplotlib is several megabytes, pandas more. Later loads are faster because the browser caches the download.
What works and what cannot
Three tiers, from best to impossible:
- Built for Pyodide. The scientific stack (numpy, pandas, matplotlib, pillow, scipy, scikit-learn) has versions compiled specifically for the browser. These work well.
- Pure Python. Any package on PyPI written in plain Python (no compiled parts) installs fine. Most small utility libraries fall here.
- Cannot work. Packages that need things browsers forbid: raw network sockets, other processes, real threads, or compiled code with no Pyodide build. Database drivers, game engines, and web scrapers with browser automation are typical casualties. No flag fixes these; the browser is the limit.
The quick test: search the package name in Pyodide's built-in package list, and if it is absent but pure Python, it will install from PyPI automatically.
Fetching data from the internet
requests works in the browser, with one big caveat: the
browser's rules apply, so the other website must allow
cross-origin requests (CORS). Public data APIs usually do;
ordinary websites usually do not, and there is nothing your code
can change about a refusal.
import requests
from drafter import *
@dataclass
class State:
weather: str
URL = ("https://forecast.weather.gov/MapClick.php"
"?lat=39.68&lon=-75.75&FcstType=json")
@route
def index(state: State) -> Page:
data = requests.get(URL).json()
state.weather = data["currentobservation"]["Weather"]
return Page(state, [
"The weather in Newark right now: " + state.weather
])
start_server(State(""))
(This one is not embedded as a live demo because it depends on an external service; copy it into your own editor to try it. It also uses a dictionary, which your course may not have covered.)
Declaring packages explicitly
Automatic detection covers imports it can see in your file. When it misses (a dynamic import, or a dependency of your own module), declare packages on the command line:
drafter my_app.py --project-packages "wordfreq;emoji"
--system-packages similarly controls the base set Drafter
itself loads, and --load-packages-automatically turns the
detection off entirely if you want full manual control.
Common problems
- Works locally, fails deployed: the library is probably in
the cannot-work tier, or you imported it somewhere detection
cannot see; try declaring it with
--project-packages. - A long first load: normal for heavy libraries. Warn your users on the page, or trim the dependency.
requestsraises about the connection: check the browser console for a CORS message; if the API does not allow browser requests, no client-side fix exists.- A friendly error names the missing package: see the package import error entry.
Related
- MatPlotLibPlot: the component that puts charts on pages.
- Python in the browser: why these constraints exist.