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-10-26 10:20:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-sphinx-scrapy (Old)
 and      /work/SRC/openSUSE:Factory/.python-sphinx-scrapy.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-sphinx-scrapy"

Mon Oct 26 10:20:01 2026 rev:4 rq:1392631 version:0.14.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-sphinx-scrapy/python-sphinx-scrapy.changes    
    2026-08-22 21:38:29.564261254 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-sphinx-scrapy.new.2252680/python-sphinx-scrapy.changes
   2026-10-26 10:20:11.001467432 +0100
@@ -1,0 +2,75 @@
+Mon Oct 26 07:09:09 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 0.14.0:
+  * Extended easy Intersphinx configuration to websockets
+  * Intersphinx mappings now point to the documentation of the
+    latest release (/en/stable/) instead of the development
+    version (/en/latest/) for projects that publish it.
+  * The sphinx-scrapy pre-commit hook now also updates Git-based
+    sphinx-scrapy pins, e.g. sphinx-scrapy @
+    git+https://github.com/scrapy/[email protected],
+    turning them into PyPI pins.
+  * sphinx-llm-friendly 0.5.1 or higher is now required.
+  * Enabled sphinx_design and sphinxcontrib.youtube, so their
+    directives, e.g. .. tab-set:: or .. youtube::, work without
+    adding them to extensions, and YouTube videos render as links
+    in the Markdown output.
+  * Extended easy Intersphinx configuration to requests
+  * The sphinx-scrapy pre-commit hook now also updates the
+    sphinx-scrapy pins in :file:`tox.ini` and
+    :file:`docs/requirements.in` to match its rev, so upgrading
+    sphinx-scrapy only takes changing that rev. After
+    :file:`docs/requirements.in` changes, recompile
+    :file:`docs/requirements.txt` with uv pip compile
+    requirements.in -o requirements.txt from the :file:`docs`
+    directory.
+  * Documentation builds now fail on Sphinx warnings. While you
+    fix existing warnings, you can suppress them by type in
+    :file:`docs/conf.py`, or allow all of them in
+    :file:`pyproject.toml` with fail-on-warning = false under
+    [tool.sphinx-scrapy].
+  * Documentation is now built with a regular parallel sphinx-
+    build -b html, which writes the Markdown pages, llms.txt and
+    llms-full.txt next to the HTML pages, in
+    :file:`docs/_build/html` instead of :file:`docs/_build/all`.
+    sphinx-scrapy build and tox -e docs accept an optional output
+    directory, e.g. tox -e docs -- $READTHEDOCS_OUTPUT/html. This
+    is backward-incompatible. To update:  Run sphinx-scrapy
+    update-rtd-config to regenerate :file:`.readthedocs.yml`. In
+    app.add_node() calls, drop llm_singlemarkdown= handlers;
+    llm_markdown= handlers cover all Markdown output.
+  * Run sphinx-scrapy update-rtd-config to regenerate
+    :file:`.readthedocs.yml`.
+  * In app.add_node() calls, drop llm_singlemarkdown= handlers;
+    llm_markdown= handlers cover all Markdown output.
+  * Sphinx 8.0.0 or higher is now required, and sphinx-llm-
+    friendly 0.3.0 or higher.
+  * Replaced the Git-based sphinx-llms-txt and sphinx-markdown-
+    builder dependencies with sphinx-llm-friendly, so sphinx-
+    scrapy can be installed from PyPI again, e.g. sphinx-
+    scrapy==0.10.0 in :file:`docs/requirements.txt` and sphinx-
+    scrapy[tox]==0.10.0 in the requires of :file:`tox.ini`. This
+    is backward-incompatible. To update:  Rename llms_txt_*
+    settings to their llm_friendly_* counterparts, or drop them
+    where the new defaults cover them, and drop markdown_flavor.
+    Remove "sphinx_llms_txt" from extensions. In app.add_node()
+    calls, rename the markdown= and singlemarkdown= handlers to
+    llm_markdown= and llm_singlemarkdown=. Replace
+    exclude_patterns workarounds that check the builder name with
+    llm_friendly_exclude or llm_friendly_llms_full_txt_exclude.
+  * Rename llms_txt_* settings to their llm_friendly_*
+    counterparts, or drop them where the new defaults cover them,
+    and drop markdown_flavor.
+  * Remove "sphinx_llms_txt" from extensions.
+  * In app.add_node() calls, rename the markdown= and
+    singlemarkdown= handlers to llm_markdown= and
+    llm_singlemarkdown=.
+  * Replace exclude_patterns workarounds that check the builder
+    name with llm_friendly_exclude or
+    llm_friendly_llms_full_txt_exclude.
+  * HTML pages now include an <link rel="alternate"
+    type="text/markdown"> tag pointing to their .md counterpart.
+  * llms-full.txt now includes a Source: line before each page's
+    content.
+
+-------------------------------------------------------------------

Old:
----
  sphinx_scrapy-0.8.12.tar.gz

New:
----
  sphinx_scrapy-0.14.0.tar.gz

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

Other differences:
------------------
++++++ python-sphinx-scrapy.spec ++++++
--- /var/tmp/diff_new_pack.BgaDSB/_old  2026-10-26 10:20:11.998509190 +0100
+++ /var/tmp/diff_new_pack.BgaDSB/_new  2026-10-26 10:20:12.000509274 +0100
@@ -19,7 +19,7 @@
 # Enable libalternatives by default
 %bcond_without libalternatives
 Name:           python-sphinx-scrapy
-Version:        0.8.12
+Version:        0.14.0
 Release:        0
 Summary:        Sphinx extension for documentation in the Scrapy ecosystem
 License:        BSD-3-Clause

++++++ sphinx_scrapy-0.8.12.tar.gz -> sphinx_scrapy-0.14.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.12/.github/workflows/publish.yml 
new/sphinx-scrapy-0.14.0/.github/workflows/publish.yml
--- old/sphinx-scrapy-0.8.12/.github/workflows/publish.yml      2026-08-14 
14:28:50.000000000 +0200
+++ new/sphinx-scrapy-0.14.0/.github/workflows/publish.yml      2026-10-14 
12:09:48.000000000 +0200
@@ -14,7 +14,6 @@
 
 jobs:
   publish:
