blob: 054e4a52480aa61473a95e19d2e0c6f2c685f0ce [file] [edit]
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Shared HTML/feed parsing helpers for the docs test suites.
Imported by both test_docs.py (offline, on the built HTML) and
test_docs_online.py (live site), so the two can't drift on how they
extract the same things.
"""
import re
ATOM_NS = {"a": "http://www.w3.org/2005/Atom"}
# Sphinx-generated utility pages (search box, general index, module
# index). Not real content, so link checks skip them. Slugs, matching
# the dirhtml URLs (e.g. /genindex/).
UTILITY_PAGES = {"search", "genindex", "py-modindex"}
def find_canonical(html):
"""The <link rel="canonical"> href, or None. Attribute order
varies between Sphinx versions, so match both.
"""
m = re.search(
r'<link rel="canonical" href="([^"]+)"'
r'|<link href="([^"]+)" rel="canonical"',
html,
)
return (m.group(1) or m.group(2)) if m else None
def og_value(html, prop):
"""The `content` of a `<meta property="og:...">` tag, or None.
Sphinx and ablog don't agree on attribute order, so accept both.
"""
m = re.search(
rf'<meta (?:property="{prop}" content="([^"]*)"'
rf'|content="([^"]*)" property="{prop}")',
html,
)
return (m.group(1) or m.group(2)) if m else None
def feed_urls(root):
"""All feed-level + per-entry URLs (link hrefs + entry ids) from a
parsed atom feed root element.
"""
urls = [link.get("href") for link in root.findall("a:link", ATOM_NS)]
for entry in root.findall("a:entry", ATOM_NS):
idel = entry.find("a:id", ATOM_NS)
if idel is not None:
urls.append(idel.text)
urls.extend(
link.get("href") for link in entry.findall("a:link", ATOM_NS)
)
return [u for u in urls if u]