From e0b0dc9c0af3177cb6397a1930a3cdeeb5d89f53 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Sun, 19 Apr 2026 21:58:27 +0800 Subject: [PATCH] refactor(readme_parser): add _href helper to narrow attrGet return type Extracts a _href(link) helper that returns link.attrGet('href') narrowed to str (falling back to '') instead of the raw str|int|float|None union. Replaces all four attrGet('href') or '' call sites with _href(), fixing ty errors where the widened union leaked into TypedDict url fields. Co-Authored-By: Claude --- website/readme_parser.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/website/readme_parser.py b/website/readme_parser.py index b527c24e..ca650985 100644 --- a/website/readme_parser.py +++ b/website/readme_parser.py @@ -72,7 +72,7 @@ def render_inline_html(children: list[SyntaxTreeNode]) -> str: case "softbreak": parts.append(" ") case "link": - href = str(escape(child.attrGet("href") or "")) + href = str(escape(_href(child))) inner = render_inline_html(child.children) parts.append( f'{inner}' @@ -147,6 +147,12 @@ def _find_child(node: SyntaxTreeNode, child_type: str) -> SyntaxTreeNode | None: return None +def _href(link: SyntaxTreeNode) -> str: + """Return the link's href attribute as a string, or '' if missing.""" + href = link.attrGet("href") + return href if isinstance(href, str) else "" + + def _find_inline(node: SyntaxTreeNode) -> SyntaxTreeNode | None: """Find the inline node in a list_item's paragraph.""" para = _find_child(node, "paragraph") @@ -223,7 +229,7 @@ def _parse_list_entries( # Entry with a link name = render_inline_text(first_link.children) - url = first_link.attrGet("href") or "" + url = _href(first_link) desc_html = _extract_description_html(inline, first_link) # Collect also_see from nested bullet_list @@ -239,7 +245,7 @@ def _parse_list_entries( if sub_link: also_see.append(AlsoSee( name=render_inline_text(sub_link.children), - url=sub_link.attrGet("href") or "", + url=_href(sub_link), )) entries.append(ParsedEntry( @@ -373,7 +379,7 @@ def _parse_sponsor_item(inline: SyntaxTreeNode) -> ParsedSponsor | None: if link is None: return None name = render_inline_text(link.children) - url = link.attrGet("href") or "" + url = _href(link) split_idx = None for i, child in enumerate(inline.children):