Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-sphinx-scrapy for 
openSUSE:Factory checked in at 2026-08-22 21:36:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-sphinx-scrapy (Old)
 and      /work/SRC/openSUSE:Factory/.python-sphinx-scrapy.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-sphinx-scrapy"

Sat Aug 22 21:36:23 2026 rev:3 rq:1373068 version:0.8.12

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-sphinx-scrapy/python-sphinx-scrapy.changes    
    2026-07-06 12:35:37.062260245 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-sphinx-scrapy.new.1258/python-sphinx-scrapy.changes
      2026-08-22 21:38:29.564261254 +0200
@@ -1,0 +2,21 @@
+Sat Aug 22 13:45:02 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 0.8.12:
+  * Extended easy Intersphinx configuration to platformdirs
+  * Added an explicit dependency on docutils.
+  * Added the :gh: role, to link to GitHub issues and pull
+    requests, of the current repository or of a different one.
+  * Fixed project data from pyproject.toml, like the automatic
+    html_baseurl value, being read relative to the current
+    working directory instead of relative to conf.py.
+  * Fixed the docs tox environment getting an invalid Python
+    interpreter in projects without a pyproject.toml.
+  * Fixed the docs tox environment failing to find its Python
+    interpreter when tox-uv is installed.
+  * Added the stat cross-reference type, for the .. stat::
+    directive and the :stat: role, to document and link to Scrapy
+    stats.
+  * Extended easy Intersphinx configuration to scrapy-lint
+  * Extended easy Intersphinx configuration to pypug
+
+-------------------------------------------------------------------

Old:
----
  sphinx_scrapy-0.8.6.tar.gz

New:
----
  sphinx_scrapy-0.8.12.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-sphinx-scrapy.spec ++++++
--- /var/tmp/diff_new_pack.3WnUfo/_old  2026-08-22 21:38:30.237285361 +0200
+++ /var/tmp/diff_new_pack.3WnUfo/_new  2026-08-22 21:38:30.239285432 +0200
@@ -19,7 +19,7 @@
 # Enable libalternatives by default
 %bcond_without libalternatives
 Name:           python-sphinx-scrapy
-Version:        0.8.6
+Version:        0.8.12
 Release:        0
 Summary:        Sphinx extension for documentation in the Scrapy ecosystem
 License:        BSD-3-Clause

++++++ sphinx_scrapy-0.8.6.tar.gz -> sphinx_scrapy-0.8.12.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/.github/actionlint.yaml 
new/sphinx-scrapy-0.8.12/.github/actionlint.yaml
--- old/sphinx-scrapy-0.8.6/.github/actionlint.yaml     1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-scrapy-0.8.12/.github/actionlint.yaml    2026-08-14 
14:28:50.000000000 +0200
@@ -0,0 +1,6 @@
+paths:
+  .github/workflows/publish.yml:
+    ignore:
+    # The job is disabled on purpose while the package cannot be published to
+    # PyPI, see the README.
+    - 'constant expression "false" in condition'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/.github/dependabot.yml 
new/sphinx-scrapy-0.8.12/.github/dependabot.yml
--- old/sphinx-scrapy-0.8.6/.github/dependabot.yml      1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-scrapy-0.8.12/.github/dependabot.yml     2026-08-14 
14:28:50.000000000 +0200
@@ -0,0 +1,12 @@
+version: 2
+updates:
+  - package-ecosystem: github-actions
+    directory: "/"
+    schedule:
+      interval: monthly
+    groups:
+      github-actions:
+        patterns:
+          - "*"
+    cooldown:
+      default-days: 7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/.github/workflows/ci.yml 
new/sphinx-scrapy-0.8.12/.github/workflows/ci.yml
--- old/sphinx-scrapy-0.8.6/.github/workflows/ci.yml    1970-01-01 
01:00:00.000000000 +0100
+++ new/sphinx-scrapy-0.8.12/.github/workflows/ci.yml   2026-08-14 
14:28:50.000000000 +0200
@@ -0,0 +1,26 @@
+name: CI
+
+permissions:
+  contents: read
+
+on:
+  push:
+    branches:
+    - main
+  pull_request:
+
+concurrency:
+  group: ${{github.workflow}}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  pre-commit:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+      with:
+        persist-credentials: false
+    - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # 
v7.0.0
+      with:
+        python-version: 3.14
+    - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/.github/workflows/publish.yml 
new/sphinx-scrapy-0.8.12/.github/workflows/publish.yml
--- old/sphinx-scrapy-0.8.6/.github/workflows/publish.yml       2026-05-12 
09:03:58.000000000 +0200
+++ new/sphinx-scrapy-0.8.12/.github/workflows/publish.yml      2026-08-14 
14:28:50.000000000 +0200
@@ -1,10 +1,20 @@
 name: Publish
