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 aDocumentnode.- Every node is a
Document,Element,Text,Comment, orDoctype- all subclasses ofNode- so kind checks areisinstance(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_opreadsdata-op) and raisesAttributeErrorwhen absent; writes remain explicit through.attrs. el.attrsis 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.).textis a text or comment node's own content, writable:t.text = 'new'.template.contentis a<template>element's contents as aDocument.Element(name, attrs=None),Text(text), andComment(text)construct detached nodes to insert. Undefined capitalized module attributes are concise element factories with fastcore.xml-style spelling:from fast5ever import CustomTagmakesCustomTag('text', cls='x', data_kind='demo')construct<custom-tag class="x" data-kind="demo">text</custom-tag>. Positional strings become escapedTextnodes and positional nodes remain nodes.fastcore.xml.Safeandfastcore.basics.NotStrare 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 ofold.parent.replace_child(new, old);el.unwrap()replaces an element with its contents. Inserting aDocumentnode splices its children in (DocumentFragment semantics), soold.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)
| File | Size | Uploaded | |
|---|---|---|---|
| fast5ever-0.1.4.tar.gz | 29.7 kB | Details |
Built distributions (wheels)
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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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