-    if: false  # Cannot be published to PyPI at the moment, see the README.
     runs-on: ubuntu-latest
     environment:
       name: pypi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.12/CHANGES.rst 
new/sphinx-scrapy-0.14.0/CHANGES.rst
--- old/sphinx-scrapy-0.8.12/CHANGES.rst        2026-08-14 14:28:50.000000000 
+0200
+++ new/sphinx-scrapy-0.14.0/CHANGES.rst        2026-10-14 12:09:48.000000000 
+0200
@@ -2,6 +2,113 @@
 Release notes
 =============
 
+0.14.0 (2026-10-14)
+===================
+
+-   | Extended easy Intersphinx configuration to
+    | `websockets <https://websockets.readthedocs.io/en/stable/>`_
+
+-   Intersphinx mappings now point to the documentation of the latest release
+    (``/en/stable/``) instead of the development version (``/en/latest/``)
+    for projects that publish it.
+
+-   The ``sphinx-scrapy`` pre-commit hook now also updates Git-based
+    sphinx-scrapy pins, e.g. ``sphinx-scrapy @
+    git+https://github.com/scrapy/[email protected]``, turning them into
+    PyPI pins.
+
+0.13.0 (2026-09-30)
+===================
+
+-   sphinx-llm-friendly 0.5.1 or higher is now required.
+
+-   Enabled `sphinx_design <https://sphinx-design.readthedocs.io/en/latest/>`_
+    and `sphinxcontrib.youtube <https://github.com/sphinx-contrib/youtube>`_,
+    so their directives, e.g. ``.. tab-set::`` or ``.. youtube::``, work
+    without adding them to ``extensions``, and YouTube videos render as links
+    in the Markdown output.
+
+-   | Extended easy Intersphinx configuration to
+    | `requests <https://docs.python-requests.org/en/stable/>`_
+
+0.12.0 (2026-09-24)
+===================
+
+-   The ``sphinx-scrapy`` pre-commit hook now also updates the sphinx-scrapy
+    pins in :file:`tox.ini` and :file:`docs/requirements.in` to match its
+    ``rev``, so upgrading sphinx-scrapy only takes changing that ``rev``.
+
+    After :file:`docs/requirements.in` changes, recompile
+    :file:`docs/requirements.txt` with ``uv pip compile requirements.in -o
+    requirements.txt`` from the :file:`docs` directory.
+
+0.11.0 (2026-09-24)
+===================
+
+-   Documentation builds now fail on Sphinx warnings.
+
+    While you fix existing warnings, you can `suppress them by type
+    
<https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-suppress_warnings>`_
+    in :file:`docs/conf.py`, or allow all of them in :file:`pyproject.toml`
+    with ``fail-on-warning = false`` under ``[tool.sphinx-scrapy]``.
+
+-   Documentation is now built with a regular parallel ``sphinx-build -b
+    html``, which writes the Markdown pages, ``llms.txt`` and
+    ``llms-full.txt`` next to the HTML pages, in :file:`docs/_build/html`
+    instead of :file:`docs/_build/all`.
+
+    ``sphinx-scrapy build`` and ``tox -e docs`` accept an optional output
+    directory, e.g. ``tox -e docs -- $READTHEDOCS_OUTPUT/html``.
+
+    This is backward-incompatible. To update:
+
+    -   Run ``sphinx-scrapy update-rtd-config`` to regenerate
+        :file:`.readthedocs.yml`.
+
+    -   In ``app.add_node()`` calls, drop ``llm_singlemarkdown=`` handlers;
+        ``llm_markdown=`` handlers cover all Markdown output.
+
+-   Sphinx 8.0.0 or higher is now required, and sphinx-llm-friendly 0.3.0 or
+    higher.
+
+0.10.0 (2026-09-24)
+===================
+
+-   Replaced the Git-based sphinx-llms-txt and sphinx-markdown-builder
+    dependencies with `sphinx-llm-friendly
+    <https://github.com/scrapy/sphinx-llm-friendly>`_, so sphinx-scrapy can be
+    installed from PyPI again, e.g. ``sphinx-scrapy==0.10.0`` in
+    :file:`docs/requirements.txt` and ``sphinx-scrapy[tox]==0.10.0`` in the
+    ``requires`` of :file:`tox.ini`.
+
+    This is backward-incompatible. To update:
+
+    -   Rename ``llms_txt_*`` settings to their ``llm_friendly_*``
+        counterparts, or drop them where the new defaults cover them, and drop
+        ``markdown_flavor``.
+
+    -   Remove ``"sphinx_llms_txt"`` from ``extensions``.
+
+    -   In ``app.add_node()`` calls, rename the ``markdown=`` and
+        ``singlemarkdown=`` handlers to ``llm_markdown=`` and
+        ``llm_singlemarkdown=``.
+
+    -   Replace ``exclude_patterns`` workarounds that check the builder name
+        with ``llm_friendly_exclude`` or
+        ``llm_friendly_llms_full_txt_exclude``.
+
+0.9.0 (2026-08-26)
+==================
+
+-   HTML pages now include an ``<link rel="alternate" type="text/markdown">``
+    tag pointing to their ``.md`` counterpart.
+
+0.8.13 (2026-08-25)
+===================
+
+-   ``llms-full.txt`` now includes a ``Source:`` line before each page's
+    content.
+
 0.8.12 (2026-08-14)
 ===================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.12/README.rst 
new/sphinx-scrapy-0.14.0/README.rst
--- old/sphinx-scrapy-0.8.12/README.rst 2026-08-14 14:28:50.000000000 +0200
+++ new/sphinx-scrapy-0.14.0/README.rst 2026-10-14 12:09:48.000000000 +0200
@@ -23,6 +23,19 @@
 
 -   Generates a `Read the Docs <https://readthedocs.org/>`_ configuration.
 