+
+permissions:
+  contents: read
+
 on:
   push:
     tags:
     - '[0-9]+.[0-9]+.[0-9]+'
+
+concurrency:
+  group: ${{github.workflow}}-${{ github.ref }}
+  cancel-in-progress: true
+
 jobs:
   publish:
+    if: false  # Cannot be published to PyPI at the moment, see the README.
     runs-on: ubuntu-latest
     environment:
       name: pypi
@@ -12,14 +22,16 @@
     permissions:
       id-token: write
     steps:
-    - uses: actions/checkout@v4
-    - uses: actions/setup-python@v5
+    - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+      with:
+        persist-credentials: false
+    - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # 
v7.0.0
       with:
         python-version: 3.14
     - run: |
         python -m pip install --upgrade build
         python -m build
     - name: Publish to PyPI
-      uses: pypa/gh-action-pypi-publish@release/v1
+      uses: 
pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
       with:
         verbose: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/.pre-commit-config.yaml 
new/sphinx-scrapy-0.8.12/.pre-commit-config.yaml
--- old/sphinx-scrapy-0.8.6/.pre-commit-config.yaml     2026-05-12 
09:03:58.000000000 +0200
+++ new/sphinx-scrapy-0.8.12/.pre-commit-config.yaml    2026-08-14 
14:28:50.000000000 +0200
@@ -9,6 +9,10 @@
   rev: v1.16.0
   hooks:
   - id: mypy
+    additional_dependencies:
+    - sphinx
+    - tox
+    - types-docutils
 - repo: https://github.com/adamchainz/blacken-docs
   rev: 1.19.1
   hooks:
@@ -16,6 +20,20 @@
     additional_dependencies:
     - black==25.1.0
 - repo: https://github.com/pre-commit/pre-commit-hooks
-  rev: v5.0.0
+  rev: v6.0.0
   hooks:
+  - id: end-of-file-fixer
   - id: trailing-whitespace
+- repo: https://github.com/sphinx-contrib/sphinx-lint
+  rev: v1.0.2
+  hooks:
+  - id: sphinx-lint
+- repo: https://github.com/rhysd/actionlint
+  rev: v1.7.12
+  hooks:
+  - id: actionlint
+- repo: https://github.com/zizmorcore/zizmor-pre-commit
+  rev: v1.29.0
+  hooks:
+  - id: zizmor
+    args: [--no-progress, --fix]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/CHANGES.rst 
new/sphinx-scrapy-0.8.12/CHANGES.rst
--- old/sphinx-scrapy-0.8.6/CHANGES.rst 2026-05-12 09:03:58.000000000 +0200
+++ new/sphinx-scrapy-0.8.12/CHANGES.rst        2026-08-14 14:28:50.000000000 
+0200
@@ -2,6 +2,51 @@
 Release notes
 =============
 
