2025, Oct 26 21:00

Running pandas with PyScript in the browser: why yfinance breaks your SMA demo and how to fix it

Fix pandas ImportError in PyScript, learn why yfinance fails in the browser due to CORS, and build an SMA calculator by moving data fetch to a Flask API.

Running pandas and yfinance in the browser with PyScript: why your SMA demo breaks and how to fix it

Building a Simple Moving Average calculator directly in the browser with PyScript looks straightforward: take user input from the page, fetch market data with yfinance, compute a rolling mean in pandas, and render the result. In practice, you’ll quickly hit an ImportError for pandas and then an even harder wall with yfinance in the browser. Let’s unpack what’s going on and what architecture actually works.

The minimal example that fails

The snippet below mirrors the original idea: HTML inputs for a ticker, a date range, and a window size; then a PyScript block that pulls the values and computes SMA with pandas after downloading prices via yfinance.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script type="module" src="https://pyscript.net/releases/2024.2.1/core.js"></script>
  <title>SMA Demo</title>
</head>
<body>
  <form>
    <label for="symField">Enter ticker symbol:</label>
    <input type="text" id="symField" />
    <br />
    <label for="fromDate">Enter start date:</label>
    <input type="datetime" id="fromDate" />
    <br />
    <label for="toDate">Enter end date:</label>
    <input type="datetime" id="toDate" />
    <br />
    <label for="spanDays">Enter number of trading days (window) for SMA:</label>
    <input type="number" id="spanDays" />
    <br />
    <button type="button" id="btnGo">Calculate SMA</button>
    <button type="button" id="btnReset">Refresh</button>
  </form>

  <py-script>
from pyodide import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import yfinance as yf

sym_el = Element('symField').element
start_el = Element('fromDate').element
stop_el = Element('toDate').element
frame = yf.download(sym_el, start=start_el, end=stop_el)
win_el = Element('spanDays').element
frame['Simple Moving Aberage'] = frame['Close'].rolling(window=win_el).mean()
print(frame)
  </py-script>
</body>
</html>

In the browser, this setup triggers an error like the following:

ImportError: cannot import name 'pandas' from 'pyodide'

What’s really breaking and why

There are two separate concerns. First, the pandas import line is wrong for PyScript. You don’t import pandas from pyodide; you declare pandas as a package to be loaded by PyScript and then import it normally. That’s easy to fix.

The second concern is structural and non-negotiable in the browser: yfinance relies on requests, and a fetch-based workaround runs into CORS. This means yfinance cannot be used directly inside the browser runtime. Even after you resolve pandas, yfinance will not work client-side due to those constraints. PyScript does not offer a way around this for the stated requirements.

The part you can fix in the browser: pandas via py-config

You can make pandas available to PyScript by declaring it in a configuration block and importing it the usual way. A working pattern looks like this, and a complete example is available at this PyScript example.

<py-config>
    name = "Pandas"
    description = "A simple application that loads a csv and displays a table of its contents."
    packages = ["pandas"]
</py-config>
<py-script>
import pandas as pd
# your pandas-based logic goes here
</py-script>

Applying this to the SMA page, the browser side can be reshaped to correctly load pandas while preserving the original logic for later integration. Note that yfinance remains present here for completeness, but it won’t execute successfully in the browser.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script type="module" src="https://pyscript.net/releases/2024.2.1/core.js"></script>
  <title>SMA Demo (Fixed pandas import)</title>
</head>
<body>
  <py-config>
    name = "Pandas"
    description = "Enable pandas in PyScript"
    packages = ["pandas"]
  </py-config>

  <form>
    <label for="symField">Enter ticker symbol:</label>
    <input type="text" id="symField" />
    <br />
    <label for="fromDate">Enter start date:</label>
    <input type="datetime" id="fromDate" />
    <br />
    <label for="toDate">Enter end date:</label>
    <input type="datetime" id="toDate" />
    <br />
    <label for="spanDays">Enter number of trading days (window) for SMA:</label>
    <input type="number" id="spanDays" />
    <br />
    <button type="button" id="btnGo">Calculate SMA</button>
    <button type="button" id="btnReset">Refresh</button>
  </form>

  <py-script>
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import yfinance as yf

sym_el = Element('symField').element
start_el = Element('fromDate').element
stop_el = Element('toDate').element
frame = yf.download(sym_el, start=start_el, end=stop_el)
win_el = Element('spanDays').element
frame['Simple Moving Aberage'] = frame['Close'].rolling(window=win_el).mean()
print(frame)
  </py-script>
</body>
</html>

The part you cannot do in the browser: yfinance

The yfinance dependency on requests prevents it from running in the browser runtime, and a fetch-based alternative is blocked by CORS. For this reason, retrieving market data needs to happen off the client. The practical path is to run a small web framework on a server, such as Flask, to perform the data retrieval and then process and display the result in the frontend. With that setup, you can use yfinance on the server without the browser constraints.

Why this matters for architecture and tooling

The takeaway is not just a fix for pandas; it’s a boundary line for what PyScript can do. Packages that rely on browser-incompatible networking stacks will not run client-side, and CORS blocks ad hoc fetch attempts to the same endpoints. Recognizing these limits early lets you design a clean split: data acquisition and compute on the server; interactivity and rendering in the browser. PyScript remains useful for in-browser Python where the packages are compatible, but it isn’t a universal drop-in replacement for server-side tasks.

Conclusion

Enable pandas in PyScript with a py-config block and a normal import, and expect that part to work as shown in the official example. Do not attempt to run yfinance in the browser; instead, move market data retrieval to a lightweight server endpoint using a web framework, then send the results to the frontend for visualization. This division respects browser security constraints and keeps your SMA workflow reliable and maintainable.

The article is based on a question from StackOverflow by rashmip_21 and an answer by Detlef.