+-   Keeps the sphinx-scrapy pins of ``tox.ini`` and ``docs/requirements.in``
+    in sync with the pre-commit ``rev``.
+
+-   Makes documentation builds fail on Sphinx warnings. While you fix existing
+    warnings, you can either `suppress them by type
+    
<https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-suppress_warnings>`_
+    in ``docs/conf.py``, or allow all of them in ``pyproject.toml``:
+
+    .. code-block:: toml
+
+        [tool.sphinx-scrapy]
+        fail-on-warning = false
+
 -   Enables `commonly-used Sphinx extensions <#sphinx-extensions>`_.
 
 -   Configures `sphinx.ext.intersphinx`_ for `Python
@@ -71,12 +84,9 @@
 
 #.  Add to ``docs/requirements.txt``:
 
-    Install from Git, because this project currently depends on Git-based
-    packages and cannot be published to PyPI:
-
     .. code-block:: text
 
-        sphinx-scrapy @ git+https://github.com/scrapy/[email protected]
+        sphinx-scrapy==0.14.0
 
 #.  Add to ``docs/conf.py``:
 
@@ -126,7 +136,7 @@
 
         repos:
         - repo: https://github.com/scrapy/sphinx-scrapy
-            rev: 0.8.12
+            rev: 0.14.0
             hooks:
             - id: sphinx-scrapy
 
@@ -136,7 +146,7 @@
 
         [tox]
         requires =
-            sphinx-scrapy[tox] @ 
git+https://github.com/scrapy/[email protected]
+            sphinx-scrapy[tox]==0.14.0
         envlist = …,docs
 
     .. note:: ``docs`` in ``envlist`` is required.
@@ -165,7 +175,12 @@
 
 -   `sphinx_copybutton <https://sphinx-copybutton.readthedocs.io/en/latest/>`_
 
--   `sphinx_llms_txt <https://sphinx-llms-txt.readthedocs.io/en/latest/>`_
+-   `sphinx_design <https://sphinx-design.readthedocs.io/en/latest/>`_
+
+-   `sphinx-llm-friendly <https://github.com/scrapy/sphinx-llm-friendly>`_,
+    which documents the ``llm_friendly_*`` settings
+
+-   `sphinxcontrib.youtube <https://github.com/sphinx-contrib/youtube>`_
 
 .. _intersphinx-packages:
 
@@ -178,43 +193,45 @@
 | `attrs <https://www.attrs.org/en/stable/>`_
 | `coverage <https://coverage.readthedocs.io/en/latest>`_
 | `cryptography <https://cryptography.io/en/latest/>`_
-| `cssselect <https://cssselect.readthedocs.io/en/latest>`_
+| `cssselect <https://cssselect.readthedocs.io/en/stable/>`_
 | `curl-cffi <https://curl-cffi.readthedocs.io/en/latest/>`_
-| `dateparser <https://dateparser.readthedocs.io/en/latest/>`_
-| `form2request <https://form2request.readthedocs.io/en/latest/>`_
-| `formasaurus <https://formasaurus.readthedocs.io/en/latest/>`_
-| `itemloaders <https://itemloaders.readthedocs.io/en/latest/>`_
-| `jinja <https://jinja.palletsprojects.com/en/latest/>`_
+| `dateparser <https://dateparser.readthedocs.io/en/stable/>`_
+| `form2request <https://form2request.readthedocs.io/en/stable/>`_
+| `formasaurus <https://formasaurus.readthedocs.io/en/stable/>`_
+| `itemloaders <https://itemloaders.readthedocs.io/en/stable/>`_
+| `jinja <https://jinja.palletsprojects.com/en/stable/>`_
 | `lxml <https://lxml.de/apidoc/>`_
-| `multidict <https://multidict.aio-libs.org/en/latest/>`_
+| `multidict <https://multidict.aio-libs.org/en/stable/>`_
 | `niquests <https://niquests.readthedocs.io/en/latest/>`_
 | `packaging <https://packaging.pypa.io/en/stable/>`_
-| `parsel <https://parsel.readthedocs.io/en/latest/>`_
+| `parsel <https://parsel.readthedocs.io/en/stable/>`_
 | `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-scrapinghub <https://python-scrapinghub.readthedocs.io/en/stable/>`_
 | `python-zyte-api <https://python-zyte-api.readthedocs.io/en/stable/>`_
+| `requests <https://docs.python-requests.org/en/stable/>`_
 | `scrapy-poet <https://scrapy-poet.readthedocs.io/en/stable/>`_
-| `scrapy-spider-metadata 
<https://scrapy-spider-metadata.readthedocs.io/en/latest/>`_
-| `scrapy-zyte-api <https://scrapy-zyte-api.readthedocs.io/en/latest/>`_
+| `scrapy-spider-metadata 
<https://scrapy-spider-metadata.readthedocs.io/en/stable/>`_
+| `scrapy-zyte-api <https://scrapy-zyte-api.readthedocs.io/en/stable/>`_
 | `scrapy-zyte-smartproxy 
<https://scrapy-zyte-smartproxy.readthedocs.io/en/latest/>`_
-| `scrapyd <https://scrapyd.readthedocs.io/en/latest/>`_
-| `shub <https://shub.readthedocs.io/en/latest/>`_
-| `shub-image <https://shub-image.readthedocs.io/en/latest/>`_
+| `scrapyd <https://scrapyd.readthedocs.io/en/stable/>`_
+| `shub <https://shub.readthedocs.io/en/stable/>`_
+| `shub-image <https://shub-image.readthedocs.io/en/stable/>`_
 | `sphinx <https://www.sphinx-doc.org/en/master>`_
-| `spidermon <https://spidermon.readthedocs.io/en/latest/>`_
+| `spidermon <https://spidermon.readthedocs.io/en/stable/>`_
 | `tenacity <https://tenacity.readthedocs.io/en/latest>`_
 | `tox <https://tox.wiki/en/latest/>`_
 | `twisted <https://docs.twisted.org/en/stable/>`_ (and `twistedapi 
<https://docs.twisted.org/en/stable/api/>`_)
 | `url-matcher <https://url-matcher.readthedocs.io/en/stable/>`_
-| `w3lib <https://w3lib.readthedocs.io/en/latest/>`_
+| `w3lib <https://w3lib.readthedocs.io/en/stable/>`_
 | `web-poet <https://web-poet.readthedocs.io/en/stable/>`_
+| `websockets <https://websockets.readthedocs.io/en/stable/>`_
 | `zyte <https://docs.zyte.com>`_
