Skip to main content

Add files and local modules

files registers named inputs for Observable's FileAttachment builtin. Local files are read during Notebook construction and sent to the browser as data URLs, so the widget carries its data wherever it renders.

from pathlib import Path
import tempfile

import marimo as mo
import observablejs as obs

data_dir = Path(tempfile.mkdtemp(prefix="observable-files-"))
(data_dir / "counts.csv").write_text(
"species,count\nAdelie,152\nChinstrap,68\nGentoo,124\n",
encoding="utf-8",
)

notebook = obs.Notebook(
obs.js(
'const speciesCounts = FileAttachment("counts.csv").csv({typed: true});',
key="species_counts",
display=False,
),
obs.js(
"""
Plot.barY(speciesCounts, {
x: "species",
y: "count",
fill: "species",
tip: {
// This example references a theme variable used by mdx-marimo.
// Replace it with a CSS color or remove `fill` in another host.
fill: "var(--marimo-island-background)"
}
}).plot({
height: 260,
color: {legend: true},
y: {grid: true, label: "Penguins"}
})
""",
key="chart",
),
files={"counts.csv": "counts.csv"},
base_path=data_dir,
)

full_view = notebook.view()
mo.ui.anywidget(full_view)

The mapping key is the name used by FileAttachment. typed: true asks the CSV reader to convert values such as numbers and dates. The counts come from the Palmer Penguins dataset.

Accepted files values

Each value can be a local path, a URL, or a prepared attachment record.

notebook = obs.Notebook(
obs.ojs('countries = FileAttachment("countries.json").json()'),
files={
"countries.json": {
"url": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",
"mimeType": "application/json",
}
},
)

Relative local paths resolve against base_path, which defaults to the current working directory. See File attachments for path resolution, record shapes, and browser access methods.

Discover files in source HTML

Notebook.from_html can discover local files referenced by literal FileAttachment("name") calls and embed them as data URLs:

from pathlib import Path

import observablejs as obs

source_path = Path("notebooks/report.html")
notebook = obs.Notebook.from_html(
source_path.read_text(encoding="utf-8"),
base_path=source_path.parent,
embed_file_attachments=True,
)
  • embed_file_attachments=True discovers local FileAttachment("...") references in notebook script cells and embeds each file as a data URL.
  • rewrite_imports=True inlines local modules referenced by quoted relative specifiers in static imports, export ... from declarations, and dynamic import(...) calls, following local imports recursively. Computed specifiers and paths that do not resolve to files stay unchanged.

Both options need a base_path because the source string has no filesystem location. Choose the directory that should resolve the document's relative attachment and module paths.

Leave both options false when the page already serves the referenced files at the same relative paths. When discovery is enabled, an explicit files entry takes precedence over a discovered file with the same name.

Use URL-backed attachments for large data that the browser should load outside widget state. Local files are embedded as data URLs and increase the synchronized payload.