pax_global_header00006660000000000000000000000064141424506670014523gustar00rootroot0000000000000052 comment=4c6d78db0f2a4de6fbf58b2910912471960428e1 sphinx-notfound-page-0.8/000077500000000000000000000000001414245066700154475ustar00rootroot00000000000000sphinx-notfound-page-0.8/.circleci/000077500000000000000000000000001414245066700173025ustar00rootroot00000000000000sphinx-notfound-page-0.8/.circleci/config.yml000066400000000000000000000026761414245066700213050ustar00rootroot00000000000000version: 2.1 commands: run-tox: description: "Run tox" parameters: version: type: string sphinx-version: type: string default: "1,2,3,4,latest" steps: - checkout - run: pip install --user tox - run: tox -e "<>-sphinx{<>}" jobs: py27: docker: - image: 'cimg/python:2.7' steps: - run-tox: version: py27 sphinx-version: '1' py36: docker: - image: 'cimg/python:3.6' steps: - run-tox: version: py36 py37: docker: - image: 'cimg/python:3.7' steps: - run-tox: version: py37 py38: docker: - image: 'cimg/python:3.8' steps: - run-tox: version: py38 py39: docker: - image: 'cimg/python:3.9' steps: - run-tox: version: py39 py310: docker: - image: 'cimg/python:3.10' steps: - run-tox: version: py310 # Do not run tests for Python 3.10 and Sphinx3 because it's broken # See https://github.com/sphinx-doc/sphinx/issues/9816 sphinx-version: '1,2,4,latest' docs: docker: - image: 'cimg/python:3.10' steps: - checkout - run: pip install --user tox - run: tox -e docs workflows: version: 2 tests: jobs: - docs - py310 - py39 - py38 - py37 - py36 - py27 sphinx-notfound-page-0.8/.eslintrc000077700000000000000000000000001414245066700223242common/eslintrcustar00rootroot00000000000000sphinx-notfound-page-0.8/.flake8000077700000000000000000000000001414245066700212022common/flake8ustar00rootroot00000000000000sphinx-notfound-page-0.8/.gitignore000066400000000000000000000024411414245066700174400ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ /tests/examples/default/_build /tests/examples/404rst/_build package-lock.json node_modules # vscode .vscode/sphinx-notfound-page-0.8/.gitmodules000066400000000000000000000001211414245066700176160ustar00rootroot00000000000000[submodule "common"] path = common url = https://github.com/readthedocs/common sphinx-notfound-page-0.8/.isort.cfg000077700000000000000000000000001414245066700224522common/isort.cfgustar00rootroot00000000000000sphinx-notfound-page-0.8/.pep8000077700000000000000000000000001414245066700204062common/pep8ustar00rootroot00000000000000sphinx-notfound-page-0.8/.pre-commit-config.yaml000077700000000000000000000000001414245066700274162common/pre-commit-config.yamlustar00rootroot00000000000000sphinx-notfound-page-0.8/.readthedocs.yml000066400000000000000000000002531414245066700205350ustar00rootroot00000000000000version: 2 python: version: 3 install: - method: pip path: . - requirements: docs/requirements.txt sphinx: configuration: docs/conf.py formats: all sphinx-notfound-page-0.8/CHANGELOG.rst000066400000000000000000000241301414245066700174700ustar00rootroot00000000000000Changelog ========= Version 0.8 ----------- :Date: October 11, 2021 * Update all Python dependencies via pyup bot * Update test suite to run tests on Python 3.10, test on Sphinx 4 and pin docutils * Fix issue with HTML logo/favicon on Sphinx 4.2.x Version 0.7.1 ------------- :Date: May 20, 2021 Version 0.7 ----------- :Date: May 20, 2021 Version 0.6 ----------- :Date: January 04, 2021 * `@pyup-bot `__: Update sphinx to 3.4.1 (`#122 `__) * `@pyup-bot `__: Update sphinx to 3.4.0 (`#121 `__) * `@pyup-bot `__: Update sphinx to 3.3.1 (`#119 `__) * `@pyup-bot `__: Update sphinx to 3.3.0 (`#118 `__) * `@pyup-bot `__: Update sphinxemoji to 0.1.8 (`#116 `__) * `@pyup-bot `__: Update sphinxemoji to 0.1.7 (`#115 `__) * `@pyup-bot `__: Update sphinx-autoapi to 1.5.1 (`#113 `__) * `@rscohn2 `__: fix parallel read error and add test (`#112 `__) * `@sbraz `__: Include tests and docs in source distributions (`#110 `__) * `@pyup-bot `__: Update sphinx-prompt to 1.3.0 (`#109 `__) * `@pyup-bot `__: Update sphinx-tabs to 1.3.0 (`#108 `__) * `@pyup-bot `__: Update sphinx-autoapi to 1.5.0 (`#107 `__) * `@pyup-bot `__: Update sphinx-tabs to 1.2.1 (`#105 `__) * `@pyup-bot `__: Update sphinx-tabs to 1.2.0 (`#104 `__) * `@pyup-bot `__: Update sphinx to 3.2.1 (`#103 `__) * `@humitos `__: Update Sphinx==3.1.2 (`#99 `__) * `@pyup-bot `__: Update sphinx-rtd-theme to 0.5.0 (`#98 `__) Version 0.5 ----------- :Date: July 23, 2020 * `@humitos `__: Update Sphinx==3.1.2 (`#99 `__) * `@pyup-bot `__: Update sphinx-rtd-theme to 0.5.0 (`#98 `__) * `@jdillard `__: Add warning about local web server for #95 (`#97 `__) * `@pyup-bot `__: Update sphinx-autoapi to 1.4.0 (`#96 `__) * `@pyup-bot `__: Update sphinxemoji to 0.1.6 (`#93 `__) * `@huonw `__: Remind about `:orphan:` in 404.rst, to silence build warnings (`#91 `__) * `@humitos `__: Implement `notfound_urls_prefix` to replace 3 deprecated configs (`#90 `__) * `@humitos `__: :nosearch: metadata on 404 page (`#89 `__) * `@humitos `__: Add more test environments (`#88 `__) * `@pyup-bot `__: Update sphinx-autoapi to 1.3.0 (`#86 `__) * `@pyup-bot `__: Update sphinxemoji to 0.1.5 (`#85 `__) * `@pyup-bot `__: Update sphinxemoji to 0.1.4 (`#83 `__) * `@Daltz333 `__: Fix sphinx3 deprecation (`#82 `__) * `@pyup-bot `__: Update sphinx-autoapi to 1.2.1 (`#78 `__) * `@agnieszkawierzbowska `__: Update how-it-works.rst (`#77 `__) * `@agnieszkawierzbowska `__: Update configuration.rst (`#75 `__) * `@pyup-bot `__: Update sphinx-tabs to 1.1.13 (`#74 `__) * `@humitos `__: Extend options for setup.py (`#73 `__) * `@humitos `__: Test on sphinx 2.2.0 (`#72 `__) * `@humitos `__: Use pytest.mark.environ to set environment variables (`#71 `__) * `@pyup-bot `__: Update sphinx-tabs to 1.1.12 (`#70 `__) * `@dojutsu-user `__: Change `rtfd` to `readthedocs` everywhere (`#69 `__) * `@pyup-bot `__: Update sphinx-autoapi to 1.1.0 (`#67 `__) * `@humitos `__: Automatic add :orphan: to avoid Sphinx WARNING (`#66 `__) * `@acozine `__: Improves configuration page of documentation (`#45 `__) Version 0.4 ----------- :Date: June 11, 2019 * `@humitos `__: Copy image into output dir when using .. image:: directive (`#46 `__) * `@humitos `__: Allow using image directive with non-local images (`#40 `__) * `@humitos `__: Pin Sphinx below 2.0 because it does not render properly (`#53 `__) * `@pyup-bot `__: Update sphinxemoji to 0.1.1 (`#51 `__) * `@humitos `__: Run tox docs with -W (`#49 `__) * `@humitos `__: Use :orphan: to remove Sphinx warning (`#47 `__) * `@humitos `__: Copy image into output dir when using .. image:: directive (`#46 `__) * `@acozine `__: Improves configuration page of documentation (`#45 `__) * `@humitos `__: Specify extension metadata (`#44 `__) * `@stsewd `__: Don't list sphinx as a requirement (`#43 `__) * `@humitos `__: Run tests on Sphinx 2.1.0 (`#37 `__) * `@humitos `__: Add useful resources in the index docs page (`#34 `__) * `@humitos `__: Generate proper Toctree URLs when _version and _language are set (`#31 `__) * `@humitos `__: Setup travis-ci (`#30 `__) * `@humitos `__: Resolve internal Sphinx javascript resources URLs (`#29 `__) * `@humitos `__: Generate valid links for toctree when using DirectoryHTMLBuilder (`#28 `__) * `@humitos `__: Docs for "How it works" (`#23 `__) * `@humitos `__: More tox test envs (`#22 `__) * `@humitos `__: Allow ..image:: directive on 404.rst (`#21 `__) * `@humitos `__: Tests for toctree links (`#19 `__) Version 0.3 ----------- :Date: May 25, 2019 * Better documentation * `#13 `_ Added ``notfound_no_urls_prefix`` configuration Version 0.2.1 ------------- :Date: March 29, 2019 * Fix release version issue Version 0.2 ----------- :Date: March 29, 2019 * `#6 `_ Sidebar links broken Version 0.1 ----------- :Date: February 4, 2019 Initial release. sphinx-notfound-page-0.8/LICENSE000066400000000000000000000020601414245066700164520ustar00rootroot00000000000000MIT License Copyright (c) 2019 Manuel Kaufmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sphinx-notfound-page-0.8/MANIFEST.in000066400000000000000000000001501414245066700172010ustar00rootroot00000000000000prune common include LICENSE graft tests graft docs global-exclude __pycache__ global-exclude *.py[cod] sphinx-notfound-page-0.8/README.rst000066400000000000000000000025221414245066700171370ustar00rootroot00000000000000|Build| |PyPI version| |Docs badge| |License| sphinx-notfound-page ==================== Create a custom 404 page with absolute URLs hardcoded. Installation ------------ .. code-block:: bash pip install sphinx-notfound-page Configuration ------------- Add this extension in your ``conf.py`` file as: .. code-block:: python extensions = [ # ... other extensions here 'notfound.extension', ] Documentation ------------- Check out the full documentation at https://sphinx-notfound-page.readthedocs.io/ Thanks ------ **Strongly** based on @ericholscher's solution from https://github.com/readthedocs/readthedocs.org/issues/353 .. |Build| image:: https://circleci.com/gh/readthedocs/sphinx-notfound-page.svg?style=svg :target: https://circleci.com/gh/readthedocs/sphinx-notfound-page :alt: Build status .. |PyPI version| image:: https://img.shields.io/pypi/v/sphinx-notfound-page.svg :target: https://pypi.org/project/sphinx-notfound-page :alt: Current PyPI version .. |Docs badge| image:: https://readthedocs.org/projects/sphinx-notfound-page/badge/?version=latest :target: https://sphinx-notfound-page.readthedocs.io/en/latest/?badge=latest :alt: Documentation status .. |License| image:: https://img.shields.io/github/license/readthedocs/sphinx-notfound-page.svg :target: LICENSE :alt: Repository license sphinx-notfound-page-0.8/common/000077500000000000000000000000001414245066700167375ustar00rootroot00000000000000sphinx-notfound-page-0.8/conftest.py000066400000000000000000000000531414245066700176440ustar00rootroot00000000000000pytest_plugins = 'sphinx.testing.fixtures' sphinx-notfound-page-0.8/docs/000077500000000000000000000000001414245066700163775ustar00rootroot00000000000000sphinx-notfound-page-0.8/docs/404.rst000066400000000000000000000003301414245066700174340ustar00rootroot00000000000000:orphan: ============= Oh, oh -- 404 ============= We could not find this page!. .. image:: loudly-crying-face.png :align: center Please, try using the links from the sidebar to find what you are looking for. sphinx-notfound-page-0.8/docs/Makefile000066400000000000000000000011041414245066700200330ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line. 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-notfound-page-0.8/docs/conf.py000066400000000000000000000130421414245066700176760ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- 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('.')) # -- Project information ----------------------------------------------------- project = 'sphinx-notfound-page' copyright = '2019, Manuel Kaufmann' author = 'Manuel Kaufmann' # The short X.Y version # The full version, including alpha/beta/rc tags import notfound version = release = notfound.__version__ # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'notfound.extension', 'autoapi.extension', 'sphinx_tabs.tabs', 'sphinx-prompt', 'sphinxemoji.sphinxemoji', ] autoapi_dirs = ['../notfound'] autoapi_add_toctree_entry = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # 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'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 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_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'sphinx-notfound-pagedoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'sphinx-notfound-page.tex', 'sphinx-notfound-page Documentation', 'Manuel Kaufmann', 'manual'), ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'sphinx-notfound-page', 'sphinx-notfound-page Documentation', [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'sphinx-notfound-page', 'sphinx-notfound-page Documentation', author, 'sphinx-notfound-page', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project # The unique identifier of the text. This can be a ISBN number # or the project homepage. # # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # -- Setup for 'confval' used in docs/configuration.rst ---------------------- def setup(app): app.add_object_type('confval', 'confval', 'pair: %s; configuration value') sphinx-notfound-page-0.8/docs/configuration.rst000066400000000000000000000060501414245066700220010ustar00rootroot00000000000000Configuration ============= The default settings generate the most commonly-used URL pattern: if you have a resource at ``_static/js/logic.js`` and you generate a 404 page with the default settings, the URL for that resource will be ``/en/latest/_static/js/logic.js``. For other use cases, you can customize these configuration options in your ``conf.py`` file: .. confval:: notfound_template Template used to render the ``404.html`` generated by this extension. Default: ``'page.html'`` Type: string .. confval:: notfound_context Context passed to the template defined by ``notfound_template``. Default: .. code-block:: python { 'title': 'Page not found', 'body': '

