From 3e8404c95f1e61b51d6e996f7c8b11b15b38564a Mon Sep 17 00:00:00 2001 From: fauzan171 Date: Sun, 7 Jun 2026 00:07:29 +0700 Subject: [PATCH 01/14] fix: update outdated version references in descriptions - sanic: Remove 'Python 3.6+' version constraint (now requires Python >=3.10 per PyPI metadata) - django-guardian: Remove 'Django 1.2+' version constraint (outdated reference, now requires Python >=3.10 per PyPI metadata) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5d198f3..403b87b 100644 --- a/README.md +++ b/README.md @@ -269,7 +269,7 @@ _Libraries for building RESTful and GraphQL APIs._ - [connexion](https://github.com/spec-first/connexion) - A spec-first framework that automatically handles requests based on your OpenAPI specification. - [falcon](https://github.com/falconry/falcon) - A high-performance framework for building cloud APIs and web app backends. - [fastapi](https://github.com/fastapi/fastapi) - A modern, fast, web framework for building APIs with standard Python type hints. - - [sanic](https://github.com/sanic-org/sanic) - A Python 3.6+ web server and web framework that's written to go fast. + - [sanic](https://github.com/sanic-org/sanic) - A Python web server and web framework that's written to go fast. - [strawberry](https://github.com/strawberry-graphql/strawberry) - A GraphQL library that leverages Python type annotations for schema definition. - [webargs](https://github.com/marshmallow-code/webargs) - A friendly library for parsing HTTP request arguments with built-in support for popular web frameworks. @@ -326,7 +326,7 @@ _Libraries for implementing authentication schemes._ - JWT - [pyjwt](https://github.com/jpadilla/pyjwt) - JSON Web Token implementation in Python. - Permissions - - [django-guardian](https://github.com/django-guardian/django-guardian) - Implementation of per object permissions for Django 1.2+ + - [django-guardian](https://github.com/django-guardian/django-guardian) - Implementation of per-object permissions for Django. - [django-rules](https://github.com/dfunckt/django-rules) - A tiny but powerful app providing object-level permissions to Django, without requiring a database. ### Admin Panels From 647d723ecf02150042f5a20de93eba3d7ce7db0e Mon Sep 17 00:00:00 2001 From: fauzan171 Date: Sun, 7 Jun 2026 00:08:39 +0700 Subject: [PATCH 02/14] fix: update chardet description to remove outdated Python 2 reference Python 2 reached end-of-life in January 2020. The 'Python 2/3 compatible' qualifier is no longer relevant and misleading. Updated to match the official repository description. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d198f3..5663170 100644 --- a/README.md +++ b/README.md @@ -869,7 +869,7 @@ _Libraries for parsing and manipulating plain texts._ - General - [babel](https://github.com/python-babel/babel) - An internationalization library for Python. - - [chardet](https://github.com/chardet/chardet) - Python 2/3 compatible character encoding detector. + - [chardet](https://github.com/chardet/chardet) - Python character encoding detector. - [difflib](https://docs.python.org/3/library/difflib.html) - (Python standard library) Helpers for computing deltas. - [ftfy](https://github.com/rspeer/python-ftfy) - Makes Unicode text less broken and more consistent automagically. - [pangu.py](https://github.com/vinta/pangu.py) - Paranoid text spacing. From bcfba785769e0c5cf26b53f93cc52ba08e7b9f77 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Sun, 7 Jun 2026 02:39:06 +0800 Subject: [PATCH 03/14] add Indie Dev sponsorship tier --- SPONSORSHIP.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/SPONSORSHIP.md b/SPONSORSHIP.md index 67f7cbc..5eade93 100644 --- a/SPONSORSHIP.md +++ b/SPONSORSHIP.md @@ -26,11 +26,19 @@ Your sponsorship puts your product in front of developers at the exact moment th - Large logo and one-line description (max 120 characters) pinned at the very top of the README, above all project entries - Logo link in the sponsor section of [awesome-python.com](https://awesome-python.com/) -### Featured Sponsor - $150/month +### Featured Sponsor - $200/month - Text entry (`[Name](URL) - Description.`, max 120 characters) pinned at the top of the README, directly below Headline sponsors - Text link in the sponsor section of [awesome-python.com](https://awesome-python.com/) +### Indie Dev Sponsor - $99/month or $249/quarter + +- Lower-cost tier for indie developers, solo founders, and one-person companies only +- Text entry (`[Name](URL) - Description.`, max 120 characters) in the README sponsor section, directly below Featured sponsors +- Text link in the sponsor section of [awesome-python.com](https://awesome-python.com/) + +Indie Dev Sponsor is available only to founder-led products (one-person company). Funded startups, agencies, recruiters, larger companies, and products with enterprise sales teams should use Featured or Headline Sponsor. + ## Previously Sponsored By - [Warp](https://www.warp.dev/) - The terminal for modern developers. @@ -40,8 +48,8 @@ Your sponsorship puts your product in front of developers at the exact moment th Email [sponsorship@awesome-python.com](mailto:sponsorship@awesome-python.com?subject=Awesome%20Python%20Sponsorship) with: -- **Tier:** Headline Sponsor ($500/mo) or Featured Sponsor ($150/mo) -- **Content:** Product name, URL, logo, and description (Headline tier) or `[Name](URL) - Description.` entry (Featured tier) +- **Tier:** Headline Sponsor ($500/mo), Featured Sponsor ($200/mo), or Indie Dev Sponsor ($99/mo or $249/quarter) +- **Content:** Product name, URL, logo, and description (Headline tier) or `[Name](URL) - Description.` entry (Featured or Indie Dev tier) - **Duration:** 1, 3, 6 months, or longer - **Payment method:** US bank transfer (ACH/wire) or PayPal @@ -49,6 +57,6 @@ One upfront payment per term. Setup takes less than 24 hours. ## Editorial Independence -Sponsorship is logo/link placement in the README header. It does not influence which projects are listed. Listings are curated on merit through the normal [contribution process](CONTRIBUTING.md). +Sponsorship is logo or link placement in the README header. It does not influence which projects are listed. Listings are curated on merit through the normal [contribution process](CONTRIBUTING.md). We reserve the right to request changes to sponsor text, logos, or links that are misleading, off-topic, or incompatible with the README formatting. From ee08cd7d8696a414f7ec352837ea01a435ea0540 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Sun, 7 Jun 2026 02:49:13 +0800 Subject: [PATCH 04/14] update sponsorship webpage --- SPONSORSHIP.md | 12 +++---- website/static/style.css | 2 +- website/templates/sponsorship.html | 53 ++++++++++++++++++++++++++---- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/SPONSORSHIP.md b/SPONSORSHIP.md index 5eade93..e61b995 100644 --- a/SPONSORSHIP.md +++ b/SPONSORSHIP.md @@ -37,12 +37,7 @@ Your sponsorship puts your product in front of developers at the exact moment th - Text entry (`[Name](URL) - Description.`, max 120 characters) in the README sponsor section, directly below Featured sponsors - Text link in the sponsor section of [awesome-python.com](https://awesome-python.com/) -Indie Dev Sponsor is available only to founder-led products (one-person company). Funded startups, agencies, recruiters, larger companies, and products with enterprise sales teams should use Featured or Headline Sponsor. - -## Previously Sponsored By - -- [Warp](https://www.warp.dev/) - The terminal for modern developers. -- [pyr](https://pyrun.dev) - Zero-config Python project manager. +Indie Dev Sponsor is available only to founder-led (one-person company) products. Funded startups, larger companies, and products with enterprise sales teams should use Featured or Headline Sponsor. ## Get Started @@ -55,6 +50,11 @@ Email [sponsorship@awesome-python.com](mailto:sponsorship@awesome-python.com?sub One upfront payment per term. Setup takes less than 24 hours. +## Previously Sponsored By + +- [Warp](https://www.warp.dev/) - The terminal for modern developers. +- [pyr](https://pyrun.dev) - Zero-config Python project manager. + ## Editorial Independence Sponsorship is logo or link placement in the README header. It does not influence which projects are listed. Listings are curated on merit through the normal [contribution process](CONTRIBUTING.md). diff --git a/website/static/style.css b/website/static/style.css index bbdac35..bac5b58 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -1278,7 +1278,7 @@ th[data-sort].sort-asc::after { padding: 0; margin: 0; display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1.5rem, 3vw, 2.75rem); } diff --git a/website/templates/sponsorship.html b/website/templates/sponsorship.html index f8807cf..7111e45 100644 --- a/website/templates/sponsorship.html +++ b/website/templates/sponsorship.html @@ -71,8 +71,8 @@
Who visits
- Mid to senior Python developers arriving with a specific question: - a maintained ORM, a fast HTTP client, a task queue worth running in + Mid to senior Python developers arriving with a specific question: a + maintained ORM, a fast HTTP client, a task queue worth running in production.
@@ -123,7 +123,7 @@
  • Logo link in the sponsor section of awesome-python.com.
  • Email about Headline tier @@ -131,7 +131,7 @@
  • Featured Sponsor

    - $150 + $200 / month

    @@ -146,11 +146,40 @@

  • Text link in the sponsor section of awesome-python.com.
  • Email about Featured tier +
  • +

    Indie Dev Sponsor

    +

    + $99 + / month or $249 / quarter +

    +

    + Lower-cost text link for eligible indie developers and solo + founders. +

    +
      +
    • + Text entry ([Name](URL) - Description., max 120 + characters) in the README sponsor section, directly below Featured + sponsors. +
    • +
    • Text link in the sponsor section of awesome-python.com.
    • +
    • + Available only to founder-led, one-person-company products. Funded + startups, agencies, recruiters, larger companies, and products + with enterprise sales teams should use Featured or Headline. +
    • +
    + Email about Indie Dev tier +
  • @@ -171,6 +200,12 @@ >The terminal for modern developers. +
  • + pyr + Zero-config Python project manager. +
  • @@ -193,13 +228,17 @@
    Tier
    -
    Headline Sponsor ($500/mo) or Featured Sponsor ($150/mo).
    +
    + Headline Sponsor ($500/mo), Featured Sponsor ($200/mo), or Indie Dev + Sponsor ($99/mo or $249/quarter). +
    Content
    Product name, URL, logo, and description (Headline tier), or - [Name](URL) - Description. entry (Featured tier). + [Name](URL) - Description. entry (Featured or Indie Dev + tier).
    From 9f156de2b499a6daa8e0f5dee47520749409946f Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Sun, 7 Jun 2026 02:58:34 +0800 Subject: [PATCH 05/14] make descriptions shorter --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a41027..1a29388 100644 --- a/README.md +++ b/README.md @@ -134,10 +134,10 @@ _Libraries for building AI applications, LLM integrations, and autonomous agents - Agent Skills - [django-ai-plugins](https://github.com/vintasoftware/django-ai-plugins) - Django backend agent skills for Django, DRF, Celery, and Django-specific code review. - - [graphify](https://github.com/safishamsi/graphify) - Turn any folder of code, SQL schemas, R scripts, shell scripts, docs, papers, images, or videos into a queryable knowledge graph. + - [graphify](https://github.com/safishamsi/graphify) - Turn any folder of code, SQL schemas, docs, papers, images, or videos into a queryable knowledge graph. - [nuwa-skill](https://github.com/alchaincyf/nuwa-skill/blob/main/README_EN.md) - Nuwa distills the thinking of anyone — let Musk, Naval, Munger, and Feynman work for you. - [sentry-skills](https://github.com/getsentry/skills) - Python-focused engineering skills for code review, debugging, and backend workflows. - - [trailofbits-skills](https://github.com/trailofbits/skills) - Python-friendly security skills for auditing, testing, and safer backend development. Also [skills-curated](https://github.com/trailofbits/skills-curated). + - [trailofbits-skills](https://github.com/trailofbits/skills) - Python-friendly security skills for auditing, testing, and safer backend development. - Orchestration - [ag2](https://github.com/ag2ai/ag2) - An open-source AgentOS for multi-agent orchestration and building agentic AI systems. - [autogen](https://github.com/microsoft/autogen) - A programming framework for building agentic AI applications. @@ -192,7 +192,7 @@ _Libraries for Machine Learning. Also see [awesome-machine-learning](https://git - [mindsdb](https://github.com/mindsdb/minds-platform) - MindsDB is an open source AI layer for existing databases that allows you to effortlessly develop, train and deploy state-of-the-art machine learning models using standard queries. - [pgmpy](https://github.com/pgmpy/pgmpy) - A Python library for probabilistic graphical models and Bayesian networks. - [scikit-learn](https://github.com/scikit-learn/scikit-learn) - The most popular Python library for Machine Learning with extensive documentation and community support. -- * [scikit-lego](https://github.com/koaning/scikit-lego) - A collection of lego bricks for scikit-learn pipelines. +- - [scikit-lego](https://github.com/koaning/scikit-lego) - A collection of lego bricks for scikit-learn pipelines. - [spark.ml](https://github.com/apache/spark) - [Apache Spark](https://spark.apache.org/)'s scalable [Machine Learning library](https://spark.apache.org/docs/latest/ml-guide.html) for distributed computing. - [TabGAN](https://github.com/Diyago/Tabular-data-generation) - Synthetic tabular data generation using GANs, Diffusion Models, and LLMs. - [timesfm](https://github.com/google-research/timesfm) - A pretrained foundation model from Google Research for time-series forecasting. From 32ae78fd9606b1b74d1e8f7098897014f66e38c9 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Sun, 7 Jun 2026 03:08:43 +0800 Subject: [PATCH 06/14] fix: improve website SEO metadata --- website/build.py | 92 +++++++++++++++++++++++++++--- website/templates/category.html | 2 +- website/templates/sponsorship.html | 5 +- website/tests/test_build.py | 78 ++++++++++++++++++++++++- 4 files changed, 167 insertions(+), 10 deletions(-) diff --git a/website/build.py b/website/build.py index bcfc64d..347c4fb 100644 --- a/website/build.py +++ b/website/build.py @@ -28,6 +28,7 @@ BUILTIN_PUBLIC_URL = f"{SITE_URL}categories/{BUILTIN_SLUG}/" 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." SOURCE_TYPE_DOMAINS = { "docs.python.org": "Built-in", @@ -128,6 +129,8 @@ def _website_node() -> dict: "@id": WEBSITE_ID, "name": "Awesome Python", "url": SITE_URL, + "inLanguage": "en", + "sameAs": "https://github.com/vinta/awesome-python", } @@ -164,21 +167,59 @@ def build_homepage_json_ld(entries: Sequence[TemplateEntry], total_categories: i "url": SITE_URL, "description": description, "isPartOf": ISPARTOF_WEBSITE, + "inLanguage": "en", "mainEntity": _item_list_payload(entries), }, ], } -def category_meta_description(name: str, entry_count: int, description: str) -> str: - count_sentence = f"Explore {entry_count} curated Python projects in {name}." +def category_meta_title(name: str, parent_name: str | None = None) -> str: + if parent_name: + title = f"{name} for {parent_name} - Awesome Python" + if len(title) <= 60: + return title + title = f"{parent_name}: {name} - Awesome Python" + if len(title) <= 60: + return title + return f"{name} - Awesome Python" + title = f"{name} Python Libraries - Awesome Python" + if len(title) <= 60: + return title + return f"{name} - Awesome Python" + + +def category_meta_description(name: str, entry_count: int, description: str, parent_name: str | None = None) -> str: + target = f"{name} for {parent_name}" if parent_name else name + count_sentence = f"Explore {entry_count} curated Python projects in {target}." if description: lead = description if description.endswith((".", "!", "?")) else f"{description}." return f"{lead} {count_sentence}" return f"{count_sentence} Part of the Awesome Python catalog." -def build_category_json_ld(name: str, url: str, description: str, entries: Sequence[TemplateEntry]) -> dict: +def build_breadcrumb_json_ld(items: Sequence[tuple[str, str]]) -> dict: + return { + "@type": "BreadcrumbList", + "itemListElement": [ + { + "@type": "ListItem", + "position": i, + "name": name, + "item": url, + } + for i, (name, url) in enumerate(items, start=1) + ], + } + + +def build_category_json_ld( + name: str, + url: str, + description: str, + entries: Sequence[TemplateEntry], + breadcrumbs: Sequence[tuple[str, str]], +) -> dict: return { "@context": "https://schema.org", "@graph": [ @@ -186,12 +227,38 @@ def build_category_json_ld(name: str, url: str, description: str, entries: Seque { "@type": "CollectionPage", "@id": url, - "name": f"{name} Python Libraries", + "name": name, "url": url, "description": description, "isPartOf": ISPARTOF_WEBSITE, + "inLanguage": "en", "mainEntity": _item_list_payload(entries), }, + build_breadcrumb_json_ld(breadcrumbs), + ], + } + + +def build_sponsorship_json_ld() -> dict: + return { + "@context": "https://schema.org", + "@graph": [ + _website_node(), + { + "@type": "WebPage", + "@id": SPONSORSHIP_PUBLIC_URL, + "name": "Sponsor Awesome Python", + "url": SPONSORSHIP_PUBLIC_URL, + "description": SPONSORSHIP_DESCRIPTION, + "isPartOf": ISPARTOF_WEBSITE, + "inLanguage": "en", + }, + build_breadcrumb_json_ld( + [ + ("Awesome Python", SITE_URL), + ("Sponsorship", SPONSORSHIP_PUBLIC_URL), + ] + ), ], } @@ -548,14 +615,21 @@ def build(repo_root: Path) -> None: group_categories: Sequence[ParsedSection] | None = None, ) -> None: page_dir.mkdir(parents=True, exist_ok=True) - category_description = category_meta_description(category["name"], len(entries), category["description"]) + parent_name = parent_category["name"] if parent_category else None + category_title = category_meta_title(category["name"], parent_name) + category_description = category_meta_description(category["name"], len(entries), category["description"], parent_name) + breadcrumbs = [("Awesome Python", SITE_URL)] + if parent_category: + breadcrumbs.append((parent_category["name"], category_public_url(parent_category))) + breadcrumbs.append((category["name"], category_url)) category_json_ld = json.dumps( - build_category_json_ld(category["name"], category_url, category_description, entries), + build_category_json_ld(category_title.removesuffix(" - Awesome Python"), category_url, category_description, entries, breadcrumbs), ensure_ascii=False, ).replace(" None: hero_stats.append(f"{repo_stars}+ stars on GitHub") hero_stats.append(f"Updated {build_date.strftime('%B %d, %Y')}") (sponsorship_dir / "index.html").write_text( - tpl_sponsorship.render(hero_stats=hero_stats), + tpl_sponsorship.render( + hero_stats=hero_stats, + sponsorship_description=SPONSORSHIP_DESCRIPTION, + sponsorship_json_ld=json.dumps(build_sponsorship_json_ld(), ensure_ascii=False).replace("{{ sponsorship_json_ld | safe }} +{% endblock %} {% block header %}
    diff --git a/website/tests/test_build.py b/website/tests/test_build.py index caada78..5649f29 100644 --- a/website/tests/test_build.py +++ b/website/tests/test_build.py @@ -569,7 +569,7 @@ class TestBuild: assert data["@context"] == "https://schema.org" graph = {node["@type"]: node for node in data["@graph"]} - assert set(graph) == {"WebSite", "CollectionPage"} + assert set(graph) == {"WebSite", "CollectionPage", "BreadcrumbList"} assert graph["WebSite"]["@id"] == "https://awesome-python.com/#website" collection = graph["CollectionPage"] assert collection["name"] == "Widgets Python Libraries" @@ -588,6 +588,12 @@ class TestBuild: positions = sorted(item["position"] for item in item_list["itemListElement"]) assert positions == [1, 2] + breadcrumbs = graph["BreadcrumbList"]["itemListElement"] + assert breadcrumbs == [ + {"@type": "ListItem", "position": 1, "name": "Awesome Python", "item": "https://awesome-python.com/"}, + {"@type": "ListItem", "position": 2, "name": "Widgets", "item": "https://awesome-python.com/categories/widgets/"}, + ] + def test_group_page_falls_back_to_default_description_in_json_ld(self, tmp_path): readme = textwrap.dedent("""\ # T @@ -685,9 +691,79 @@ class TestBuild: assert "

    Synchronous

    " in sync assert "category-breadcrumb" in sync + parser = HeadMetadataParser() + parser.feed(sync) + assert parser.title.strip() == "Synchronous for Web Frameworks - Awesome Python" + assert parser.meta_by_name["description"] == "Explore 1 curated Python projects in Synchronous for Web Frameworks. Part of the Awesome Python catalog." + + marker = '", start) + graph = {node["@type"]: node for node in json.loads(sync[start:end])["@graph"]} + assert graph["CollectionPage"]["name"] == "Synchronous for Web Frameworks" + assert graph["BreadcrumbList"]["itemListElement"] == [ + {"@type": "ListItem", "position": 1, "name": "Awesome Python", "item": "https://awesome-python.com/"}, + { + "@type": "ListItem", + "position": 2, + "name": "Web Frameworks", + "item": "https://awesome-python.com/categories/web-frameworks/", + }, + { + "@type": "ListItem", + "position": 3, + "name": "Synchronous", + "item": "https://awesome-python.com/categories/web-frameworks/synchronous/", + }, + ] + parent = (site / "categories" / "web-frameworks" / "index.html").read_text(encoding="utf-8") assert "category-breadcrumb" not in parent + def test_sponsorship_page_contains_json_ld(self, tmp_path): + readme = textwrap.dedent("""\ + # T + + ## Projects + + **Tools** + + ## Widgets + + - [w1](https://example.com/w1) - A widget. + + # Contributing + + Done. + """) + self._copy_real_templates(tmp_path) + (tmp_path / "README.md").write_text(readme, encoding="utf-8") + build(tmp_path) + + site = tmp_path / "website" / "output" + html = (site / "sponsorship" / "index.html").read_text(encoding="utf-8") + parser = HeadMetadataParser() + parser.feed(html) + + assert parser.title.strip() == "Sponsor Awesome Python" + assert parser.meta_by_name["description"] == ( + "Sponsorship for awesome-python: tiers, audience, and how to get your product in front of professional Python developers evaluating tools for production use." + ) + assert parser.links_by_rel["canonical"] == "https://awesome-python.com/sponsorship/" + + marker = '", start) + graph = {node["@type"]: node for node in json.loads(html[start:end])["@graph"]} + + assert set(graph) == {"WebSite", "WebPage", "BreadcrumbList"} + assert graph["WebPage"]["@id"] == "https://awesome-python.com/sponsorship/" + assert graph["WebPage"]["url"] == "https://awesome-python.com/sponsorship/" + assert graph["BreadcrumbList"]["itemListElement"] == [ + {"@type": "ListItem", "position": 1, "name": "Awesome Python", "item": "https://awesome-python.com/"}, + {"@type": "ListItem", "position": 2, "name": "Sponsorship", "item": "https://awesome-python.com/sponsorship/"}, + ] + def test_index_embeds_filter_urls_json(self, tmp_path): readme = textwrap.dedent("""\ # T From c0b80fd75fca6b683703f015388346c1386689de Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Sun, 7 Jun 2026 03:21:12 +0800 Subject: [PATCH 07/14] fix: surface sponsorship link in header --- website/static/style.css | 2 ++ website/templates/category.html | 1 + website/templates/index.html | 1 + website/templates/sponsorship.html | 3 ++- website/tests/test_build.py | 3 +++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/website/static/style.css b/website/static/style.css index bac5b58..9305657 100644 --- a/website/static/style.css +++ b/website/static/style.css @@ -236,7 +236,9 @@ kbd { .hero-topbar-actions { display: flex; + flex-wrap: wrap; align-items: center; + justify-content: flex-end; gap: 0.75rem; } diff --git a/website/templates/category.html b/website/templates/category.html index 3911544..6e4b03e 100644 --- a/website/templates/category.html +++ b/website/templates/category.html @@ -23,6 +23,7 @@ rel="noopener" >Submit a project + Sponsorship
    diff --git a/website/templates/index.html b/website/templates/index.html index bf2abd2..e7f1c9e 100644 --- a/website/templates/index.html +++ b/website/templates/index.html @@ -18,6 +18,7 @@ rel="noopener" >Submit a project + Sponsorship diff --git a/website/templates/sponsorship.html b/website/templates/sponsorship.html index aeda4ca..224d87e 100644 --- a/website/templates/sponsorship.html +++ b/website/templates/sponsorship.html @@ -22,6 +22,7 @@ rel="noopener" >Submit a project + Sponsorship @@ -48,7 +49,7 @@ >Email sponsorship@awesome-python.com ' not in category_html + assert 'Sponsorship' in category_html assert "

    Widgets

    " in category_html assert 'Widget libraries. Also see awesome-widgets.' in category_html assert 'href="https://example.com/w1"' in category_html @@ -481,6 +482,7 @@ class TestBuild: assert parser.meta_by_name["twitter:description"] == expected_description assert parser.meta_by_name["twitter:image"] == expected_image assert "\n Sponsorship' in html assert 'id="hero-category-heading">Browse by category' in html assert 'class="hero-category-link" href="/categories/ai-and-agents/"' in html @@ -750,6 +752,7 @@ class TestBuild: "Sponsorship for awesome-python: tiers, audience, and how to get your product in front of professional Python developers evaluating tools for production use." ) assert parser.links_by_rel["canonical"] == "https://awesome-python.com/sponsorship/" + assert 'Sponsorship' in html marker = '