Skip to content

API reference

Every call and argument this package exposes, pulled directly from the source's own docstrings — so a person or an AI agent doesn't have to go read structile's Python source to know what open() accepts. This page is generated (via mkdocstrings) from whatever's actually installed, so it can't drift from the real signatures the way a hand-written reference could.

This covers the everyday surface — open()/diff(), format/interpreter selection, viewer settings, and what a call hands back. It doesn't list every public name: deeper plugin-authoring internals like load_plugins and PluginRecord, and the raw StructileWidget/StructileDiffWidget classes behind the widget renderer, are covered in Writing and distributing interpreters instead, in context, rather than repeated here as bare signatures.

Rendering a value

structile.open

open(
    obj: Any,
    *,
    name: Optional[str] = None,
    height: int = 600,
    config: Optional[Union[Options, Dict[str, Any]]] = None,
    interpreter: Optional[InterpreterSpec] = None,
    format: Optional[str] = None,
    path: Optional[Union[str, Path]] = None,
    renderer: Optional[str] = None,
    out: Optional[Union[str, Path]] = None,
    auto_open: bool = True,
    default: Optional[Callable[[Any], Any]] = None,
    **settings: Any,
) -> RenderHandle

Display a Python value through the active renderer. Always returns a RenderHandle (never None) with .path, .value, .open(), .to_html(), .save(path), and a one-line repr() — evaluate it as the last expression in a Jupyter cell, or pass it to IPython.display.display, and it renders itself richly there too.

See https://danieltuzes.github.io/structile/python-library/ for examples and the full picture — this is a parameter reference, not a tutorial. Shadows the open builtin — always call this namespace-qualified (structile.open(...)), never from structile import open.

Parameters:

Name Type Description Default
obj Any

the value to display — any mix of dict/list/tuple/set/None/bool/ int (any size)/float/str/numpy scalar — or a pathlib.Path/str naming an existing file to load it from (JSON, falling back to plain text). When loaded from a path whose content IS valid JSON, the file's own literal bytes (not a re-serialization) are what the viewer's source pane shows/edits/saves — so original formatting (whitespace, key order, ...) survives untouched until an edit actually touches it. There's no such "original text" for an in-memory obj (no path) or for a path that falls back to plain text (below) — both show a freshly-serialized JSON view instead, as they always have. A path whose extension is markup-like (.xml, .html/.htm — see interpreters.MARKUP_FORMATS), or has an interpreter attached to it (interpreter=, or something already registered via register_interpreter), or format= set explicitly to anything other than "json"/"python", switches to interpreter mode: obj (or a literal string, with format= then required) is handed to an interpreter instead of being read as a Python value — see interpreter= below. .xml/.html use the DOM-based interpretXML(xmlDocument) contract; any other format (.ini, .toml, ...) uses the raw-text interpretText(text) contract — see interpreters/generic_xml.js vs interpreters/generic_ini.js.

required
name Optional[str]

display name. Defaults to the loaded file's stem, else "data".

None
height int

iframe height in px (widget renderer only).

600
config Optional[Union[Options, Dict[str, Any]]]

viewer settings for this call — an Options instance, or a plain dict of the same keys (config={"gap": 8, "forNull": "N/A"}), whichever's more convenient; a dict is just turned into an Options internally (see options_from_dict).

None
**settings Any

individual viewer settings for this call — the numeric layout knobs (gap, n, m, N, M, nameMax, valMax, headerLabelMax, detCols, detRows, dwellMs, kvRows, kvCols, maxWidthFrac), theme, the "Special values" display overrides the viewer's Settings panel edits under that name — forNull/forEmpty (strings shown in place of None/"") and values (a {exact_string: replacement} table) — cosmetic only, never changes the underlying data; and linkOpen/linkClose, the viewer's cross-reference-value marker — a dict value/table cell wrapped between them, verbatim (delimiters included), that names another dict/table anywhere in the document becomes a clickable link that jumps to it (see Options). config= and **settings both take precedence over structile.options / set_option(...); anything left unset everywhere falls back to the viewer's default. There's no Settings panel in embedded (widget) mode, so this is the only way to reach these from Python there — e.g. structile.open(data, forNull="N/A") to show None as "N/A" everywhere it appears, including nested inside dicts/lists, or structile.open(data, linkOpen="<link.id", linkClose=">") so a value like "<link.id.20>" links to a same-named dict/table.

