feat: rename Built-in source type to Stdlib and show it in downloads column

Standard-library entries rendered "Not on PyPI" in the PyPI Downloads
column, which read like missing data rather than a deliberate category
— the build already forces downloads to None for them so they never
pick up a same-named PyPI backport. They now render a "Stdlib" badge
instead, while genuine non-PyPI entries keep "Not on PyPI".

The filter tag is renamed to match, so the source-type value, the row
filter tag, and the synthetic category heading all read Stdlib now.
The literal "Built-in" strings scattered through build.py are routed
through the existing BUILTIN_FILTER constant so the label lives in one
place. The category page slug stays "built-in" so the public URL
/categories/built-in/ does not break.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vinta Chen
2026-08-23 01:01:17 +08:00
co-authored by Claude
parent b1f473319c
commit 2fc0edd565
4 changed files with 26 additions and 24 deletions
+9 -9
View File
@@ -22,7 +22,7 @@ SITE_URL = "https://awesome-python.com/"
SITEMAP_URL = f"{SITE_URL}sitemap.xml" SITEMAP_URL = f"{SITE_URL}sitemap.xml"
SITEMAP_NS = "http://www.sitemaps.org/schemas/sitemap/0.9" SITEMAP_NS = "http://www.sitemaps.org/schemas/sitemap/0.9"
BUILTIN_FILTER = "Built-in" BUILTIN_FILTER = "Stdlib"
BUILTIN_SLUG = "built-in" BUILTIN_SLUG = "built-in"
BUILTIN_PATH = f"/categories/{BUILTIN_SLUG}/" BUILTIN_PATH = f"/categories/{BUILTIN_SLUG}/"
BUILTIN_PUBLIC_URL = f"{SITE_URL}categories/{BUILTIN_SLUG}/" BUILTIN_PUBLIC_URL = f"{SITE_URL}categories/{BUILTIN_SLUG}/"
@@ -32,7 +32,7 @@ SPONSORSHIP_PUBLIC_URL = f"{SITE_URL}sponsorship/"
SPONSORSHIP_DESCRIPTION = "Sponsorship for awesome-python: tiers, audience, and how to get your product in front of professional Python developers evaluating tools for production use." SPONSORSHIP_DESCRIPTION = "Sponsorship for awesome-python: tiers, audience, and how to get your product in front of professional Python developers evaluating tools for production use."
SOURCE_TYPE_DOMAINS = { SOURCE_TYPE_DOMAINS = {
"docs.python.org": "Built-in", "docs.python.org": BUILTIN_FILTER,
"gitlab.com": "GitLab", "gitlab.com": "GitLab",
"bitbucket.org": "Bitbucket", "bitbucket.org": "Bitbucket",
} }
@@ -128,9 +128,9 @@ def sort_entries(entries: Sequence[TemplateEntry]) -> list[TemplateEntry]:
if downloads is not None: if downloads is not None:
return (0, -downloads, 0, name) return (0, -downloads, 0, name)
if stars is not None: if stars is not None:
builtin = 1 if entry.get("source_type") == "Built-in" else 0 builtin = 1 if entry.get("source_type") == BUILTIN_FILTER else 0
return (1, -stars, builtin, name) return (1, -stars, builtin, name)
if entry.get("source_type") == "Built-in": if entry.get("source_type") == BUILTIN_FILTER:
return (2, 0, 0, name) return (2, 0, 0, name)
return (3, 0, 0, name) return (3, 0, 0, name)
@@ -445,9 +445,9 @@ def annotate_entries_with_stats(
parts: list[str] = [] parts: list[str] = []
if links: if links:
name, url = links[0] name, url = links[0]
# Category-index bullets link into the site itself, and Built-in entries # Category-index bullets link into the site itself, and stdlib entries
# would hit same-named PyPI backports (e.g. logging) — no counts for either. # would hit same-named PyPI backports (e.g. logging) — no counts for either.
if not url.startswith((SITE_URL, "#")) and detect_source_type(url) != "Built-in": if not url.startswith((SITE_URL, "#")) and detect_source_type(url) != BUILTIN_FILTER:
downloads = downloads_data.get(normalize(name)) downloads = downloads_data.get(normalize(name))
if downloads is not None: if downloads is not None:
parts.append(f"PyPI downloads/month: {downloads}") parts.append(f"PyPI downloads/month: {downloads}")
@@ -581,15 +581,15 @@ def build(repo_root: Path) -> None:
for entry in entries: for entry in entries:
repo_key = extract_github_repo(entry["url"]) repo_key = extract_github_repo(entry["url"])
if not repo_key and entry.get("source_type") == "Built-in": if not repo_key and entry.get("source_type") == BUILTIN_FILTER:
repo_key = "python/cpython" repo_key = "python/cpython"
if repo_key and repo_key in stars_data: if repo_key and repo_key in stars_data:
sd = stars_data[repo_key] sd = stars_data[repo_key]
entry["stars"] = sd["stars"] entry["stars"] = sd["stars"]
entry["owner"] = sd["owner"] entry["owner"] = sd["owner"]
entry["last_commit_at"] = sd.get("last_commit_at", "") entry["last_commit_at"] = sd.get("last_commit_at", "")
# Built-in entries would hit same-named PyPI backports (e.g. asyncio), not the stdlib. # Stdlib entries would hit same-named PyPI backports (e.g. asyncio), not the stdlib.
if entry.get("source_type") != "Built-in": if entry.get("source_type") != BUILTIN_FILTER:
entry["downloads"] = downloads_data.get(normalize(entry["name"])) entry["downloads"] = downloads_data.get(normalize(entry["name"]))
entries = sort_entries(entries) entries = sort_entries(entries)
+6 -5
View File
@@ -138,7 +138,7 @@
{% for entry in entries %} {% for entry in entries %}
<tr <tr
class="row" class="row"
data-tags="{{ entry.categories | join('||') }}{% if entry.subcategories %}||{{ entry.subcategories | map(attribute='value') | join('||') }}{% endif %}||{{ entry.groups | join('||') }}{% if entry.source_type == 'Built-in' %}||Built-in{% endif %}" data-tags="{{ entry.categories | join('||') }}{% if entry.subcategories %}||{{ entry.subcategories | map(attribute='value') | join('||') }}{% endif %}||{{ entry.groups | join('||') }}{% if entry.source_type == 'Stdlib' %}||Stdlib{% endif %}"
tabindex="0" tabindex="0"
aria-expanded="false" aria-expanded="false"
aria-controls="expand-{{ loop.index }}" aria-controls="expand-{{ loop.index }}"
@@ -155,7 +155,8 @@
</td> </td>
<td class="col-downloads"> <td class="col-downloads">
{% if entry.downloads is not none %}{{ {% if entry.downloads is not none %}{{
"{:,}".format(entry.downloads) }}{% else %}<span "{:,}".format(entry.downloads) }}{% elif entry.source_type ==
'Stdlib' %}<span class="source-badge">Stdlib</span>{% else %}<span
class="source-badge" class="source-badge"
>Not on PyPI</span >Not on PyPI</span
>{% endif %} >{% endif %}
@@ -207,14 +208,14 @@
{{ entry.groups[0] }} {{ entry.groups[0] }}
</a> </a>
{% endif %} {% endif %}
{% if entry.source_type == 'Built-in' %} {% if entry.source_type == 'Stdlib' %}
<a <a
class="tag tag-source{% if '/categories/built-in/' == current_path %} active{% endif %}" class="tag tag-source{% if '/categories/built-in/' == current_path %} active{% endif %}"
href="/categories/built-in/" href="/categories/built-in/"
data-value="Built-in" data-value="Stdlib"
data-url="/categories/built-in/" data-url="/categories/built-in/"
> >
Built-in Stdlib
</a> </a>
{% endif %} {% endif %}
</td> </td>
+6 -5
View File
@@ -175,7 +175,7 @@
{% for entry in entries %} {% for entry in entries %}
<tr <tr
class="row" class="row"
data-tags="{{ entry.categories | join('||') }}{% if entry.subcategories %}||{{ entry.subcategories | map(attribute='value') | join('||') }}{% endif %}||{{ entry.groups | join('||') }}{% if entry.source_type == 'Built-in' %}||Built-in{% endif %}" data-tags="{{ entry.categories | join('||') }}{% if entry.subcategories %}||{{ entry.subcategories | map(attribute='value') | join('||') }}{% endif %}||{{ entry.groups | join('||') }}{% if entry.source_type == 'Stdlib' %}||Stdlib{% endif %}"
tabindex="0" tabindex="0"
aria-expanded="false" aria-expanded="false"
aria-controls="expand-{{ loop.index }}" aria-controls="expand-{{ loop.index }}"
@@ -192,7 +192,8 @@
</td> </td>
<td class="col-downloads"> <td class="col-downloads">
{% if entry.downloads is not none %}{{ {% if entry.downloads is not none %}{{
"{:,}".format(entry.downloads) }}{% else %}<span "{:,}".format(entry.downloads) }}{% elif entry.source_type ==
'Stdlib' %}<span class="source-badge">Stdlib</span>{% else %}<span
class="source-badge" class="source-badge"
>Not on PyPI</span >Not on PyPI</span
>{% endif %} >{% endif %}
@@ -240,14 +241,14 @@
> >
{{ entry.groups[0] }} {{ entry.groups[0] }}
</a> </a>
{% if entry.source_type == 'Built-in' %} {% if entry.source_type == 'Stdlib' %}
<a <a
class="tag tag-source" class="tag tag-source"
href="/categories/built-in/" href="/categories/built-in/"
data-value="Built-in" data-value="Stdlib"
data-url="/categories/built-in/" data-url="/categories/built-in/"
> >
Built-in Stdlib
</a> </a>
{% endif %} {% endif %}
</td> </td>
+5 -5
View File
@@ -445,7 +445,7 @@ class TestBuild:
- [My-Lib](https://github.com/org/mylib) - On PyPI. - [My-Lib](https://github.com/org/mylib) - On PyPI.
- [no-pypi](https://example.com/none) - Not on PyPI. - [no-pypi](https://example.com/none) - Not on PyPI.
- [asyncio](https://docs.python.org/3/library/asyncio.html) - Built-in. - [asyncio](https://docs.python.org/3/library/asyncio.html) - Stdlib.
# Contributing # Contributing
@@ -466,7 +466,7 @@ class TestBuild:
html = (tmp_path / "website" / "output" / "index.html").read_text(encoding="utf-8") html = (tmp_path / "website" / "output" / "index.html").read_text(encoding="utf-8")
assert "1,234,567" in html assert "1,234,567" in html
# Built-in entries never show PyPI counts: the asyncio row is the backport package # Stdlib entries never show PyPI counts: the asyncio row is the backport package
assert "26,305,454" not in html assert "26,305,454" not in html
# Default sort: entries with download counts come first # Default sort: entries with download counts come first
assert html.index("My-Lib") < html.index("no-pypi") assert html.index("My-Lib") < html.index("no-pypi")
@@ -1060,7 +1060,7 @@ class TestSortEntries:
def test_builtin_between_starred_and_unstarred(self): def test_builtin_between_starred_and_unstarred(self):
entries = [ entries = [
_template_entry("builtin", None, "Built-in"), _template_entry("builtin", None, "Stdlib"),
_template_entry("starred", 100), _template_entry("starred", 100),
_template_entry("unstarred", None), _template_entry("unstarred", None),
] ]
@@ -1078,7 +1078,7 @@ class TestDetectSourceType:
assert detect_source_type("https://github.com/psf/requests") is None assert detect_source_type("https://github.com/psf/requests") is None
def test_stdlib_url(self): def test_stdlib_url(self):
assert detect_source_type("https://docs.python.org/3/library/asyncio.html") == "Built-in" assert detect_source_type("https://docs.python.org/3/library/asyncio.html") == "Stdlib"
def test_gitlab_url(self): def test_gitlab_url(self):
assert detect_source_type("https://gitlab.com/org/repo") == "GitLab" assert detect_source_type("https://gitlab.com/org/repo") == "GitLab"
@@ -1167,7 +1167,7 @@ class TestExtractEntries:
groups = parse_readme(readme) groups = parse_readme(readme)
categories = [c for g in groups for c in g["categories"]] categories = [c for g in groups for c in g["categories"]]
entries = extract_entries(categories, groups) entries = extract_entries(categories, groups)
assert entries[0]["source_type"] == "Built-in" assert entries[0]["source_type"] == "Stdlib"
def test_subcategory_includes_slug_and_url(self): def test_subcategory_includes_slug_and_url(self):
readme = textwrap.dedent("""\ readme = textwrap.dedent("""\