+0.8.12 (2026-08-14)
+===================
+
+-   | Extended easy Intersphinx configuration to
+    | `platformdirs <https://platformdirs.readthedocs.io/en/latest/>`_
+
+-   Added an explicit dependency on ``docutils``.
+
+0.8.11 (2026-08-10)
+===================
+
+-   Added the ``:gh:`` role, to link to GitHub issues and pull requests, of the
+    current repository or of a different one.
+
+-   Fixed project data from ``pyproject.toml``, like the automatic
+    ``html_baseurl`` value, being read relative to the current working
+    directory instead of relative to ``conf.py``.
+
+-   Fixed the ``docs`` tox environment getting an invalid Python interpreter in
+    projects without a ``pyproject.toml``.
+
+0.8.10 (2026-07-31)
+===================
+
+-   Fixed the ``docs`` tox environment failing to find its Python interpreter
+    when `tox-uv <https://github.com/tox-dev/tox-uv>`_ is installed.
+
+0.8.9 (2026-07-29)
+==================
+
+-   Added the ``stat`` cross-reference type, for the ``.. stat::`` directive
+    and the ``:stat:`` role, to document and link to Scrapy stats.
+
+0.8.8 (2026-06-15)
+==================
+
+-   | Extended easy Intersphinx configuration to
+    | `scrapy-lint <https://scrapy-lint.readthedocs.io/en/latest/>`_
+
+0.8.7 (2026-06-11)
+==================
+
+-   | Extended easy Intersphinx configuration to
+    | `pypug <https://packaging.python.org/en/latest/>`_
+
 0.8.6 (2026-05-12)
 ==================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/README.rst 
new/sphinx-scrapy-0.8.12/README.rst
--- old/sphinx-scrapy-0.8.6/README.rst  2026-05-12 09:03:58.000000000 +0200
+++ new/sphinx-scrapy-0.8.12/README.rst 2026-08-14 14:28:50.000000000 +0200
@@ -30,7 +30,7 @@
     `additional packages <#intersphinx-packages>`_.
 
 -   Allows you to easily link to Scrapy settings, request metadata keys,
-    signals and commands:
+    signals, commands and stats:
 
     .. code-block:: rst
 
@@ -39,6 +39,21 @@
         :reqmeta:`download_slot`
         :signal:`spider_opened`
         :command:`crawl`
+        :stat:`item_scraped_count`
+
+-   Allows you to easily link to GitHub issues and pull requests:
+
+    .. code-block:: rst
+
+        :gh:`1908`
+        :gh:`parsel#12`
+        :gh:`sphinx-doc/sphinx#13000`
+
+    They render as ``#1908``, ``parsel#12`` and ``sphinx#13000``. Use the 
number
+    alone for the current repository, which comes from the GitHub URLs in
+    ``pyproject.toml``. For a different repository, its name alone is enough if
+    it is a known repository of the Scrapy ecosystem or it belongs to the same
+    owner as the current repository.
 
 Setup
 =====
@@ -50,7 +65,7 @@
 
         [tool.sphinx-scrapy]
         python-version = "3.14"
-    
+
     It must be `supported by Read the Docs
     
<https://docs.readthedocs.com/platform/latest/config-file/v2.html#build-tools-python>`_.
 
@@ -61,7 +76,7 @@
 
     .. code-block:: text
 
-        sphinx-scrapy @ git+https://github.com/scrapy/[email protected]
+        sphinx-scrapy @ git+https://github.com/scrapy/[email protected]
 
 #.  Add to ``docs/conf.py``:
 
@@ -111,7 +126,7 @@
 
         repos:
         - repo: https://github.com/scrapy/sphinx-scrapy
-            rev: 0.8.6
+            rev: 0.8.12
             hooks:
             - id: sphinx-scrapy
 
@@ -121,7 +136,7 @@
 
         [tox]
         requires =
-            sphinx-scrapy[tox] @ 
git+https://github.com/scrapy/[email protected]
+            sphinx-scrapy[tox] @ 
git+https://github.com/scrapy/[email protected]
         envlist = …,docs
 
     .. note:: ``docs`` in ``envlist`` is required.
@@ -175,7 +190,9 @@
 | `niquests <https://niquests.readthedocs.io/en/latest/>`_
 | `packaging <https://packaging.pypa.io/en/stable/>`_
 | `parsel <https://parsel.readthedocs.io/en/latest/>`_
