sphinx-reredirects-0.1.2/000077500000000000000000000000001443135300400153315ustar00rootroot00000000000000sphinx-reredirects-0.1.2/.gitignore000066400000000000000000000003061443135300400173200ustar00rootroot00000000000000# Python venv/ __pycache__ dist *.egg-info build .eggs .tox # IDEs .idea/ !.idea/runConfigurations .vscode/ # Where GitLab Pages expects website public/ # Sphinx .doctrees _build # Mac .DS_Storesphinx-reredirects-0.1.2/.gitlab-ci.yml000066400000000000000000000006231443135300400177660ustar00rootroot00000000000000image: python:3.9 variables: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" cache: paths: - .cache/pip - venv - .tox before_script: - python3 --version - python3 -m pip install tox test: stage: test script: - tox docs: stage: test script: - tox -e docs pages: only: - master stage: deploy script: - tox -e docs artifacts: paths: - public sphinx-reredirects-0.1.2/LICENSE000066400000000000000000000027441443135300400163450ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2020, documatt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. sphinx-reredirects-0.1.2/README.rst000066400000000000000000000033171443135300400170240ustar00rootroot00000000000000################## sphinx-reredirects ################## .. image:: https://img.icons8.com/wired/64/undefined/forward-arrow--v1.png :align: right .. image:: https://gitlab.com/documatt/sphinx-reredirects/badges/master/pipeline.svg :target: https://gitlab.com/documatt/sphinx-reredirects/-/commits/master .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black .. image:: https://img.shields.io/pypi/v/sphinx-reredirects :target: https://pypi.org/project/sphinx-reredirects/ sphinx-reredirects is the extension for `Sphinx documentation `_ projects that handles redirects for moved pages. It generates HTML pages with meta refresh redirects to the new page location to prevent 404 errors if you rename or move your documents. * docs: https://documatt.gitlab.io/sphinx-reredirects * code: https://gitlab.com/documatt/sphinx-reredirects where issues and contributions are welcome Good URLs are never changing URLs. But if you must, sphinx-reredirects helps you manage redirects with ease and from the single place in project's ``conf.py``. For example, if you rename document ``start`` to ``intro``, and tell it to sphinx-reredirects, it will generate HTML page ``start.html`` with ````. The extension supports wildcards and moving to different domain too. ***** About ***** sphinx-reredirects started from the urge to manage redirects for all documents during moving our *Tech writer at work blog* to the new domain https://documatt.com/blog/. ***** Legal ***** Forward Arrow icon by `Icons8 `_. sphinx-reredirects is licensed under BSD3. sphinx-reredirects-0.1.2/docs/000077500000000000000000000000001443135300400162615ustar00rootroot00000000000000sphinx-reredirects-0.1.2/docs/Makefile000066400000000000000000000011721443135300400177220ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) sphinx-reredirects-0.1.2/docs/conf.py000066400000000000000000000042101443135300400175550ustar00rootroot00000000000000# Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) from datetime import date # -- Project information ----------------------------------------------------- project = 'sphinx-reredirects' copyright = f'{date.today().year}, Documatt' author = 'Matt' # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] rst_epilog = f''' .. |project| replace:: {project} ''' highlight_language = 'none' # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_logo = 'logo.png' html_theme = 'sphinx_documatt_theme' html_theme_options = { 'motto': f'{project} is the extension for Sphinx documentation projects that handles redirects for moved pages. It generates HTML pages with meta refresh redirects to the new page location to prevent 404 errors if you rename or move your documents.', 'header_text': project, 'header_logo_style': 'height: 3em', 'footer_logo_style': 'height: 3em', }sphinx-reredirects-0.1.2/docs/faq.rst000066400000000000000000000026651443135300400175730ustar00rootroot00000000000000FAQ #### Aren't 301 redirects better? **************************** Client-side redirects with meta refresh are okay for search engines, even the most ancient browsers, and users too. |project| extension was created for tech writers who don't want or can't manage redirects with server-side 301 redirects. Generally, SEO consultants recommend server-side redirects created with ``.htaccess`` and similar files. However, many documentation is hosted as on static website hosting which doesn't support server-side redirects. I know better how to write HTML redirect file ********************************************* By default, created HTML redirect files contains ````. If you want JavaScript redirection instead, wait longer, or whatever, set ``redirect_html_template`` option. This option should points to file inside source dir (directory containing ``conf.py``). For example:: redirect_html_template_file = "redirect.html.template" Actual target URI requested in configuration is available under ``${to_uri}`` placeholder. Why name "reredirects"? *********************** Because the name "redirects" is already taken by `another `_ extension. Unfortunately, it doesn't fulfil our requirements (the most notable it doesn't support wildcards and placeholders). These were reasons why we decided to bring a new extension. sphinx-reredirects-0.1.2/docs/index.rst000066400000000000000000000001461443135300400201230ustar00rootroot00000000000000.. include:: ../README.rst .. toctree:: :maxdepth: 2 :hidden: install usage faq rnsphinx-reredirects-0.1.2/docs/install.rst000066400000000000000000000003631443135300400204630ustar00rootroot00000000000000Install and setup ################# Perform:: pip3 install sphinx-reredirects Then, open your ``conf.py`` and append ``sphinx_reredirects`` to the ``extensions`` list:: extensions = [ ... 'sphinx_reredirects' ] sphinx-reredirects-0.1.2/docs/logo.png000066400000000000000000000022211443135300400177240ustar00rootroot00000000000000PNG  IHDR@@iqbKGDFIDATxMEh,MrQC Qa6^Z`0H~s(W_ y$.ތNw%&9ދضY\&8v?{^' x =ٸ.hC%"L ~ѽ>;se7i| Ka .)M,aB&,ZIr&Qfe)ܾVWT3 r#x^3xEd"`W<NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd sphinx-reredirects-0.1.2/docs/rn.rst000066400000000000000000000025041443135300400174330ustar00rootroot00000000000000Release notes ############# 0.1.2 (2023-05-18) ****************** - be explicit about parallel reads (by `Feanil Patel `__) - docs: fix URL in README (by `Angus Hollands `__ `T `__) - docs: fix name of redirect template option (by `Angus Hollands `__ `T `__) 0.1.1 (2022-06-04) ****************** - add more tests - add tox.ini - bugfix failure for non-HTML-based Sphinx builders (by Lynn Root `W `__ `T `__) - use suffix for redirect HTML file from html_file_suffix config parameter (by Robbert Schreuder Hes `W `__) - add type hints (by Daniël van Noord `W `__) - improve docs with comment that redirects are relative (by Daniël van Noord `W `__) - include LICENCE in sdist 0.0.1 (2021-04-26) ****************** (In Git tagged as v0.1.0.) - bugfix wildcard/non-wildcard implementation and code clean-up - migrate README to Sphinx docs - rewrite Usage article in docs 0.0.0 (2020-09-09) ****************** Initial release.sphinx-reredirects-0.1.2/docs/usage.rst000066400000000000000000000116371443135300400201270ustar00rootroot00000000000000Usage ##### The extension relies on the ``redirects`` configuration option in ``conf.py``. ``redirects`` option maps a *source* to a *target*. .. highlight:: python3 :: redirects = { "": "" } By default, ``redirects`` is empty (i.e. generates no redirect files). *Source* (the key in ``redirects`` map) is a *docname*, i.e. document path without a suffix (an extension). Most Sphinx projects use ``.rst`` as extension. For example, a docname for the file ``index.rst`` is ``index``, for ``agents/intro.rst`` is ``agents/intro``, etc. Source may be non-existing document or existing document. If source does not exist, |project| creates new redirect .html file. For existing document, document's .html file will be overwritten with redirect file. To select multiple existing documents, a `source wildcards `_ can be used. *Target* (the value in ``redirects`` map) is an URL that will be used in the HTML redirecting file. It may be specified using the placeholder to reuse source docname (see `Target placeholders`_). Target value must correspond to the output file naming of chosen Sphinx builder. For example, html builder creates ``docname.html``, while dirhtml ``docname/index.html``. .. important:: The extension works only for HTML-based builders like html and dirhtml. When building to other outputs (linkcheck, latex), it does nothing. The redirect is relative to the current page. So, if you want to redirect ``guides/index.html`` to ``index.html`` use: .. highlight:: python3 :: redirects = { "guides/index": "../index.html" } Redirect old documents ********************** The basic usage is to redirect document you delete or rename to a new file within the same project. For example, if you rename ``setup.rst`` to ``install.rst``:: redirects = { "setup": "install.html", } Newly created ``setup.html`` will contain ````. Or, if you output to dirhtml, target must be a folder:: redirects = { "setup": "install/", } .. rubric:: Absolute URLs The target maybe any value. For example, if particular page is now on the different website:: redirects = { "install/requirements": "https://anotherwebsite.com/docs/requirements.html", } It will create ``install`` folder (if it does not exist) and ``requirements.html`` containing ````. Redirect existing documents *************************** Source (the key in the ``redirects`` option) may be specified with wildcards. If wildcard is used, it means that you want to expand it against existing documents. |project| creates redirect .html file that will overwrite original document's html file. For example, if all FAQ documents in ``faq/`` folder should be redirected to dedicated forum website, but you don't want to delete them in your documentation:: redirects = { "faq/*": "https://website.com/forum/faq", } Now, html files originally produced by documents in ``faq/`` like ``supported-os.html``, ``licencing.html``, etc., are all replaced with body ```` Wildcard syntax =============== Wildcards for selecting existing source documents know only ``*``, ``?``, ``[seq]`` and ``[!seq]`` patterns. * ``*`` matches everything, while ``?`` any single character. * ``[seq]`` matches any character in the seq, ``[!seq]`` any character not in seq. (If you are curious, matching is using Python3 `fnmatch() `_.) .. important:: In other words, for example ``**`` used as "recursive" has no meaning here. Target placeholders ******************* Matched document in the source, is available in the target as ``$source`` or ``${source}`` placeholder. Because source notation (a docname) is without suffix, you may need to append ``.html`` or ``/`` suffix after the placeholder. For example, if all FAQ documents in ``faq/`` folder should be redirected to dedicated forum website with the identical filenames in URL, but you don't want to delete them in your documentation:: redirects = { "faq/*": "https://website.com/forum/faq/$source", } Now, html files originally produced by documents in ``faq/`` like ``supported-os.html``, ``licencing.html``, etc., have replaced bodies like ````, etc. Redirect everything ******************* Occasionally, you have to move complete documentation to a new home. It's easy with wildcard and placeholder:: redirects = { "*": "https://anotherwebsite.com/docs/$source.html" } .. tip:: To help search engines to understand the transfer, update (or set) `html_baseurl `_ option to the new website, too. sphinx-reredirects-0.1.2/pyproject.toml000066400000000000000000000001201443135300400202360ustar00rootroot00000000000000[build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta"sphinx-reredirects-0.1.2/releasing.rst000066400000000000000000000014511443135300400200350ustar00rootroot00000000000000How to release new version ########################## Part 1: Git release ******************* #. Choose version. #. Describe new version in ``docs/rn.rst``. #. Increment version in setup.py. #. Create commit with message "release ". #. Run local tests $ tox #. Push $ git push origin HEAD #. Wait for CI. #. If they CI passed, stay on master branch, tag just released commit as "vX.Y.Z" $ git tag -a vX.Y.Z $ git push origin HEAD Part 2: PyPI release ******************** #. If no errors so far, build with $ tox -e build that creates sdist and wheel in dist/. #. Upload to TestPyPI $ tox -e publish and go to https://test.pypi.org/project/sphinx-reredirects// #. If you are happy with it, upload to PyPI. $ tox -e publish -- --repository pypisphinx-reredirects-0.1.2/requirements.txt000066400000000000000000000000061443135300400206110ustar00rootroot00000000000000sphinxsphinx-reredirects-0.1.2/setup.py000066400000000000000000000021261443135300400170440ustar00rootroot00000000000000from setuptools import setup setup( name="sphinx_reredirects", version="0.1.2", url="https://gitlab.com/documatt/sphinx-reredirects", license="BSD3", author="Matt from Documatt", author_email="matt@documatt.com", description="Handles redirects for moved pages in Sphinx documentation " "projects", long_description=open("README.rst", encoding="utf-8").read(), long_description_content_type="text/x-rst", packages=["sphinx_reredirects"], install_requires=["sphinx"], python_requires=">=3.5", setup_requires=["wheel"], classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Environment :: Web Environment", "Framework :: Sphinx :: Extension", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.5", "Topic :: Documentation", "Topic :: Documentation :: Sphinx", "Topic :: Utilities", ], ) sphinx-reredirects-0.1.2/sphinx_reredirects/000077500000000000000000000000001443135300400212355ustar00rootroot00000000000000sphinx-reredirects-0.1.2/sphinx_reredirects/__init__.py000066400000000000000000000134111443135300400233460ustar00rootroot00000000000000import re from fnmatch import fnmatch from pathlib import Path from string import Template from typing import Dict, Mapping, Optional, Sequence from sphinx.application import Sphinx from sphinx.util import logging from sphinx.util.osutil import SEP OPTION_REDIRECTS = "redirects" OPTION_REDIRECTS_DEFAULT: Dict[str, str] = {} OPTION_TEMPLATE_FILE = "redirect_html_template_file" OPTION_TEMPLATE_FILE_DEFAULT = None REDIRECT_FILE_DEFAULT_TEMPLATE = '' # noqa: E501 logger = logging.getLogger(__name__) wildcard_pattern = re.compile(r"[\*\?\[\]]") def setup(app: Sphinx) -> Dict: """ Extension setup, called by Sphinx """ app.connect("html-collect-pages", init) app.add_config_value(OPTION_REDIRECTS, OPTION_REDIRECTS_DEFAULT, "env") app.add_config_value(OPTION_TEMPLATE_FILE, OPTION_TEMPLATE_FILE_DEFAULT, "env") return dict(parallel_read_safe=True) def init(app: Sphinx) -> Optional[Sequence]: if not app.config[OPTION_REDIRECTS]: logger.debug("No redirects configured") return [] rr = Reredirects(app) to_be_redirected = rr.grab_redirects() rr.create_redirects(to_be_redirected) # html-collect-pages requires to return iterable of pages to write, # we have no additional pages to write return [] class Reredirects: def __init__(self, app: Sphinx) -> None: self.app = app self.redirects_option: Dict[str, str] = getattr(app.config, OPTION_REDIRECTS) self.template_file_option: str = getattr(app.config, OPTION_TEMPLATE_FILE) def grab_redirects(self) -> Mapping[str, str]: """Inspect redirects option in conf.py and returns dict mapping \ docname to target (with expanded placeholder).""" # docname-target dict to_be_redirected = {} # For each source-target redirect pair in conf.py for source, target in self.redirects_option.items(): # no wildcard, append source as-is if not self._contains_wildcard(source): to_be_redirected[source] = target continue assert self.app.env # wildcarded source, expand to docnames expanded_docs = [ doc for doc in self.app.env.found_docs if fnmatch(doc, source) ] if not expanded_docs: logger.warning(f"No documents match to '{source}' redirect.") continue for doc in expanded_docs: new_target = self._apply_placeholders(doc, target) to_be_redirected[doc] = new_target return to_be_redirected def docname_out_path(self, docname: str, suffix: str) -> Sequence[str]: """ For a Sphinx docname (the path to a source document without suffix), returns path to outfile that would be created by the used builder. """ # Return as-is, if the docname already has been passed with a suffix if docname.endswith(suffix): return [docname] # Remove any trailing slashes, except for "/"" index if len(docname) > 1 and docname.endswith(SEP): docname = docname.rstrip(SEP) # Figure out whether we have dirhtml builder out_uri = self.app.builder.get_target_uri(docname=docname) # type: ignore if not out_uri.endswith(suffix): # If dirhtml builder is used, need to append "index" return [out_uri, "index"] # Otherwise, convert e.g. 'source' to 'source.html' return [out_uri] def create_redirects(self, to_be_redirected: Mapping[str, str]) -> None: """Create actual redirect file for each pair in passed mapping of \ docnames to targets.""" # Corresponds to value of `html_file_suffix`, but takes into account # modifications done by the builder class try: suffix = self.app.builder.out_suffix # type: ignore except Exception: suffix = ".html" for docname, target in to_be_redirected.items(): out = self.docname_out_path(docname, suffix) redirect_file_abs = Path(self.app.outdir).joinpath(*out).with_suffix(suffix) redirect_file_rel = redirect_file_abs.relative_to(self.app.outdir) if redirect_file_abs.exists(): logger.info( f"Overwriting '{redirect_file_rel}' with redirect to '{target}'." ) else: logger.info(f"Creating redirect '{redirect_file_rel}' to '{target}'.") self._create_redirect_file(redirect_file_abs, target) @staticmethod def _contains_wildcard(text: str) -> bool: """Tells whether passed argument contains wildcard characters.""" return bool(wildcard_pattern.search(text)) @staticmethod def _apply_placeholders(source: str, target: str) -> str: """Expand "source" placeholder in target and return it""" return Template(target).substitute({"source": source}) def _create_redirect_file(self, at_path: Path, to_uri: str) -> None: """Actually create a redirect file according to redirect template""" content = self._render_redirect_template(to_uri) # create any missing parent folders at_path.parent.mkdir(parents=True, exist_ok=True) at_path.write_text(content) def _render_redirect_template(self, to_uri: str) -> str: # HTML used as redirect file content redirect_template = REDIRECT_FILE_DEFAULT_TEMPLATE if self.template_file_option: redirect_file_abs = Path(self.app.srcdir, self.template_file_option) redirect_template = redirect_file_abs.read_text() content = Template(redirect_template).substitute({"to_uri": to_uri}) return content sphinx-reredirects-0.1.2/test-requirements.txt000066400000000000000000000000151443135300400215660ustar00rootroot00000000000000sphinx==5.0.1sphinx-reredirects-0.1.2/tests/000077500000000000000000000000001443135300400164735ustar00rootroot00000000000000sphinx-reredirects-0.1.2/tests/__init__.py000066400000000000000000000000001443135300400205720ustar00rootroot00000000000000sphinx-reredirects-0.1.2/tests/conftest.py000066400000000000000000000004231443135300400206710ustar00rootroot00000000000000import pytest from sphinx.testing.path import path pytest_plugins = "sphinx.testing.fixtures" # Exclude 'roots' dirs for pytest test collector collect_ignore = ["roots"] @pytest.fixture(scope="session") def rootdir(): return path(__file__).parent.abspath() / "roots" sphinx-reredirects-0.1.2/tests/roots/000077500000000000000000000000001443135300400176415ustar00rootroot00000000000000sphinx-reredirects-0.1.2/tests/roots/test-dirhtml/000077500000000000000000000000001443135300400222615ustar00rootroot00000000000000sphinx-reredirects-0.1.2/tests/roots/test-dirhtml/conf.py000066400000000000000000000000441443135300400235560ustar00rootroot00000000000000extensions = ["sphinx_reredirects"] sphinx-reredirects-0.1.2/tests/roots/test-dirhtml/index.rst000066400000000000000000000001431443135300400241200ustar00rootroot00000000000000Welcome to sphinx-reredirects ============================= .. toctree:: :glob: installing sphinx-reredirects-0.1.2/tests/roots/test-dirhtml/installing.rst000066400000000000000000000000541443135300400251560ustar00rootroot00000000000000Installing ########## I'm sample document. sphinx-reredirects-0.1.2/tests/roots/test-redirects/000077500000000000000000000000001443135300400226025ustar00rootroot00000000000000sphinx-reredirects-0.1.2/tests/roots/test-redirects/conf.py000066400000000000000000000000441443135300400240770ustar00rootroot00000000000000extensions = ["sphinx_reredirects"] sphinx-reredirects-0.1.2/tests/roots/test-redirects/faq/000077500000000000000000000000001443135300400233515ustar00rootroot00000000000000sphinx-reredirects-0.1.2/tests/roots/test-redirects/faq/one.rst000066400000000000000000000000071443135300400246610ustar00rootroot00000000000000One ###sphinx-reredirects-0.1.2/tests/roots/test-redirects/faq/two.rst000066400000000000000000000000071443135300400247110ustar00rootroot00000000000000Two ###sphinx-reredirects-0.1.2/tests/roots/test-redirects/index.rst000066400000000000000000000001421443135300400244400ustar00rootroot00000000000000Welcome to sphinx-reredirects ============================= .. toctree:: :glob: * faq/*sphinx-reredirects-0.1.2/tests/roots/test-redirects/install.rst000066400000000000000000000000571443135300400250040ustar00rootroot00000000000000Installation ############ I'm sample document.sphinx-reredirects-0.1.2/tests/roots/test-redirects/rn.rst000066400000000000000000000000611443135300400237500ustar00rootroot00000000000000Release Notes ############# I'm sample document.sphinx-reredirects-0.1.2/tests/test_end2end.py000066400000000000000000000107251443135300400214300ustar00rootroot00000000000000import pytest from sphinx.application import Sphinx from sphinx.errors import ExtensionError @pytest.mark.sphinx( "html", testroot="redirects", freshenv=True, confoverrides={ "redirects": { "faq/*": "https://new.com/$source.html", "*all": "go-to-${source}", "setup": "install.html", "install/requirements": "https://web.com/docs/requirements.html", } }, ) def test_ext(app: Sphinx, status, warning): app.build() status = status.getvalue() assert ( app.outdir / "faq/one.html" ).read_text() == '' # noqa: E501 assert ( """Overwriting 'faq/one.html' with redirect to 'https://new.com/faq/one.html'.""" # noqa: E501 in status ) assert ( app.outdir / "faq/two.html" ).read_text() == '' # noqa: E501 assert ( """Overwriting 'faq/two.html' with redirect to 'https://new.com/faq/two.html'.""" # noqa: E501 in status ) assert ( app.outdir / "install.html" ).read_text() == '' # noqa: E501 assert ( """Overwriting 'install.html' with redirect to 'go-to-install'.""" # noqa: E501 in status ) assert ( app.outdir / "setup.html" ).read_text() == '' # noqa: E501 assert """Creating redirect 'setup.html' to 'install.html'.""" in status assert ( app.outdir / "install/requirements.html" ).read_text() == '' # noqa: E501 assert ( """Creating redirect 'install/requirements.html' to 'https://web.com/docs/requirements.html'.""" # noqa: E501 in status ) @pytest.mark.sphinx( "dirhtml", testroot="dirhtml", freshenv=True, confoverrides={ "redirects": { "index.html": "/newindex/", "index": "http://new.com/index", "install": "/installing/trailingslash", "install/": "/installing/trailingslash", "install/index": "/installing", "install/index.html": "/installing.html", } }, ) def test_dirhtml(app: Sphinx, status, warning): app.build() status = status.getvalue() assert ( app.outdir / "index.html" ).read_text() == '' # noqa: E501 assert ( """Overwriting 'index.html' with redirect to '/newindex/'.""" # noqa: E501 in status ) assert ( """Overwriting 'index.html' with redirect to 'http://new.com/index'.""" # noqa: E501 in status ) assert ( app.outdir / "install/index.html" ).read_text() == '' # noqa: E501 assert ( """Creating redirect 'install/index.html' to '/installing/trailingslash'.""" # noqa: E501 in status ) assert ( """Overwriting 'install/index.html' with redirect to '/installing/trailingslash'.""" # noqa: E501 in status ) assert ( """Overwriting 'install/index.html' with redirect to '/installing'.""" # noqa: E501 in status ) assert ( """Overwriting 'install/index.html' with redirect to '/installing.html'.""" # noqa: E501 in status ) # Redirect sources starting with a slash are not allowed, use relative URIs @pytest.mark.sphinx( "html", testroot="redirects", freshenv=True, confoverrides={ "redirects": { "/index": "http://new.com/faq/", } }, ) def test_invalid_uri(app: Sphinx, status, warning): with pytest.raises(ExtensionError) as excinfo: app.build() assert "for event 'html-collect-pages' threw an exception" in str( excinfo.value ) # noqa: E501 assert any( [ # Newer python versions: "exception: '/index.html' is not in the subpath of" in str(excinfo.value), # Older python versions: "'/index.html' does not start with" in str(excinfo.value), ] ) sphinx-reredirects-0.1.2/tests/test_placeholders.py000066400000000000000000000025041443135300400225520ustar00rootroot00000000000000from unittest.mock import Mock import pytest from sphinx_reredirects import Reredirects def test_placeholder1(): actual = Reredirects._apply_placeholders( "features/one", "https://elsewhere/$source.html" ) expected = "https://elsewhere/features/one.html" assert actual == expected def test_placeholder2(): actual = Reredirects._apply_placeholders( "features", "https://elsewhere/$source.html" ) expected = "https://elsewhere/features.html" assert actual == expected def test_no_placeholder(): actual = Reredirects._apply_placeholders( "features", "https://elsewhere/features.html" ) expected = "https://elsewhere/features.html" assert actual == expected @pytest.mark.xfail( reason="To be fixed. Reported in https://gitlab.com/documatt/sphinx-reredirects/-/issues/1" # noqa: E501 ) def test_source_placeholder_returns_just_matched_part(): sphinx_mock = Mock() sphinx_mock.config = { "redirects": {"faq/*": "http://new.com/$source.html"}, "redirect_html_template_file": None, } sphinx_mock.env.found_docs = ["faq/one", "faq/two"] actual = Reredirects(sphinx_mock).grab_redirects() expected = { "faq/one": "http://new.com/one.html", "faq/two": "http://new.com/two.html", } assert actual == expected sphinx-reredirects-0.1.2/tests/test_wildcards.py000066400000000000000000000011261443135300400220600ustar00rootroot00000000000000from unittest.mock import Mock from sphinx_reredirects import Reredirects def test_wildcard_expansion(): sphinx_mock = Mock() sphinx_mock.config.redirects = { "faq/*": "http://new.com/faq/", "welcome": "intro.html", } sphinx_mock.config.redirect_html_template_file = None sphinx_mock.env.found_docs = ["faq/one", "faq/two", "intro"] actual = Reredirects(sphinx_mock).grab_redirects() expected = { "faq/one": "http://new.com/faq/", "faq/two": "http://new.com/faq/", "welcome": "intro.html", } assert actual == expected sphinx-reredirects-0.1.2/tox.ini000066400000000000000000000046611443135300400166530ustar00rootroot00000000000000# tox (https://tox.readthedocs.io/) is a tool for running tests # in multiple virtualenvs. This configuration file will run the # test suite on all supported python versions. To use it, "pip install tox" # and then run "tox" from this directory. [tox] # we use any Python 3 envlist = py3,mypy,check_style skip_missing_interpreters=true [testenv] deps = -r{toxinidir}/test-requirements.txt pytest==7.1.2 commands= pytest [testenv:mypy] description = Run type checks. skip_install = True deps = -r{toxinidir}/test-requirements.txt mypy==0.960 commands= mypy sphinx_reredirects [testenv:check_style] description = Run style checks. Do not modify files. skip_install = True deps = isort==5.10.1 black==22.3.0 flake8==4.0.1 commands = ; import order compatible with black formatter isort --check-only --diff --profile black sphinx_reredirects tests setup.py black --check --diff sphinx_reredirects tests setup.py ; Make Flake8 linter compatible with Black formatter ; https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#flake8 flake8 --ignore E203 --max-line-length 88 sphinx_reredirects tests setup.py [testenv:fix_style] description = Run and fix style (modify files). skip_install = True deps = isort==5.10.1 black==22.3.0 flake8==4.0.1 commands = isort --profile black sphinx_reredirects tests setup.py black sphinx_reredirects tests setup.py flake8 --ignore E203 --max-line-length 88 sphinx_reredirects tests setup.py [testenv:docs] description = Build docs skip_install = True deps = sphinx==5.0.1 sphinx_documatt_theme commands = ; -W turn warnings into errors ; -q be quiet sphinx-build -b html -q -W docs public [testenv:build] description = Package and release isolated_build = True skip_install = True deps = build==0.8.0 allowlist_externals = rm commands = rm -rf dist python -m build [testenv:publish] description = Publish the package you have been developing to a package index server. By default, it uses testpypi. If you really want to publish your package to be publicly accessible in PyPI, use the `-- --repository pypi` option. skip_install = True changedir = {toxinidir} passenv = TWINE_USERNAME TWINE_PASSWORD TWINE_REPOSITORY deps = twine commands = python -m twine check dist/* python -m twine upload {posargs:--repository {env:TWINE_REPOSITORY:testpypi}} dist/*