mirror of
https://github.com/vinta/awesome-python.git
synced 2026-08-04 15:05:39 +00:00
add missing links of category descriptions
This commit is contained in:
parent
c98cbe2cb1
commit
b00395a301
5 changed files with 34 additions and 14 deletions
|
|
@ -27,6 +27,7 @@ class ParsedSection(TypedDict):
|
||||||
name: str
|
name: str
|
||||||
slug: str
|
slug: str
|
||||||
description: str # plain text, links resolved to text
|
description: str # plain text, links resolved to text
|
||||||
|
description_html: str # inline HTML, properly escaped
|
||||||
entries: list[ParsedEntry]
|
entries: list[ParsedEntry]
|
||||||
entry_count: int
|
entry_count: int
|
||||||
|
|
||||||
|
|
@ -113,22 +114,22 @@ def _heading_text(node: SyntaxTreeNode) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def _extract_description(nodes: list[SyntaxTreeNode]) -> str:
|
def _extract_description_children(nodes: list[SyntaxTreeNode]) -> list[SyntaxTreeNode]:
|
||||||
"""Extract description from the first paragraph if it's a single <em> block.
|
"""Extract description children from the first paragraph if it's a single <em> block.
|
||||||
|
|
||||||
Pattern: _Libraries for foo._ -> "Libraries for foo."
|
Pattern: _Libraries for foo._ -> "Libraries for foo."
|
||||||
"""
|
"""
|
||||||
if not nodes:
|
if not nodes:
|
||||||
return ""
|
return []
|
||||||
first = nodes[0]
|
first = nodes[0]
|
||||||
if first.type != "paragraph":
|
if first.type != "paragraph":
|
||||||
return ""
|
return []
|
||||||
for child in first.children:
|
for child in first.children:
|
||||||
if child.type == "inline" and len(child.children) == 1:
|
if child.type == "inline" and len(child.children) == 1:
|
||||||
em = child.children[0]
|
em = child.children[0]
|
||||||
if em.type == "em":
|
if em.type == "em":
|
||||||
return render_inline_text(em.children)
|
return em.children
|
||||||
return ""
|
return []
|
||||||
|
|
||||||
|
|
||||||
# --- Entry extraction --------------------------------------------------------
|
# --- Entry extraction --------------------------------------------------------
|
||||||
|
|
@ -258,14 +259,17 @@ def _parse_section_entries(content_nodes: list[SyntaxTreeNode]) -> list[ParsedEn
|
||||||
|
|
||||||
def _build_section(name: str, body: list[SyntaxTreeNode]) -> ParsedSection:
|
def _build_section(name: str, body: list[SyntaxTreeNode]) -> ParsedSection:
|
||||||
"""Build a ParsedSection from a heading name and its body nodes."""
|
"""Build a ParsedSection from a heading name and its body nodes."""
|
||||||
desc = _extract_description(body)
|
desc_children = _extract_description_children(body)
|
||||||
content_nodes = body[1:] if desc else body
|
desc = render_inline_text(desc_children) if desc_children else ""
|
||||||
|
desc_html = render_inline_html(desc_children) if desc_children else ""
|
||||||
|
content_nodes = body[1:] if desc_children else body
|
||||||
entries = _parse_section_entries(content_nodes)
|
entries = _parse_section_entries(content_nodes)
|
||||||
entry_count = len(entries) + sum(len(e["also_see"]) for e in entries)
|
entry_count = len(entries) + sum(len(e["also_see"]) for e in entries)
|
||||||
return ParsedSection(
|
return ParsedSection(
|
||||||
name=name,
|
name=name,
|
||||||
slug=slugify(name),
|
slug=slugify(name),
|
||||||
description=desc,
|
description=desc,
|
||||||
|
description_html=desc_html,
|
||||||
entries=entries,
|
entries=entries,
|
||||||
entry_count=entry_count,
|
entry_count=entry_count,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -423,6 +423,17 @@ kbd {
|
||||||
text-wrap: pretty;
|
text-wrap: pretty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.category-subtitle a {
|
||||||
|
color: var(--hero-text);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: oklch(100% 0 0 / 0.32);
|
||||||
|
text-underline-offset: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-subtitle a:hover {
|
||||||
|
text-decoration-color: oklch(100% 0 0 / 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
.category-results {
|
.category-results {
|
||||||
padding-top: clamp(2.5rem, 5vw, 3.75rem);
|
padding-top: clamp(2.5rem, 5vw, 3.75rem);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@
|
||||||
|
|
||||||
<div class="category-hero-copy">
|
<div class="category-hero-copy">
|
||||||
<h1>{{ category.name }}</h1>
|
<h1>{{ category.name }}</h1>
|
||||||
{% if category.description %}
|
{% if category.description_html %}
|
||||||
<p class="category-subtitle">{{ category.description }}</p>
|
<p class="category-subtitle">{{ category.description_html | safe }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ class TestBuild:
|
||||||
|
|
||||||
## Widgets
|
## Widgets
|
||||||
|
|
||||||
_Widget libraries._
|
_Widget libraries. Also see [awesome-widgets](https://example.com/widgets)._
|
||||||
|
|
||||||
- [w1](https://example.com) - A widget.
|
- [w1](https://example.com) - A widget.
|
||||||
|
|
||||||
|
|
@ -235,7 +235,7 @@ class TestBuild:
|
||||||
|
|
||||||
## Widgets
|
## Widgets
|
||||||
|
|
||||||
_Widget libraries._
|
_Widget libraries. Also see [awesome-widgets](https://example.com/widgets)._
|
||||||
|
|
||||||
- [w1](https://example.com/w1) - A widget.
|
- [w1](https://example.com/w1) - A widget.
|
||||||
- [w2](https://github.com/owner/w2) - A starred widget.
|
- [w2](https://github.com/owner/w2) - A starred widget.
|
||||||
|
|
@ -276,12 +276,12 @@ class TestBuild:
|
||||||
assert 'href="/categories/widgets/"' in index_html
|
assert 'href="/categories/widgets/"' in index_html
|
||||||
assert 'data-value="Widgets"' in index_html
|
assert 'data-value="Widgets"' in index_html
|
||||||
assert parser.title.strip() == "Widgets Python Libraries | Awesome Python"
|
assert parser.title.strip() == "Widgets Python Libraries | Awesome Python"
|
||||||
assert parser.meta_by_name["description"] == "Explore 2 curated Python projects in Widgets. Widget libraries."
|
assert parser.meta_by_name["description"] == "Explore 2 curated Python projects in Widgets. Widget libraries. Also see awesome-widgets."
|
||||||
assert parser.links_by_rel["canonical"] == "https://awesome-python.com/categories/widgets/"
|
assert parser.links_by_rel["canonical"] == "https://awesome-python.com/categories/widgets/"
|
||||||
assert parser.meta_by_property["og:url"] == "https://awesome-python.com/categories/widgets/"
|
assert parser.meta_by_property["og:url"] == "https://awesome-python.com/categories/widgets/"
|
||||||
assert '<link rel="alternate" type="text/markdown" href="/index.md" />' not in category_html
|
assert '<link rel="alternate" type="text/markdown" href="/index.md" />' not in category_html
|
||||||
assert "<h1>Widgets</h1>" in category_html
|
assert "<h1>Widgets</h1>" in category_html
|
||||||
assert "Widget libraries." in category_html
|
assert 'Widget libraries. Also see <a href="https://example.com/widgets" target="_blank" rel="noopener">awesome-widgets</a>.' in category_html
|
||||||
assert 'href="https://example.com/w1"' in category_html
|
assert 'href="https://example.com/w1"' in category_html
|
||||||
assert "A widget." in category_html
|
assert "A widget." in category_html
|
||||||
assert 'href="https://github.com/owner/w2"' in category_html
|
assert 'href="https://github.com/owner/w2"' in category_html
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,9 @@ class TestParseReadmeSections:
|
||||||
groups = parse_readme(MINIMAL_README)
|
groups = parse_readme(MINIMAL_README)
|
||||||
cats = groups[0]["categories"]
|
cats = groups[0]["categories"]
|
||||||
assert cats[0]["description"] == "Libraries for alpha stuff."
|
assert cats[0]["description"] == "Libraries for alpha stuff."
|
||||||
|
assert cats[0]["description_html"] == "Libraries for alpha stuff."
|
||||||
assert cats[1]["description"] == "Tools for beta."
|
assert cats[1]["description"] == "Tools for beta."
|
||||||
|
assert cats[1]["description_html"] == "Tools for beta."
|
||||||
|
|
||||||
def test_contributing_skipped(self):
|
def test_contributing_skipped(self):
|
||||||
groups = parse_readme(MINIMAL_README)
|
groups = parse_readme(MINIMAL_README)
|
||||||
|
|
@ -216,6 +218,7 @@ class TestParseReadmeSections:
|
||||||
groups = parse_readme(readme)
|
groups = parse_readme(readme)
|
||||||
cats = groups[0]["categories"]
|
cats = groups[0]["categories"]
|
||||||
assert cats[0]["description"] == ""
|
assert cats[0]["description"] == ""
|
||||||
|
assert cats[0]["description_html"] == ""
|
||||||
assert cats[0]["entries"][0]["name"] == "item"
|
assert cats[0]["entries"][0]["name"] == "item"
|
||||||
|
|
||||||
def test_description_with_link_stripped(self):
|
def test_description_with_link_stripped(self):
|
||||||
|
|
@ -237,6 +240,7 @@ class TestParseReadmeSections:
|
||||||
groups = parse_readme(readme)
|
groups = parse_readme(readme)
|
||||||
cats = groups[0]["categories"]
|
cats = groups[0]["categories"]
|
||||||
assert cats[0]["description"] == "Algorithms. Also see awesome-algos."
|
assert cats[0]["description"] == "Algorithms. Also see awesome-algos."
|
||||||
|
assert cats[0]["description_html"] == 'Algorithms. Also see <a href="https://example.com" target="_blank" rel="noopener">awesome-algos</a>.'
|
||||||
|
|
||||||
|
|
||||||
class TestParseGroupedReadme:
|
class TestParseGroupedReadme:
|
||||||
|
|
@ -481,6 +485,7 @@ class TestParseRealReadme:
|
||||||
algos = next(c for c in self.cats if c["name"] == "Algorithms and Design Patterns")
|
algos = next(c for c in self.cats if c["name"] == "Algorithms and Design Patterns")
|
||||||
assert "awesome-algorithms" in algos["description"]
|
assert "awesome-algorithms" in algos["description"]
|
||||||
assert "https://" not in algos["description"]
|
assert "https://" not in algos["description"]
|
||||||
|
assert 'href="https://github.com/tayllan/awesome-algorithms"' in algos["description_html"]
|
||||||
|
|
||||||
def test_miscellaneous_in_own_group(self):
|
def test_miscellaneous_in_own_group(self):
|
||||||
misc_group = next((g for g in self.groups if g["name"] == "Miscellaneous"), None)
|
misc_group = next((g for g in self.groups if g["name"] == "Miscellaneous"), None)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue