diff --git a/great_docs/config.py b/great_docs/config.py
index 7b1a24e7..ac49abec 100644
--- a/great_docs/config.py
+++ b/great_docs/config.py
@@ -21,6 +21,11 @@
"exclude": [],
"auto_include": [], # Names to force-include even if they match AUTO_EXCLUDE
"no_auto_exclude": False, # Bypass the built-in AUTO_EXCLUDE list entirely
+ # PyPI link
+ # True (default): auto-detect package name and link to pypi.org
+ # False: disable the PyPI link entirely
+ # str: custom package index URL (e.g., "https://artifactory.example.com/packages/my-pkg")
+ "pypi": True,
# GitHub integration
"repo": None, # GitHub repository URL override (e.g., "https://github.com/owner/repo")
# Site URL for subdirectory deployments (sets website.site-url in _quarto.yml)
@@ -502,6 +507,19 @@ def no_auto_exclude(self) -> bool:
"""Check if the built-in AUTO_EXCLUDE list should be bypassed."""
return self.get("no_auto_exclude", False)
+ @property
+ def pypi(self) -> bool | str:
+ """Get the PyPI link configuration.
+
+ Returns
+ -------
+ bool | str
+ - True: auto-detect package name and link to pypi.org (default)
+ - False: disable the PyPI link entirely
+ - str: custom package index URL
+ """
+ return self.get("pypi", True)
+
@property
def repo(self) -> str | None:
"""Get the GitHub repository URL override."""
diff --git a/great_docs/core.py b/great_docs/core.py
index 828bf2b5..973bd78c 100644
--- a/great_docs/core.py
+++ b/great_docs/core.py
@@ -9452,10 +9452,15 @@ def _build_metadata_margin(self) -> str:
# ── 1. Links ─────────────────────────────────────────────────────
links_items: list[str] = []
- package_name = self._detect_package_name()
- if package_name:
- pypi_url = f"https://pypi.org/project/{package_name}/"
- links_items.append(f"[{get_translation('view_on_pypi', lang)}]({pypi_url})
")
+ pypi_setting = self._config.pypi
+ if pypi_setting is not False:
+ if isinstance(pypi_setting, str):
+ pypi_url = pypi_setting
+ else:
+ package_name = self._detect_package_name()
+ pypi_url = f"https://pypi.org/project/{package_name}/" if package_name else None
+ if pypi_url:
+ links_items.append(f"[{get_translation('view_on_pypi', lang)}]({pypi_url})
")
if metadata.get("urls"):
urls = metadata["urls"]
diff --git a/tests/test_great_docs.py b/tests/test_great_docs.py
index 0cbdeac5..c9272cd9 100644
--- a/tests/test_great_docs.py
+++ b/tests/test_great_docs.py
@@ -12826,6 +12826,41 @@ def test_build_metadata_margin_with_package_name():
assert "#### Links" in result
+def test_build_metadata_margin_pypi_disabled():
+ """_build_metadata_margin omits PyPI link when pypi: false."""
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ pyproject = Path(tmp_dir) / "pyproject.toml"
+ pyproject.write_text('[project]\nname = "testpkg"\n', encoding="utf-8")
+ config_file = Path(tmp_dir) / "great-docs.yml"
+ config_file.write_text("pypi: false\n", encoding="utf-8")
+ gd_dir = Path(tmp_dir) / "great-docs"
+ gd_dir.mkdir()
+ docs = GreatDocs(project_path=tmp_dir)
+ result = docs._build_metadata_margin()
+
+ assert "pypi.org" not in result
+ assert "View on PyPI" not in result
+
+
+def test_build_metadata_margin_pypi_custom_url():
+ """_build_metadata_margin uses custom URL when pypi is a string."""
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ pyproject = Path(tmp_dir) / "pyproject.toml"
+ pyproject.write_text('[project]\nname = "testpkg"\n', encoding="utf-8")
+ config_file = Path(tmp_dir) / "great-docs.yml"
+ config_file.write_text(
+ 'pypi: "https://packages.example.com/simple/testpkg"\n',
+ encoding="utf-8",
+ )
+ gd_dir = Path(tmp_dir) / "great-docs"
+ gd_dir.mkdir()
+ docs = GreatDocs(project_path=tmp_dir)
+ result = docs._build_metadata_margin()
+
+ assert "packages.example.com/simple/testpkg" in result
+ assert "pypi.org" not in result
+
+
def test_build_metadata_margin_with_license():
"""_build_metadata_margin omits license when no LICENSE file exists."""
with tempfile.TemporaryDirectory() as tmp_dir:
diff --git a/user_guide/05-configuration.qmd b/user_guide/05-configuration.qmd
index 9f2b0993..8fa3d8bd 100644
--- a/user_guide/05-configuration.qmd
+++ b/user_guide/05-configuration.qmd
@@ -350,6 +350,24 @@ source:
placement: usage # Where to place the link: "usage" (default) or "title"
```
+## PyPI Link
+
+The homepage metadata sidebar includes a "View on PyPI" link, auto-detected from your package name
+in `pyproject.toml`. You can disable it or point it to a custom package index:
+
+```{.yaml filename="great-docs.yml"}
+# Disable the PyPI link entirely
+pypi: false
+```
+
+```{.yaml filename="great-docs.yml"}
+# Use a custom package index URL (e.g., a private registry)
+pypi: "https://packages.example.com/simple/my-package"
+```
+
+When `pypi` is `true` (the default), the link is auto-generated as
+`https://pypi.org/project/{package_name}/`.
+
## Sidebar Filter
The API reference sidebar includes a search filter for large APIs. Configure it:
@@ -849,6 +867,9 @@ source:
branch: main
placement: usage
+# PyPI Link
+pypi: true # true (default), false to disable, or a custom URL string
+
# Sidebar
sidebar_filter:
enabled: true