-| `zyte-common-items <https://zyte-common-items.readthedocs.io/en/latest>`_
-| `zyte-parsers <https://zyte-parsers.readthedocs.io/en/latest/>`_
-| `zyte-spider-templates 
<https://zyte-spider-templates.readthedocs.io/en/latest>`_
+| `zyte-common-items <https://zyte-common-items.readthedocs.io/en/stable/>`_
+| `zyte-parsers <https://zyte-parsers.readthedocs.io/en/stable/>`_
+| `zyte-spider-templates 
<https://zyte-spider-templates.readthedocs.io/en/stable/>`_
 
 Release notes
 =============
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.12/pyproject.toml 
new/sphinx-scrapy-0.14.0/pyproject.toml
--- old/sphinx-scrapy-0.8.12/pyproject.toml     2026-08-14 14:28:50.000000000 
+0200
+++ new/sphinx-scrapy-0.14.0/pyproject.toml     2026-10-14 12:09:48.000000000 
+0200
@@ -4,16 +4,17 @@
 
 [project]
 name = "sphinx-scrapy"
-version = "0.8.12"
+version = "0.14.0"
 description = "Sphinx extension for documentation in the Scrapy ecosystem"
 dependencies = [
     "docutils",
     "packaging",
-    "sphinx",
+    "sphinx>=8.0.0",
     "sphinx-copybutton",
-    "sphinx-llms-txt @ 
git+https://github.com/zytedata/sphinx-llms-txt.git@5e8866cb0cc249aa2017ad9050b3b83a7ca16f69";,
-    "sphinx-markdown-builder @ 
git+https://github.com/zytedata/sphinx-markdown-builder.git@cfe4c0bfd7b4542f7e6b65a58cdf9ec765829940";,
+    "sphinx-design",
+    "sphinx-llm-friendly>=0.5.1",
     "sphinx-sitemap",
+    "sphinxcontrib-youtube",
     "tomli; python_version < '3.11'",
 ]
 classifiers = [
@@ -53,14 +54,11 @@
 [project.optional-dependencies]
 tox = ["tox>=4.29.0"]
 
-[tool.hatch.metadata]
-allow-direct-references = true
-
 [tool.mypy]
 strict = true
 
 [tool.bumpversion]
-current_version = "0.8.12"
+current_version = "0.14.0"
 commit = true
 tag = true
 tag_name = "{new_version}"
@@ -78,13 +76,13 @@
 
 [[tool.bumpversion.files]]
 filename = "README.rst"
-search = "sphinx-scrapy @ 
git+https://github.com/scrapy/sphinx-scrapy.git@{current_version}";
-replace = "sphinx-scrapy @ 
git+https://github.com/scrapy/sphinx-scrapy.git@{new_version}";
+search = "sphinx-scrapy=={current_version}"
+replace = "sphinx-scrapy=={new_version}"
 
 [[tool.bumpversion.files]]
 filename = "README.rst"
-search = "sphinx-scrapy[tox] @ 
git+https://github.com/scrapy/sphinx-scrapy.git@{current_version}";
-replace = "sphinx-scrapy[tox] @ 
git+https://github.com/scrapy/sphinx-scrapy.git@{new_version}";
+search = "sphinx-scrapy[tox]=={current_version}"
+replace = "sphinx-scrapy[tox]=={new_version}"
 
 [tool.ruff.lint]
 extend-select = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.12/sphinx_scrapy/__init__.py 
new/sphinx-scrapy-0.14.0/sphinx_scrapy/__init__.py
--- old/sphinx-scrapy-0.8.12/sphinx_scrapy/__init__.py  2026-08-14 
14:28:50.000000000 +0200
+++ new/sphinx-scrapy-0.14.0/sphinx_scrapy/__init__.py  2026-10-14 
12:09:48.000000000 +0200
@@ -16,6 +16,7 @@
 
     from sphinx.application import Sphinx
     from sphinx.config import Config
+    from sphinx.util.typing import ExtensionMetadata
 
     from .config import ProjectConfig
 
@@ -26,57 +27,59 @@
     "attrs": ("https://www.attrs.org/en/stable/";, None),
     "coverage": ("https://coverage.readthedocs.io/en/latest/";, None),
     "cryptography": ("https://cryptography.io/en/latest/";, None),
-    "cssselect": ("https://cssselect.readthedocs.io/en/latest/";, None),
+    "cssselect": ("https://cssselect.readthedocs.io/en/stable/";, None),
     "curl-cffi": ("https://curl-cffi.readthedocs.io/en/latest/";, None),
-    "dateparser": ("https://dateparser.readthedocs.io/en/latest/";, None),
-    "form2request": ("https://form2request.readthedocs.io/en/latest/";, None),
-    "formasaurus": ("https://formasaurus.readthedocs.io/en/latest/";, None),
-    "itemloaders": ("https://itemloaders.readthedocs.io/en/latest/";, None),
-    "jinja": ("https://jinja.palletsprojects.com/en/latest/";, None),
+    "dateparser": ("https://dateparser.readthedocs.io/en/stable/";, None),
+    "form2request": ("https://form2request.readthedocs.io/en/stable/";, None),
+    "formasaurus": ("https://formasaurus.readthedocs.io/en/stable/";, None),
+    "itemloaders": ("https://itemloaders.readthedocs.io/en/stable/";, None),
+    "jinja": ("https://jinja.palletsprojects.com/en/stable/";, None),
     "lxml": ("https://lxml.de/apidoc/";, None),
-    "multidict": ("https://multidict.aio-libs.org/en/latest/";, None),
+    "multidict": ("https://multidict.aio-libs.org/en/stable/";, None),
     "niquests": ("https://niquests.readthedocs.io/en/latest/";, None),
     "packaging": ("https://packaging.pypa.io/en/stable/";, None),
-    "parsel": ("https://parsel.readthedocs.io/en/latest/";, None),
+    "parsel": ("https://parsel.readthedocs.io/en/stable/";, 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": (
-        "https://python-scrapinghub.readthedocs.io/en/latest/";,
+        "https://python-scrapinghub.readthedocs.io/en/stable/";,
         None,
     ),
     "python-zyte-api": ("https://python-zyte-api.readthedocs.io/en/stable/";, 
None),
+    "requests": ("https://docs.python-requests.org/en/stable/";, None),
     "scrapy": ("https://docs.scrapy.org/en/latest/";, None),
-    "scrapy-lint": ("https://scrapy-lint.readthedocs.io/en/latest/";, None),
+    "scrapy-lint": ("https://scrapy-lint.readthedocs.io/en/stable/";, None),
     "scrapy-poet": ("https://scrapy-poet.readthedocs.io/en/stable/";, None),
     "scrapy-spider-metadata": (
-        "https://scrapy-spider-metadata.readthedocs.io/en/latest/";,
+        "https://scrapy-spider-metadata.readthedocs.io/en/stable/";,
         None,
     ),
-    "scrapy-zyte-api": ("https://scrapy-zyte-api.readthedocs.io/en/latest/";, 
None),
+    "scrapy-zyte-api": ("https://scrapy-zyte-api.readthedocs.io/en/stable/";, 
None),
     "scrapy-zyte-smartproxy": (
         "https://scrapy-zyte-smartproxy.readthedocs.io/en/latest/";,
         None,
     ),
-    "scrapyd": ("https://scrapyd.readthedocs.io/en/latest/";, None),
-    "shub": ("https://shub.readthedocs.io/en/latest/";, None),
-    "shub-image": ("https://shub-image.readthedocs.io/en/latest/";, None),
+    "scrapyd": ("https://scrapyd.readthedocs.io/en/stable/";, None),
+    "shub": ("https://shub.readthedocs.io/en/stable/";, None),
+    "shub-image": ("https://shub-image.readthedocs.io/en/stable/";, None),
     "sphinx": ("https://www.sphinx-doc.org/en/master/";, None),
-    "spidermon": ("https://spidermon.readthedocs.io/en/latest/";, None),
+    "spidermon": ("https://spidermon.readthedocs.io/en/stable/";, None),
     "tenacity": ("https://tenacity.readthedocs.io/en/latest/";, None),
     "tox": ("https://tox.wiki/en/latest/";, None),
     "twisted": ("https://docs.twisted.org/en/stable/";, None),
     "twistedapi": ("https://docs.twisted.org/en/stable/api/";, None),
-    "url-matcher": ("https://url-matcher.readthedocs.io/en/latest/";, None),
-    "w3lib": ("https://w3lib.readthedocs.io/en/latest/";, None),
+    "url-matcher": ("https://url-matcher.readthedocs.io/en/stable/";, None),
+    "w3lib": ("https://w3lib.readthedocs.io/en/stable/";, None),
     "web-poet": ("https://web-poet.readthedocs.io/en/stable/";, None),
+    "websockets": ("https://websockets.readthedocs.io/en/stable/";, None),
     "zyte": ("https://docs.zyte.com/";, None),
-    "zyte-common-items": 
("https://zyte-common-items.readthedocs.io/en/latest/";, None),
-    "zyte-parsers": ("https://zyte-parsers.readthedocs.io/en/latest/";, None),
+    "zyte-common-items": 
("https://zyte-common-items.readthedocs.io/en/stable/";, None),
+    "zyte-parsers": ("https://zyte-parsers.readthedocs.io/en/stable/";, None),
     "zyte-spider-templates": (
-        "https://zyte-spider-templates.readthedocs.io/en/latest/";,
+        "https://zyte-spider-templates.readthedocs.io/en/stable/";,
         None,
     ),
 }
