The Pyodide kernel mounts a virtual /drive
directory which allows access to files that
are provided by JupyterLite.
{warning}
**NOTE:** The virtual file system **does not work when in private mode under Firefox** and you'll get permission errors. It will also fail to work if you **hard refresh** the page.
from pathlib import Path
The kernel will be start in a location in the virtual drive.
Path.cwd()
a_dir = Path("dir")
a_dir.exists()
New paths should appear almost immediately in the file tree.
a_dir.mkdir(exist_ok=True)
sorted(Path.cwd().glob("*"))
Contents should disappear immediately from the file browser when removed.
a_dir.exists() and a_dir.rmdir()
sorted(Path.cwd().glob("*"))
txt = Path("test.txt")
txt.write_text("Hello! I write this from the kernel worker")
txt.read_text()
from PIL import Image
img = Path("pil_color.png")
Image.new("RGB", (60, 30), color=(73, 109, 137)).save(img)
from IPython.display import Image, Markdown, display
Image(data=img, format="png")
Files can be renamed.
txt.exists()
txt.rename("test_rename.txt")
txt.exists()
sorted(Path.cwd().glob("*"))
for path in sorted(Path.cwd().glob("*")):
display(Markdown(f"- [{path}]({path.name})" "\n" f" - `{path.stat()}`"))
import sqlite3
def create_movies(path):
path.unlink(missing_ok=True)
con = sqlite3.connect(path)
cur = con.cursor()
with con:
cur.execute("CREATE TABLE movie(title, year, score)")
cur.execute(
"""
INSERT INTO movie VALUES
('Monty Python and the Holy Grail', 1975, 8.2),
('And Now for Something Completely Different', 1971, 7.5)
"""
)
con.close()
def query_movies(path):
con = sqlite3.connect(path)
cur = con.cursor()
res = cur.execute("SELECT * FROM movie").fetchall()
con.close()
return res
db = Path("tutorial.db")
try:
create_movies(db)
assert False, "if we got here, something awesome happened!"
except sqlite3.DatabaseError as err:
print(err)
For now, one can work in a separate folder:
tmp_db = Path("/tmp/tutorial.db")
create_movies(tmp_db)
display(*query_movies(tmp_db))
And copy (not rename) the file back out, and then reading works fine.
import shutil
db.unlink(missing_ok=True)
shutil.copy2(tmp_db, db)
display(*query_movies(db))
By extension, SQLite databases hosted from the server will also be readable with
sqlite3
, such as the classic
northwind example.
con = sqlite3.connect("data/northwind.sqlite3")
cur = con.cursor()
display(*cur.execute("SELECT LastName, FirstName FROM Employees").fetchall())
Or even with pandas
:
import base64
import IPython
import pandas
df = pandas.read_sql_query("SELECT * from Employees", con, "EmployeeID")
df["Photo"] = df["Photo"].apply(
lambda raw: f"""<img src="data:image/png;base64,{base64.b64encode(raw).decode("utf-8")}"/>"""
)
IPython.display.HTML(df.T.to_html(escape=False))
{note}
Future work could potentially expose reasonably-sized queries against _huge_ databases
with techniques like [`sql.js-httpvfs`](https://github.com/phiresky/sql.js-httpvfs): see [the original post](https://phiresky.github.io/blog/2021/hosting-sqlite-databases-on-github-pages).