Page not found

\n\nThanks for trying.', } Type: dict .. note:: If you prefer, you can create a file called ``404.rst`` and use reStructuredText to create the context of your ``404.html`` page. Add the ``:orphan:`` `metadata `__ to the top of ``404.rst``, to silence the spurious ``document isn't included in any toctree`` warning. .. confval:: notfound_pagename Page name generated by the extension. Default: ``'404'`` Type: string .. confval:: notfound_urls_prefix Prefix added to all the URLs generated in the 404 page. Default: ``'/en/latest/'`` Type: string .. warning:: Make sure this config starts and ends with a ``/``. Otherwise, you may have unexpected behaviours. .. tip:: The prefix can be completely removed by setting it to ``None``. .. confval:: notfound_default_language Language used as default to generate all links to the resources. Default: :envvar:`READTHEDOCS_LANGUAGE` environment variable, if set, else ``'en'`` Type: string .. note:: All links generated will have this prefix (e.g. ``/en/``). This setting works with ``notfound_default_version`` to create a prefix for all URLs. .. deprecated:: 0.5 ``notfound_default_language`` is deprecated. Use :confval:`notfound_urls_prefix` instead .. confval:: notfound_default_version Version used as default to generate all links to the resources. Default: :envvar:`READTHEDOCS_VERSION` environment variable, if set, else ``'latest'`` Type: string .. note:: All links generated will have this prefix (e.g. ``/latest/``). This setting works with ``notfound_default_language`` to create a prefix for all URLs. .. deprecated:: 0.5 ``notfound_default_version`` is deprecated. Use :confval:`notfound_urls_prefix` instead .. confval:: notfound_no_urls_prefix URL prefixes skipped or included. Default: ``False``. Type: bool .. note:: If this option is set to ``True``, the extension omits any prefix values from the URLs, including explicit values for ``notfound_default_language`` and ``notfound_default_version``. .. deprecated:: 0.5 ``notfound_no_urls_prefix`` is deprecated. Use :confval:`notfound_urls_prefix` instead sphinx-notfound-page-0.8/docs/faq.rst000066400000000000000000000031521414245066700177010ustar00rootroot00000000000000Frequently Asked Questions ========================== Does this extension work with Read the Docs? -------------------------------------------- Yes. Read the Docs should detect the ``404.html`` page generated by the extension automatically, and serve it when a user hits a not found page. If you are using a Single Version project, you may want to set :confval:`notfound_urls_prefix` to ``None``. Does this extension work with GitHub pages? ------------------------------------------- Yes. You may want to set :confval:`notfound_urls_prefix` to ``None``, and then add ``permalink: /404.html`` in the `YAML front matter`_. If you are using the github provided domain, make sure to set the :confval:`notfound_urls_prefix` to your repository's name in between two forward slashes. For example if your repository is named ``MyRepo``, then ``notfound_urls_prefix = "/MyRepo/"``. .. _YAML front matter: http://jekyllrb.com/docs/frontmatter/ Why is my local web server not showing a 404.html? -------------------------------------------------- Simple web servers, such as ``http.server``, don't have a default handler for 404 codes, so it doesn't know to point to the generated ``404.html``. To see an example of adding a custom request handler for 404 codes, see: https://stackoverflow.com/questions/22467908/python-simplehttpserver-404-page The answer I'm looking for is not here -------------------------------------- |:cry:| Please, `open an issue in our issue tracker`_, and let us know what's the problem you are having. .. _open an issue in our issue tracker: https://github.com/readthedocs/sphinx-notfound-page/issues/new sphinx-notfound-page-0.8/docs/get-involved.rst000066400000000000000000000007571414245066700215450ustar00rootroot00000000000000Get Involved ============ We appreciate a lot your interest on getting involved in this small project! Your help will benefit a lot of people around the world. Please, if you want to collaborate with us, you can check out `the list of issues we have on GitHub`_ and comment there if you need further guidance or just send a Pull Request |:heart:|. .. _the list of issues we have on GitHub: https://github.com/readthedocs/sphinx-notfound-page/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc sphinx-notfound-page-0.8/docs/how-it-works.rst000066400000000000000000000031711414245066700215050ustar00rootroot00000000000000How It Works ============ The extension subscribes to some events emitted by the Sphinx application. When these events are triggered, our functions are called and they manipulate the doctree and context passed to the template. Events subscribed ----------------- There are 3 main events that this extension subscribes: * ``doctree-resolved`` * ``html-collect-pages`` * ``html-page-context`` Each one has an specific goal persuading the same objective: make all resources URLs absolutes. doctree-resolved ~~~~~~~~~~~~~~~~ After Sphinx has parsed our source files, this event is triggered. Here, we check if the page being rendered is ``notfound_pagename`` and in that case, we replace all the URLs for ``.. image::``, ``.. figure::`` and other directives to point the right path. html-collect-pages ~~~~~~~~~~~~~~~~~~ After all HTML pages are collected and this event is emitted, we check for the existence of a ``404`` page already. If there is one, we do not need to do anything here. If the user has not defined this page, we render the template ``notfound_template`` with the context ``notfound_context``. html-page-context ~~~~~~~~~~~~~~~~~ Immediately before the template is rendered with the context, this event is emitted. At this point, we override ``pathto`` [#pathto]_ function with our custom one that will generate the proper URLs. We also override ``toctree`` [#toctree]_ key with the same content of the regular toctree but with all the URLs fixed to find the resources from the 404 page. .. [#pathto] https://www.sphinx-doc.org/page/templating.html#pathto .. [#toctree] https://www.sphinx-doc.org/page/templating.html#toctree sphinx-notfound-page-0.8/docs/index.rst000066400000000000000000000042541414245066700202450ustar00rootroot00000000000000Welcome to sphinx-notfound-page! ================================ ``sphinx-notfound-page`` is a Sphinx_ extension to create custom 404 pages and help you to generate proper resource links (js, css, images, etc) to render the page properly. This extension was originally developed to be used on `Read the Docs`_ but it can be used in other hosting services as well. Online documentation: https://sphinx-notfound-page.readthedocs.io/ Source code repository (and issue tracker): https://github.com/readthedocs/sphinx-notfound-page/ Badges: |Build| |PyPI version| |Docs badge| |License| Why I need this extension? -------------------------- Sphinx does not create a 404 page by default. Although, you can create it by adding a simple ``404.rst`` file to your docs but... If you are reading this documentation, you may already experienced the problem that all your images do no load, all your styles are broken and all the javascript events does not work, when accessing the 404 page of your documentation. So, if you want to have a nice custom 404 page, you will probably want to use this extension to avoid this headache and let the extension handle these URLs properly for you. .. toctree:: :maxdepth: 1 :caption: Contents installation configuration how-it-works get-involved who-is-using-it faq .. toctree:: :maxdepth: 1 :caption: API Reference autoapi/notfound/index .. _Sphinx: https://www.sphinx-doc.org/ .. _Read the Docs: https://readthedocs.org .. |Build| image:: https://circleci.com/gh/readthedocs/sphinx-notfound-page.svg?style=svg :target: https://circleci.com/gh/readthedocs/sphinx-notfound-page :alt: Build status .. |PyPI version| image:: https://img.shields.io/pypi/v/sphinx-notfound-page.svg :target: https://pypi.org/project/sphinx-notfound-page :alt: Current PyPI version .. |Docs badge| image:: https://readthedocs.org/projects/sphinx-notfound-page/badge/?version=latest :target: https://sphinx-notfound-page.readthedocs.io/en/latest/?badge=latest :alt: Documentation status .. |License| image:: https://img.shields.io/github/license/readthedocs/sphinx-notfound-page.svg :target: LICENSE :alt: Repository license sphinx-notfound-page-0.8/docs/installation.rst000066400000000000000000000027531414245066700216410ustar00rootroot00000000000000Installation ============ Install the package .. tabs:: .. tab:: from PyPI .. prompt:: bash pip install sphinx-notfound-page .. tab:: from GitHub .. prompt:: bash pip install git+https://github.com/readthedocs/sphinx-notfound-page@master Once we have the package installed, we have to configure it on our Sphinx documentation. To do this, add this extension to your Sphinx's extensions in the ``conf.py`` file. .. code-block:: python # conf.py extensions = [ # ... other extensions here 'notfound.extension', ] After installing the package and adding the extension in the ``conf.py`` file, you can build your documentation again and you will see a new file called ``404.html`` in your documentation's build output. .. warning:: If you open the ``404.html`` file on the browser, you will see that all of the images and css does not display properly. This is because all the URLs are absolute and since the file is being rendered from ``file://`` in the browser, it does not know where to find those resources. Do not worry too much about this, this is the expected behavior and those resources will appear once the docs are deployed. If you can't see the 404.html file using a local simple web server, it is most likely because they often don't support requests for 404 codes. Refer to the :doc:`faq` for more information. .. note:: This extension requires, * Python 2.7+ or 3.x * Sphinx 1.5+ or 2.x sphinx-notfound-page-0.8/docs/loudly-crying-face.png000066400000000000000000000317211414245066700226060ustar00rootroot00000000000000PNG  IHDRg-gAMA a cHRMz&u0`:pQ<tIME $FbKGD2IDATx]xeW)]*I{"鈴BR!tD "A))@Hgyݖݽpw>(~;߻73C>>>>>O}0^`3J12^eftatc ` xљърQcgseYv SrnH>$_!j=!x:U! ψg3Z] 'Či!h̄ 65h;L댒ӯlU3s8Gv d3!B66D2@vcpʳ!KbeZh5/Y *O#ZִLI/NxN%clǨ 2IhC-j)w4-ZL?L).v$NFAߨB++жə c0Fcح di!$yBJL$tN;-q=4, m^?ǵNWލs)~Hۼ`0Fc xM dAVZH\E8+جbAlO A˞2w4QzD#}Vʴ{\)0H,زl3YLx6<!4ۅ uDbAW"_^R b9~H *9$s{T ] RxNAvHXB(+P!!2Fd X$ ?7fߌ <=%Jȩ]I<@_6;Q\xf<{ʪAv&L"%ݼ:Nh1XQO%sN<5"!B% C&0n&GpK31Rp R˲k~xC|;VvW嬥 @dY&ўo(#+W݈W'QjԥA[=W%0?+=AC&jYBI:]BBdCVmҲaK@äCLlE ^|$l #JJBTjP 1DזwXKAgzN4,LQ-elao'\^6jĆH~' yh ,j7SDd2ɟa6)4LKum3L?o[+s6?O7ьfj[L˘dE&|,2QL\1/ J^dӓH/ōZol ;#4OO朴y}`ڙRi3M&٘_LsPO㞗*ZXX$+(rUA&+diL߈0I3ъ&Y1*Ӗ̴s%{*h溵iA7/KC:_@W`h /-$f 2bJcX6b$_ (Pwa+@ՃMT&=µ]~%zfvے 47gr| 3m.b *GmwDP )y. m']0gzò;gbM8;*y#>(6v[F~HGSj ؔ3{X cM²k2{N>=l/VȖA!k.ЦЧJFv=F=67<߼B^=>xz崵 !ad@JG.;#"ѯo B놚(8µrf3&lȊ 7S*ts-8 iذFXMd@QdҼ#X[]o%ƶ5uzB-O3dÀ2NRj3ol)B2txK|\l`(O:0(` 4XpYA%)r;Cja359o*LUh4k7NVi=$"UՏ굎dӰ|.ڙEhӂHzAIjl 'Xyp"` "S[[u ١4jwm p*hhO0SAO%rԪ12*E&N#P.;)|[~ӗsҷY ZP" \l!,dѼ3x 5+OQɂ@xKA#f\Si\1&x AJz}-Uټ!&yDŽ uHBIbPLRL۶t6we{ [AdPSXpӫ=㘀Ie=z-j;T%!4`03x{ Gg .Y7L {Raeqd:5ݮRٜ W%! 7:jXu-wnaq\GG u< #qd L $ HBܳM3]{c4_&&A6Z ظWEݯSxu Q$!=\ܚ[W*0@l9fAe37M&*_cz)|@!)N ش-YcVk OTyLO½Boޖ -hM:RMl疦*MVd0<1G1DY9eE?,^,$*qōtJ!j ?M% }W*hJI>CuP j5SWz,/٢g%9EM3 GDMjD+-VPbV6圀Mz&vƾِ^/8u@AI2N*pχ=IY^ZPjCkQX$=\.ۂ{f]gOzwJ\m93f-e&{ Mj% r?`f9G締RCFIiwFn۫rӗ@Afy-N{Lj%m Sأ݌ m;;G:)GF+Cs4H  -Tua8sTpi+_/K{? \Q̣p􁲀i3vĶ?i9,Vj#6~ԧt˃JQ./{-N.#VC%ض 5`[{9a7AzJڨL+ DYI@hh[glŶ%U=e]!# l;-QrІbWyT!%,.M<-Z mH خtzql`:pleVFAC/{ Lno ض:A' wFmi@vF o>tV{m$&ɢ  mmjS[@4je9hy-< A~gaC[Z|b[-yV` CVF#G -(Sst1 hb2;FCJÁ9q$˶`hOykκ"8}x7HA[y H;hBLFX9BpZ2O\ߊ˥Z0z>Swm>Ϳ|`o[N}DYZ|oq :YkezQs=M{A3 \QHF0&k"][f$ #?CP^~=O~ Mc@Ԕu&[az'A8|h wpM\:jS+uD@;}zۢ<?̧Y+X2YBtwYF#GlZ==tg ?c˟i`3ukd`'sKb̖kڸe{o5$K˪RjeKtta J^9MXZB*0E~\Jb&]ACں"8*N4}4SozyC3Mj:-' %VB{Ǣ4t&.gVF;BtdakUٸ pՔ|yQ\Amp/7֖6UkޟH) N37,M+MYܶ0cX+~*{P :Q'~nOp$nbQRM9/en`dc%}>$o4ӵe`õPZkx}Jh܋ǝi]]@Pm) 1c0F1KQ> ʨyAu.1np|ٙhrTO]pEF}]㔸%A@nDfux԰Z0y6%ob^?|@]?ފ/N~~~/ 1iln1& ccNOG2\+cuФF=Ӯy}(GΐozX\Gκb9ЭHlUPkWx&--lleC@^z ,Hywֽ.I۫ S J6l5ӅsoPOjfY@c:PH6<{Zh}PB1b5L%oAu#2#|6{$29Ub!Êe( ":>uϞ^w48h-uoh9Щ=f4 }…rk>lѫ6uC #wd4k }nv|&,SlӻPo@`Ef'Y 3 !:1gS}h37|c K-Y5B@+/؉ڝT*2dCnNG+/FiOBge]x7D?GFΤ/elksnRdL@&DL6`. l7WgO@ ItMWЦyVth9+EߘԴlsh,[Ѕ F 4b. usz^j"ЌRjK@LMjK_Zw} 5giGXɣ"=B> floDfJ?^ҏ҄ctJ4 ]$KWݲg2 h8cO@d xO8.٣?tl{'a s{wGqBRA}1@BX_%)v4`#SA"MB df:!&? l._u!S\}]U:ea sz8b*z c*d̕į^X p(g!i (&~WgZ(03) : `i}Nk+f=t,! CĂc{dce,(NRȻ"O p1{E 7>БtRZƽ7[t0I{$lY0'qHI{X7SLqT)P}6zC JCd{~nu< k@]`Th_Fp0i?R2tXz,% (5?8Y.lB.+J8 Xud2Jr~rz}9zgn|WdU[ XJo!JM_lxt9JUFb#`ӦY+7gx2NGRƟeAgJŃM` ĺ2-雄&=; 3"^,< OEi8yDo෸kIJj'`3 6< By~N[LR cx)Nmӱǔz42Ζ32tzz== , -deeتF G[9 !tq_4DU ~kZ&mՠN# ;LK)MHJo{,vHf>jwKZwcѵd;7B1'k3{G^{31I&4c{ѣÑShАdc]_&` g/LoOBx!XBT;!zigQhŘh2}7vfz)}HgEnFF}e:O{^άE*@R-/Ngmomg.䣋t*ǎF3ŕ#Z~xuj2ڤx^cf(H'ɨꙿW]OW!쳄;JRFt03B"c4gHu@HQd;] ;}8xkH(IHFQA =`\!ً"):5KǗ%lHrY(Ihveq6F,@$`)@V5I(=k$jwoxc1$*E @DdcVD 1y$ɗqPmJ"|A]b\֍)b9\&2B6y)I{hA,3A&xQWiIe$(w'M>XX0FD/lecY9,!e!?h@b?[$tnqHk< ؃/7Cj{EpcH=_|ӓ&*-WOM0Lc撊MNG~t aokx,#&D|`r]Z$$KFjqT~e{#R誫 pPpm/6N@#Y'vJˌV'[<b07eu-E۷r;ܚW[4V# R%ϨuiO'RJ$ߨ7W%a'3+lB6[ T\yGh_lA#Z]6> l<ي6$|\̒It e.{լƎp0M1Y:>&-=Gh駱psCʖb >lVGDeŋeOl҅~xq\OcZvq+{xWf!(L̞>/QdE`kGsxhK'ֽ̄X<9F/Q~n ^X X32el=|aO]yb϶Sخ.u!]jD ;@&+)b.1P4#6_JKM3H%[b=- a|X([7Җxrqȝm.:DZ2(=t1,4Q^V(F~M)FT+FgCx$@ ߩϨ̈``?"-$febS0^1s@Dxc{,f$nVzpmdGM.⦨){bv703^ȱs"\0F41ts#ALD Z,8ib@$\q}v8'D{Iq {n/IFHG3H'm@FU,(4E1Pj^'8i椷F6O1 1Qhh%EU [S}}|}|}GX%tEXtdate:create2018-08-07T10:26:11+00:00¿%tEXtdate:modify2018-08-07T10:26:11+00:00YtEXtSoftwareAdobe ImageReadyqe<IENDB`sphinx-notfound-page-0.8/docs/requirements.txt000066400000000000000000000004261414245066700216650ustar00rootroot00000000000000sphinx==4.2.0 sphinx-prompt==1.4.0 sphinx-tabs==3.2.0 sphinx-rtd-theme==1.0.0 sphinxemoji==0.2.0 sphinx-autoapi==1.8.4 # We need to ignore upgrading it here, because we install it from the # repository when building the docs on Read the Docs sphinx-notfound-page # pyup: ignoresphinx-notfound-page-0.8/docs/who-is-using-it.rst000066400000000000000000000023361414245066700221000ustar00rootroot00000000000000Who Is Using It? ================ These are some projects using this extension that you can take a look at to understand how they are configured and what's the behavior. Read the Docs ------------- * https://github.com/readthedocs/readthedocs.org * `Example URL `__ * `Configuration file `__ PyVista ------- * https://github.com/pyvista/pyvista * `Example URL `__ * `Configuration file `__ Write the Docs -------------- * https://github.com/writethedocs/www * `Example URL `__ * `Configuration file `__ The Carpentries --------------- * https://github.com/carpentries/handbook * `Example URL `__ * `Configuration file `__ attrs ----- * https://www.attrs.org/ * `Example URL `__ * `Configuration file `__ sphinx-notfound-page-0.8/notfound/000077500000000000000000000000001414245066700173035ustar00rootroot00000000000000sphinx-notfound-page-0.8/notfound/__init__.py000066400000000000000000000000241414245066700214100ustar00rootroot00000000000000__version__ = '0.8' sphinx-notfound-page-0.8/notfound/extension.py000066400000000000000000000307761414245066700217060ustar00rootroot00000000000000import docutils import os import sphinx import warnings from sphinx.environment.collectors import EnvironmentCollector from sphinx.errors import ExtensionError from . import __version__ from .utils import replace_uris class BaseURIError(ExtensionError): """Exception for malformed base URI.""" pass # https://www.sphinx-doc.org/en/stable/extdev/appapi.html#event-html-collect-pages def html_collect_pages(app): """ Create a ``404.html`` page. Uses ``notfound_template`` as a template to be rendered with ``notfound_context`` for its context. The resulting file generated is ``notfound_pagename``.html. If the user already defined a page with pagename title ``notfound_pagename``, we don't generate this page. :param app: Sphinx Application :type app: sphinx.application.Sphinx """ if app.config.notfound_pagename in app.env.titles: # There is already a ``404.rst`` file rendered. # Skip generating our default one. return [] return [( app.config.notfound_pagename, app.config.notfound_context, app.config.notfound_template, )] # https://www.sphinx-doc.org/en/stable/extdev/appapi.html#event-html-page-context def finalize_media(app, pagename, templatename, context, doctree): """ Point media files at our media server. Generate absolute URLs for resources (js, images, css, etc) to point to the right. For example, if a URL in the page is ``_static/js/custom.js`` it will be replaced by ``/_static/js/custom.js``. On the other hand, if ``notfound_no_urls_prefix`` is set, it will be replaced by ``/_static/js/custom.js``. Also, all the links from the sidebar (toctree) are replaced with their absolute version. For example, ``../section/pagename.html`` will be replaced by ``/section/pagename.html``. :param app: Sphinx Application :type app: sphinx.application.Sphinx :param pagename: name of the page being rendered :type pagename: str :param templatename: template used to render the page :type templatename: str :param context: context used to render the page :type context: dict :param doctree: doctree of the page being rendered :type doctree: docutils.nodes.document """ # https://github.com/sphinx-doc/sphinx/blob/7138d03ba033e384f1e7740f639849ba5f2cc71d/sphinx/builders/html.py#L1054-L1065 def pathto(otheruri, resource=False, baseuri=None): """ Hack pathto to display absolute URL's. Instead of calling ``relative_url`` function, we call ``app.builder.get_target_uri`` to get the absolut URL. .. note:: If ``otheruri`` is a external ``resource`` it does not modify it. """ if resource and '://' in otheruri: # allow non-local resources given by scheme return otheruri if not resource: otheruri = app.builder.get_target_uri(otheruri) if baseuri is None: if app.config.notfound_no_urls_prefix: baseuri = '/' else: baseuri = '{prefix}'.format( prefix=app.config.notfound_urls_prefix or '/', ) if not baseuri.startswith('/'): raise BaseURIError('"baseuri" must be absolute') if otheruri and not otheruri.startswith('/'): otheruri = '/' + otheruri if otheruri: if baseuri.endswith('/'): baseuri = baseuri[:-1] otheruri = baseuri + otheruri uri = otheruri or '#' return uri # https://github.com/sphinx-doc/sphinx/blob/2adeb68af1763be46359d5e808dae59d708661b1/sphinx/builders/html.py#L1081 def toctree(*args, **kwargs): try: # Sphinx >= 1.6 from sphinx.environment.adapters.toctree import TocTree get_toctree_for = TocTree(app.env).get_toctree_for except ImportError: # Sphinx < 1.6 get_toctree_for = app.env.get_toctree_for toc = get_toctree_for( app.config.notfound_pagename, app.builder, collapse=kwargs.pop('collapse', False), includehidden=kwargs.pop('includehidden', False), **kwargs # not using trailing comma here makes this compatible with # Python2 syntax ) # If no TOC is found, just return ``None`` instead of failing here if not toc: return None replace_uris(app, toc, docutils.nodes.reference, 'refuri') return app.builder.render_partial(toc)['fragment'] # Borrowed from Sphinx<4.x to backward compatibility # https://github.com/sphinx-doc/sphinx/blob/v3.5.4/sphinx/builders/html/__init__.py#L1003-L1010 def css_tag(css): attrs = [] for key in sorted(css.attributes): value = css.attributes[key] if value is not None: if sphinx.version_info < (2, 0): # https://github.com/sphinx-doc/sphinx/blob/v1.8.5/sphinx/builders/html.py#L1144 from sphinx.util.pycompat import htmlescape attrs.append('%s="%s"' % (key, htmlescape(value, True))) else: import html attrs.append('%s="%s"' % (key, html.escape(value, True))) attrs.append('href="%s"' % pathto(css.filename, resource=True)) return '' % ' '.join(attrs) # Apply our custom manipulation to 404.html page only if pagename == app.config.notfound_pagename: # Override the ``pathto`` helper function from the context to use a custom ones # https://www.sphinx-doc.org/en/master/templating.html#pathto context['pathto'] = pathto # Override the ``toctree`` helper function from context to use a custom # one and generate valid links on not found page. # https://www.sphinx-doc.org/en/master/templating.html#toctree # NOTE: not used on ``singlehtml`` builder for RTD Sphinx theme context['toctree'] = toctree if sphinx.version_info < (4, 0): context['css_tag'] = css_tag # https://www.sphinx-doc.org/en/stable/extdev/appapi.html#event-doctree-resolved def doctree_resolved(app, doctree, docname): """ Generate and override URLs for ``.. image::`` Sphinx directive. When ``.. image::`` is used in the ``404.rst`` file, this function will override the URLs to point to the right place. :param app: Sphinx Application :type app: sphinx.application.Sphinx :param doctree: doctree representing the document :type doctree: docutils.nodes.document :param docname: name of the document :type docname: str """ if docname == app.config.notfound_pagename: # Replace image ``uri`` to its absolute version replace_uris(app, doctree, docutils.nodes.image, 'uri') class OrphanMetadataCollector(EnvironmentCollector): """ Force the 404 page to be ``orphan``. This way we remove the WARNING that Sphinx raises saying the page is not included in any toctree. This collector has the same effect than ``:orphan:`` at the top of the page. """ def clear_doc(self, app, env, docname): return None def process_doc(self, app, doctree): metadata = app.env.metadata[app.config.notfound_pagename] metadata.update({'orphan': True}) if sphinx.version_info >= (3, 0, 0): metadata.update({'nosearch': True}) def merge_other(self, app, env, docnames, other): """Merge in specified data regarding docnames from a different `BuildEnvironment` object which coming from a subprocess in parallel builds.""" # TODO: find an example about why this is strictly required for parallel read # https://github.com/readthedocs/sphinx-notfound-page/pull/112/files#r498219556 env.metadata.update(other.metadata) def handle_deprecated_configs(app, *args, **kwargs): """ Handle deprecated configurations. Looks for old deprecated configurations, define the new ones and triggers warnings for old configs. """ default, rebuild, types = app.config.values.get('notfound_urls_prefix') if app.config.notfound_urls_prefix == default: language = app.config.notfound_default_language version = app.config.notfound_default_version app.config.notfound_urls_prefix = '/{language}/{version}/'.format( language=language, version=version, ) deprecated_configs = [ 'notfound_default_language', 'notfound_default_version', 'notfound_no_urls_prefix', ] for config in deprecated_configs: default, rebuild, types = app.config.values.get(config) if getattr(app.config, config) != default: message = '{config} is deprecated. Use "notfound_urls_prefix" instead.'.format( config=config, ) warnings.warn(message, DeprecationWarning, stacklevel=2) def validate_configs(app, *args, **kwargs): """ Validate configs. Shows a warning if one of the configs is not valid. """ default, rebuild, types = app.config.values.get('notfound_urls_prefix') if app.config.notfound_urls_prefix != default: if app.config.notfound_urls_prefix and not all([ app.config.notfound_urls_prefix.startswith('/'), app.config.notfound_urls_prefix.endswith('/'), ]): message = 'notfound_urls_prefix should start and end with "/" (slash)' warnings.warn(message, UserWarning, stacklevel=2) def setup(app): default_context = { 'title': 'Page not found', 'body': "