@@ -146,148 +149,7 @@
 )
 
 
-COPY_AS_MARKDOWN_BUTTON_JS = """
-(function () {
-    var DEFAULT_LABEL = 'M\u2193';
-    var SUCCESS_LABEL = 'Copied';
-    var ERROR_LABEL = 'Error';
-
-    function markdownPathFromCurrentPage(pathname) {
-        if (pathname.endsWith('.html')) {
-            return pathname.slice(0, -5) + '.md';
-        }
-        if (pathname.endsWith('/')) {
-            return pathname + 'index.md';
-        }
-        var lastPart = pathname.split('/').pop() || '';
-        if (!lastPart.includes('.')) {
-            return pathname + '.md';
-        }
-        return pathname + '.md';
-    }
-
-    async function copyToClipboard(text) {
-        if (navigator.clipboard && window.isSecureContext) {
-            await navigator.clipboard.writeText(text);
-            return;
-        }
-        var textarea = document.createElement('textarea');
-        textarea.value = text;
-        textarea.setAttribute('readonly', 'readonly');
-        textarea.style.position = 'fixed';
-        textarea.style.left = '-9999px';
-        document.body.appendChild(textarea);
-        textarea.select();
-        document.execCommand('copy');
-        document.body.removeChild(textarea);
-    }
-
-    function setTemporaryLabel(button, label, previousLabel) {
-        var prev = typeof previousLabel !== 'undefined' ? previousLabel : 
button.textContent;
-        button.textContent = label;
-        window.setTimeout(function () {
-            button.textContent = prev;
-            button.disabled = false;
-        }, 1000);
-    }
-
-    async function onButtonClick(button) {
-        var previousLabel = button.textContent;
-        button.disabled = true;
-        button.textContent = '...';
-        try {
-            var mdPath = markdownPathFromCurrentPage(window.location.pathname);
-            var response = await fetch(mdPath, { credentials: 'same-origin' });
-            if (!response.ok) {
-                throw new Error('Unable to fetch markdown source');
-            }
-            var markdown = await response.text();
-            await copyToClipboard(markdown);
-            setTemporaryLabel(button, SUCCESS_LABEL, previousLabel);
-        } catch (_error) {
-            setTemporaryLabel(button, ERROR_LABEL, previousLabel);
-        }
-    }
-
-    function addStyles() {
-        var style = document.createElement('style');
-        style.textContent = [
-            '.scrapy-copy-as-markdown {',
-            '  display: inline-block;',
-            '  margin-left: 0.25rem;',
-            '  border: 1px solid #c9d4de;',
-            '  border-radius: 0.45rem;',
-            '  background: #ffffff;',
-            '  color: #233a50;',
-            '  font: inherit;',
-            '  font-size: 0.875rem;',
-            '  line-height: 1;',
-            '  padding: 0.25rem 0.25rem;',
-            '  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);',
-            '  cursor: pointer;',
-            '}',
-            '.scrapy-copy-as-markdown:hover {',
-            '  background: #f3f7fb;',
-            '}',
-            '.scrapy-copy-as-markdown:disabled {',
-            '  opacity: 0.75;',
-            '  cursor: default;',
-            '}',
-            '.scrapy-copy-as-markdown-title-wrapper {',
-            '  display: flex;',
-            '  align-items: center;',
-            '  justify-content: space-between;',
-            '  gap: 1rem;',
-            '  width: 100%;',
-            '}',
-            '.scrapy-copy-as-markdown-title-wrapper h1 {',
-            '  margin: 0;',
-            '}',
-        ].join('\\n');
-        document.head.appendChild(style);
-    }
-
-    function addButton() {
-        if (!document.body || 
document.querySelector('.scrapy-copy-as-markdown')) {
-            return;
-        }
-
-        addStyles();
-        var button = document.createElement('button');
-        button.type = 'button';
-        button.className = 'scrapy-copy-as-markdown';
-        button.title = 'Copy this page as Markdown';
-        button.setAttribute('aria-label', 'Copy this page as Markdown');
-        button.textContent = DEFAULT_LABEL;
-        button.addEventListener('click', function () {
-            onButtonClick(button);
-        });
-
-        var h1 = document.querySelector('#main h1') || 
document.querySelector('h1');
-        if (h1 && h1.parentNode) {
-            var parent = h1.parentNode;
-            var wrapper = document.createElement('div');
-            wrapper.className = 'scrapy-copy-as-markdown-title-wrapper';
-            parent.replaceChild(wrapper, h1);
-            wrapper.appendChild(h1);
-            wrapper.appendChild(button);
-        } else {
-            // fallback: insert at top of body but keep within the first 
container
-            var container = document.body.firstElementChild || document.body;
-            container.insertBefore(button, container.firstChild);
-        }
-    }
-
-    if (document.readyState === 'loading') {
-        document.addEventListener('DOMContentLoaded', addButton);
-    } else {
-        addButton();
-    }
-})();
-"""
-
-
-def setup(app: Sphinx) -> None:
+def setup(app: Sphinx) -> ExtensionMetadata:
     app.add_config_value(
         "scrapy_intersphinx_enable", [], "env", types=frozenset({list})
     )