{}
interpreter Optional[InterpreterSpec]

a path to a .js interpreter script, raw JS source (interpretXML(xmlDocument) + optional serializeXML(value) for markup; interpretText(text) + optional serializeText(value) for any other text format — see interpreters/generic_xml.js, interpreters/html.js, interpreters/generic_ini.js), or an InterpreterSource (source text supplied directly rather than read from a path — what an installed plugin package hands register_interpreter; see structile.plugins()); a list mixing any of the above; or a dict keyed by file extension ({".xml": [...], ".html": [...]}) — only the entry matching the actual file/format is tried, never another extension's candidates (see resolve_candidates). Multiple candidates are never disambiguated in Python — the source(s) are forwarded as-is to whichever renderer is active, which tries each one itself (tryInterpreterCandidates in structile.html) and reports which one worked. This needs no Node.js, for any renderer including widget. Not required if something's already registered for the extension (register_interpreter, set up once at import time) — this only overrides that for one call.

None
format Optional[str]

"xml" | "html" | any other string (e.g. "ini") — required alongside interpreter=/a registered interpreter when obj isn't a path (no extension to infer it from) — unless interpreter= is a dict spanning more than one extension, in which case omitting format= forwards every entry (each under its own extension's format) to the renderer, which determines the format itself the same no-Node way (tryInterpreterCandidatesAnyFormat) — Python never has to run anything just to decide which format applies, or which contract (DOM vs. raw-text) it uses. Any format other than "xml"/"html" runs through the raw-text interpretText(text) contract instead of DOM parsing.

None
path Optional[Union[str, Path]]

save destination, overriding obj's own source path (if any) — widget renderer only (the other renderers never write back to a source file; see the browser/file/none/text docs).

None
renderer Optional[str]

"widget" | "browser" | "file" | "none" | "text" — overrides resolution for this call only. Otherwise resolved via STRUCTILE_RENDERER -> config/structile.options.renderer (set_option/use) -> auto-detect (see render.detect_renderer).

None
out Optional[Union[str, Path]]

also write the standalone HTML snapshot here (any renderer).

None
auto_open bool

set False to suppress the browser renderer's automatic webbrowser.open() (it still writes the file; call .open() later to open it manually).

True
default Optional[Callable[[Any], Any]]

called on any value that isn't one of obj's own supported types (see above); its return value is normalized in its place, same escape hatch as json.dumps(..., default=...) — e.g. default=str displays an otherwise-unsupported object as whatever str() shows for it, instead of raising TypeError. See structile.normalize.

None

structile.diff

diff(
    left: Any,
    right: Any,
    *,
    interpreter: Optional[
        Union[
            InterpreterSpec,
            Tuple[
                Optional[InterpreterSpec],
                Optional[InterpreterSpec],
            ],
        ]
    ] = None,
    format: Optional[
        Union[str, Tuple[Optional[str], Optional[str]]]
    ] = None,
    name: Optional[
        Tuple[Optional[str], Optional[str]]
    ] = None,
    view: str = "unified",
    key_columns: Optional[list] = None,
    height: int = 600,
    renderer: Optional[str] = None,
    out: Optional[Union[str, Path]] = None,
    auto_open: bool = True,
    default: Optional[
        Union[
            Callable[[Any], Any],
            Tuple[
                Optional[Callable[[Any], Any]],
                Optional[Callable[[Any], Any]],
            ],
        ]
    ] = None,
) -> DiffRenderHandle

Display a two-sided diff of left vs right through the active renderer. Always returns a DiffRenderHandle with .path, .left_payload/.right_payload, .left_value/.right_value, .open(), .to_html(), .save(path).