Page not found

\n\nUnfortunately we couldn't find the content you were looking for.", } # https://github.com/sphinx-doc/sphinx/blob/master/sphinx/themes/basic/page.html app.add_config_value('notfound_template', 'page.html', 'html') app.add_config_value('notfound_context', default_context, 'html') app.add_config_value('notfound_pagename', '404', 'html') # TODO: get these values from Project's settings default_language = os.environ.get('READTHEDOCS_LANGUAGE', 'en') default_version = os.environ.get('READTHEDOCS_VERSION', 'latest') app.add_config_value('notfound_default_language', default_language, 'html') app.add_config_value('notfound_default_version', default_version, 'html') app.add_config_value('notfound_no_urls_prefix', False, 'html') # This config should replace the previous three app.add_config_value( 'notfound_urls_prefix', '/{default_language}/{default_version}/'.format( default_language=default_language, default_version=default_version, ), 'html', ) if sphinx.version_info > (1, 8, 0): app.connect('config-inited', handle_deprecated_configs) app.connect('config-inited', validate_configs) else: app.connect('builder-inited', handle_deprecated_configs) app.connect('builder-inited', validate_configs) app.connect('html-collect-pages', html_collect_pages) if sphinx.version_info >= (3, 0, 0): # Use ``priority=400`` argument here because we want to execute our function # *before* Sphinx's ``setup_resource_paths`` where the ``logo_url`` and # ``favicon_url`` are resolved. # See https://github.com/readthedocs/sphinx-notfound-page/issues/180#issuecomment-959506037 app.connect('html-page-context', finalize_media, priority=400) else: app.connect('html-page-context', finalize_media) app.connect('doctree-resolved', doctree_resolved) # Sphinx injects some javascript files using ``add_js_file``. The path for # this file is rendered in the template using ``js_tag`` instead of # ``pathto``. The ``js_tag`` uses ``pathto`` internally to resolve these # paths, we call again the setup function for this tag *after* the context # was overriden by our extension with the patched ``pathto`` function. if sphinx.version_info >= (1, 8): from sphinx.builders.html import setup_js_tag_helper app.connect('html-page-context', setup_js_tag_helper) if sphinx.version_info >= (4, 0): # CSS are now added via a ``css_tag`` # https://github.com/sphinx-doc/sphinx/pull/8643 from sphinx.builders.html import setup_css_tag_helper app.connect('html-page-context', setup_css_tag_helper) app.add_env_collector(OrphanMetadataCollector) return { 'version': __version__, 'parallel_read_safe': True, 'parallel_write_safe': True, } sphinx-notfound-page-0.8/notfound/utils.py000066400000000000000000000064641414245066700210270ustar00rootroot00000000000000import docutils import re import sphinx # Sphinx <2 Compatibility if sphinx.version_info >= (2, 0): from sphinx.builders.dirhtml import DirectoryHTMLBuilder else: from sphinx.builders.html import DirectoryHTMLBuilder def replace_uris(app, doctree, nodetype, nodeattr): """ Replace ``nodetype`` URIs from ``doctree`` to the proper one. If ``nodetype`` is an image (``docutils.nodes.image``), the URL is prefixed with ``Builder.imagedir`` and the original image path is added to ``Builder.images`` so it's copied using Sphinx's internals before finalizing the building. :param app: Sphinx Application :type app: sphinx.application.Sphinx :param doctree: doctree representing the document :type doctree: docutils.nodes.document :param nodetype: type of node to replace URIs :type nodetype: docutils.nodes.Node :param nodeattr: node attribute to be replaced :type nodeattr: str """ # https://github.com/sphinx-doc/sphinx/blob/2adeb68af1763be46359d5e808dae59d708661b1/sphinx/environment/adapters/toctree.py#L260-L266 for node in doctree.traverse(nodetype): uri = olduri = node.attributes.get(nodeattr) # somepage.html (or ../sompage.html) if isinstance(app.builder, DirectoryHTMLBuilder): # When the builder is ``DirectoryHTMLBuilder``, refuri will be # ``../somepage.html``. In that case, we want to remove the # initial ``../`` to make valid links if uri.startswith('../'): uri = uri.replace('../', '') if re.match('^https?://', uri): # allow non-local URLs for resources continue imagedir = '' if nodetype is docutils.nodes.image: # Prefix the URL with ``Builder.imagedir`` to use the internal's # Sphinx image handling if the node is an image imagedir = '{imagedir}/'.format( imagedir=app.builder.imagedir, ) # The image is copied into ``app.builder.imagedir`` without keeping # the directory structure, so we need only the filename for the # correct link uri = olduri.split('/')[-1] if app.config.notfound_no_urls_prefix: uri = '/{imagedir}{filename}'.format( filename=uri, imagedir=imagedir, ) else: uri = '{prefix}{imagedir}{filename}'.format( prefix=app.config.notfound_urls_prefix or '/', imagedir=imagedir, filename=uri, ) node.replace_attr(nodeattr, uri) # Force adding the image to the builder so it's copied at ``Builder.copy_image_files`` # https://github.com/sphinx-doc/sphinx/blob/5ce5c2c3156c53c1f1b758c38150e48080138b15/sphinx/builders/html.py#L721 # We need to do this at this point because ``Builder.post_process_images`` # does not add it automatically as the path does not match. # https://github.com/sphinx-doc/sphinx/blob/5ce5c2c3156c53c1f1b758c38150e48080138b15/sphinx/builders/__init__.py#L189 if nodetype is docutils.nodes.image: if all([ not olduri.startswith('data:'), '://' not in olduri, ]): app.builder.images[olduri] = olduri.split('/')[-1] sphinx-notfound-page-0.8/prospector.yml000077700000000000000000000000001414245066700246002common/prospector.ymlustar00rootroot00000000000000sphinx-notfound-page-0.8/pytest.ini000066400000000000000000000011641414245066700175020ustar00rootroot00000000000000[pytest] markers = sphinx environ filterwarnings = ignore:'U' mode is deprecated:DeprecationWarning: ignore:sphinx.builders.html.DirectoryHTMLBuilder is now deprecated.*:DeprecationWarning: ignore:sphinx.builders.html.DirectoryHTMLBuilder is now deprecated.*:PendingDeprecationWarning: ignore:notfound_default_language is deprecated. Use "notfound_urls_prefix" instead.:DeprecationWarning: ignore:notfound_default_version is deprecated. Use "notfound_urls_prefix" instead.:DeprecationWarning: ignore:notfound_no_urls_prefix is deprecated. Use "notfound_urls_prefix" instead.:DeprecationWarning: sphinx-notfound-page-0.8/setup.py000066400000000000000000000024741414245066700171700ustar00rootroot00000000000000import notfound import setuptools with open('README.rst', 'r') as fh: long_description = fh.read() setuptools.setup( name='sphinx-notfound-page', version=notfound.__version__, author='Manuel Kaufmann', author_email='humitos@gmail.com', description='Sphinx extension to build a 404 page with absolute URLs', url='https://github.com/readthedocs/sphinx-notfound-page', license='MIT', packages=setuptools.find_packages(), long_description=long_description, long_description_content_type='text/x-rst', include_package_data=True, zip_safe=False, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Framework :: Sphinx', 'Framework :: Sphinx :: Extension', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Topic :: Documentation :: Sphinx', 'Topic :: Software Development :: Documentation', ], keywords='notfound 404 page sphinx', project_urls={ 'Documentation': 'https://sphinx-notfound-page.readthedocs.io/', 'Source': 'https://github.com/readthedocs/sphinx-notfound-page', 'Tracker': 'https://github.com/readthedocs/sphinx-notfound-page/issues', }, ) sphinx-notfound-page-0.8/tasks.py000077700000000000000000000000001414245066700221302common/tasks.pyustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/000077500000000000000000000000001414245066700166115ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/conftest.py000066400000000000000000000021021414245066700210030ustar00rootroot00000000000000import pytest @pytest.fixture(scope='function') def environ(request, monkeypatch): """ Fixture to define environment variables before Sphinx App is created. The test case needs to be marked as ``@pytest.mark.environ(VARIABLE='value')`` with all the environment variables wanted to define. Also, the test has to use this fixture before the ``app`` once to have effect. This idea is borrowed from, https://github.com/sphinx-doc/sphinx/blob/3f6565df6323534e69d797003d8cb20e99c2c255/sphinx/testing/fixtures.py#L30 """ if hasattr(request.node, 'iter_markers'): # pytest-3.6.0 or newer markers = request.node.iter_markers('environ') else: markers = request.node.get_marker('environ') pargs = {} kwargs = {} if markers is not None: # to avoid stacking positional args for info in reversed(list(markers)): for i, a in enumerate(info.args): pargs[i] = a kwargs.update(info.kwargs) for name, value in kwargs.items(): monkeypatch.setenv(name, value) sphinx-notfound-page-0.8/tests/examples/000077500000000000000000000000001414245066700204275ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/examples/404rst/000077500000000000000000000000001414245066700214675ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/examples/404rst/404.rst000066400000000000000000000014511414245066700225310ustar00rootroot00000000000000========================== Oh, oh - Page not found ========================== This is a custom 404.rst file. This file should be rendered instead of the default one. Variables Sphinx substitution should be allowed here. Example, version: |version|. Including an image using ``.. image::`` directive, should also make the extension to fix the URIs. .. image:: test.png :alt: An image .. image:: images/loudly-crying-face.png :alt: Image from folder Also, using ``.. figure::`` should work as well. .. figure:: test.png Description. Including an image using an absolute URL should not be modified by the extension: .. image:: https://read-the-docs-guidelines.readthedocs-hosted.com/_images/logo-dark.png :alt: Read the Docs Logo .. image:: https.png :alt: PATH looking as an URL sphinx-notfound-page-0.8/tests/examples/404rst/conf.py000066400000000000000000000001301414245066700227600ustar00rootroot00000000000000# conf.py to run tests master_doc = 'index' extensions = [ 'notfound.extension', ] sphinx-notfound-page-0.8/tests/examples/404rst/https.png000066400000000000000000000001241414245066700233340ustar00rootroot00000000000000This is just a file to be found by Sphinx when using ".. figure::" and do not fail. sphinx-notfound-page-0.8/tests/examples/404rst/images/000077500000000000000000000000001414245066700227345ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/examples/404rst/images/loudly-crying-face.png000066400000000000000000000317211414245066700271430ustar00rootroot00000000000000PNG  IHDRg-gAMA a cHRMz&u0`:pQ<tIME $FbKGD2IDATx]xeW)]*I{"鈴BR!tD "A))@Hgyݖݽpw>(~;߻73C>>>>>O}0^`3J12^eftatc ` xљърQcgseYv SrnH>$_!j=!x:U! ψg3Z] 'Či!h̄ 65h;L댒ӯlU3s8Gv d3!B66D2@vcpʳ!KbeZh5/Y *O#ZִLI/NxN%clǨ 2IhC-j)w4-ZL?L).v$NFAߨB++жə c0Fcح di!$yBJL$tN;-q=4, m^?ǵNWލs)~Hۼ`0Fc xM dAVZH\E8+جbAlO A˞2w4QzD#}Vʴ{\)0H,زl3YLx6<!4ۅ uDbAW"_^R b9~H *9$s{T ] RxNAvHXB(+P!!2Fd X$ ?7fߌ <=%Jȩ]I<@_6;Q\xf<{ʪAv&L"%ݼ:Nh1XQO%sN<5"!B% C&0n&GpK31Rp R˲k~xC|;VvW嬥 @dY&ўo(#+W݈W'QjԥA[=W%0?+=AC&jYBI:]BBdCVmҲaK@äCLlE ^|$l #JJBTjP 1DזwXKAgzN4,LQ-elao'\^6jĆH~' yh ,j7SDd2ɟa6)4LKum3L?o[+s6?O7ьfj[L˘dE&|,2QL\1/ J^dӓH/ōZol ;#4OO朴y}`ڙRi3M&٘_LsPO㞗*ZXX$+(rUA&+diL߈0I3ъ&Y1*Ӗ̴s%{*h溵iA7/KC:_@W`h /-$f 2bJcX6b$_ (Pwa+@ՃMT&=µ]~%zfvے 47gr| 3m.b *GmwDP )y. m']0gzò;gbM8;*y#>(6v[F~HGSj ؔ3{X cM²k2{N>=l/VȖA!k.ЦЧJFv=F=67<߼B^=>xz崵 !ad@JG.;#"ѯo B놚(8µrf3&lȊ 7S*ts-8 iذFXMd@QdҼ#X[]o%ƶ5uzB-O3dÀ2NRj3ol)B2txK|\l`(O:0(` 4XpYA%)r;Cja359o*LUh4k7NVi=$"UՏ굎dӰ|.ڙEhӂHzAIjl 'Xyp"` "S[[u ١4jwm p*hhO0SAO%rԪ12*E&N#P.;)|[~ӗsҷY ZP" \l!,dѼ3x 5+OQɂ@xKA#f\Si\1&x AJz}-Uټ!&yDŽ uHBIbPLRL۶t6we{ [AdPSXpӫ=㘀Ie=z-j;T%!4`03x{ Gg .Y7L {Raeqd:5ݮRٜ W%! 7:jXu-wnaq\GG u< #qd L $ HBܳM3]{c4_&&A6Z ظWEݯSxu Q$!=\ܚ[W*0@l9fAe37M&*_cz)|@!)N ش-YcVk OTyLO½Boޖ -hM:RMl疦*MVd0<1G1DY9eE?,^,$*qōtJ!j ?M% }W*hJI>CuP j5SWz,/٢g%9EM3 GDMjD+-VPbV6圀Mz&vƾِ^/8u@AI2N*pχ=IY^ZPjCkQX$=\.ۂ{f]gOzwJ\m93f-e&{ Mj% r?`f9G締RCFIiwFn۫rӗ@Afy-N{Lj%m Sأ݌ m;;G:)GF+Cs4H  -Tua8sTpi+_/K{? \Q̣p􁲀i3vĶ?i9,Vj#6~ԧt˃JQ./{-N.#VC%ض 5`[{9a7AzJڨL+ DYI@hh[glŶ%U=e]!# l;-QrІbWyT!%,.M<-Z mH خtzql`:pleVFAC/{ Lno ض:A' wFmi@vF o>tV{m$&ɢ  mmjS[@4je9hy-< A~gaC[Z|b[-yV` CVF#G -(Sst1 hb2;FCJÁ9q$˶`hOykκ"8}x7HA[y H;hBLFX9BpZ2O\ߊ˥Z0z>Swm>Ϳ|`o[N}DYZ|oq :YkezQs=M{A3 \QHF0&k"][f$ #?CP^~=O~ Mc@Ԕu&[az'A8|h wpM\:jS+uD@;}zۢ<?̧Y+X2YBtwYF#GlZ==tg ?c˟i`3ukd`'sKb̖kڸe{o5$K˪RjeKtta J^9MXZB*0E~\Jb&]ACں"8*N4}4SozyC3Mj:-' %VB{Ǣ4t&.gVF;BtdakUٸ pՔ|yQ\Amp/7֖6UkޟH) N37,M+MYܶ0cX+~*{P :Q'~nOp$nbQRM9/en`dc%}>$o4ӵe`õPZkx}Jh܋ǝi]]@Pm) 1c0F1KQ> ʨyAu.1np|ٙhrTO]pEF}]㔸%A@nDfux԰Z0y6%ob^?|@]?ފ/N~~~/ 1iln1& ccNOG2\+cuФF=Ӯy}(GΐozX\Gκb9ЭHlUPkWx&--lleC@^z ,Hywֽ.I۫ S J6l5ӅsoPOjfY@c:PH6<{Zh}PB1b5L%oAu#2#|6{$29Ub!Êe( ":>uϞ^w48h-uoh9Щ=f4 }…rk>lѫ6uC #wd4k }nv|&,SlӻPo@`Ef'Y 3 !:1gS}h37|c K-Y5B@+/؉ڝT*2dCnNG+/FiOBge]x7D?GFΤ/elksnRdL@&DL6`. l7WgO@ ItMWЦyVth9+EߘԴlsh,[Ѕ F 4b. usz^j"ЌRjK@LMjK_Zw} 5giGXɣ"=B> floDfJ?^ҏ҄ctJ4 ]$KWݲg2 h8cO@d xO8.٣?tl{'a s{wGqBRA}1@BX_%)v4`#SA"MB df:!&? l._u!S\}]U:ea sz8b*z c*d̕į^X p(g!i (&~WgZ(03) : `i}Nk+f=t,! CĂc{dce,(NRȻ"O p1{E 7>БtRZƽ7[t0I{$lY0'qHI{X7SLqT)P}6zC JCd{~nu< k@]`Th_Fp0i?R2tXz,% (5?8Y.lB.+J8 Xud2Jr~rz}9zgn|WdU[ XJo!JM_lxt9JUFb#`ӦY+7gx2NGRƟeAgJŃM` ĺ2-雄&=; 3"^,< OEi8yDo෸kIJj'`3 6< By~N[LR cx)Nmӱǔz42Ζ32tzz== , -deeتF G[9 !tq_4DU ~kZ&mՠN# ;LK)MHJo{,vHf>jwKZwcѵd;7B1'k3{G^{31I&4c{ѣÑShАdc]_&` g/LoOBx!XBT;!zigQhŘh2}7vfz)}HgEnFF}e:O{^άE*@R-/Ngmomg.䣋t*ǎF3ŕ#Z~xuj2ڤx^cf(H'ɨꙿW]OW!쳄;JRFt03B"c4gHu@HQd;] ;}8xkH(IHFQA =`\!ً"):5KǗ%lHrY(Ihveq6F,@$`)@V5I(=k$jwoxc1$*E @DdcVD 1y$ɗqPmJ"|A]b\֍)b9\&2B6y)I{hA,3A&xQWiIe$(w'M>XX0FD/lecY9,!e!?h@b?[$tnqHk< ؃/7Cj{EpcH=_|ӓ&*-WOM0Lc撊MNG~t aokx,#&D|`r]Z$$KFjqT~e{#R誫 pPpm/6N@#Y'vJˌV'[<b07eu-E۷r;ܚW[4V# R%ϨuiO'RJ$ߨ7W%a'3+lB6[ T\yGh_lA#Z]6> l<ي6$|\̒It e.{լƎp0M1Y:>&-=Gh駱psCʖb >lVGDeŋeOl҅~xq\OcZvq+{xWf!(L̞>/QdE`kGsxhK'ֽ̄X<9F/Q~n ^X X32el=|aO]yb϶Sخ.u!]jD ;@&+)b.1P4#6_JKM3H%[b=- a|X([7Җxrqȝm.:DZ2(=t1,4Q^V(F~M)FT+FgCx$@ ߩϨ̈``?"-$febS0^1s@Dxc{,f$nVzpmdGM.⦨){bv703^ȱs"\0F41ts#ALD Z,8ib@$\q}v8'D{Iq {n/IFHG3H'm@FU,(4E1Pj^'8i椷F6O1 1Qhh%EU [S}}|}|}GX%tEXtdate:create2018-08-07T10:26:11+00:00¿%tEXtdate:modify2018-08-07T10:26:11+00:00YtEXtSoftwareAdobe ImageReadyqe<IENDB`sphinx-notfound-page-0.8/tests/examples/404rst/index.rst000066400000000000000000000000521414245066700233250ustar00rootroot00000000000000404 rst ======= This is an example page. sphinx-notfound-page-0.8/tests/examples/404rst/test.png000066400000000000000000000001241414245066700231510ustar00rootroot00000000000000This is just a file to be found by Sphinx when using ".. figure::" and do not fail. sphinx-notfound-page-0.8/tests/examples/default/000077500000000000000000000000001414245066700220535ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/examples/default/_templates/000077500000000000000000000000001414245066700242105ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/examples/default/_templates/template.html000066400000000000000000000004311414245066700267070ustar00rootroot00000000000000{# https://github.com/sphinx-doc/sphinx/blob/master/sphinx/themes/basic/page.html #} {%- extends "layout.html" %} {% block body %} {{ body }}