@@ -303,14 +165,15 @@
         "sphinx.ext.intersphinx",
         "sphinx.ext.viewcode",
         "sphinx_copybutton",
-        "sphinx_llms_txt",
+        "sphinx_design",
+        "sphinx_llm_friendly",
         "sphinx_sitemap",
+        "sphinxcontrib.youtube",
     ):
         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)
 
@@ -322,11 +185,7 @@
             indextemplate=f"pair: %s; {crossref_type}",
         )
 
-
-def add_copy_as_markdown_button(app: Sphinx) -> None:
-    if app.builder.format != "html":
-        return
-    app.add_js_file(None, body=COPY_AS_MARKDOWN_BUTTON_JS)
+    return {"parallel_read_safe": True}
 
 
 class _GitHubRole(SphinxRole):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.12/sphinx_scrapy/cli.py 
new/sphinx-scrapy-0.14.0/sphinx_scrapy/cli.py
--- old/sphinx-scrapy-0.8.12/sphinx_scrapy/cli.py       2026-08-14 
14:28:50.000000000 +0200
+++ new/sphinx-scrapy-0.14.0/sphinx_scrapy/cli.py       2026-10-14 
12:09:48.000000000 +0200
@@ -1,324 +1,37 @@
 from __future__ import annotations
 
 import argparse
-import concurrent.futures
 import re
-import shutil
 import sys
-from http import HTTPStatus
-from typing import TYPE_CHECKING
-from urllib.error import HTTPError, URLError
-from urllib.parse import urlsplit, urlunsplit
-from urllib.request import Request, urlopen
+from importlib.metadata import version
+from pathlib import Path
 
 from packaging.version import InvalidVersion, Version
-from sphinx.cmd.build import main as sphinx_build_main
+from sphinx.cmd.build import main as sphinx_build
 