See https://danieltuzes.github.io/structile/python-library/#comparing-two-files-structilediff for examples. Deliberately narrower than open(): no per-side viewer config=/**settings, and the diff graph itself is always read-only for every renderer (including widget) — only each side's own source pane can be independently edited/saved (see .left_value/ .right_value, which read through to the live StructileDiffWidget for the widget renderer, same as RenderHandle.value does for open()).

Parameters:

Name Type Description Default
left Any

each independently accepts anything open()'s obj does — a Python value, a path, or (with interpreter=/ format=) a raw XML string.

required
right Any

same contract as left, independently — the two sides don't have to be the same format or schema.

required
interpreter Optional[Union[InterpreterSpec, Tuple[Optional[InterpreterSpec], Optional[InterpreterSpec]]]]

a single value applies to BOTH sides (the common case: two files in the same format/schema); a (left, right) 2-tuple gives each side its own — this is what lets left and right be two genuinely different, mutually-incompatible XML schemas, each with its own interpreter. See open()'s interpreter= docs for what a single value can be.

None
format Optional[Union[str, Tuple[Optional[str], Optional[str]]]]

same single-value-or-(left, right)-tuple convention as interpreter=. See open()'s format= docs for what a single value can be.

None
name Optional[Tuple[Optional[str], Optional[str]]]

(left_name, right_name) — defaults to each side's own inferred name (its file stem, or "left"/"right" for a raw string/value).

None
view str

"unified" | "split".

'unified'
key_columns Optional[list]

table key-column overrides — same shape the standalone viewer's own diff header accepts.

None
height int

iframe height in px (widget renderer only).

600
renderer Optional[str]

same as open().

None
out Optional[Union[str, Path]]

same as open().

None
auto_open bool

same as open().

True
default Optional[Union[Callable[[Any], Any], Tuple[Optional[Callable[[Any], Any]], Optional[Callable[[Any], Any]]]]]

same escape hatch as open()'s default=, for whichever side(s) are plain Python values (a markup/interpreter-mode side never reaches normalize(), so this has no effect there) — a single value applies to both sides; a (left, right) 2-tuple gives each side its own, same convention as interpreter=/format=.

None

Converting between formats

convert

convert(
    src: Union[str, Path],
    dst_format: str,
    interpreter: Optional[InterpreterSpec] = None,
) -> str

Convert data from one of the viewer's formats to another, entirely outside the widget/notebook — parse src, then serialize the result as dst_format, returning the converted text. See https://danieltuzes.github.io/structile/python-library/#converting-between-formats for the built-in-vs-JS-runtime boundary and examples.

Parameters:

Name Type Description Default
src Union[str, Path]

a path (format inferred from its extension: .json/.py/.csv/.tsv/ .xml/.html — or, once an interpreter is attached to it, any other extension too, e.g. .ini) or a literal string of source text (sniffed: JSON, else Python-repr, else XML if it looks like markup — there's no src_format= parameter, so a literal string for any OTHER format needs a . path instead, since there's no reliable way to sniff an arbitrary text format from content alone the way XML's leading < works).

required
dst_format str

"json" | "python" | "csv" | "tsv" (the same format written with tabs) | "xml" | "html" | any other string an interpreter is registered/provided for (e.g. "ini").

required
interpreter Optional[InterpreterSpec]

a path to a .js interpreter script, raw JS source, or a list of candidates tried in order (same contract as structile.open(..., interpreter=...) — see select_interpreter) — required whenever src or dst_format isn't "json"/"python" and isn't "csv"/"tsv" either, and nothing is registered for the relevant extension (see register_interpreter); needs the optional mini-racer package (pip install mini-racer) to run it — no Node.js, no jsdom, no system install (see interpreters.run_interpreter_source). Converting purely between the built-in formats ("json", "python", "csv", "tsv") needs nothing extra at all.

None

Custom formats

structile.register_interpreter

register_interpreter(
    ext: str, interpreter: Optional[InterpreterSpec]
) -> None

Register one or more interpreters for a file extension, once, at import time — so later structile.open(path) / convert(path, ...) calls don't need interpreter= at all:

structile.register_interpreter(".xml", "interpreters/generic_xml.js")
structile.register_interpreter(".html", ["interpreters/html.js", "interpreters/generic_xml.js"])

interpreter is a single path/raw JS source/InterpreterSource, or a list/tuple of candidates tried in order — the first one that successfully parses the data wins (see select_interpreter). None unregisters ext (same as unregister_interpreter).

A direct call here always wins over a plugin's own registration for the same ext (see _plugins.py's precedence rule) — calling this "forgets" any plugin ownership of ext recorded so far, so a later load_plugins(force=True) can't silently re-overwrite what was just set directly.

