├── requirements ├── test.txt ├── default.txt └── pkgutils.txt ├── sphinx_celery ├── tests │ └── __init__.py ├── theme.conf ├── utils.py ├── setting_crossref.py ├── signal_crossref.py ├── autodocargspec.py ├── templates │ └── page.html ├── builders.py ├── __init__.py ├── github_issues.py ├── configcheck.py ├── apicheck.py ├── static │ └── celery.css_t └── conf.py ├── setup.cfg ├── AUTHORS ├── extra ├── release │ └── removepyc.sh └── appveyor │ ├── run_with_compiler.cmd │ └── install.ps1 ├── .coveragerc ├── .editorconfig ├── MANIFEST.in ├── .bumpversion.cfg ├── .gitignore ├── .cookiecutterrc ├── .pre-commit-config.yaml ├── tox.ini ├── .github └── workflows │ └── codeql.yml ├── README.rst ├── LICENSE ├── Changelog ├── setup.py └── Makefile /requirements/test.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sphinx_celery/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements/default.txt: -------------------------------------------------------------------------------- 1 | Sphinx>=2.0.0 2 | -------------------------------------------------------------------------------- /sphinx_celery/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = celery.css 4 | 5 | [options] 6 | -------------------------------------------------------------------------------- /sphinx_celery/utils.py: -------------------------------------------------------------------------------- 1 | __all__ = ['bytes_if_py2'] 2 | 3 | 4 | def bytes_if_py2(s): 5 | return s 6 | -------------------------------------------------------------------------------- /requirements/pkgutils.txt: -------------------------------------------------------------------------------- 1 | setuptools>=59.2.0 2 | wheel>=0.37.0 3 | flake8>=4.0.1 4 | tox>=3.24.4 5 | bumpversion 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [nosetests] 2 | where = sphinx_celery/tests 3 | 4 | [wheel] 5 | universal = 1 6 | 7 | [isort] 8 | profile=black 9 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The Celery theme was created by Armin Ronacher. 2 | 3 | Rest of contributors: 4 | - Ask Solem 5 | 6 | -------------------------------------------------------------------------------- /extra/release/removepyc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | (cd "${1:-.}"; 3 | find . -name "*.pyc" | xargs rm -- 2>/dev/null) || echo "ok" 4 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = 1 3 | cover_pylib = 0 4 | include=*sphinx_celery/* 5 | omit = sphinx_celery.tests.* 6 | 7 | [report] 8 | omit = 9 | */python?.?/* 10 | */site-packages/* 11 | */pypy/* 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [Makefile] 14 | indent_style = tab 15 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst Changelog LICENSE 2 | recursive-include extra README *.py 3 | recursive-include requirements *.txt 4 | recursive-include sphinx_celery *.conf 5 | recursive-include sphinx_celery *.css_t 6 | recursive-include sphinx_celery *.html 7 | recursive-include sphinx_celery *.js 8 | recursive-include sphinx_celery *.css 9 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 2.1.3 3 | commit = True 4 | tag = True 5 | parse = (?P\d+)\.(?P\d+)\.(?P\d+)(?P[a-z]+)? 6 | serialize = 7 | {major}.{minor}.{patch}{releaselevel} 8 | {major}.{minor}.{patch} 9 | 10 | [bumpversion:file:sphinx_celery/__init__.py] 11 | 12 | [bumpversion:file:README.rst] 13 | -------------------------------------------------------------------------------- /sphinx_celery/setting_crossref.py: -------------------------------------------------------------------------------- 1 | from .utils import bytes_if_py2 2 | 3 | 4 | def setup(app): 5 | app.add_crossref_type( 6 | directivename=bytes_if_py2('setting'), 7 | rolename=bytes_if_py2('setting'), 8 | indextemplate=bytes_if_py2('pair: %s; setting'), 9 | ) 10 | 11 | return { 12 | 'parallel_read_safe': True 13 | } 14 | -------------------------------------------------------------------------------- /sphinx_celery/signal_crossref.py: -------------------------------------------------------------------------------- 1 | from .utils import bytes_if_py2 2 | 3 | 4 | def setup(app): 5 | app.add_crossref_type( 6 | directivename=bytes_if_py2('signal'), 7 | rolename=bytes_if_py2('signal'), 8 | indextemplate=bytes_if_py2('pair: %s; signal'), 9 | ) 10 | 11 | return { 12 | 'parallel_read_safe': True 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *$py.class 4 | *~ 5 | .*.sw[pon] 6 | dist/ 7 | *.egg-info 8 | *.egg 9 | *.egg/ 10 | doc/__build/* 11 | build/ 12 | .build/ 13 | pip-log.txt 14 | .directory 15 | erl_crash.dump 16 | *.db 17 | Documentation/ 18 | .tox/ 19 | .ropeproject/ 20 | .project 21 | .pydevproject 22 | .idea/ 23 | .coverage 24 | celery/tests/cover/ 25 | .ve* 26 | cover/ 27 | .vagrant/ 28 | *.sqlite3 29 | .python-version 30 | .env 31 | -------------------------------------------------------------------------------- /.cookiecutterrc: -------------------------------------------------------------------------------- 1 | default_context: 2 | 3 | email: 'ask@celeryproject.org' 4 | full_name: 'Ask Solem' 5 | github_username: 'celery' 6 | project_name: 'sphinx_celery' 7 | project_short_description: 'Sphinx Celery Theme and Utilities' 8 | project_slug: 'sphinx_celery' 9 | version: '1.0.0' 10 | year: '2016' 11 | -------------------------------------------------------------------------------- /sphinx_celery/autodocargspec.py: -------------------------------------------------------------------------------- 1 | from sphinx.ext import autodoc as _autodoc 2 | from sphinx.util import inspect 3 | 4 | 5 | def wrapped_getargspec(fun, *args, **kwargs): 6 | while 1: 7 | try: 8 | wrapped = fun.__wrapped__ 9 | if wrapped is fun: 10 | break 11 | fun = wrapped 12 | except AttributeError: 13 | break 14 | return inspect.getargspec(fun, *args, **kwargs) 15 | 16 | 17 | _autodoc.getargspec = wrapped_getargspec 18 | 19 | 20 | def setup(app): 21 | app.require_sphinx('1.0') 22 | 23 | return { 24 | 'parallel_read_safe': True 25 | } 26 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/asottile/pyupgrade 3 | rev: v3.19.1 4 | hooks: 5 | - id: pyupgrade 6 | args: ["--py38-plus"] 7 | 8 | - repo: https://github.com/PyCQA/flake8 9 | rev: 7.1.1 10 | hooks: 11 | - id: flake8 12 | 13 | - repo: https://github.com/asottile/yesqa 14 | rev: v1.5.0 15 | hooks: 16 | - id: yesqa 17 | 18 | - repo: https://github.com/pre-commit/pre-commit-hooks 19 | rev: v5.0.0 20 | hooks: 21 | - id: check-merge-conflict 22 | - id: check-toml 23 | - id: check-yaml 24 | - id: mixed-line-ending 25 | 26 | - repo: https://github.com/pycqa/isort 27 | rev: 5.13.2 28 | hooks: 29 | - id: isort 30 | -------------------------------------------------------------------------------- /sphinx_celery/templates/page.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 | 5 | {% if version >= version_dev %} 6 |

7 | This document is for {{ project }}'s development version, which can be 8 | significantly different from previous releases. Get the stable docs here: 9 | 10 | {{ version_stable }}. 11 |

12 | {% else %} 13 |

14 | This document describes the current stable version of {{project}} ({{ version }}). 15 | For development docs, 16 | go here. 17 |

18 | {% endif %} 19 | 20 |
21 | {{ body }} 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3.8,3.9,3.10,3.11,3.12,pypy3,flake8 3 | 4 | [testenv] 5 | deps= 6 | -r{toxinidir}/requirements/test.txt 7 | 8 | sitepackages = False 9 | recreate = False 10 | commands = {toxinidir}/extra/release/removepyc.sh {toxinidir} 11 | nosetests -xsv --with-coverage \ 12 | --cover-inclusive --cover-erase [] 13 | 14 | basepython = 15 | 16 | 3.12: python3.12 17 | 3.11: python3.11 18 | 3.10: python3.10 19 | 3.9: python3.9 20 | 3.8: python3.8 21 | pypy3: pypy3 22 | 23 | [testenv:docs] 24 | deps = -r{toxinidir}/requirements/docs.txt 25 | commands = 26 | sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/linkcheck 27 | 28 | [testenv:flake8] 29 | deps = -r{toxinidir}/requirements/pkgutils.txt 30 | commands = 31 | flake8 --ignore=X999 {toxinidir}/sphinx_celery 32 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | runs-on: blacksmith-4vcpu-ubuntu-2204 13 | permissions: 14 | actions: read 15 | contents: read 16 | security-events: write 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | language: [ python ] 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v3 26 | 27 | - name: Initialize CodeQL 28 | uses: github/codeql-action/init@v2 29 | with: 30 | languages: ${{ matrix.language }} 31 | queries: +security-and-quality 32 | 33 | - name: Autobuild 34 | uses: github/codeql-action/autobuild@v2 35 | 36 | - name: Perform CodeQL Analysis 37 | uses: github/codeql-action/analyze@v2 38 | with: 39 | category: "/language:${{ matrix.language }}" 40 | -------------------------------------------------------------------------------- /sphinx_celery/builders.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pickle 3 | import re 4 | 5 | from sphinx.builders import Builder 6 | 7 | ERR_INVALID_REGEX = 'Invalid regex {0!r} in apicheck_ignore_modules: {1!r}' 8 | 9 | 10 | class BaseBuilder(Builder): 11 | 12 | def get_outdated_docs(self): 13 | return f'{self.name} overview' 14 | 15 | def finish(self): 16 | picklepath = os.path.join(self.outdir, self.pickle_filename) 17 | with open(picklepath, mode='wb') as fh: 18 | pickle.dump(self.as_dict(), fh) 19 | 20 | def compile_regex(self, regex): 21 | if not regex.startswith('^'): 22 | regex = f'^{regex}' 23 | if not regex.endswith('$'): 24 | regex = f'{regex}$' 25 | try: 26 | return re.compile(regex) 27 | except Exception as exc: 28 | self.warn(ERR_INVALID_REGEX.format(regex, exc)) 29 | 30 | def compile_regexes(self, regexes): 31 | return [self.compile_regex(regex) for regex in regexes] 32 | -------------------------------------------------------------------------------- /sphinx_celery/__init__.py: -------------------------------------------------------------------------------- 1 | """Sphinx Celery Theme.""" 2 | 3 | import os 4 | import re 5 | from collections import namedtuple 6 | 7 | __version__ = '2.1.3' 8 | __author__ = 'Ask Solem' 9 | __contact__ = 'ask@celeryproject.org' 10 | __homepage__ = 'http://github.com/celery/sphinx_celery' 11 | __docformat__ = 'restructuredtext' 12 | 13 | # -eof meta- 14 | 15 | __all__ = ['get_html_templates_path', 'get_html_theme_path', 'setup'] 16 | 17 | version_info_t = namedtuple('version_info_t', ( 18 | 'major', 'minor', 'micro', 'releaselevel', 'serial', 19 | )) 20 | 21 | # bumpversion can only search for {current_version} 22 | # so we have to parse the version here. 23 | _temp = re.match( 24 | r'(\d+)\.(\d+).(\d+)(.+)?', __version__).groups() 25 | VERSION = version_info = version_info_t( 26 | int(_temp[0]), int(_temp[1]), int(_temp[2]), _temp[3] or '', '') 27 | del (_temp) 28 | del (re) 29 | 30 | 31 | def get_html_theme_path(): 32 | return os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 33 | 34 | 35 | def get_html_templates_path(): 36 | return os.path.join( 37 | os.path.abspath(os.path.dirname(__file__)), 38 | 'templates', 39 | ) 40 | 41 | 42 | def setup(app): 43 | app.add_html_theme( 44 | 'sphinx_celery', 45 | os.path.abspath(os.path.dirname(__file__)), 46 | ) 47 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ===================================================================== 2 | Celery Sphinx Utilities 3 | ===================================================================== 4 | 5 | :Version: 2.1.3 6 | :Download: http://pypi.python.org/pypi/sphinx_celery/ 7 | :Source: http://github.com/celery/sphinx_celery/ 8 | :DeepWiki: |deepwiki| 9 | :Keywords: Sphinx, documentation, python 10 | 11 | .. |deepwiki| image:: https://devin.ai/assets/deepwiki-badge.png 12 | :alt: Ask http://DeepWiki.com 13 | :target: https://deepwiki.com/celery/sphinx_celery 14 | :width: 125px 15 | 16 | About 17 | ===== 18 | 19 | This project provides the Celery sphinx theme and common Sphinx utilities. 20 | 21 | .. _installation: 22 | 23 | Installation 24 | ============ 25 | 26 | You can install sphinx_celery either via the Python Package Index (PyPI) 27 | or from source. 28 | 29 | To install using `pip`,:: 30 | 31 | $ pip install -U sphinx_celery 32 | 33 | To install using `easy_install`,:: 34 | 35 | $ easy_install -U sphinx_celery 36 | 37 | .. _installing-from-source: 38 | 39 | Downloading and installing from source 40 | -------------------------------------- 41 | 42 | Download the latest version of sphinx_celery from 43 | http://pypi.python.org/pypi/sphinx_celery/ 44 | 45 | You can install it by doing the following,:: 46 | 47 | $ tar xvfz sphinx_celery.0.0.tar.gz 48 | $ cd sphinx_celery.0.0 49 | $ python setup.py build 50 | # python setup.py install 51 | 52 | The last command must be executed as a privileged user if 53 | you are not currently using a virtualenv. 54 | 55 | .. _installing-from-git: 56 | 57 | Using the development version 58 | ----------------------------- 59 | 60 | With pip 61 | ~~~~~~~~ 62 | 63 | You can install the latest snapshot of sphinx_celery using the following 64 | pip command:: 65 | 66 | $ pip install https://github.com/celery/sphinx_celery/zipball/master#egg=sphinx_celery 67 | 68 | -------------------------------------------------------------------------------- /extra/appveyor/run_with_compiler.cmd: -------------------------------------------------------------------------------- 1 | :: To build extensions for 64 bit Python 3, we need to configure environment 2 | :: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: 3 | :: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) 4 | :: 5 | :: To build extensions for 64 bit Python 2, we need to configure environment 6 | :: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: 7 | :: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) 8 | :: 9 | :: 32 bit builds do not require specific environment configurations. 10 | :: 11 | :: Note: this script needs to be run with the /E:ON and /V:ON flags for the 12 | :: cmd interpreter, at least for (SDK v7.0) 13 | :: 14 | :: More details at: 15 | :: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows 16 | :: http://stackoverflow.com/a/13751649/163740 17 | :: 18 | :: Author: Olivier Grisel 19 | :: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ 20 | @ECHO OFF 21 | 22 | SET COMMAND_TO_RUN=%* 23 | SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows 24 | 25 | SET MAJOR_PYTHON_VERSION="%PYTHON_VERSION:~0,1%" 26 | IF %MAJOR_PYTHON_VERSION% == "2" ( 27 | SET WINDOWS_SDK_VERSION="v7.0" 28 | ) ELSE IF %MAJOR_PYTHON_VERSION% == "3" ( 29 | SET WINDOWS_SDK_VERSION="v7.1" 30 | ) ELSE ( 31 | ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" 32 | EXIT 1 33 | ) 34 | 35 | IF "%PYTHON_ARCH%"=="64" ( 36 | ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture 37 | SET DISTUTILS_USE_SDK=1 38 | SET MSSdk=1 39 | "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% 40 | "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release 41 | ECHO Executing: %COMMAND_TO_RUN% 42 | call %COMMAND_TO_RUN% || EXIT 1 43 | ) ELSE ( 44 | ECHO Using default MSVC build environment for 32 bit architecture 45 | ECHO Executing: %COMMAND_TO_RUN% 46 | call %COMMAND_TO_RUN% || EXIT 1 47 | ) 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2016 Ask Solem & contributors. All rights reserved. 2 | 3 | SPHINX_CELERY is licensed under The BSD License (3 Clause, also known as 4 | the new BSD license). The license is an OSI approved Open Source 5 | license and is GPL-compatible(1). 6 | 7 | The license text can also be found here: 8 | http://www.opensource.org/licenses/BSD-3-Clause 9 | 10 | License 11 | ======= 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | * Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | * Neither the name of Ask Solem, nor the 21 | names of its contributors may be used to endorse or promote products 22 | derived from this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 26 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Ask Solem OR CONTRIBUTORS 28 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | POSSIBILITY OF SUCH DAMAGE. 35 | 36 | Documentation License 37 | ===================== 38 | 39 | The documentation portion of SPHINX_CELERY (the rendered contents of the 40 | "docs" directory of a software distribution or checkout) is supplied 41 | under the "Creative Commons Attribution-ShareAlike 4.0 42 | International" (CC BY-SA 4.0) License as described by 43 | http://creativecommons.org/licenses/by-sa/4.0/ 44 | 45 | Footnotes 46 | ========= 47 | (1) A GPL-compatible license makes it possible to 48 | combine SPHINX_CELERY with other software that is released 49 | under the GPL, it does not mean that we're distributing 50 | SPHINX_CELERY under the GPL license. The BSD license, unlike the GPL, 51 | let you distribute a modified version without making your 52 | changes open source. 53 | -------------------------------------------------------------------------------- /extra/appveyor/install.ps1: -------------------------------------------------------------------------------- 1 | # Sample script to install Python and pip under Windows 2 | # Authors: Olivier Grisel and Kyle Kastner 3 | # License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ 4 | 5 | $BASE_URL = "https://www.python.org/ftp/python/" 6 | $GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" 7 | $GET_PIP_PATH = "C:\get-pip.py" 8 | 9 | 10 | function DownloadPython ($python_version, $platform_suffix) { 11 | $webclient = New-Object System.Net.WebClient 12 | $filename = "python-" + $python_version + $platform_suffix + ".msi" 13 | $url = $BASE_URL + $python_version + "/" + $filename 14 | 15 | $basedir = $pwd.Path + "\" 16 | $filepath = $basedir + $filename 17 | if (Test-Path $filename) { 18 | Write-Host "Reusing" $filepath 19 | return $filepath 20 | } 21 | 22 | # Download and retry up to 5 times in case of network transient errors. 23 | Write-Host "Downloading" $filename "from" $url 24 | $retry_attempts = 3 25 | for($i=0; $i -lt $retry_attempts; $i++){ 26 | try { 27 | $webclient.DownloadFile($url, $filepath) 28 | break 29 | } 30 | Catch [Exception]{ 31 | Start-Sleep 1 32 | } 33 | } 34 | Write-Host "File saved at" $filepath 35 | return $filepath 36 | } 37 | 38 | 39 | function InstallPython ($python_version, $architecture, $python_home) { 40 | Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home 41 | if (Test-Path $python_home) { 42 | Write-Host $python_home "already exists, skipping." 43 | return $false 44 | } 45 | if ($architecture -eq "32") { 46 | $platform_suffix = "" 47 | } else { 48 | $platform_suffix = ".amd64" 49 | } 50 | $filepath = DownloadPython $python_version $platform_suffix 51 | Write-Host "Installing" $filepath "to" $python_home 52 | $args = "/qn /i $filepath TARGETDIR=$python_home" 53 | Write-Host "msiexec.exe" $args 54 | Start-Process -FilePath "msiexec.exe" -ArgumentList $args -Wait -Passthru 55 | Write-Host "Python $python_version ($architecture) installation complete" 56 | return $true 57 | } 58 | 59 | 60 | function InstallPip ($python_home) { 61 | $pip_path = $python_home + "/Scripts/pip.exe" 62 | $python_path = $python_home + "/python.exe" 63 | if (-not(Test-Path $pip_path)) { 64 | Write-Host "Installing pip..." 65 | $webclient = New-Object System.Net.WebClient 66 | $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH) 67 | Write-Host "Executing:" $python_path $GET_PIP_PATH 68 | Start-Process -FilePath "$python_path" -ArgumentList "$GET_PIP_PATH" -Wait -Passthru 69 | } else { 70 | Write-Host "pip already installed." 71 | } 72 | } 73 | 74 | function InstallPackage ($python_home, $pkg) { 75 | $pip_path = $python_home + "/Scripts/pip.exe" 76 | & $pip_path install $pkg 77 | } 78 | 79 | function main () { 80 | InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON 81 | InstallPip $env:PYTHON 82 | InstallPackage $env:PYTHON wheel 83 | } 84 | 85 | main 86 | -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | Changes 2 | ======= 3 | 4 | .. _version-2.0.0: 5 | 6 | 2.0.0 7 | ===== 8 | :release-date: 2019-06-12 3:00 p.m. UTC+3 9 | 10 | - Fix support for Sphinx 2.0 11 | - Drop support for Sphinx < 2.0 12 | 13 | .. _version-1.4.8: 14 | 15 | 1.4.8 16 | ===== 17 | :release-date: 2019-03-29 12:28 p.m. UTC-8 18 | 19 | - apicheck: Removes warning about directive automodule being overridden 20 | when running apicheck. 21 | 22 | Tested on :pypi:`Sphinx` versions 1.7.1, 1.8.0, 1.8.5 and 2.0.0. 23 | 24 | .. _version-1.4.7: 25 | 26 | 1.4.7 27 | ===== 28 | :release-date: 2019-03-29 10:00 a.m. UTC-8 29 | 30 | - apicheck: Support for :pypi:`Sphinx` 2.0. 31 | 32 | .. _version-1.4.6: 33 | 34 | 1.4.6 35 | ===== 36 | :release-date: 2019-02-13 2:00 p.m. UTC+2 37 | 38 | - Fix links to object inventories. 39 | 40 | .. _version-1.4.5: 41 | 42 | 1.4.5 43 | ===== 44 | :release-date: 2019-02-13 2:00 p.m. UTC+2 45 | 46 | - Fix link to Kombu object inventory. 47 | 48 | .. _version-1.4.4: 49 | 50 | 1.4.4 51 | ===== 52 | :release-date: 2019-02-13 2:00 p.m. UTC+2 53 | 54 | - Revert entrypoint fix for now. 55 | 56 | .. _version-1.4.3: 57 | 58 | 1.4.3 59 | ===== 60 | :release-date: 2019-02-13 2:00 p.m. UTC+2 61 | 62 | - Fix entrypoint. 63 | 64 | .. _version-1.4.2: 65 | 66 | 1.4.2 67 | ===== 68 | :release-date: 2019-02-13 2:00 p.m. UTC+2 69 | 70 | - Use HTTPS for object inventories. 71 | - Fix deprecation warning. 72 | 73 | .. _version-1.4.1: 74 | 75 | 1.4.1 76 | ===== 77 | 78 | - Update intersphinx mapping url for gevent 79 | 80 | - PEP8 fixes. 81 | 82 | .. _version-1.4.0: 83 | 84 | 1.4.0 85 | ===== 86 | :release-date: 2017-03-15 11:26 p.m. PDT 87 | 88 | - Now requires :pypi:`Spinx` 1.7.1 89 | 90 | - Added ``:wikipedia:`` extlink. 91 | 92 | - ``epub_title`` was hardcoded to Celery, now uses project name. 93 | 94 | - :pypi:`pytest` added as intersphinx mapping, :pypi:`nose` removed. 95 | 96 | - Removed unnecessary dependency on :pypi:`case` 97 | 98 | Contributed by Christopher Hoskin. 99 | 100 | - All extensions are now marked as ``read_parallel_safe``. 101 | 102 | Contributed by Omer Katz. 103 | 104 | - Fixed intersphinx URL and Github issue resolution. 105 | 106 | Contributed by George Psarakis. 107 | 108 | - Update :pypi:`msgpack-python` documentation URL 109 | 110 | Contributed by George Psarakis. 111 | 112 | .. _version-1.3.1: 113 | 114 | 1.3.1 115 | ===== 116 | :release-date: 2016-08-10 01:40 p.m. PDT 117 | 118 | - No longer depends on sphinxcontrib-spelling. 119 | 120 | This library depends on the enchant C library being installed, 121 | and are crashing Travis builds. 122 | 123 | .. _version-1.3.0: 124 | 125 | 1.3.0 126 | ===== 127 | :release-date: 2016-05-27 01:41 p.m. PDT 128 | 129 | - Removes dependency on non-Python3 compatible sphinxcontrib-cheeseshop 130 | 131 | The ``:pypi:`` role has been replaced using extlinks, so will still work. 132 | 133 | .. _version-1.2.0: 134 | 135 | 1.2.0 136 | ===== 137 | :release-date: 2016-04-14 11:22 p.m. PDT 138 | 139 | - New extlink crossref type: ``:github_username:``. 140 | 141 | - New extlink crossref type: ``:github_branch:``. 142 | 143 | - New extlink crossref type: ``:sha:``. 144 | 145 | - Adds :pypi:`sphinxcontrib-spelling`. 146 | 147 | To check spelling mistakes run the following command: 148 | 149 | .. code-block:: console 150 | 151 | $ sphinx-build -b spelling 152 | 153 | .. _version-1.1.0: 154 | 155 | 1.1.0 156 | ===== 157 | :release-date: 2016-04-08 04:18 p.m. PDT 158 | 159 | - New apicheck extension 160 | 161 | - New configcheck extension 162 | 163 | .. _version-1.0.0: 164 | 165 | 1.0.0 166 | ===== 167 | :release-date: 2016-04-07 05:19 p.m. PDT 168 | :release-by: Ask Solem 169 | 170 | - Initial release 171 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import codecs 4 | import os 5 | import re 6 | import sys 7 | 8 | from setuptools import find_packages, setup 9 | 10 | NAME = 'sphinx_celery' 11 | extra = {} 12 | 13 | # -*- Classifiers -*- 14 | 15 | classes = """ 16 | Development Status :: 5 - Production/Stable 17 | Programming Language :: Python 18 | Programming Language :: Python :: 3 19 | Programming Language :: Python :: 3.8 20 | Programming Language :: Python :: 3.9 21 | Programming Language :: Python :: 3.10 22 | Programming Language :: Python :: 3.11 23 | Programming Language :: Python :: 3.12 24 | License :: OSI Approved :: BSD License 25 | Intended Audience :: Developers 26 | Operating System :: OS Independent 27 | """ 28 | classifiers = [s.strip() for s in classes.split('\n') if s] 29 | 30 | # -*- Distribution Meta -*- 31 | 32 | re_meta = re.compile(r'__(\w+?)__\s*=\s*(.*)') 33 | re_doc = re.compile(r'^"""(.+?)"""') 34 | 35 | 36 | def add_default(m): 37 | attr_name, attr_value = m.groups() 38 | return ((attr_name, attr_value.strip("\"'")),) 39 | 40 | 41 | def add_doc(m): 42 | return (('doc', m.groups()[0]),) 43 | 44 | 45 | pats = {re_meta: add_default, re_doc: add_doc} 46 | here = os.path.abspath(os.path.dirname(__file__)) 47 | with open(os.path.join(here, 'sphinx_celery', '__init__.py')) as meta_fh: 48 | meta = {} 49 | for line in meta_fh: 50 | if line.strip() == '# -eof meta-': 51 | break 52 | for pattern, handler in pats.items(): 53 | m = pattern.match(line.strip()) 54 | if m: 55 | meta.update(handler(m)) 56 | 57 | # -*- Installation Requires -*- 58 | 59 | py_version = sys.version_info 60 | is_jython = sys.platform.startswith('java') 61 | is_pypy = hasattr(sys, 'pypy_version_info') 62 | 63 | 64 | def strip_comments(line): 65 | return line.split('#', 1)[0].strip() 66 | 67 | 68 | def _pip_requirement(req): 69 | if req.startswith('-r '): 70 | _, path = req.split() 71 | return reqs(*path.split('/')) 72 | return [req] 73 | 74 | 75 | def _reqs(*f): 76 | with open(os.path.join(os.getcwd(), "requirements", *f)) as fp: 77 | return [ 78 | _pip_requirement(r) for r in ( 79 | strip_comments(line) for line in fp 80 | ) if r 81 | ] 82 | 83 | 84 | def reqs(*f): 85 | return [req for subreq in _reqs(*f) for req in subreq] 86 | 87 | # -*- Long Description -*- 88 | 89 | 90 | if os.path.exists('README.rst'): 91 | long_description = codecs.open('README.rst', 'r', 'utf-8').read() 92 | else: 93 | long_description = 'See http://pypi.python.org/pypi/sphinx_celery/' 94 | 95 | # -*- Entry Points -*- # 96 | 97 | # -*- %%% -*- 98 | 99 | 100 | setup( 101 | name=NAME, 102 | version=meta['version'], 103 | description=meta['doc'], 104 | author=meta['author'], 105 | author_email=meta['contact'], 106 | url=meta['homepage'], 107 | platforms=['any'], 108 | license='BSD', 109 | keywords='sphinx docs', 110 | packages=find_packages(exclude=['ez_setup', 'tests', 'tests.*']), 111 | package_data={ 112 | 'sphinx_celery': [ 113 | 'theme.conf', 114 | ], 115 | os.path.join('sphinx_celery', 'static'): [ 116 | 'celery.css_t', 117 | ], 118 | os.path.join('sphinx_celery', 'templates'): [ 119 | 'page.html', 120 | ], 121 | }, 122 | include_package_data=True, 123 | zip_safe=False, 124 | install_requires=reqs('default.txt'), 125 | tests_require=reqs('test.txt'), 126 | test_suite='nose.collector', 127 | classifiers=classifiers, 128 | entry_points={ 129 | 'sphinx.html_themes': [ 130 | 'sphinx_celery = sphinx_celery', 131 | ], 132 | }, 133 | long_description=long_description, 134 | **extra) 135 | -------------------------------------------------------------------------------- /sphinx_celery/github_issues.py: -------------------------------------------------------------------------------- 1 | """Stolen from sphinxcontrib-issuetracker. 2 | 3 | Had to modify this as the original will make one Github API request 4 | per issue, which is not at all needed if we just want to link to issues. 5 | 6 | """ 7 | 8 | import re 9 | from collections import namedtuple 10 | 11 | from docutils import nodes 12 | from docutils.transforms import Transform 13 | from sphinx.addnodes import pending_xref 14 | from sphinx.roles import XRefRole 15 | 16 | URL = 'https://github.com/{project}/issues/{issue_id}' 17 | 18 | Issue = namedtuple('Issue', ('id', 'title', 'url')) 19 | 20 | 21 | class IssueRole(XRefRole): 22 | innernodeclass = nodes.inline 23 | 24 | 25 | class Issues(Transform): 26 | default_priority = 999 27 | 28 | def apply(self): 29 | config = self.document.settings.env.config 30 | github_project = config.github_project 31 | issue_pattern = config.github_issue_pattern 32 | if isinstance(issue_pattern, str): 33 | issue_pattern = re.compile(issue_pattern) 34 | for node in self.document.traverse(nodes.Text): 35 | parent = node.parent 36 | if isinstance(parent, (nodes.literal, nodes.FixedTextElement)): 37 | continue 38 | text = str(node) 39 | new_nodes = [] 40 | last_issue_ref_end = 0 41 | for match in issue_pattern.finditer(text): 42 | head = text[last_issue_ref_end:match.start()] 43 | if head: 44 | new_nodes.append(nodes.Text(head)) 45 | last_issue_ref_end = match.end() 46 | issuetext = match.group(0) 47 | issue_id = match.group(1) 48 | refnode = pending_xref() 49 | refnode['reftarget'] = issue_id 50 | refnode['reftype'] = 'issue' 51 | refnode['refdomain'] = 'github' 52 | refnode['github_project'] = github_project 53 | reftitle = issuetext 54 | refnode.append(nodes.inline( 55 | issuetext, reftitle, classes=['xref', 'issue'])) 56 | new_nodes.append(refnode) 57 | if not new_nodes: 58 | continue 59 | tail = text[last_issue_ref_end:] 60 | if tail: 61 | new_nodes.append(nodes.Text(tail)) 62 | parent.replace(node, new_nodes) 63 | 64 | 65 | def make_issue_reference(issue, content_node): 66 | reference = nodes.reference() 67 | reference['refuri'] = issue.url 68 | if issue.title: 69 | reference['reftitle'] = issue.title 70 | reference.append(content_node) 71 | return reference 72 | 73 | 74 | def resolve_issue_reference(app, env, node, contnode): 75 | if node['reftype'] != 'issue': 76 | return 77 | issue_id = node['reftarget'] 78 | project = node['github_project'] 79 | 80 | issue = Issue(issue_id, None, URL.format(project=project, 81 | issue_id=issue_id)) 82 | conttext = str(contnode[0]) 83 | formatted_conttext = nodes.Text(conttext.format(issue=issue)) 84 | formatted_contnode = nodes.inline(conttext, formatted_conttext, 85 | classes=contnode['classes']) 86 | return make_issue_reference(issue, formatted_contnode) 87 | 88 | 89 | def init_transformer(app): 90 | app.add_transform(Issues) 91 | 92 | 93 | def setup(app): 94 | app.require_sphinx('1.0') 95 | app.add_role('issue', IssueRole()) 96 | 97 | app.add_config_value('github_project', None, 'env') 98 | app.add_config_value('github_issue_pattern', 99 | re.compile(r'[Ii]ssue #(\d+)'), 'env') 100 | 101 | app.connect('builder-inited', init_transformer) 102 | app.connect('missing-reference', resolve_issue_reference) 103 | 104 | return { 105 | 'parallel_read_safe': True 106 | } 107 | -------------------------------------------------------------------------------- /sphinx_celery/configcheck.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Sphinx Configuration Reference Checker 4 | ====================================== 5 | 6 | This builder extension makes sure all settings in the documented 7 | package are represented in the configuration reference ( 8 | meaning they all have ``.. setting::`` directives). 9 | 10 | Usage 11 | ----- 12 | 13 | .. code-block:: console 14 | 15 | $ sphinx-build -b configcheck -d _build/doctrees . _build/configcheck 16 | 17 | Configuration 18 | ------------- 19 | 20 | configcheck_ignore_settings 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | 23 | List of settings to ignore, either as setting names or regexes. 24 | 25 | Example: 26 | 27 | .. code-block:: python 28 | 29 | configcheck_ignore_settings = [ 30 | 'USE_TZ', 31 | r'.*SECRET.*', 32 | ] 33 | 34 | configcheck_project_settings 35 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 36 | 37 | A function returning a set of all setting names. 38 | 39 | Example: 40 | 41 | .. code-block:: python 42 | 43 | def configcheck_project_settings(): 44 | from django import conf 45 | 46 | return set(conf._all_settings) 47 | 48 | 49 | configcheck_should_ignore 50 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 51 | 52 | Optional function that can be used in addition to 53 | ``configcheck_ignore_settings`` to ignore setting names programmatically. 54 | 55 | 56 | Example: 57 | 58 | .. code-block:: python 59 | 60 | def configcheck_should_ignore(setting): 61 | from django import conf 62 | return conf.is_deprecated(setting) 63 | 64 | 65 | """ 66 | 67 | from sphinx.util.console import bold, green, red 68 | 69 | from .builders import BaseBuilder 70 | from .utils import bytes_if_py2 71 | 72 | ERR = 'ERROR' 73 | ERR_MISSING_DOC = '{error}: Setting not documented: {name}' 74 | OK_STATUS = 'OK: All settings documented :o)' 75 | 76 | 77 | class ConfigCheckBuilder(BaseBuilder): 78 | name = 'configcheck' 79 | pickle_filename = 'configcheck.pickle' 80 | 81 | def init(self): 82 | self.ignore_patterns = self.compile_regexes( 83 | self.config.configcheck_ignore_settings, 84 | ) 85 | self.should_ignore = ( 86 | self.config.configcheck_should_ignore or (lambda s: False)) 87 | self.project_settings = self.config.configcheck_project_settings 88 | self.undocumented = set() 89 | 90 | def is_ignored_setting(self, setting): 91 | return self.should_ignore(setting) or any( 92 | regex.match(setting) for regex in self.ignore_patterns) 93 | 94 | def write(self, *ignored): 95 | self.check_missing() 96 | 97 | def documented_settings(self): 98 | domaindata_std_objects = self.app.env.domaindata['std']['objects'] 99 | return { 100 | name 101 | for reftype, name in domaindata_std_objects.keys() 102 | if reftype == 'setting' 103 | } 104 | 105 | def check_missing(self): 106 | all_settings = self.project_settings() 107 | documented_settings = self.documented_settings() 108 | self.undocumented.update( 109 | setting for setting in all_settings ^ documented_settings 110 | if not self.is_ignored_setting(setting) 111 | ) 112 | 113 | for setting in self.undocumented: 114 | self.app.statuscode = 2 115 | print(ERR_MISSING_DOC.format( 116 | error=red(ERR), 117 | name=bold(setting), 118 | )) 119 | if not self.app.statuscode: 120 | print(green(OK_STATUS)) 121 | 122 | def as_dict(self): 123 | return { 124 | 'undocumented': self.undocumented, 125 | } 126 | 127 | 128 | def setup(app): 129 | app.add_builder(ConfigCheckBuilder) 130 | app.add_config_value( 131 | bytes_if_py2('configcheck_ignore_settings'), [], False) 132 | app.add_config_value( 133 | bytes_if_py2('configcheck_project_settings'), None, False) 134 | app.add_config_value( 135 | bytes_if_py2('configcheck_should_ignore'), None, False) 136 | 137 | return { 138 | 'parallel_read_safe': True 139 | } 140 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJ=sphinx_celery 2 | PGPIDENT="Celery Security Team" 3 | PYTHON=python 4 | GIT=git 5 | TOX=tox 6 | NOSETESTS=nosetests 7 | ICONV=iconv 8 | FLAKE8=flake8 9 | FLAKEPLUS=flakeplus 10 | SPHINX2RST=sphinx2rst 11 | 12 | SPHINX_DIR=docs/ 13 | SPHINX_BUILDDIR="${SPHINX_DIR}/_build" 14 | README=README.rst 15 | README_SRC="docs/templates/readme.txt" 16 | CONTRIBUTING=CONTRIBUTING.rst 17 | CONTRIBUTING_SRC="docs/contributing.rst" 18 | SPHINX_HTMLDIR="${SPHINX_BUILDDIR}/html" 19 | DOCUMENTATION=Documentation 20 | FLAKEPLUSTARGET=2.7 21 | 22 | all: help 23 | 24 | help: 25 | @echo "docs - Build documentation." 26 | @echo "test-all - Run tests for all supported python versions." 27 | @echo "distcheck ---------- - Check distribution for problems." 28 | @echo " test - Run unittests using current python." 29 | @echo " lint ------------ - Check codebase for problems." 30 | @echo " apicheck - Check API reference coverage." 31 | @echo " configcheck - Check configuration reference coverage." 32 | @echo " readmecheck - Check README.rst encoding." 33 | @echo " contribcheck - Check CONTRIBUTING.rst encoding" 34 | @echo " flakes -------- - Check code for syntax and style errors." 35 | @echo " flakecheck - Run flake8 on the source code." 36 | @echo " flakepluscheck - Run flakeplus on the source code." 37 | @echo "readme - Regenerate README.rst file." 38 | @echo "contrib - Regenerate CONTRIBUTING.rst file" 39 | @echo "clean-dist --------- - Clean all distribution build artifacts." 40 | @echo " clean-git-force - Remove all uncommitted files." 41 | @echo " clean ------------ - Non-destructive clean" 42 | @echo " clean-pyc - Remove .pyc/__pycache__ files" 43 | @echo " clean-docs - Remove documentation build artifacts." 44 | @echo " clean-build - Remove setup artifacts." 45 | @echo "bump - Bump patch version number." 46 | @echo "bump-minor - Bump minor version number." 47 | @echo "bump-major - Bump major version number." 48 | @echo "release - Make PyPI release." 49 | 50 | clean: clean-docs clean-pyc clean-build 51 | 52 | clean-dist: clean clean-git-force 53 | 54 | bump: 55 | bumpversion patch 56 | 57 | bump-minor: 58 | bumpversion minor 59 | 60 | bump-major: 61 | bumpversion major 62 | 63 | release: 64 | python setup.py register sdist bdist_wheel upload --sign --identity="$(PGPIDENT)" 65 | 66 | Documentation: 67 | (cd "$(SPHINX_DIR)"; $(MAKE) html) 68 | mv "$(SPHINX_HTMLDIR)" $(DOCUMENTATION) 69 | 70 | docs: Documentation 71 | 72 | clean-docs: 73 | -rm -rf "$(SPHINX_BUILDDIR)" 74 | 75 | lint: flakecheck apicheck configcheck readmecheck 76 | 77 | apicheck: 78 | (cd "$(SPHINX_DIR)"; $(MAKE) apicheck) 79 | 80 | configcheck: 81 | (cd "$(SPHINX_DIR)"; $(MAKE) configcheck) 82 | 83 | flakecheck: 84 | $(FLAKE8) --ignore=X999 "$(PROJ)" 85 | 86 | flakediag: 87 | -$(MAKE) flakecheck 88 | 89 | flakepluscheck: 90 | $(FLAKEPLUS) --$(FLAKEPLUSTARGET) "$(PROJ)" 91 | 92 | flakeplusdiag: 93 | -$(MAKE) flakepluscheck 94 | 95 | flakes: flakediag flakeplusdiag 96 | 97 | clean-readme: 98 | -rm -f $(README) 99 | 100 | readmecheck: 101 | $(ICONV) -f ascii -t ascii $(README) >/dev/null 102 | 103 | $(README): 104 | $(SPHINX2RST) "$(README_SRC)" --ascii > $@ 105 | 106 | readme: clean-readme $(README) readmecheck 107 | 108 | clean-contrib: 109 | -rm -f "$(CONTRIBUTING)" 110 | 111 | $(CONTRIBUTING): 112 | $(SPHINX2RST) "$(CONTRIBUTING_SRC)" > $@ 113 | 114 | contrib: clean-contrib $(CONTRIBUTING) 115 | 116 | clean-pyc: 117 | -find . -type f -a \( -name "*.pyc" -o -name "*$$py.class" \) | xargs rm 118 | -find . -type d -name "__pycache__" | xargs rm -r 119 | 120 | removepyc: clean-pyc 121 | 122 | clean-build: 123 | rm -rf build/ dist/ .eggs/ *.egg-info/ .tox/ .coverage cover/ 124 | 125 | clean-git: 126 | $(GIT) clean -xdn 127 | 128 | clean-git-force: 129 | $(GIT) clean -xdf 130 | 131 | test-all: clean-pyc 132 | $(TOX) 133 | 134 | test: 135 | $(PYTHON) setup.py test 136 | 137 | cov: 138 | $(NOSETESTS) -xv --with-coverage --cover-html --cover-branch 139 | 140 | build: 141 | $(PYTHON) setup.py sdist bdist_wheel 142 | 143 | distcheck: lint test clean 144 | 145 | dist: readme contrib clean-dist build 146 | -------------------------------------------------------------------------------- /sphinx_celery/apicheck.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Sphinx Autodoc coverage checker. 4 | ================================ 5 | 6 | This builder extension makes sure all modules in the documented 7 | package is represented in the autodoc API reference. 8 | 9 | Usage 10 | ----- 11 | 12 | .. code-block:: console 13 | 14 | $ sphinx-build -b apicheck -d _build/doctrees . _build/apicheck 15 | 16 | Configuration 17 | ------------- 18 | 19 | apicheck_ignore_modules 20 | ~~~~~~~~~~~~~~~~~~~~~~~ 21 | 22 | List of modules to ignore, either as module names or regexes. 23 | 24 | Example: 25 | 26 | .. code-block:: python 27 | 28 | apicheck_ignore_modules = [ 29 | 'django.utils.functional', 30 | r'django.db.*', 31 | ] 32 | 33 | Test packages are ignored by default, even if this setting is defined. 34 | 35 | apicheck_package 36 | ~~~~~~~~~~~~~~~~ 37 | 38 | The package to verify, can be the fully-qualified name of a module 39 | or an actual module. 40 | 41 | Example: 42 | 43 | .. code-block:: python 44 | 45 | apicheck_package = 'django' 46 | 47 | Default is the value of the ``project`` configuration key in all lowercase. 48 | 49 | 50 | apicheck_domains 51 | ~~~~~~~~~~~~~~~~ 52 | 53 | List of domains to check. 54 | 55 | Default is ``['py']`` and Python is the only domain currently supported. 56 | 57 | """ 58 | 59 | import importlib 60 | import os 61 | from collections import defaultdict 62 | 63 | import sphinx 64 | from sphinx.ext import autodoc 65 | from sphinx.util.console import bold, darkgreen, green, red 66 | 67 | from .builders import BaseBuilder 68 | from .utils import bytes_if_py2 69 | 70 | DEFAULT_IGNORE = [r'.*?\.tests.*'] 71 | 72 | TITLEHEADER = '=' 73 | SUBHEADER = '-' 74 | 75 | ERR = 'ERROR' 76 | ERR_MISSING = '{error}: In index but module does not exist: {module}' 77 | ERR_UNDOCUMENTED = 'Undocumented Autodoc Modules' 78 | OK_STATUS = 'OK: All modules documented :o)' 79 | 80 | NOK_STATUS = """ 81 | {title} 82 | 83 | {undocumented}\ 84 | """ 85 | 86 | DOMAIN_FORMAT = """\ 87 | {domain} 88 | 89 | {modules} 90 | """ 91 | 92 | MODULE_FORMAT = '- {module}' 93 | 94 | 95 | class ModuleDocumenter(autodoc.ModuleDocumenter): 96 | missing_modules = set() 97 | 98 | def import_object(self): 99 | if not super().import_object(): 100 | self.missing_modules.add(self.modname) 101 | return False 102 | return True 103 | 104 | 105 | def title(s, spacing=2, sep=TITLEHEADER): 106 | return '\n'.join([ 107 | sep * (len(s) + spacing), 108 | '{0}{1}{0}'.format(' ' * (spacing // 2), red(s)), 109 | sep * (len(s) + spacing), 110 | ]) 111 | 112 | 113 | def header(s, sep=SUBHEADER): 114 | return '\n'.join([bold(s), sep * len(s)]) 115 | 116 | 117 | def find_python_modules(package): 118 | if isinstance(package, str): 119 | package = importlib.import_module(package) 120 | name, path = package.__name__, package.__file__ 121 | current_dist_depth = len(name.split('.')) - 1 122 | current_dist = os.path.join(os.path.dirname(path), 123 | *([os.pardir] * current_dist_depth)) 124 | abs = os.path.abspath(current_dist) 125 | dist_name = os.path.basename(abs) 126 | 127 | for dirpath, _, filenames in os.walk(abs): 128 | package = (dist_name + dirpath[len(abs):]).replace('/', '.') 129 | if '__init__.py' in filenames: 130 | yield package 131 | for filename in filenames: 132 | if filename.endswith('.py') and filename != '__init__.py': 133 | yield '.'.join([package, filename])[:-3] 134 | 135 | 136 | class APICheckBuilder(BaseBuilder): 137 | 138 | name = 'apicheck' 139 | pickle_filename = 'apicheck.pickle' 140 | 141 | find_modules = { 142 | 'py': find_python_modules, 143 | } 144 | 145 | def init(self): 146 | self.ignore_patterns = self.compile_regexes( 147 | self.config.apicheck_ignore_modules + DEFAULT_IGNORE, 148 | ) 149 | self.check_domains = self.config.apicheck_domains 150 | self.check_package = ( 151 | self.config.apicheck_package or self.config.project.lower()) 152 | 153 | self.undocumented = defaultdict(list) 154 | self.all_modules = defaultdict(set) 155 | 156 | def is_ignored_module(self, module): 157 | return any(regex.match(module) for regex in self.ignore_patterns) 158 | 159 | def write(self, *ignored): 160 | for domain in self.check_domains: 161 | self.build_coverage(domain) 162 | self.check_missing() 163 | if not self.app.statuscode: 164 | self.write_coverage(self.check_domains) 165 | 166 | def build_coverage(self, domain): 167 | self.all_modules[domain].update(self.find_modules[domain]( 168 | self.check_package, 169 | )) 170 | self.undocumented[domain].extend(self.find_undocumented( 171 | domain, self.env.domaindata[domain]['modules'], 172 | )) 173 | 174 | def find_undocumented(self, domain, documented): 175 | return ( 176 | mod for mod in self.all_modules[domain] 177 | if mod not in documented and not self.is_ignored_module(mod) 178 | ) 179 | 180 | def write_coverage(self, domains): 181 | status = any(self.undocumented.values()) 182 | if status: 183 | self.app.statuscode = 2 184 | print(self.format_undocumented_domains(domains)) 185 | else: 186 | print(green(OK_STATUS)) 187 | 188 | def check_missing(self): 189 | for mod in ModuleDocumenter.missing_modules: 190 | self.app.statuscode = 3 191 | print(ERR_MISSING.format( 192 | error=red(ERR), 193 | module=bold(mod), 194 | )) 195 | 196 | def format_undocumented_domains(self, domains): 197 | return NOK_STATUS.format( 198 | title=title(ERR_UNDOCUMENTED), 199 | undocumented='\n'.join( 200 | self.format_undocumented_domain(domain) for domain in domains 201 | ), 202 | ) 203 | 204 | def format_undocumented_domain(self, domain): 205 | return DOMAIN_FORMAT.format(domain=header(domain), modules='\n'.join( 206 | self.format_undocumented_module(module) 207 | for module in self.undocumented[domain] 208 | )) 209 | 210 | def format_undocumented_module(self, module): 211 | return MODULE_FORMAT.format(module=darkgreen(module)) 212 | 213 | def as_dict(self): 214 | return { 215 | 'undocumented': dict(self.undocumented), 216 | } 217 | 218 | 219 | def _add_documenter_override(app, cls): 220 | # Install documenter for automodule without generating warning. 221 | from sphinx.ext.autodoc.directive import AutodocDirective 222 | app.registry.add_documenter(cls.objtype, cls) 223 | directive_name = 'auto' + cls.objtype 224 | if sphinx.version_info < (1, 8): 225 | try: 226 | from docutils.parsers.rst import directives 227 | except ImportError: 228 | pass 229 | else: 230 | directives._directives.pop(directive_name, None) 231 | app.add_directive(directive_name, AutodocDirective) 232 | else: 233 | # override was added in Sphinx 1.8 234 | app.add_directive(directive_name, AutodocDirective, override=True) 235 | 236 | 237 | def setup(app): 238 | app.add_builder(APICheckBuilder) 239 | app.add_config_value( 240 | bytes_if_py2('apicheck_ignore_modules'), [], False) 241 | app.add_config_value( 242 | bytes_if_py2('apicheck_domains'), ['py'], False) 243 | app.add_config_value( 244 | bytes_if_py2('apicheck_package'), None, False) 245 | _add_documenter_override(app, ModuleDocumenter) 246 | 247 | return { 248 | 'parallel_read_safe': True, 249 | } 250 | -------------------------------------------------------------------------------- /sphinx_celery/static/celery.css_t: -------------------------------------------------------------------------------- 1 | /* 2 | * celery.css_t 3 | * ~~~~~~~~~~~~ 4 | * 5 | * :copyright: Copyright 2010 by Armin Ronacher. 6 | * :license: BSD, see LICENSE for details. 7 | */ 8 | 9 | {% set page_width = 940 %} 10 | {% set sidebar_width = 220 %} 11 | {% set body_font_stack = 'Optima, Segoe, "Segoe UI", Candara, Calibri, Arial, sans-serif' %} 12 | {% set headline_font_stack = 'Futura, "Trebuchet MS", Arial, sans-serif' %} 13 | {% set code_font_stack = "'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace" %} 14 | 15 | @import url("basic.css"); 16 | 17 | /* -- page layout ----------------------------------------------------------- */ 18 | 19 | body { 20 | font-family: {{ body_font_stack }}; 21 | font-size: 17px; 22 | background-color: white; 23 | color: #000; 24 | margin: 30px 0 0 0; 25 | padding: 0; 26 | } 27 | 28 | div.document { 29 | width: {{ page_width }}px; 30 | margin: 0 auto; 31 | } 32 | 33 | div.deck { 34 | font-size: 18px; 35 | } 36 | 37 | p.developmentversion { 38 | color: red; 39 | } 40 | 41 | div.related { 42 | width: {{ page_width - 20 }}px; 43 | padding: 5px 10px; 44 | background: #F2FCEE; 45 | margin: 15px auto 15px auto; 46 | } 47 | 48 | div.documentwrapper { 49 | float: left; 50 | width: 100%; 51 | } 52 | 53 | div.bodywrapper { 54 | margin: 0 0 0 {{ sidebar_width }}px; 55 | } 56 | 57 | div.sphinxsidebar { 58 | width: {{ sidebar_width }}px; 59 | } 60 | 61 | hr { 62 | border: 1px solid #B1B4B6; 63 | } 64 | 65 | div.body { 66 | background-color: #ffffff; 67 | color: #3E4349; 68 | padding: 0 30px 0 30px; 69 | } 70 | 71 | img.celerylogo { 72 | padding: 0 0 10px 10px; 73 | float: right; 74 | } 75 | 76 | div.footer { 77 | width: {{ page_width - 15 }}px; 78 | margin: 10px auto 30px auto; 79 | padding-right: 15px; 80 | font-size: 14px; 81 | color: #888; 82 | text-align: right; 83 | } 84 | 85 | div.footer a { 86 | color: #888; 87 | } 88 | 89 | div.sphinxsidebar a { 90 | color: #444; 91 | text-decoration: none; 92 | border-bottom: 1px dashed #DCF0D5; 93 | } 94 | 95 | div.sphinxsidebar a:hover { 96 | border-bottom: 1px solid #999; 97 | } 98 | 99 | div.sphinxsidebar { 100 | font-size: 14px; 101 | line-height: 1.5; 102 | } 103 | 104 | div.sphinxsidebarwrapper { 105 | padding: 7px 10px; 106 | } 107 | 108 | div.sphinxsidebarwrapper p.logo { 109 | padding: 0 0 20px 0; 110 | margin: 0; 111 | } 112 | 113 | div.sphinxsidebar h3, 114 | div.sphinxsidebar h4 { 115 | font-family: {{ headline_font_stack }}; 116 | color: #444; 117 | font-size: 24px; 118 | font-weight: normal; 119 | margin: 0 0 5px 0; 120 | padding: 0; 121 | } 122 | 123 | div.sphinxsidebar h4 { 124 | font-size: 20px; 125 | } 126 | 127 | div.sphinxsidebar h3 a { 128 | color: #444; 129 | } 130 | 131 | div.sphinxsidebar p.logo a, 132 | div.sphinxsidebar h3 a, 133 | div.sphinxsidebar p.logo a:hover, 134 | div.sphinxsidebar h3 a:hover { 135 | border: none; 136 | } 137 | 138 | div.sphinxsidebar p { 139 | color: #555; 140 | margin: 10px 0; 141 | } 142 | 143 | div.sphinxsidebar ul { 144 | margin: 10px 0; 145 | padding: 0; 146 | color: #000; 147 | } 148 | 149 | div.sphinxsidebar input { 150 | border: 1px solid #ccc; 151 | font-family: {{ body_font_stack }}; 152 | font-size: 1em; 153 | } 154 | 155 | /* -- body styles ----------------------------------------------------------- */ 156 | 157 | a { 158 | color: #348613; 159 | text-decoration: underline; 160 | } 161 | 162 | a:hover { 163 | color: #59B833; 164 | text-decoration: underline; 165 | } 166 | 167 | div.body h1, 168 | div.body h2, 169 | div.body h3, 170 | div.body h4, 171 | div.body h5, 172 | div.body h6 { 173 | font-family: {{ headline_font_stack }}; 174 | font-weight: normal; 175 | margin: 30px 0px 10px 0px; 176 | padding: 0; 177 | } 178 | 179 | div.body h1 { margin-top: 0; padding-top: 0; font-size: 200%; } 180 | div.body h2 { font-size: 180%; } 181 | div.body h3 { font-size: 150%; } 182 | div.body h4 { font-size: 130%; } 183 | div.body h5 { font-size: 100%; } 184 | div.body h6 { font-size: 100%; } 185 | 186 | div.body h1 a.toc-backref, 187 | div.body h2 a.toc-backref, 188 | div.body h3 a.toc-backref, 189 | div.body h4 a.toc-backref, 190 | div.body h5 a.toc-backref, 191 | div.body h6 a.toc-backref { 192 | color: inherit!important; 193 | text-decoration: none; 194 | } 195 | 196 | a.headerlink { 197 | color: #ddd; 198 | padding: 0 4px; 199 | text-decoration: none; 200 | } 201 | 202 | a.headerlink:hover { 203 | color: #444; 204 | background: #eaeaea; 205 | } 206 | 207 | div.body p, div.body dd, div.body li { 208 | line-height: 1.4em; 209 | } 210 | 211 | div.admonition { 212 | background: #fafafa; 213 | margin: 20px -30px; 214 | padding: 10px 30px; 215 | border-top: 1px solid #ccc; 216 | border-bottom: 1px solid #ccc; 217 | } 218 | 219 | div.admonition p.admonition-title { 220 | font-family: {{ headline_font_stack }}; 221 | font-weight: normal; 222 | font-size: 24px; 223 | margin: 0 0 10px 0; 224 | padding: 0; 225 | line-height: 1; 226 | } 227 | 228 | div.admonition p.last { 229 | margin-bottom: 0; 230 | } 231 | 232 | div.highlight{ 233 | background-color: white; 234 | } 235 | 236 | dt:target, .highlight { 237 | background: #FAF3E8; 238 | } 239 | 240 | div.note { 241 | background-color: #eee; 242 | border: 1px solid #ccc; 243 | } 244 | 245 | div.seealso { 246 | background-color: #ffc; 247 | border: 1px solid #ff6; 248 | } 249 | 250 | div.topic { 251 | background-color: #eee; 252 | } 253 | 254 | div.warning { 255 | background-color: #ffe4e4; 256 | border: 1px solid #f66; 257 | } 258 | 259 | p.admonition-title { 260 | display: inline; 261 | } 262 | 263 | p.admonition-title:after { 264 | content: ":"; 265 | } 266 | 267 | pre, tt { 268 | font-family: {{ code_font_stack }}; 269 | font-size: 0.9em; 270 | } 271 | 272 | img.screenshot { 273 | } 274 | 275 | tt.descname, tt.descclassname { 276 | font-size: 0.95em; 277 | } 278 | 279 | tt.descname { 280 | padding-right: 0.08em; 281 | } 282 | 283 | img.screenshot { 284 | -moz-box-shadow: 2px 2px 4px #eee; 285 | -webkit-box-shadow: 2px 2px 4px #eee; 286 | box-shadow: 2px 2px 4px #eee; 287 | } 288 | 289 | table.docutils { 290 | border: 1px solid #888; 291 | -moz-box-shadow: 2px 2px 4px #eee; 292 | -webkit-box-shadow: 2px 2px 4px #eee; 293 | box-shadow: 2px 2px 4px #eee; 294 | } 295 | 296 | table.docutils td, table.docutils th { 297 | border: 1px solid #888; 298 | padding: 0.25em 0.7em; 299 | } 300 | 301 | table.field-list, table.footnote { 302 | border: none; 303 | -moz-box-shadow: none; 304 | -webkit-box-shadow: none; 305 | box-shadow: none; 306 | } 307 | 308 | table.footnote { 309 | margin: 15px 0; 310 | width: 100%; 311 | border: 1px solid #eee; 312 | background: #fdfdfd; 313 | font-size: 0.9em; 314 | } 315 | 316 | table.footnote + table.footnote { 317 | margin-top: -15px; 318 | border-top: none; 319 | } 320 | 321 | table.field-list th { 322 | padding: 0 0.8em 0 0; 323 | } 324 | 325 | table.field-list td { 326 | padding: 0; 327 | } 328 | 329 | table.footnote td.label { 330 | width: 0px; 331 | padding: 0.3em 0 0.3em 0.5em; 332 | } 333 | 334 | table.footnote td { 335 | padding: 0.3em 0.5em; 336 | } 337 | 338 | dl { 339 | margin: 0; 340 | padding: 0; 341 | } 342 | 343 | dl dd { 344 | margin-left: 30px; 345 | } 346 | 347 | blockquote { 348 | margin: 0 0 0 30px; 349 | padding: 0; 350 | } 351 | 352 | ul { 353 | margin: 10px 0 10px 30px; 354 | padding: 0; 355 | } 356 | 357 | pre { 358 | background: #F0FFEB; 359 | padding: 7px 10px; 360 | margin: 15px 0; 361 | border: 1px solid #C7ECB8; 362 | border-radius: 2px; 363 | -moz-border-radius: 2px; 364 | -webkit-border-radius: 2px; 365 | line-height: 1.3em; 366 | } 367 | 368 | tt { 369 | background: #F0FFEB; 370 | color: #222; 371 | /* padding: 1px 2px; */ 372 | } 373 | 374 | tt.xref, a tt { 375 | background: #F0FFEB; 376 | border-bottom: 1px solid white; 377 | } 378 | 379 | a.reference { 380 | text-decoration: none; 381 | border-bottom: 1px dashed #DCF0D5; 382 | } 383 | 384 | a.reference:hover { 385 | border-bottom: 1px solid #6D4100; 386 | } 387 | 388 | a.footnote-reference { 389 | text-decoration: none; 390 | font-size: 0.7em; 391 | vertical-align: top; 392 | border-bottom: 1px dashed #DCF0D5; 393 | } 394 | 395 | a.footnote-reference:hover { 396 | border-bottom: 1px solid #6D4100; 397 | } 398 | 399 | a:hover tt { 400 | background: #EEE; 401 | } 402 | -------------------------------------------------------------------------------- /sphinx_celery/conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from . import get_html_templates_path 5 | 6 | LINKCODE_URL = 'https://github.com/{proj}/tree/{branch}/{filename}.py' 7 | GITHUB_BRANCH = 'master' 8 | 9 | EXTENSIONS = [ 10 | 'sphinx.ext.autodoc', 11 | 'sphinx.ext.intersphinx', 12 | 'sphinx.ext.todo', 13 | 'sphinx.ext.coverage', 14 | 'sphinx.ext.imgmath', 15 | 'sphinx.ext.ifconfig', 16 | 'sphinx.ext.viewcode', 17 | 'sphinx.ext.extlinks', 18 | 19 | 'sphinx_celery.autodocargspec', 20 | 'sphinx_celery.github_issues', 21 | 'sphinx_celery.signal_crossref', 22 | 'sphinx_celery.setting_crossref', 23 | 'sphinx_celery.apicheck', 24 | 'sphinx_celery.configcheck', 25 | ] 26 | 27 | INTERSPHINX_MAPPING = { 28 | 'python': ('https://docs.python.org/dev/', None), 29 | 'sphinx': ('https://www.sphinx-doc.org/en/stable/', None), 30 | 'kombu': ('https://kombu.readthedocs.io/en/main/', None), 31 | 'celery': ('https://celery.readthedocs.io/en/main/', None), 32 | 'pytest-celery': ('https://pytest-celery.readthedocs.io/en/main/', None), 33 | 'djcelery': ('https://django-celery.readthedocs.io/en/latest/', None), 34 | 'cyme': ('https://cyme.readthedocs.io/en/latest/', None), 35 | 'amqp': ('https://amqp.readthedocs.io/en/latest/', None), 36 | 'vine': ('https://vine.readthedocs.io/en/latest/', None), 37 | 'flower': ('https://flower.readthedocs.io/en/latest/', None), 38 | 'redis': ('https://redis-py.readthedocs.io/en/latest/', None), 39 | 'django': ( 40 | 'http://docs.djangoproject.com/en/dev/', 41 | 'https://docs.djangoproject.com/en/dev/_objects', 42 | ), 43 | 'boto': ('https://boto.readthedocs.io/en/latest/', None), 44 | 'sqlalchemy': ('https://sqlalchemy.readthedocs.io/en/latest', None), 45 | 'kazoo': ('https://kazoo.readthedocs.io/en/latest/', None), 46 | 'msgpack': ('https://msgpack-python.readthedocs.io/en/latest/', None), 47 | 'riak': ('https://basho.github.io/riak-python-client/', None), 48 | 'pylibmc': ('http://sendapatch.se/projects/pylibmc/', None), 49 | 'eventlet': ('https://eventlet.net/doc/', None), 50 | 'gevent': ('http://www.gevent.org/', None), 51 | 'pyOpenSSL': ('https://pyopenssl.readthedocs.io/en/stable/', None), 52 | 'pytest': ('https://docs.pytest.org/en/latest/', None), 53 | 'tox': ('https://tox.readthedocs.io/en/latest', None), 54 | } 55 | 56 | 57 | def add_paths(config_file, path_additions): 58 | this = os.path.dirname(os.path.abspath(config_file)) 59 | 60 | sys.path.insert(0, os.path.join(this, os.pardir)) 61 | for path in path_additions: 62 | sys.path.append(os.path.join(this, path)) 63 | 64 | 65 | def configure_django(django_settings, **config): 66 | if django_settings: 67 | os.environ['DJANGO_SETTINGS_MODULE'] = django_settings 68 | else: 69 | from django.conf import settings 70 | if not settings.configured: 71 | settings.configure(**config) 72 | try: 73 | from django import setup as django_setup 74 | except ImportError: 75 | pass 76 | else: 77 | django_setup() 78 | 79 | 80 | def import_package(package): 81 | if isinstance(package, str): 82 | return __import__(package) 83 | return package 84 | 85 | 86 | def prepare_intersphinx_mapping(project, mapping, 87 | include, exclude, **extra): 88 | if include: 89 | mapping = {k: v for k, v in mapping.items() if k in include} 90 | if exclude: 91 | mapping = {k: v for k, v in mapping.items() if k not in exclude} 92 | mapping = dict(mapping, **extra) 93 | 94 | # Remove project itself from intersphinx 95 | mapping.pop(project.lower(), None) 96 | 97 | return mapping 98 | 99 | 100 | def create_linkcode_resolver(linkcode_url, github_project, github_branch): 101 | def linkcode_resolve(domain, info): 102 | if domain != 'py' or not info['module']: 103 | return 104 | filename = info['module'].replace('.', '/') 105 | return linkcode_url.format( 106 | proj=github_project, 107 | branch=github_branch, 108 | filename=filename, 109 | ) 110 | return linkcode_resolve 111 | 112 | 113 | def build_config( 114 | package, config_file, project, 115 | author=None, 116 | author_name=None, 117 | github_project=None, 118 | webdomain=None, 119 | canonical_url=None, 120 | canonical_stable_url=None, 121 | canonical_dev_url=None, 122 | django_settings=None, 123 | configure_django_settings={}, 124 | copyright=None, 125 | publisher=None, 126 | description='', 127 | path_additions=['_ext'], 128 | version_dev=None, 129 | version_stable=None, 130 | extensions=EXTENSIONS, 131 | extra_extensions=[], 132 | linkcode_url=LINKCODE_URL, 133 | github_branch=GITHUB_BRANCH, 134 | master_doc='index', 135 | html_logo=None, 136 | html_prepend_sidebars=[], 137 | templates_path=None, 138 | latex_logo=None, 139 | intersphinx_mapping=INTERSPHINX_MAPPING, 140 | extra_intersphinx_mapping={}, 141 | include_intersphinx=frozenset(), 142 | exclude_intersphinx=frozenset(), 143 | spelling_lang='en_US', 144 | spelling_show_suggestions=True, 145 | extlinks=None, 146 | **kwargs): 147 | add_paths(config_file, path_additions) 148 | if configure_django_settings or django_settings: 149 | configure_django(django_settings, **configure_django_settings or {}) 150 | package = import_package(package) 151 | description = description or package.__doc__ 152 | author = author or package.__author__ 153 | author_name = author_name or author 154 | extlinks = extlinks or {} 155 | 156 | extlinks.setdefault('sha', ( 157 | f'https://github.com/{github_project}/commit/%s', 158 | 'GitHub SHA@%s', 159 | )) 160 | extlinks.setdefault('github_branch', ( 161 | f'https://github.com/{github_project}/tree/%s', 162 | 'GitHub branch %s', 163 | )) 164 | extlinks.setdefault('github_user', ( 165 | 'https://github.com/%s/', '@%s', 166 | )) 167 | extlinks.setdefault('pypi', ( 168 | 'https://pypi.org/project/%s/', None, 169 | )) 170 | extlinks.setdefault('wikipedia', ( 171 | 'https://en.wikipedia.org/wiki/%s', None, 172 | )) 173 | 174 | if not canonical_dev_url: 175 | canonical_dev_url = '/'.join([ 176 | canonical_url.rstrip('/'), 'en', 'main', 177 | ]) 178 | if not canonical_stable_url: 179 | canonical_stable_url = '/'.join([ 180 | canonical_url.rstrip('/'), 'en', 'latest', 181 | ]) 182 | 183 | if templates_path is None: 184 | templates_path = ['_templates'] 185 | if version_dev: 186 | templates_path.append(get_html_templates_path()) 187 | 188 | version = '.'.join(map(str, package.VERSION[0:2])) 189 | 190 | extensions = extensions + extra_extensions 191 | if os.environ.get('SPELLCHECK'): 192 | extensions.append('sphinxcontrib.spelling') 193 | 194 | conf = dict( 195 | extensions=extensions + extra_extensions, 196 | 197 | project=project, 198 | github_project=github_project, 199 | 200 | html_show_sphinx=False, 201 | 202 | # Add any paths that contain templates here, 203 | # relative to this directory. 204 | templates_path=templates_path, 205 | 206 | # The suffix of source filenames. 207 | source_suffix='.rst', 208 | 209 | # The master toctree document. 210 | master_doc=master_doc, 211 | 212 | copyright=f'{copyright}, {author}', 213 | 214 | # The short X.Y version. 215 | version=version, 216 | 217 | # The full version, including alpha/beta/rc tags. 218 | release=package.__version__, 219 | 220 | exclude_patterns=['_build', 'Thumbs.db', '.DS_Store'], 221 | 222 | # If true, '()' will be appended to :func: etc. cross-reference text. 223 | add_function_parentheses=True, 224 | 225 | linkcode_resolve=create_linkcode_resolver( 226 | linkcode_url, github_project, github_branch, 227 | ), 228 | 229 | intersphinx_mapping=prepare_intersphinx_mapping( 230 | project, 231 | intersphinx_mapping, 232 | include_intersphinx, 233 | exclude_intersphinx, 234 | **extra_intersphinx_mapping 235 | ), 236 | 237 | # The name of the Pygments (syntax highlighting) style to use. 238 | pygments_style='colorful', 239 | 240 | # Add any paths that contain custom static files 241 | # (such as style sheets) here, relative to this directory. 242 | # They are copied after the builtin static files, so a file named 243 | # "default.css" will overwrite the builtin "default.css". 244 | html_static_path=['_static'], 245 | 246 | add_module_names=True, 247 | highlight_language='python3', 248 | 249 | # If true, `todo` and `todoList` produce output, 250 | # else they produce nothing. 251 | todo_include_todos=True, 252 | 253 | # If false, no module index is generated. 254 | html_use_modindex=True, 255 | 256 | # If false, no index is generated. 257 | html_use_index=True, 258 | 259 | html_logo=html_logo, 260 | 261 | html_context={ 262 | 'version_dev': version_dev or version, 263 | 'version_stable': version_stable or version, 264 | 'canonical_stable_url': canonical_stable_url, 265 | 'canonical_dev_url': canonical_dev_url, 266 | }, 267 | 268 | man_pages=[ 269 | (master_doc, project.lower(), 270 | f'{project} Documentation', [author_name], 1) 271 | ], 272 | 273 | # Grouping the document tree into Texinfo files. List of tuples 274 | # (source start file, target name, title, author, 275 | # dir menu entry, description, category) 276 | texinfo_documents=[ 277 | (master_doc, project, f'{project} Documentation', 278 | author_name, project, description, 279 | 'Miscellaneous'), 280 | ], 281 | latex_logo=latex_logo or html_logo, 282 | 283 | latex_documents=[ 284 | ('index', f'{project}.tex', 285 | f'{project} Documentation', author, 'manual'), 286 | ], 287 | html_theme='sphinx_celery', 288 | html_sidebars={ 289 | 'index': list(html_prepend_sidebars) + [ 290 | 'sourcelink.html', 291 | 'searchbox.html', 292 | ], 293 | '**': list(html_prepend_sidebars) + [ 294 | 'relations.html', 295 | 'sourcelink.html', 296 | 'searchbox.html', 297 | ], 298 | }, 299 | # Bibliographic Dublin Core info. 300 | epub_title=f'{project} Manual, Version {version}', 301 | epub_author=author_name, 302 | epub_publisher=publisher or author_name, 303 | epub_copyright=copyright, 304 | 305 | # The language of the text. It defaults to the language option 306 | # or en if the language is not set. 307 | epub_language='en', 308 | 309 | # The scheme of the identifier. Typical schemes are ISBN or URL. 310 | epub_scheme='ISBN', 311 | 312 | # The unique identifier of the text. This can be a ISBN number 313 | # or the project homepage. 314 | epub_identifier=webdomain, 315 | 316 | # A unique identification for the text. 317 | epub_uid=f"{project} Manual, Version {version}", 318 | 319 | # A list of files that should not be packed into the epub file. 320 | epub_exclude_files=['search.html'], 321 | 322 | # The depth of the table of contents in toc.ncx. 323 | epub_tocdepth=3, 324 | 325 | # -- spelling 326 | spelling_lang=spelling_lang, 327 | spelling_show_suggestions=spelling_show_suggestions, 328 | 329 | # -- extlinks 330 | extlinks=extlinks, 331 | ) 332 | return dict(conf, **kwargs) 333 | --------------------------------------------------------------------------------