This is rendered using a custom template

... which has a custom context as well: {{ special_setting }}

{% endblock %} sphinx-notfound-page-0.8/tests/examples/default/chapter-i.rst000066400000000000000000000001111414245066700244520ustar00rootroot00000000000000Chapter I ========= This is another chapter in a different source file. sphinx-notfound-page-0.8/tests/examples/default/chapter.rst000066400000000000000000000000711414245066700242310ustar00rootroot00000000000000Chapter ======= This a chapter included in the toctree. sphinx-notfound-page-0.8/tests/examples/default/conf.py000066400000000000000000000002741414245066700233550ustar00rootroot00000000000000# conf.py to run tests master_doc = 'index' extensions = [ 'notfound.extension', ] html_favicon = 'images/favicon.png' html_logo = 'images/logo.svg' templates_path = ['_templates'] sphinx-notfound-page-0.8/tests/examples/default/images/000077500000000000000000000000001414245066700233205ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/examples/default/images/favicon.png000066400000000000000000000002511414245066700254510ustar00rootroot00000000000000PNG  IHDR pIDATHct `%`r ǣn׆Ɯi17%+NA`n\A7h z"+0 dJg F)A%ɔ8It[8% TEIENDB`sphinx-notfound-page-0.8/tests/examples/default/images/logo.svg000066400000000000000000000370611414245066700250100ustar00rootroot00000000000000 image/svg+xml sphinx-notfound-page-0.8/tests/examples/default/index.rst000066400000000000000000000001231414245066700237100ustar00rootroot00000000000000Example page ============ This is an example page. .. toctree:: :glob: * sphinx-notfound-page-0.8/tests/examples/extension/000077500000000000000000000000001414245066700224435ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/examples/extension/conf.py000066400000000000000000000003561414245066700237460ustar00rootroot00000000000000# conf.py to run tests master_doc = 'index' extensions = [ 'notfound.extension', ] templates_path = ['_templates'] def setup(app): app.add_css_file('css_added_by_extension.css') app.add_js_file('js_added_by_extension.js') sphinx-notfound-page-0.8/tests/examples/extension/index.rst000066400000000000000000000001231414245066700243000ustar00rootroot00000000000000Example page ============ This is an example page. .. toctree:: :glob: * sphinx-notfound-page-0.8/tests/examples/parallel-build/000077500000000000000000000000001414245066700233205ustar00rootroot00000000000000sphinx-notfound-page-0.8/tests/examples/parallel-build/conf.py000066400000000000000000000001401414245066700246120ustar00rootroot00000000000000""" Sample ``conf.py``. """ master_doc = 'index' extensions = [ 'notfound.extension', ] sphinx-notfound-page-0.8/tests/examples/parallel-build/five.rst000066400000000000000000000000271414245066700250020ustar00rootroot00000000000000======= Five ======= sphinx-notfound-page-0.8/tests/examples/parallel-build/four.rst000066400000000000000000000000271414245066700250240ustar00rootroot00000000000000======= Four ======= sphinx-notfound-page-0.8/tests/examples/parallel-build/index.rst000066400000000000000000000004561414245066700251660ustar00rootroot00000000000000Samples for substitution directives =================================== .. This is a test of parallel document builds. You need at least 5 documents. See: https://github.com/adamtheturtle/sphinx-substitution-extensions/pull/173 .. toctree:: :hidden: one two three four five sphinx-notfound-page-0.8/tests/examples/parallel-build/one.rst000066400000000000000000000000221414245066700246250ustar00rootroot00000000000000===== One ===== sphinx-notfound-page-0.8/tests/examples/parallel-build/three.rst000066400000000000000000000000301414245066700251520ustar00rootroot00000000000000======= Three ======= sphinx-notfound-page-0.8/tests/examples/parallel-build/two.rst000066400000000000000000000000221414245066700246550ustar00rootroot00000000000000===== Two ===== sphinx-notfound-page-0.8/tests/test_urls.py000066400000000000000000000544101414245066700212130ustar00rootroot00000000000000# -*- coding: utf-8 -*- import os import docutils import pytest import sphinx import shutil import subprocess import warnings from utils import _get_css_html_link_tag, _get_js_html_link_tag srcdir = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'examples', 'default', ) rstsrcdir = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'examples', '404rst', ) extensiondir = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'examples', 'extension', ) @pytest.fixture(autouse=True, scope='function') def remove_sphinx_build_output(): """Remove _build/ folder, if exist.""" for path in (srcdir, rstsrcdir): build_path = os.path.join(path, '_build') if os.path.exists(build_path): shutil.rmtree(build_path) @pytest.mark.sphinx(srcdir=srcdir) def test_parallel_build(): # TODO: migrate to `app.build(..., parallel=2)` after merging # https://github.com/sphinx-doc/sphinx/pull/8257 subprocess.check_call('sphinx-build -j 2 -W -b html tests/examples/parallel-build build', shell=True) @pytest.mark.sphinx(srcdir=srcdir) def test_404_page_created(app, status, warning): app.build() path = app.outdir / '404.html' assert path.exists() @pytest.mark.sphinx(srcdir=srcdir) def test_default_settings(app, status, warning): app.build() path = app.outdir / '404.html' assert path.exists() content = open(path).read() chunks = [ '

Page not found

', "Unfortunately we couldn't find the content you were looking for.", 'Page not found — Python documentation', # favicon and logo '', '', # sidebar URLs '

Python

', '