structile.unregister_interpreter

unregister_interpreter(ext: str) -> None

Remove any interpreter(s) registered for ext.

structile.get_registered_interpreter

get_registered_interpreter(
    ext: str,
) -> Optional[InterpreterSpec]

The raw spec registered for ext — a single candidate, a list, or None if nothing's registered. See resolve_candidates for the normalized list form callers actually use.

Triggers entry-point plugin discovery first (lazy, at most once per process — see _plugins.load_plugins): every renderer's resolution path (open()/diff()'s markup-mode detection, resolve_candidates's own registry fallback below, convert()'s format inference) reaches the registry through this one function, so a plugin's registration becomes visible here with no import of the plugin package and no explicit registration call needed.

Custom/branded distributions

The calls behind building a custom/branded distribution — baking a curated set of interpreters into your own copy of the viewer, registering that same manifest with the Python-side registry, and pointing every renderer at the result. See that guide for the end-to-end walkthrough and a downloadable template; these are the exact signatures.

structile.build_custom_html

build_custom_html(
    manifest: ManifestSource,
    *,
    source_html: Optional[Union[str, Path]] = None,
    output: Optional[Union[str, Path]] = None,
) -> str

Bake manifest's {extensions, path, name, format} entries into a copy of structile.html, and return the resulting HTML text.

manifest holds ANY NUMBER of interpreters, and baking several formats into one branded viewer is the normal case. Two accepted shapes (see structile.manifest.load_manifest): a path to a JSON file shaped {"interpreters": [ ... ]}, whose path values resolve relative to that file; or, in memory, the inner list of entry dicts on its own — NOT the wrapping object. Each entry names its own extensions (one or several) and format, and one build freely mixes the two contracts ("xml"/"html" use interpretXML/serializeXML, every other format string uses interpretText/serializeText). If two entries claim the same extension the later one silently wins — no error — so keep the list unambiguous. Extensions absent from the manifest behave exactly as in the stock viewer, and the built-in JSON/Python-repr/CSV formats need no entry at all.

source_html: the base HTML to bake into — defaults to find_viewer_html()'s own resolution (the dev source next to this repo, or the bundled production build). Pass an explicit path to bake into a specific build instead (e.g. an already-minified structile.prod.html). output: if given, the resulting HTML is also written there.

structile.register_interpreters_from_manifest

register_interpreters_from_manifest(
    manifest: ManifestSource,
) -> None

Call register_interpreter() once per entry in manifest (see structile.manifest.load_manifest for accepted shapes) — the Python-side counterpart to structile.custom_html.build_custom_html, so a custom distribution can drive both the standalone-HTML baking and the Python registry from the exact same manifest instead of maintaining two separate lists.