-from . import INTERSPHINX_MAPPING
-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
-
-
-URL_PATTERN = re.compile(r"https?://[^\s<>()\[\]{}\"']+")
-MARKDOWN_LINK_PATTERN = re.compile(
-    r"(?P<prefix>!?\[[^\]]*\]\()"
-    r"(?P<target>[^)\s]+)"
-    r"(?P<title>\s+\"[^\"]*\")?"
-    r"(?P<suffix>\))"
-)
-
-
-def _intersphinx_base_urls() -> tuple[str, ...]:
-    bases = {url for url, _inventory in INTERSPHINX_MAPPING.values()}
-    return tuple(sorted(bases, key=len, reverse=True))
-
-
-def _project_docs_base_url(project_id: str | None) -> str | None:
-    if not project_id:
-        return None
-    normalized_project_id = normalize_project_id(project_id)
-    if not normalized_project_id:
-        return None
-    if normalized_project_id in INTERSPHINX_MAPPING:
-        return INTERSPHINX_MAPPING[normalized_project_id][0]
-    return f"https://{normalized_project_id}.readthedocs.io/en/latest/";
-
-
-def _split_wrapped_markdown_target(target: str) -> tuple[str, str, str]:
-    if target.startswith("<") and target.endswith(">"):
-        return "<", target[1:-1], ">"
-    return "", target, ""
-
-
-def _rewrite_markdown_links(
-    content: str,
-    rewrite_target: Callable[[str], str],
-) -> str:
-    in_fence = False
-    fence_char = ""
-    rewritten_lines: list[str] = []
-
-    def replacement(match: re.Match[str]) -> str:
-        target = match.group("target")
-        rewritten_target = rewrite_target(target)
-        if rewritten_target == target:
-            return match.group(0)
-
-        title = match.group("title") or ""
-        return (
-            
f"{match.group('prefix')}{rewritten_target}{title}{match.group('suffix')}"
-        )
-
-    for line in content.splitlines(keepends=True):
-        stripped = line.lstrip()
-        if stripped.startswith(("```", "~~~")):
-            marker = stripped[0]
-            if not in_fence:
-                in_fence = True
-                fence_char = marker
-            elif marker == fence_char:
-                in_fence = False
-                fence_char = ""
-            rewritten_lines.append(line)
-            continue
-
-        if in_fence:
-            rewritten_lines.append(line)
-            continue
-
-        rewritten_lines.append(MARKDOWN_LINK_PATTERN.sub(replacement, line))
-
-    return "".join(rewritten_lines)
-
-
-def _rewrite_llms_link_target(
-    target: str,
-    docs_host: str,
-    docs_path_prefix: str,
-) -> str:
-    wrapper_prefix, wrapped_target, wrapper_suffix = 
_split_wrapped_markdown_target(
-        target
-    )
-    parts = urlsplit(wrapped_target)
-
-    if parts.scheme or parts.netloc:
-        if parts.scheme not in {"http", "https"}:
-            return target
-        if parts.netloc.lower() != docs_host:
-            return target
-
-    if not parts.path.endswith(".md"):
-        return target
-
-    clean_path = parts.path.lstrip("/")
-    while clean_path.startswith("./"):
-        clean_path = clean_path[2:]
-    if clean_path.startswith("../"):
-        return target
-
-    if docs_path_prefix and not clean_path.startswith(docs_path_prefix):
-        clean_path = f"{docs_path_prefix}{clean_path}"
-
-    rewritten_target = urlunsplit(("", "", clean_path, parts.query, 
parts.fragment))
-    return f"{wrapper_prefix}{rewritten_target}{wrapper_suffix}"
-
-
-def _rewrite_llms_links_to_docs_path(
-    output_dir: Path,
-    docs_base_url: str | None,
-) -> None:
-    llms_path = output_dir / "llms.txt"
-    if docs_base_url is None or not llms_path.is_file():
-        return
-
-    docs_parts = urlsplit(docs_base_url)
-    docs_host = docs_parts.netloc.lower()
-    docs_path = docs_parts.path.strip("/")
-    docs_path_prefix = f"{docs_path}/" if docs_path else ""
-
-    content = llms_path.read_text(encoding="utf-8")
-    rewritten = _rewrite_markdown_links(
-        content,
-        lambda target: _rewrite_llms_link_target(target, docs_host, 
docs_path_prefix),
-    )
-    if rewritten != content:
-        llms_path.write_text(rewritten, encoding="utf-8")
-
-
-def _iter_markdown_outputs(output_dir: Path) -> list[Path]:
-    files = sorted(output_dir.rglob("*.md"))
-    for filename in ("llms.txt", "llms-full.txt"):
-        path = output_dir / filename
-        if path.is_file():
-            files.append(path)
-    return files
-
-
-def _matching_base_url(url: str, base_urls: tuple[str, ...]) -> str | None:
-    for base_url in base_urls:
-        if url.startswith(base_url):
-            return base_url
-    return None
-
-
-def _supports_markdown(base_url: str) -> bool:
-    probe_url = f"{base_url.rstrip('/')}/index.md"
-    headers = {"User-Agent": "sphinx-scrapy"}
-    for method in ("HEAD", "GET"):
-        request = Request(probe_url, headers=headers, method=method)  # noqa: 
S310
-        try:
-            with urlopen(request, timeout=5) as response:  # noqa: S310
-                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,
-                HTTPStatus.NOT_IMPLEMENTED,
-            }:
-                continue
-            return False
-        except URLError:
-            return False
-    return False
-
-
-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
-
-    parts = urlsplit(url)
-    path = parts.path
-    if not path.endswith(".html"):
-        return url
-    new_path = f"{path[:-5]}.md"
-
-    return urlunsplit(
-        (parts.scheme, parts.netloc, new_path, parts.query, parts.fragment)
-    )
-
-
-def _rewrite_intersphinx_links_to_markdown(output_dir: Path) -> None:
-    target_files = _iter_markdown_outputs(output_dir)
-    if not target_files:
-        return
-
-    base_urls = _intersphinx_base_urls()
-    file_contents: dict[Path, str] = {}
-    candidate_base_urls: set[str] = set()
-
-    for file in target_files:
-        content = file.read_text(encoding="utf-8")
-        file_contents[file] = content
-        for match in URL_PATTERN.finditer(content):
-            url = match.group(0)
-            if ".html" not in url:
-                continue
-            base_url = _matching_base_url(url, base_urls)
-            if base_url is not None:
-                candidate_base_urls.add(base_url)
-
-    if not candidate_base_urls:
-        return
-
-    with concurrent.futures.ThreadPoolExecutor(
-        max_workers=min(8, len(candidate_base_urls))
-    ) as executor:
-        availability = {
-            base_url: executor.submit(_supports_markdown, base_url)
-            for base_url in candidate_base_urls
-        }
-        enabled_base_urls = {
-            base_url for base_url, future in availability.items() if 
future.result()
-        }
-
-    if not enabled_base_urls:
-        return
-
-    for file, content in file_contents.items():
-        rewritten = URL_PATTERN.sub(
-            lambda match: _rewrite_url_to_markdown(
-                match.group(0),
-                enabled_base_urls,
-                base_urls,
-            ),
-            content,
-        )
-        if rewritten != content:
-            file.write_text(rewritten, encoding="utf-8")
+from .config import LATEST_RTD_PYTHON_VERSION, load_project_config
 
 
-def _builder_settings(builder: str) -> list[str]:
-    if builder == "html":
-        return ["-D", "llms_txt_uri_template={docname}.md"]
-    if builder == "singlemarkdown":
-        return [
-            "-D",
-            "llms_txt_uri_template={docname}.md",
-            "-D",
-            "singlemarkdown_flavor=llm",
-        ]
-    return []
-
-
-def _run_builder(builder: str, source_dir: Path, build_dir: Path) -> None:
-    args = [
-        "-b",
-        builder,
-        *_builder_settings(builder),
-        str(source_dir),
-        str(build_dir / builder),
-    ]
-    exit_code = sphinx_build_main(args)
-    if exit_code != 0:
-        msg = f"sphinx builder failed for '{builder}' with exit code 
{exit_code}"
-        raise RuntimeError(msg)
-
-
-def build_docs() -> int:
+def build_docs(output_dir: Path | None) -> int:
     config = load_project_config()
