Skip to content

✨ feat(extract): parse RSS and Atom feeds#562

Merged
gaborbernat merged 3 commits into
tox-dev:mainfrom
gaborbernat:feat/530-feed-parsing
Jul 7, 2026
Merged

✨ feat(extract): parse RSS and Atom feeds#562
gaborbernat merged 3 commits into
tox-dev:mainfrom
gaborbernat:feat/530-feed-parsing

Conversation

@gaborbernat

Copy link
Copy Markdown
Member

Adds a feed parser to the extract surface: turbohtml.extract.feed(xml) and Document.feed() normalize an RSS 2.0, Atom 1.0, or RDF/RSS-1.0 document into one frozen, typed Feed of Entry records.

The format is detected from the root element and each dialect's spelling of a field is mapped onto one shape in a C walk of the parsed tree, following the established structured-data extractor pattern: the walk lives in the C core (_c/features/feed.c) and a thin Python facade (_feed.py) defines the Feed/Entry NamedTuples and registers them.

Field precedence follows feedparsercontent:encoded/content over summary/description, a permalink <guid> as the link fallback, Atom rel="alternate" link selection — kept to the minimal typed shape htmlparser2's parseFeed models. Timestamps are returned verbatim. turbohtml reuses the HTML tree builder rather than adding a parser: it lowercases and keeps namespaced element names (dc:creator, content:encoded), and the walk works with the void <link> (whose URL lands as the next text sibling in RSS/RDF) rather than around it.

Includes reference/how-to/explanation docs, a feedparser migration guide, a syndication benchmark op against feedparser, and a changelog fragment.

Closes #530

Add turbohtml.extract.feed(xml) and Document.feed(), normalizing an
RSS 2.0, Atom 1.0, or RDF/RSS-1.0 document into one frozen, typed Feed
of Entry records. The format is detected from the root element and each
dialect's spelling of a field is mapped onto one shape in a C walk of
the parsed tree, following the structured-data extractor pattern: the
walk lives in the C core and a thin Python facade defines the records.

Field precedence follows feedparser (content:encoded/content over
summary/description, guid-as-permalink link, Atom rel="alternate" link
selection), kept to the minimal typed shape htmlparser2's parseFeed
models. Timestamps come back verbatim. The HTML tree builder handles
the feed XML: it lowercases and keeps namespaced element names, and the
walk works with the void <link> (its URL is the next text sibling in
RSS/RDF) rather than around it.

Closes tox-dev#530
@gaborbernat gaborbernat added the enhancement New feature or request label Jul 7, 2026
@codspeed-hq

codspeed-hq Bot commented Jul 7, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 62 untouched benchmarks
🆕 1 new benchmark
⏩ 18 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 test_feature[syndication] N/A 673.9 µs N/A

Comparing gaborbernat:feat/530-feed-parsing (057cfc4) with main (e0b857d)

Open in CodSpeed

Footnotes

  1. 18 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

The feed() docstring and the feedparser migration guide linked Feed and
Entry NamedTuple fields with :attr:, but those fields are documented via
:param: in the class docstrings, not emitted as py:attribute targets, so
the -W docs build failed on 15 unresolved references. Match the record
convention used by PublicationDate and Paragraph: refer to the fields as
plain literals and keep :class: links to the records themselves.

Also folds in the clang-format comment rewrap and ruff-format reflow that
prek --all-files flags on the feed C walk and its tests.
@gaborbernat gaborbernat merged commit 15cf7c6 into tox-dev:main Jul 7, 2026
48 checks passed
@gaborbernat gaborbernat deleted the feat/530-feed-parsing branch July 10, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extract: RSS/Atom/RDF feed parsing

1 participant