+| `platformdirs <https://platformdirs.readthedocs.io/en/latest/>`_
 | `pydantic <https://docs.pydantic.dev/latest/>`_
+| `pypug <https://packaging.python.org/en/latest/>`_
 | `pytest <https://docs.pytest.org/en/stable/>`_
 | `python-scrapinghub <https://python-scrapinghub.readthedocs.io/en/latest/>`_
 | `python-zyte-api <https://python-zyte-api.readthedocs.io/en/stable/>`_
@@ -206,4 +223,4 @@
 <https://github.com/scrapy/sphinx-scrapy/blob/main/CHANGES.rst>`_ for a list of
 releases and their changes.
 
-.. _sphinx.ext.intersphinx: 
https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html
\ No newline at end of file
+.. _sphinx.ext.intersphinx: 
https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/pyproject.toml 
new/sphinx-scrapy-0.8.12/pyproject.toml
--- old/sphinx-scrapy-0.8.6/pyproject.toml      2026-05-12 09:03:58.000000000 
+0200
+++ new/sphinx-scrapy-0.8.12/pyproject.toml     2026-08-14 14:28:50.000000000 
+0200
@@ -4,9 +4,10 @@
 
 [project]
 name = "sphinx-scrapy"
-version = "0.8.6"
+version = "0.8.12"
 description = "Sphinx extension for documentation in the Scrapy ecosystem"
 dependencies = [
+    "docutils",
     "packaging",
     "sphinx",
     "sphinx-copybutton",
@@ -59,7 +60,7 @@
 strict = true
 
 [tool.bumpversion]
-current_version = "0.8.6"
+current_version = "0.8.12"
 commit = true
 tag = true
 tag_name = "{new_version}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/sphinx_scrapy/__init__.py 
new/sphinx-scrapy-0.8.12/sphinx_scrapy/__init__.py
--- old/sphinx-scrapy-0.8.6/sphinx_scrapy/__init__.py   2026-05-12 
09:03:58.000000000 +0200
+++ new/sphinx-scrapy-0.8.12/sphinx_scrapy/__init__.py  2026-08-14 
14:28:50.000000000 +0200
@@ -1,9 +1,14 @@
 from __future__ import annotations
 
 import re
+from functools import cache
 from logging import getLogger
+from pathlib import Path
 from typing import TYPE_CHECKING
 
+from docutils import nodes
+from sphinx.util.docutils import SphinxRole
+
 from .config import load_project_config, normalize_project_id
 
 if TYPE_CHECKING:
@@ -12,6 +17,8 @@
     from sphinx.application import Sphinx
     from sphinx.config import Config
 
+    from .config import ProjectConfig
+
 logger = getLogger(__name__)
 
 INTERSPHINX_MAPPING = {
@@ -31,7 +38,9 @@
     "niquests": ("https://niquests.readthedocs.io/en/latest/";, None),
     "packaging": ("https://packaging.pypa.io/en/stable/";, None),
     "parsel": ("https://parsel.readthedocs.io/en/latest/";, None),
+    "platformdirs": ("https://platformdirs.readthedocs.io/en/latest/";, None),
     "pydantic": ("https://pydantic.dev/docs/validation/latest/";, None),
+    "pypug": ("https://packaging.python.org/en/latest/";, None),
     "pytest": ("https://docs.pytest.org/en/stable/";, None),
     "python": ("https://docs.python.org/3/";, None),
     "python-scrapinghub": (
@@ -40,6 +49,7 @@
     ),
     "python-zyte-api": ("https://python-zyte-api.readthedocs.io/en/stable/";, 
None),
     "scrapy": ("https://docs.scrapy.org/en/latest/";, None),
+    "scrapy-lint": ("https://scrapy-lint.readthedocs.io/en/latest/";, None),
     "scrapy-poet": ("https://scrapy-poet.readthedocs.io/en/stable/";, None),
     "scrapy-spider-metadata": (
         "https://scrapy-spider-metadata.readthedocs.io/en/latest/";,
@@ -83,6 +93,58 @@
     "zyte": False,
 }
 
+# Repositories that :gh: can target by name alone, e.g. :gh:`parsel#12`.
+_GITHUB_OWNERS = {
+    "scrapinghub": (
+        "andi",
+        "dateparser",
+        "extruct",
+        "price-parser",
+        "python-scrapinghub",
+        "scrapy-poet",
+        "scrapyrt",
+        "shub",
+        "spidermon",
+        "web-poet",
+    ),
+    "scrapy": (
+        "cssselect",
+        "form2request",
+        "itemadapter",
+        "itemloaders",
+        "parsel",
+        "protego",
+        "queuelib",
+        "scrapy",
+        "scrapy-lint",
+        "scrapyd",
+        "scrapyd-client",
+        "sphinx-scrapy",
+        "w3lib",
+    ),
+    "scrapy-plugins": (
+        "scrapy-playwright",
+        "scrapy-splash",
+        "scrapy-zyte-api",
+        "scrapy-zyte-smartproxy",
+    ),
+    "zytedata": (
+        "python-zyte-api",
+        "scrapy-spider-metadata",
+        "url-matcher",
+        "zyte-common-items",
+        "zyte-parsers",
+        "zyte-spider-templates",
+    ),
+}
+_GITHUB_REPO_OWNERS = {
+    repo: owner for owner, repos in _GITHUB_OWNERS.items() for repo in repos
+}
+
+_GITHUB_REFERENCE = re.compile(
+    r"(?:(?:(?P<owner>[\w.-]+)/)?(?P<repo>[\w.-]+)#)?(?P<number>\d+)"
+)
+
 
 COPY_AS_MARKDOWN_BUTTON_JS = """
 (function () {
@@ -246,12 +308,14 @@
     ):
         app.setup_extension(extension)
 
+    app.add_role("gh", _GitHubRole())
+
     app.connect("builder-inited", add_copy_as_markdown_button)
     app.connect("builder-inited", set_better_defaults)
     app.connect("config-inited", update_config)
 
     # 
https://github.com/scrapy/scrapy/blob/dba37674e6eaa6c2030c8eb35ebf8127cd488062/docs/_ext/scrapydocs.py#L90C16-L110C6
-    for crossref_type in ("setting", "signal", "command", "reqmeta"):
+    for crossref_type in ("setting", "signal", "command", "reqmeta", "stat"):
         app.add_crossref_type(
             directivename=crossref_type,
             rolename=crossref_type,
@@ -265,9 +329,55 @@
     app.add_js_file(None, body=COPY_AS_MARKDOWN_BUTTON_JS)
 
 
+class _GitHubRole(SphinxRole):
+    """Link to a GitHub issue or pull request, given ``123`` for the current
+    repository, or ``repo#123`` or ``owner/repo#123`` for a different one.
+    """
+
+    def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]:
+        current_repo = _project_config(self.env.app.confdir).github_repo or ""
+        match = _GITHUB_REFERENCE.fullmatch(self.text.strip())
+        error = owner = repo = number = ""
+        if not match:
+            error = f"Unsupported GitHub reference: {self.text!r}"
+        else:
+            number = match["number"]
+            repo = match["repo"] or current_repo.partition("/")[2]
+            owner = (
+                match["owner"]
+                or _GITHUB_REPO_OWNERS.get(repo)
+                or current_repo.partition("/")[0]
+            )
+            if not (owner and repo):
+                error = (
+                    f"Could not determine the repository of {self.text!r}; use 
"
+                    f"the owner/repo#number syntax"
+                )
+            elif match["repo"] and f"{owner}/{repo}" == current_repo:
+                error = (
+                    f"{self.text!r} targets the current repository; use the "
+                    f"number alone"
+                )
+        if error:
+            message = self.inliner.reporter.error(error, line=self.lineno)
+            problem = self.inliner.problematic(self.rawtext, self.rawtext, 
message)
+            return [problem], [message]
+        label = (
+            f"#{number}" if f"{owner}/{repo}" == current_repo else 
f"{repo}#{number}"
+        )
+        # GitHub redirects the issue URL of a pull request to the pull request.
+        url = f"https://github.com/{owner}/{repo}/issues/{number}";
+        return [nodes.reference(self.rawtext, label, refuri=url)], []
+
+
+@cache
+def _project_config(confdir: str | Path) -> ProjectConfig:
+    return load_project_config(Path(confdir))
+
+
 def update_config(app: Sphinx, config: Config) -> None:
     configure_intersphinx(config)
-    configure_sitemap(config)
+    configure_sitemap(config, _project_config(app.confdir))
 
 
 def set_better_defaults(app: Sphinx) -> None:
@@ -301,10 +411,9 @@
         config.intersphinx_mapping[k] = INTERSPHINX_MAPPING[k]
 
 
-def configure_sitemap(config: Config) -> None:
+def configure_sitemap(config: Config, project_config: ProjectConfig) -> None:
     if not config.html_baseurl:
         package: str | None = None
-        project_config = load_project_config()
         if project_config.project_id:
             package = normalize_project_id(project_config.project_id)
         elif hasattr(config, "project"):
@@ -318,7 +427,10 @@
         config.html_baseurl = base_url
     if not config.html_baseurl.endswith("/"):
         config.html_baseurl = config.html_baseurl + "/"
-        logger.warning("html_baseurl should end with a slash; automatically 
fixed to %r", config.html_baseurl)
+        logger.warning(
+            "html_baseurl should end with a slash; automatically fixed to %r",
+            config.html_baseurl,
+        )
 
 
 def installed(names: set[str]) -> Generator[str, None, None]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/sphinx_scrapy/cli.py 
new/sphinx-scrapy-0.8.12/sphinx_scrapy/cli.py
--- old/sphinx-scrapy-0.8.6/sphinx_scrapy/cli.py        2026-05-12 
09:03:58.000000000 +0200
+++ new/sphinx-scrapy-0.8.12/sphinx_scrapy/cli.py       2026-08-14 
14:28:50.000000000 +0200
@@ -1,7 +1,6 @@
 from __future__ import annotations
 
 import argparse
-from collections.abc import Callable
 import concurrent.futures
 import re
 import shutil
@@ -19,6 +18,7 @@
 from .config import LATEST_RTD_PYTHON_VERSION, load_project_config, 
normalize_project_id
 
 if TYPE_CHECKING:
+    from collections.abc import Callable
     from pathlib import Path
 
 
@@ -48,7 +48,7 @@
 
 
 def _split_wrapped_markdown_target(target: str) -> tuple[str, str, str]:
-    if len(target) >= 2 and target.startswith("<") and target.endswith(">"):
+    if target.startswith("<") and target.endswith(">"):
         return "<", target[1:-1], ">"
     return "", target, ""
 
@@ -69,15 +69,12 @@
 
         title = match.group("title") or ""
         return (
-            f"{match.group('prefix')}"
-            f"{rewritten_target}"
-            f"{title}"
-            f"{match.group('suffix')}"
+            
f"{match.group('prefix')}{rewritten_target}{title}{match.group('suffix')}"
         )
 
     for line in content.splitlines(keepends=True):
         stripped = line.lstrip()
-        if stripped.startswith("```") or stripped.startswith("~~~"):
+        if stripped.startswith(("```", "~~~")):
             marker = stripped[0]
             if not in_fence:
                 in_fence = True
@@ -102,8 +99,8 @@
     docs_host: str,
     docs_path_prefix: str,
 ) -> str:
-    wrapper_prefix, wrapped_target, wrapper_suffix = (
-        _split_wrapped_markdown_target(target)
+    wrapper_prefix, wrapped_target, wrapper_suffix = 
_split_wrapped_markdown_target(
+        target
     )
     parts = urlsplit(wrapped_target)
 
@@ -174,7 +171,8 @@
         request = Request(probe_url, headers=headers, method=method)  # noqa: 
S310
         try:
             with urlopen(request, timeout=5) as response:  # noqa: S310
-                return HTTPStatus.OK <= response.status < 
HTTPStatus.BAD_REQUEST
+                status = int(response.status)
+                return HTTPStatus.OK <= status < HTTPStatus.BAD_REQUEST
         except HTTPError as error:
             if method == "HEAD" and error.code in {
                 HTTPStatus.METHOD_NOT_ALLOWED,
@@ -187,7 +185,9 @@
     return False
 
 
-def _rewrite_url_to_markdown(url: str, enabled_base_urls: set[str], base_urls: 
tuple[str, ...]) -> str:
+def _rewrite_url_to_markdown(
+    url: str, enabled_base_urls: set[str], base_urls: tuple[str, ...]
+) -> str:
     base_url = _matching_base_url(url, base_urls)
     if not base_url or base_url not in enabled_base_urls:
         return url
@@ -198,7 +198,9 @@
         return url
     new_path = f"{path[:-5]}.md"
 
-    return urlunsplit((parts.scheme, parts.netloc, new_path, parts.query, 
parts.fragment))
+    return urlunsplit(
+        (parts.scheme, parts.netloc, new_path, parts.query, parts.fragment)
+    )
 
 
 def _rewrite_intersphinx_links_to_markdown(output_dir: Path) -> None:
@@ -232,9 +234,7 @@
             for base_url in candidate_base_urls
         }
         enabled_base_urls = {
-            base_url
-            for base_url, future in availability.items()
-            if future.result()
+            base_url for base_url, future in availability.items() if 
future.result()
         }
 
     if not enabled_base_urls:
@@ -258,8 +258,10 @@
         return ["-D", "llms_txt_uri_template={docname}.md"]
     if builder == "singlemarkdown":
         return [
-            "-D", "llms_txt_uri_template={docname}.md",
-            "-D", "singlemarkdown_flavor=llm",
+            "-D",
+            "llms_txt_uri_template={docname}.md",
+            "-D",
+            "singlemarkdown_flavor=llm",
         ]
     return []
 
@@ -309,7 +311,9 @@
 
     shutil.copytree(sphinx_build_dir / "html", all_dir, dirs_exist_ok=True)
     shutil.copytree(sphinx_build_dir / "markdown", all_dir, dirs_exist_ok=True)
-    shutil.copy2(sphinx_build_dir / "singlemarkdown" / "index.md", all_dir / 
"llms-full.txt")
+    shutil.copy2(
+        sphinx_build_dir / "singlemarkdown" / "index.md", all_dir / 
"llms-full.txt"
+    )
     _rewrite_intersphinx_links_to_markdown(all_dir)
     _rewrite_llms_links_to_docs_path(all_dir, docs_base_url)
 
@@ -321,7 +325,7 @@
     config = load_project_config()
 
     try:
-        config_python_version = Version(config.python_version)
+        config_python_version = Version(str(config.python_version))
     except InvalidVersion:
         print(
             f"Invalid Python version in pyproject.toml: 
{config.python_version}",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/sphinx_scrapy/config.py 
new/sphinx-scrapy-0.8.12/sphinx_scrapy/config.py
--- old/sphinx-scrapy-0.8.6/sphinx_scrapy/config.py     2026-05-12 
09:03:58.000000000 +0200
+++ new/sphinx-scrapy-0.8.12/sphinx_scrapy/config.py    2026-08-14 
14:28:50.000000000 +0200
@@ -1,17 +1,22 @@
 from __future__ import annotations
 
+import re
+import sys
 from dataclasses import dataclass, field
 from pathlib import Path
+from typing import Any
 
 from packaging.utils import canonicalize_name
 
-try:
+if sys.version_info >= (3, 11):
     import tomllib
-except ModuleNotFoundError:
+else:
     import tomli as tomllib
 
 LATEST_RTD_PYTHON_VERSION = "3.14"
 
+_GITHUB_URL = 
re.compile(r"https?://github\.com/(?P<owner>[\w.-]+)/(?P<repo>[\w.-]+)")
+
 
 @dataclass(frozen=True)
 class ProjectConfig:
@@ -19,6 +24,7 @@
     python_version: str | None = None
     extras: set[str] = field(default_factory=set)
     project_id: str | None = None
+    github_repo: str | None = None
 
 
 def find_project_root(start: Path | None = None) -> Path:
@@ -30,27 +36,40 @@
     raise FileNotFoundError(msg)
 
 
-def get_extras(pyproject_data: dict[str, object]) -> set[str]:
+def get_extras(pyproject_data: dict[str, Any]) -> set[str]:
     project_data = pyproject_data.get("project", {})
     optional_dependencies = project_data.get("optional-dependencies", {})
     return {str(key) for key in optional_dependencies}
 
 
+def _get_github_repo(pyproject_data: dict[str, Any]) -> str | None:
+    urls: dict[str, Any] = pyproject_data.get("project", {}).get("urls", {})
+    # Repository URLs first, since other entries may point to a different
+    # repository, e.g. a documentation page hosted elsewhere.
+    keys = sorted(urls, key=lambda key: key.lower() not in {"repository", 
"source"})
+    for key in keys:
+        match = _GITHUB_URL.match(str(urls[key]))
+        if match:
+            owner, repo = match.group("owner", "repo")
+            return f"{owner}/{repo.removesuffix('.git')}"
+    return None
+
+
 def normalize_project_id(project_id: str) -> str:
     return canonicalize_name(project_id.strip())
 
 
-def load_project_config(root: Path | None = None) -> ProjectConfig:
-    """Load project configuration from a pyproject.toml if available.
+def load_project_config(start: Path | None = None) -> ProjectConfig:
+    """Load project configuration from a :file:`pyproject.toml` if available.
 
-    If no pyproject.toml can be found (starting from ``root`` or CWD),
-    return a minimal ``ProjectConfig`` containing only the resolved
-    project root and leaving other fields empty/None.
+    The file is searched for in *start* (CWD by default) and its parents. If
+    there is none, return a minimal ``ProjectConfig`` containing only the
+    resolved project root and leaving other fields empty/None.
     """
     try:
-        project_root = root or find_project_root()
+        project_root = find_project_root(start)
     except FileNotFoundError:
-        resolved_root = (root or Path.cwd()).resolve()
+        resolved_root = (start or Path.cwd()).resolve()
         return ProjectConfig(root=resolved_root)
 
     pyproject_path = project_root / "pyproject.toml"
@@ -71,4 +90,5 @@
         python_version=str(python_version) if python_version is not None else 
None,
         extras=extras,
         project_id=project_id,
+        github_repo=_get_github_repo(pyproject_data),
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.6/sphinx_scrapy/tox_plugin.py 
new/sphinx-scrapy-0.8.12/sphinx_scrapy/tox_plugin.py
--- old/sphinx-scrapy-0.8.6/sphinx_scrapy/tox_plugin.py 2026-05-12 
09:03:58.000000000 +0200
+++ new/sphinx-scrapy-0.8.12/sphinx_scrapy/tox_plugin.py        2026-08-14 
14:28:50.000000000 +0200
@@ -5,7 +5,7 @@
 from tox.config.loader.memory import MemoryLoader
 from tox.plugin import impl
 
-from .config import load_project_config
+from .config import LATEST_RTD_PYTHON_VERSION, load_project_config
 
 if TYPE_CHECKING:
     from tox.config.sets import ConfigSet
@@ -27,7 +27,11 @@
     state.conf.memory_seed_loaders["docs"].append(
         MemoryLoader(
             description="build documentation",
-            base_python=_python_executable(project_config.python_version),
+            base_python=[
+                _python_executable(
+                    project_config.python_version or LATEST_RTD_PYTHON_VERSION
+                )
+            ],
             deps=["-rdocs/requirements.txt"],
             extras=tuple(project_config.extras),
             commands=["sphinx-scrapy build"],

Reply via email to