-    docs_base_url = _project_docs_base_url(config.project_id)
     docs_dir = config.root / "docs"
     if not docs_dir.is_dir():
         print("docs directory not found", file=sys.stderr)
         return 1
-
-    sphinx_build_dir = docs_dir / "_build"
-    sphinx_build_dir.mkdir(parents=True, exist_ok=True)
-
-    builders = ["html", "markdown", "singlemarkdown"]
-
-    with concurrent.futures.ProcessPoolExecutor(max_workers=len(builders)) as 
executor:
-        futures = [
-            executor.submit(
-                _run_builder,
-                builder,
-                docs_dir,
-                sphinx_build_dir,
-            )
-            for builder in builders
-        ]
-        for future in concurrent.futures.as_completed(futures):
-            future.result()
-
-    all_dir = sphinx_build_dir / "all"
-    all_dir.mkdir(parents=True, exist_ok=True)
-
-    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"
-    )
-    _rewrite_intersphinx_links_to_markdown(all_dir)
-    _rewrite_llms_links_to_docs_path(all_dir, docs_base_url)
-
-    print("\nDocumentation generated in docs/_build/all.")
-    return 0
+    build_dir = docs_dir / "_build"
+    args = [
+        "-b",
+        "html",
+        "-d",
+        str(build_dir / "doctrees"),
+        "-j",
+        "auto",
+        str(docs_dir),
+        str(output_dir or build_dir / "html"),
+    ]
+    if config.fail_on_warning:
+        args += ["-W", "--keep-going"]
+    return sphinx_build(args)
 
 
 def update_rtd_config() -> int:
@@ -353,22 +66,39 @@
                 f'    python: "{config.python_version}"',
                 "  commands:",
                 "    - pip install tox",
-                "    - tox -e docs",
-                "    - mkdir -p $READTHEDOCS_OUTPUT/html",
-                "    - cp -a docs/_build/all/. $READTHEDOCS_OUTPUT/html/",
+                "    - tox -e docs -- $READTHEDOCS_OUTPUT/html",
                 "",
             ]
         ),
         encoding="utf-8",
     )
     print("Updated .readthedocs.yml")
+
+    pin = rf"\g<1>=={version('sphinx-scrapy')}"
+    for path in ("tox.ini", "docs/requirements.in"):
+        file = config.root / path
+        if not file.is_file():
+            continue
+        text = file.read_text(encoding="utf-8")
+        new_text = re.sub(
+            r"(sphinx-scrapy(?:\[tox\])?)(?:==\S+|\s*@\s*git\+\S+)", pin, text
+        )
+        if new_text != text:
+            file.write_text(new_text, encoding="utf-8")
+            print(f"Updated {path}")
+            if path == "docs/requirements.in":
+                print(
+                    "Run `uv pip compile requirements.in -o requirements.txt` "
+                    "from docs/"
+                )
     return 0
 
 
 def build_parser() -> argparse.ArgumentParser:
     parser = argparse.ArgumentParser(prog="sphinx-scrapy")
     subparsers = parser.add_subparsers(dest="command", required=True)
-    subparsers.add_parser("build")
+    build_parser = subparsers.add_parser("build")
+    build_parser.add_argument("output_dir", nargs="?", type=Path)
     subparsers.add_parser("update-rtd-config")
     return parser
 
@@ -377,7 +107,7 @@
     parser = build_parser()
     args = parser.parse_args(argv)
     if args.command == "build":
-        return build_docs()
+        return build_docs(args.output_dir)
     if args.command == "update-rtd-config":
         return update_rtd_config()
     parser.error(f"Unknown command: {args.command}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.12/sphinx_scrapy/config.py 
new/sphinx-scrapy-0.14.0/sphinx_scrapy/config.py
--- old/sphinx-scrapy-0.8.12/sphinx_scrapy/config.py    2026-08-14 
14:28:50.000000000 +0200
+++ new/sphinx-scrapy-0.14.0/sphinx_scrapy/config.py    2026-10-14 
12:09:48.000000000 +0200
@@ -25,6 +25,7 @@
     extras: set[str] = field(default_factory=set)
     project_id: str | None = None
     github_repo: str | None = None
+    fail_on_warning: bool = True
 
 
 def find_project_root(start: Path | None = None) -> Path:
@@ -78,6 +79,7 @@
     tool_data = pyproject_data.get("tool", {})
     scrapy_data = tool_data.get("sphinx-scrapy", {})
     python_version = scrapy_data.get("python-version", 
LATEST_RTD_PYTHON_VERSION)
+    fail_on_warning = bool(scrapy_data.get("fail-on-warning", True))
     extras = get_extras(pyproject_data)
     raw_project_id = pyproject_data.get("project", {}).get("name")
     project_id = None
@@ -91,4 +93,5 @@
         extras=extras,
         project_id=project_id,
         github_repo=_get_github_repo(pyproject_data),
+        fail_on_warning=fail_on_warning,
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sphinx-scrapy-0.8.12/sphinx_scrapy/tox_plugin.py 
new/sphinx-scrapy-0.14.0/sphinx_scrapy/tox_plugin.py
--- old/sphinx-scrapy-0.8.12/sphinx_scrapy/tox_plugin.py        2026-08-14 
14:28:50.000000000 +0200
+++ new/sphinx-scrapy-0.14.0/sphinx_scrapy/tox_plugin.py        2026-10-14 
12:09:48.000000000 +0200
@@ -3,6 +3,7 @@
 from typing import TYPE_CHECKING
 
 from tox.config.loader.memory import MemoryLoader
+from tox.config.types import Command
 from tox.plugin import impl
 
 from .config import LATEST_RTD_PYTHON_VERSION, load_project_config
@@ -34,6 +35,8 @@
             ],
             deps=["-rdocs/requirements.txt"],
             extras=tuple(project_config.extras),
-            commands=["sphinx-scrapy build"],
+            commands=[
+                Command(["sphinx-scrapy", "build", *(state.conf.pos_args(None) 
or ())])
+            ],
         )
     )

Reply via email to