mirror of
https://github.com/vinta/awesome-python.git
synced 2026-10-02 08:23:10 +08:00
feat: add Bundled badge for entries shipped inside a larger project
django.db.models, geodjango, httpx.URL and uv audit were rendering "Not on PyPI" alongside eighteen genuinely standalone projects that simply are not packaged on PyPI, conflating two different reasons for a missing download count. These four entries now carry a "(part of X)" description prefix in README.md, mirroring the existing "(Python standard library)" convention. build.py reads that prefix into a bundled flag that both templates render as a "Bundled" badge. The prefix approach was chosen over a separate data file so README.md stays the single source of content truth, and over inferring from the entry name because geodjango is neither dotted nor spaced and would have been missed. Redundant tail wording was trimmed from the httpx.URL, geodjango and uv audit descriptions now that the prefix names the parent. The new entry format is documented in CONTRIBUTING.md and the vocabulary in CONTEXT.md. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,10 @@ A single listed project: `- [name](url) - Description.` The unit that is admitte
|
||||
**Sub-item**:
|
||||
An indented awesome-* also-see link under an Entry (awesome-django under django, awesome-pytest under pytest). Not an Entry: it holds no slot, does not count against the Cap, and rides its parent — re-homed or removed with it. Maintainer-only placement, and only for awesome-* lists: a companion project either earns a full Entry in its proper Use Case or is not listed.
|
||||
|
||||
**Bundled Entry**:
|
||||
An Entry for a feature that ships inside a larger library, framework, or tool rather than as its own PyPI package (django.db.models, geodjango, httpx.URL, uv audit). Marked in README.md by a `(part of X)` description prefix, which the website reads to render a "Bundled" badge where a download count would go. It holds a normal slot and is audited like any other Entry; only its download signal is absent.
|
||||
_Avoid_: Pointer entry (reform-era name)
|
||||
|
||||
**Thematic Group**:
|
||||
A bold group line (e.g. "AI & ML", "Web Development") that clusters Sections in the TOC and the Projects body.
|
||||
|
||||
|
||||
@@ -55,6 +55,14 @@ Use the **PyPI package name** as the display name so developers can copy it dire
|
||||
- [module](https://docs.python.org/3/library/module.html) - (Python standard library) Description.
|
||||
```
|
||||
|
||||
### Bundled Feature
|
||||
|
||||
A feature that ships inside a larger library, framework, or tool rather than as its own PyPI package. The `(part of X)` prefix is parsed by the website, which renders a "Bundled" badge in place of a download count, so write it exactly in that form and name the parent as developers say it.
|
||||
|
||||
```markdown
|
||||
- [name](url) - (part of Parent) Description ending with period.
|
||||
```
|
||||
|
||||
### Fork of Another Project
|
||||
|
||||
```markdown
|
||||
|
||||
@@ -369,7 +369,7 @@ _Libraries for working with HTTP._
|
||||
- [httpx2](https://github.com/pydantic/httpx2) - HTTP/1.1 and HTTP/2 client with sync and async APIs, maintained by Pydantic ([httpx](https://github.com/encode/httpx) fork).
|
||||
- URL Manipulation
|
||||
- [yarl](https://github.com/aio-libs/yarl) - Yet another URL library.
|
||||
- [httpx.URL](https://www.python-httpx.org/api/) - The immutable URL class bundled with HTTPX.
|
||||
- [httpx.URL](https://www.python-httpx.org/api/) - (part of HTTPX) The immutable URL class.
|
||||
|
||||
### Web Scraping
|
||||
|
||||
@@ -399,7 +399,7 @@ _Libraries that implement Object-Relational Mapping or data mapping techniques._
|
||||
- Relational Databases
|
||||
- [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) - The Python SQL Toolkit and Object Relational Mapper.
|
||||
- [awesome-sqlalchemy](https://github.com/dahlia/awesome-sqlalchemy)
|
||||
- [django.db.models](https://github.com/django/django) - The Django [ORM](https://docs.djangoproject.com/en/dev/topics/db/models/).
|
||||
- [django.db.models](https://github.com/django/django) - (part of Django) The Django [ORM](https://docs.djangoproject.com/en/dev/topics/db/models/).
|
||||
- [peewee](https://github.com/coleifer/peewee) - A small, expressive ORM.
|
||||
- [sqlmodel](https://github.com/fastapi/sqlmodel) - SQLModel is based on Python type annotations, and powered by Pydantic and SQLAlchemy.
|
||||
- NoSQL Databases
|
||||
@@ -531,7 +531,7 @@ _Libraries for geocoding addresses and working with latitudes and longitudes._
|
||||
- [geopandas](https://github.com/geopandas/geopandas) - Python tools for geographic data (GeoSeries/GeoDataFrame) built on pandas.
|
||||
- [geopy](https://github.com/geopy/geopy) - Python Geocoding Toolbox.
|
||||
- [geojson](https://github.com/jazzband/geojson) - Python bindings and utilities for GeoJSON.
|
||||
- [geodjango](https://github.com/django/django) - A world-class geographic web framework that is part of [Django](https://docs.djangoproject.com/en/dev/ref/contrib/gis/).
|
||||
- [geodjango](https://github.com/django/django) - (part of Django) A world-class [geographic web framework](https://docs.djangoproject.com/en/dev/ref/contrib/gis/).
|
||||
|
||||
### Science
|
||||
|
||||
@@ -1118,7 +1118,7 @@ _Frameworks and tools for penetration testing._
|
||||
_Tools for auditing dependencies against known vulnerabilities._
|
||||
|
||||
- [pip-audit](https://github.com/pypa/pip-audit) - Audits Python environments and dependency trees for known vulnerabilities, using the PyPI Advisory Database and OSV.
|
||||
- [uv audit](https://docs.astral.sh/uv/reference/cli/#uv-audit) - uv's built-in dependency vulnerability and malware scanning backed by OSV.
|
||||
- [uv audit](https://docs.astral.sh/uv/reference/cli/#uv-audit) - (part of uv) Built-in dependency vulnerability and malware scanning backed by OSV.
|
||||
|
||||
### Web Security
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ SPONSORSHIP_PATH = "/sponsorship/"
|
||||
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."
|
||||
|
||||
BUNDLED_PREFIX_RE = re.compile(r"^\(part of ")
|
||||
|
||||
SOURCE_TYPE_DOMAINS = {
|
||||
"docs.python.org": BUILTIN_FILTER,
|
||||
"gitlab.com": "GitLab",
|
||||
@@ -57,6 +59,7 @@ class TemplateEntry(TypedDict):
|
||||
owner: str | None
|
||||
last_commit_at: str | None
|
||||
source_type: str | None
|
||||
bundled: bool
|
||||
also_see: list[AlsoSee]
|
||||
|
||||
|
||||
@@ -520,6 +523,7 @@ def extract_entries(
|
||||
owner=None,
|
||||
last_commit_at=None,
|
||||
source_type=detect_source_type(entry["url"]),
|
||||
bundled=bool(BUNDLED_PREFIX_RE.match(entry["description"])),
|
||||
also_see=entry["also_see"],
|
||||
)
|
||||
seen[key] = existing
|
||||
|
||||
@@ -156,10 +156,9 @@
|
||||
<td class="col-downloads">
|
||||
{% if entry.downloads is not none %}{{
|
||||
"{:,}".format(entry.downloads) }}{% elif entry.source_type ==
|
||||
'Stdlib' %}<span class="source-badge">Stdlib</span>{% else %}<span
|
||||
class="source-badge"
|
||||
>Not on PyPI</span
|
||||
>{% endif %}
|
||||
'Stdlib' %}<span class="source-badge">Stdlib</span>{% elif
|
||||
entry.bundled %}<span class="source-badge">Bundled</span>{% else
|
||||
%}<span class="source-badge">Not on PyPI</span>{% endif %}
|
||||
</td>
|
||||
<td class="col-stars">
|
||||
{% if entry.stars is not none %}{{ "{:,}".format(entry.stars) }}{%
|
||||
|
||||
@@ -193,10 +193,9 @@
|
||||
<td class="col-downloads">
|
||||
{% if entry.downloads is not none %}{{
|
||||
"{:,}".format(entry.downloads) }}{% elif entry.source_type ==
|
||||
'Stdlib' %}<span class="source-badge">Stdlib</span>{% else %}<span
|
||||
class="source-badge"
|
||||
>Not on PyPI</span
|
||||
>{% endif %}
|
||||
'Stdlib' %}<span class="source-badge">Stdlib</span>{% elif
|
||||
entry.bundled %}<span class="source-badge">Bundled</span>{% else
|
||||
%}<span class="source-badge">Not on PyPI</span>{% endif %}
|
||||
</td>
|
||||
<td class="col-stars">
|
||||
{% if entry.stars is not none %}{{ "{:,}".format(entry.stars) }}{%
|
||||
|
||||
@@ -446,6 +446,7 @@ class TestBuild:
|
||||
- [My-Lib](https://github.com/org/mylib) - On PyPI.
|
||||
- [no-pypi](https://example.com/none) - Not on PyPI.
|
||||
- [asyncio](https://docs.python.org/3/library/asyncio.html) - Stdlib.
|
||||
- [my-lib.thing](https://github.com/org/mylib) - (part of My-Lib) A bundled feature.
|
||||
|
||||
# Contributing
|
||||
|
||||
@@ -470,6 +471,10 @@ class TestBuild:
|
||||
assert "26,305,454" not in html
|
||||
# Default sort: entries with download counts come first
|
||||
assert html.index("My-Lib") < html.index("no-pypi")
|
||||
# Each no-download entry gets the badge matching why it has no count
|
||||
assert html.count('<span class="source-badge">Stdlib</span>') == 1
|
||||
assert html.count('<span class="source-badge">Bundled</span>') == 1
|
||||
assert html.count('<span class="source-badge">Not on PyPI</span>') == 1
|
||||
|
||||
def test_build_fails_when_group_and_category_slug_collide(self, tmp_path):
|
||||
readme = textwrap.dedent("""\
|
||||
@@ -1020,6 +1025,7 @@ def _template_entry(name: str, stars: int | None, source_type: str | None = None
|
||||
owner=None,
|
||||
last_commit_at=None,
|
||||
source_type=source_type,
|
||||
bundled=False,
|
||||
also_see=[],
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user