A plugin's own register(registry) callback can't call this directly — the facade it receives only exposes register_interpreter() (see _plugins.py's _RegistryFacade) — so loop over structile.manifest.load_manifest(...) and call registry.register_interpreter(ext, InterpreterSource(text, name=...)) per entry there instead; see README.md's "Building a custom/branded distribution" section for a worked example.

structile.set_viewer_html

set_viewer_html(path: Optional[Union[str, Path]]) -> None

Point every structile renderer (open(), diff(), the widget/ browser/file renderers, .to_html()) at a specific viewer HTML file — None reverts to find_viewer_html()'s normal resolution.

This is the documented way for a thin wrapper package to ship its own customized structile.html (e.g. one built with interpreters baked in via structile.build_custom_html) without forking structile itself: call this once, from the wrapper package's own __init__.py, with the path to its bundled HTML. It's a thin wrapper around the STRUCTILE_VIEWER_HTML env var (read fresh by find_viewer_html() on every call, never cached), just under a name that documents this as a supported integration point rather than only a dev/testing knob.

structile.load_manifest

load_manifest(
    source: ManifestSource,
) -> List[InterpreterManifestEntry]

Normalize source into a list of InterpreterManifestEntry.

source is either: - a path to a JSON manifest file — {"interpreters": [...]}, each item shaped like InterpreterManifestEntry's fields, with path values resolved relative to the manifest file's own directory; or - a plain list of dicts (that same shape) or InterpreterManifestEntry instances directly — path values are used as-is, since there's no manifest file to resolve a relative path against.

structile.plugins

plugins() -> List[PluginRecord]

Every structile.interpreters entry point discovered so far — loaded successfully or not (check .success/.error): entry-point name, distribution name/version, and which extensions it registered — a support/debugging surface a user can run themselves to answer "why did my file open with the wrong schema?" or "why didn't my plugin load at all?" without reading any source or turning on logging. Including failures here (rather than only ones that loaded) matters precisely because the person most likely to call this is the one whose plugin isn't working — for them, an empty/incomplete list is indistinguishable from "never installed". Triggers discovery itself (same lazy/idempotent rule as everywhere else), so it's safe to call before anything else has resolved an interpreter.

Viewer settings

structile.Options

A namespace of viewer settings, matplotlib.rcParams-style.

Every attribute defaults to None (unset). Assigning None back to an attribute restores that "use the viewer's default" state.

as_dict

as_dict() -> Dict[str, Any]

The currently-set (non-None) options, as a plain dict.

structile.set_option

set_option(name: str, value: Any) -> None

Set a module-level default option.

structile.set_option("theme", "dark")

Equivalent to structile.options.<name> = value. Pass value=None to unset it again (falls back to the viewer's built-in default).

structile.get_option

get_option(name: str) -> Optional[Any]

Read a module-level default option (None if unset).

structile.reset_option

reset_option(name: str) -> None

Unset a module-level default option (falls back to the viewer default).

structile.use

use(renderer: str) -> None

Set the module-level default renderer, matplotlib.use()-style.

structile.use("browser")

Equivalent to set_option("renderer", renderer) / options.renderer = renderer. See structile.render.RENDERERS for the valid names.

What a call returns

structile.RenderHandle

Bases: _RenderHandleBase

What every open() call returns, regardless of renderer.

.value is the displayed value (JSON-safe data, or raw XML text when an interpreter= was used) — for the widget renderer this stays live, updated on every Save (same as StructileWidget.value always was); for every other renderer it's a static snapshot of what was rendered, since there's no channel back from a plain browser tab/file to Python. .widget is the underlying StructileWidget for the widget renderer, None otherwise — an escape hatch for anywidget-specific features (.dirty, .dirty_count, .on_msg, ...) this handle doesn't itself proxy.

set_value

set_value(obj: Any, *, name: Optional[str] = None) -> None

Replace the displayed value — only meaningful for the widget renderer (every other renderer is a static, already-written artifact).

structile.DiffRenderHandle

Bases: _RenderHandleBase

Returned by structile.diff() — the two-sided counterpart to RenderHandle, deliberately narrow: the diff GRAPH is always read-only (there's no single .value the way a plain document has one — see .left_payload/.right_payload for the static snapshot each side started from), but for the widget renderer, .left_value/ .right_value read through to the live StructileDiffWidget the same way RenderHandle.value reads through to StructileWidget — each side's own source pane is independently editable/saveable in embedded diff mode (structile.html's performDiffSideSave), even though the graph itself never is.