Skip to main content

fast5ever

WHATWG-compliant HTML parsing, mutation, and serialization for Python, powered by Rust's html5ever (the engine written for Servo).

html5ever uses the spec's algorithms but does not include the tree. fast5ever adds the missing piece, a fast arena DOM, and exposes both through a small Python API. Parsing, error recovery, and serialization all behave exactly as a browser's innerHTML does, because they are the same algorithms.

from fast5ever import parse, parse_fragment

frag = parse_fragment('<p>one<p>two')
frag.to_html()                        # '<p>one</p><p>two</p>'
[c.name for c in frag.children]       # ['p', 'p']
frag.children[0].attrs['class'] = 'lead'   # attrs is live: writes go straight to the tree

from fast5ever import Span
frag.children[0].replace(Span('replacement', cls='lead'))

doc = parse('<!DOCTYPE html><title>t</title>hello')
doc.to_html()                         # '<!DOCTYPE html><html><head><title>t'...

API

  • parse(html) parses a complete document; parse_fragment(html, context='body') parses a fragment in a context element (pass e.g. context='tbody' to parse table rows). Both return a Document node.
  • Every node is a Document, Element, Text, Comment, or Doctype - all subclasses of Node - so kind checks are isinstance(c, Text). Shared surface: .name (tag, or #document/#text/#comment/#doctype; writable on elements — el.name = 'details' renames in place, keeping attributes and children), .children, .parent, to_html(), to_text(). A missing Python property reads the correspondingly hyphenated HTML attribute (el.data_op reads data-op) and raises AttributeError when absent; writes remain explicit through .attrs.
  • el.attrs is a live mapping in source order: attrs['k'], attrs['k'] = v, del attrs['k'], in/len/iteration, get/keys/values/items/update/pop, == {...} against any mapping; dict(attrs) snapshots. (Non-elements read as empty and refuse writes.)
  • .text is a text or comment node's own content, writable: t.text = 'new'. template.content is a <template> element's contents as a Document.
  • Element(name, attrs=None), Text(text), and Comment(text) construct detached nodes to insert. Undefined capitalized module attributes are concise element factories with fastcore.xml-style spelling: from fast5ever import CustomTag makes CustomTag('text', cls='x', data_kind='demo') construct <custom-tag class="x" data-kind="demo">text</custom-tag>. Positional strings become escaped Text nodes and positional nodes remain nodes. fastcore.xml.Safe and fastcore.basics.NotStr are trusted markup: they parse as fragments in the new element's context, so table children and other context-sensitive HTML work correctly.
  • Structure: append_child, insert_before(child, reference), replace_child(new, old), replace(new), unwrap(), detach(). old.replace(new) is the convenient form of old.parent.replace_child(new, old); el.unwrap() replaces an element with its contents. Inserting a Document node splices its children in (DocumentFragment semantics), so old.replace(parse_fragment(markup)) splices markup in place. Inserting a node from another tree deep-copies it; handles stay valid across all mutations.

The node API follows the WHATWG DOM's vocabulary, with a pythonic surface (real node classes, attrs as a live mapping, to_html()/to_text()) modeled on Emil Stenström's JustHTML. The parsing and serialization engine is Servo's html5ever.

Serialization is the spec's

Output spelling comes from html5ever's own serializer - the WHATWG serialization algorithm, byte-for-byte what Chrome's innerHTML builds: boolean attributes as open="", double-quoted values, voids without /, raw text unescaped inside script/style. fast5ever adds no styling options and no compatibility shims with other serializers, by design.

Parsing is also bounded Chromium-style: element nesting beyond 512 flattens at the cap (Chromium's own limit), which keeps adversarially deep input linear-time - html5ever's tree builder alone is quadratic there.

The Rust API

fast5ever is a Rust crate first (fast5ever = { git = "https://github.com/AnswerDotAI/fast5ever" }); the Python API is a thin binding over it, so the two surfaces match verb for verb. The one structural difference: Rust has no node objects - you hold the Dom (a Vec-indexed arena) and address nodes by NodeId, with node 0 (DOCUMENT) always the document. Every id stays valid for the life of the Dom, however the tree is mutated.

use fast5ever::{parse_fragment, DOCUMENT};

let mut dom = parse_fragment("<p>one<p>two", "body");
let p = dom.children(DOCUMENT)[0];
dom.set_attr(p, "class", "lead").unwrap();
let extra = parse_fragment("<b>!</b>", "body");
let extra = dom.import(&extra, DOCUMENT);   // cross-tree moves go through an explicit import
dom.append_child(p, extra).unwrap();        // a document node splices its children, as in Python
assert_eq!(dom.to_html(DOCUMENT), r#"<p class="lead">one<b>!</b></p><p>two</p>"#);

Reads mirror the Python names (children, parent, attr, to_html, to_text); writes return Result where Python raises (set_attr, set_text, append_child, insert_before, replace_child, detach); construction is create_element/create_text/create_comment (Python's Element/Text/Comment); and Rust additionally exposes NodeData matching for direct tree inspection.

Development

pip install -e .[dev]
maturin develop && pytest -q

All tests are pytest; cargo check/cargo clippy stay warning-free and need no Python (pyo3 sits behind the python feature).

Release

Release flow: tag-push (CI publishes), then the version bump, all in one command.

maturin develop && pytest -q
ship-release

The GitHub workflow builds wheels on tags matching v* and publishes them to GitHub Releases and PyPI.

Release files for fast5ever 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fast5ever 0.1.4
File Size Uploaded
fast5ever-0.1.4.tar.gz 29.7 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for fast5ever 0.1.4
File
fast5ever-0.1.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.17+ x86-64 Details
fast5ever-0.1.4-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
fast5ever-0.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.17+ x86-64 Details
fast5ever-0.1.4-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
fast5ever-0.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.17+ x86-64 Details
fast5ever-0.1.4-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details
fast5ever-0.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.17+ x86-64 Details
fast5ever-0.1.4-cp310-cp310-macosx_11_0_arm64.whl CPython 3.10 CPython 3.10 macOS 11.0+ ARM64 Details

Total release size: 4.6 MB

Release files / fast5ever-0.1.4.tar.gz

Download URL fast5ever-0.1.4.tar.gz
Size 29.7 kB
Tags Source
SHA-256 checksum
How to use checksums
6a1feb37f31af747df536fe73b75a4aa66bb71af50e42796843dcd8ba53bb511
BLAKE2b-256 checksum
How to use checksums
46da46532e16162ed9a0d22e2f76cd09614f20abeb22929e82f2c2f06b5d64ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / fast5ever-0.1.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fast5ever-0.1.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 600.0 kB
Tags CPython 3.13 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
a208c8f23f259143b81046a352ee4ff84fd2767f759af0ec90bc361f819f3206
BLAKE2b-256 checksum
How to use checksums
0adfdf2b3abc6571769abf6e3184133497505f1e25b9a9eb776594ea7dc4be1e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / fast5ever-0.1.4-cp313-cp313-macosx_11_0_arm64.whl

Download URL fast5ever-0.1.4-cp313-cp313-macosx_11_0_arm64.whl
Size 530.3 kB
Tags CPython 3.13 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
22cd443a604e713e420ad2d999d943b9fe8ae1f4d9dfe6195e90ea933859019f
BLAKE2b-256 checksum
How to use checksums
fb747bb4d575480d2d6ee60c65f57d6dfc2fd64db876af2dcb1ba1111bfb5ee8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / fast5ever-0.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fast5ever-0.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 600.0 kB
Tags CPython 3.12 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
f673ca895867f367a3dc8a0cc2bb73e7a6ccab66b34d71caf75c2bc8fe5419eb
BLAKE2b-256 checksum
How to use checksums
983ccba454f05bdc2c5e893e216983e89c18255485562d5d1a7e7e00a8ac35b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / fast5ever-0.1.4-cp312-cp312-macosx_11_0_arm64.whl

Download URL fast5ever-0.1.4-cp312-cp312-macosx_11_0_arm64.whl
Size 530.5 kB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
7274b0f8971b6206025b6ec5a0b944e5f2e3c6b2ea519472263a02bff6914a17
BLAKE2b-256 checksum
How to use checksums
c46fba7edecce8da3eb7511221cf10c40605ae7ff47cf9031cb0ec2633d618a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / fast5ever-0.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fast5ever-0.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 603.1 kB
Tags CPython 3.11 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
771ca061f5181b88528be069c4427c7aebb5a9ab265f73fccd93e12a9ee39496
BLAKE2b-256 checksum
How to use checksums
4866726f42ab9acc2eebb0e39e878ded722951ac77cac8da7dd49679a0cd4233
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / fast5ever-0.1.4-cp311-cp311-macosx_11_0_arm64.whl

Download URL fast5ever-0.1.4-cp311-cp311-macosx_11_0_arm64.whl
Size 534.2 kB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
4c7cea5e9ce2b4292cfba8ed926c2ac687b974165d82462629a921a1de8a7f2c
BLAKE2b-256 checksum
How to use checksums
a7ee2fb68cdfda5dafee0861fde41c0f42b4eb07a43389ae4ddf192f62d3cc79
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / fast5ever-0.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fast5ever-0.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 603.0 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
5ade956045e20837f56e5a1307a3e03241a3e9ebdbc1d91b87db42c8c4975c2f
BLAKE2b-256 checksum
How to use checksums
6211e3a01af29f8906910a64f03f8f54e115c2061d014317c600512bbd730e02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / fast5ever-0.1.4-cp310-cp310-macosx_11_0_arm64.whl

Download URL fast5ever-0.1.4-cp310-cp310-macosx_11_0_arm64.whl
Size 534.3 kB
Tags CPython 3.10 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
fea5e178c5e4281e8d5e5b826bbada33d2a1a266c8c70459a1d8ded20a92f28d
BLAKE2b-256 checksum
How to use checksums
907098246643008a8e03ce07b87787115874aaf51666944713ee7e9d7eb36462
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.6

9 release files

0.1.5

9 release files

This release

0.1.4 This release

9 release files

0.1.3

9 release files

0.1.2

9 release files

0.1.1

9 release files

0.1.0

9 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page