mirror of
https://github.com/vinta/awesome-python.git
synced 2026-11-08 02:15:12 -06:00
feat: tag sponsor links with UTM parameters
Sponsor links carried no UTM tags, so sponsors saw awesome-python clicks at best as generic referral traffic and could not tell README clicks from website clicks. README sponsor entries now carry utm_source=awesome-python&utm_medium=sponsorship&utm_campaign=sponsor&utm_content=readme, and the website build rewrites utm_content to website for the sponsor band. New sponsor entries in README.md need the same UTM suffix. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ An opinionated guide to the best Python frameworks, libraries, and tools.
|
||||
|
||||
## **Sponsors**
|
||||
|
||||
- [iPulse AI](https://ipulseai.com) - Open Agentic Investment Research Platform. Inspect deep multi-agent market forecasts and stock picks.
|
||||
- [iPulse AI](https://ipulseai.com?utm_source=awesome-python&utm_medium=sponsorship&utm_campaign=sponsor&utm_content=readme) - Open Agentic Investment Research Platform. Inspect deep multi-agent market forecasts and stock picks.
|
||||
|
||||
> **Sponsor slots open**, from $99/month. The **#10 most-starred repo on GitHub**. Put your product in front of Python developers. [Become a sponsor](https://awesome-python.com/sponsorship/).
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ Email [sponsorship@awesome-python.com](mailto:sponsorship@awesome-python.com?sub
|
||||
|
||||
One upfront payment per term. Setup takes less than 24 hours.
|
||||
|
||||
Sponsor links carry UTM tags, so clicks show up in your own analytics as `awesome-python / sponsorship`.
|
||||
|
||||
## Previously Sponsored By
|
||||
|
||||
- [Warp](https://www.warp.dev/) - The terminal for modern developers.
|
||||
|
||||
@@ -11,6 +11,7 @@ from collections.abc import Sequence
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import TypedDict
|
||||
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
from markdown_it import MarkdownIt
|
||||
@@ -130,6 +131,16 @@ def extract_github_repo(url: str) -> str | None:
|
||||
return m.group(1) if m else None
|
||||
|
||||
|
||||
def sponsor_website_url(url: str) -> str:
|
||||
"""Set utm_content=website so sponsors can tell website clicks from README clicks."""
|
||||
parts = urlsplit(url)
|
||||
pairs = parse_qsl(parts.query, keep_blank_values=True)
|
||||
if not any(k == "utm_content" for k, _ in pairs):
|
||||
return url
|
||||
query = [(k, "website" if k == "utm_content" else v) for k, v in pairs]
|
||||
return urlunsplit(parts._replace(query=urlencode(query)))
|
||||
|
||||
|
||||
def load_stars(path: Path) -> dict[str, dict]:
|
||||
"""Load star data from JSON. Returns empty dict if file doesn't exist or is corrupt."""
|
||||
if path.exists():
|
||||
@@ -749,6 +760,8 @@ def build(repo_root: Path) -> None:
|
||||
|
||||
parsed_groups = parse_readme(readme_text)
|
||||
sponsors = parse_sponsors(readme_text)
|
||||
for sponsor in sponsors:
|
||||
sponsor["url"] = sponsor_website_url(sponsor["url"])
|
||||
|
||||
categories = [cat for g in parsed_groups for cat in g["categories"]]
|
||||
cat_slugs = [cat["slug"] for cat in categories]
|
||||
|
||||
@@ -26,6 +26,7 @@ from build import (
|
||||
load_pypi_badges,
|
||||
load_stars,
|
||||
sort_entries,
|
||||
sponsor_website_url,
|
||||
subcategory_path,
|
||||
)
|
||||
from readme_parser import parse_readme, slugify
|
||||
@@ -458,6 +459,37 @@ class TestBuild:
|
||||
assert llms_txt != readme
|
||||
assert "# Contributing" not in llms_txt
|
||||
|
||||
def test_homepage_sponsor_link_tags_website_clicks(self, tmp_path):
|
||||
readme = textwrap.dedent("""\
|
||||
# Awesome Python
|
||||
|
||||
Intro.
|
||||
|
||||
## **Sponsors**
|
||||
|
||||
- [Sponsor](https://sponsor.example.com/?ref=x&utm_source=awesome-python&utm_content=readme) - Sponsored tool.
|
||||
|
||||
## Projects
|
||||
|
||||
**Tools**
|
||||
|
||||
## Widgets
|
||||
|
||||
- [w1](https://example.com) - A widget.
|
||||
|
||||
# Contributing
|
||||
|
||||
Help!
|
||||
""")
|
||||
(tmp_path / "README.md").write_text(readme, encoding="utf-8")
|
||||
self._copy_real_templates(tmp_path)
|
||||
|
||||
build(tmp_path)
|
||||
|
||||
index_html = (tmp_path / "website" / "output" / "index.html").read_text(encoding="utf-8")
|
||||
assert 'href="https://sponsor.example.com/?ref=x&utm_source=awesome-python&utm_content=website"' in index_html
|
||||
assert "utm_content=readme" not in index_html
|
||||
|
||||
def test_build_cleans_stale_output(self, tmp_path):
|
||||
readme = textwrap.dedent("""\
|
||||
# T
|
||||
@@ -1278,6 +1310,23 @@ class TestExtractGithubRepo:
|
||||
assert extract_github_repo("https://github.com/org") is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# sponsor_website_url
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestSponsorWebsiteUrl:
|
||||
def test_replaces_readme_utm_content(self):
|
||||
url = "https://example.com?utm_source=awesome-python&utm_medium=sponsorship&utm_campaign=sponsor&utm_content=readme"
|
||||
assert sponsor_website_url(url) == "https://example.com?utm_source=awesome-python&utm_medium=sponsorship&utm_campaign=sponsor&utm_content=website"
|
||||
|
||||
def test_keeps_path_and_other_params(self):
|
||||
assert sponsor_website_url("https://example.com/landing?ref=x&utm_content=readme") == "https://example.com/landing?ref=x&utm_content=website"
|
||||
|
||||
def test_leaves_untagged_url_unchanged(self):
|
||||
assert sponsor_website_url("https://example.com") == "https://example.com"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# load_stars
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user