1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
from __future__ import annotations
import re
from importlib.machinery import SourceFileLoader
from pathlib import Path
from typing import TYPE_CHECKING, Any
from sphinx.domains.python import PythonDomain
from sphinx.ext.extlinks import ExternalLinksChecker
from truststore import inject_into_ssl
from tox import __version__
if TYPE_CHECKING:
from docutils.nodes import Element, reference
from sphinx.addnodes import pending_xref
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.environment import BuildEnvironment
from sphinx.ext.autodoc import Options
company, name = "tox-dev", "tox"
release, version = __version__, ".".join(__version__.split(".")[:2])
copyright = f"{company}" # noqa: A001
master_doc = "index"
source_suffix = {".rst": "restructuredtext"}
html_theme = "furo"
html_theme_options = {
"sidebar_hide_name": True,
}
html_title, html_last_updated_fmt = "tox", "%Y-%m-%dT%H:%M:%S"
html_show_sourcelink = False
pygments_style, pygments_dark_style = "sphinx", "monokai"
html_static_path, html_css_files = ["_static"], ["custom.css"]
html_js_files = ["mermaid-reset.js"]
html_logo, html_favicon = "_static/img/tox.svg", "_static/img/toxfavi.ico"
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosectionlabel",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinx_argparse_cli",
"sphinx_autodoc_typehints",
"sphinx_inline_tabs",
"sphinx_copybutton",
"sphinx_issues", # :user: and similar roles
"sphinxcontrib.mermaid",
"sphinxcontrib.towncrier.ext",
"sphinx_reredirects",
]
mermaid_output_format = "raw"
mermaid_d3_zoom = True
d3_use_local = "d3.min.js"
mermaid_height = "auto"
exclude_patterns = ["_build", "changelog/*"]
autoclass_content, autodoc_member_order, autodoc_typehints = "class", "bysource", "none"
autodoc_default_options = {
"member-order": "bysource",
"undoc-members": True,
"show-inheritance": True,
}
autosectionlabel_prefix_document = True
extlinks = {
"discussion": ("https://github.com/tox-dev/tox/discussions/%s", "#%s"),
"gh_repo": ("https://github.com/%s", "%s"),
"gh": ("https://github.com/%s", "%s"),
}
intersphinx_mapping = {
"python": ("/usr/share/doc/python3-doc/html", "/usr/share/doc/python3-doc/html/objects.inv"),
"packaging": ("https://packaging.pypa.io/en/latest", None),
}
nitpicky = True
nitpick_ignore = []
linkcheck_workers = 10
linkcheck_ignore = [
re.escape(i)
for i in (
r"https://github.com/tox-dev/tox/issues/new?title=Trouble+with+development+environment",
r"https://porkbun.com/", # has captcha on it that makes it return with 405
r"https://opensource.org/license/mit",
)
]
linkcheck_allowed_redirects = {r"https://github.com/tox-dev/tox/issues/\d+": r"https://github.com/tox-dev/tox/pull/\d+"}
extlinks_detect_hardcoded_links = True
issues_github_path = f"{company}/{name}" # `sphinx-issues` ext
# Man page configuration
man_pages = [("man/tox.1", "tox", "virtualenv-based automation of test activities", ["tox development team"], 1)]
man_show_urls = True
redirects = {
"config": "reference/config.html",
"cli_interface": "reference/cli.html",
"user_guide": "explanation.html",
"installation": "how-to/install.html",
"howto": "how-to/usage.html",
"getting_started": "tutorial/getting-started.html",
"plugins": "plugin/index.html",
"plugins_api": "plugin/api.html",
"plugins/index": "plugin/index.html",
"plugins/api": "plugin/api.html",
"plugins/getting_started": "plugin/getting_started.html",
"plugins/howto": "plugin/howto.html",
"upgrading": "index.html",
"faq": "index.html",
"example/general": "index.html",
"example/basic": "index.html",
"example/devenv": "index.html",
"example/documentation": "index.html",
"example/jenkins": "index.html",
"example/nose": "index.html",
"example/package": "index.html",
"example/platform": "index.html",
"example/pytest": "index.html",
"example/result": "index.html",
"example/unittest": "index.html",
}
towncrier_draft_autoversion_mode = "draft"
towncrier_draft_include_empty = True
towncrier_draft_working_directory = Path(__file__).parent.parent
def process_signature( # noqa: PLR0913
app: Sphinx, # noqa: ARG001
objtype: str,
name: str, # noqa: ARG001
obj: Any, # noqa: ARG001
options: Options,
args: str | None, # noqa: ARG001
retann: str | None, # noqa: ARG001
) -> tuple[None, None] | None:
# skip-member is not checked for class level docs, so disable via signature processing
if objtype == "class" and (exclude := options.get("exclude-members")) and "__init__" in exclude:
return None, None
return None
def setup(app: Sphinx) -> None:
here = Path(__file__).parent
class PatchedPythonDomain(PythonDomain):
def resolve_xref( # noqa: PLR0913
self,
env: BuildEnvironment,
fromdocname: str,
builder: Builder,
type: str, # noqa: A002
target: str,
node: pending_xref,
contnode: Element,
) -> reference | None:
# fixup some wrongly resolved mappings
mapping = {
"tox.config.of_type.T": "typing.TypeVar", # used by Sphinx bases
"tox.config.loader.api.T": "typing.TypeVar", # used by Sphinx bases
"tox.config.loader.convert.T": "typing.TypeVar", # used by Sphinx bases
"tox.tox_env.installer.T": "typing.TypeVar", # used by Sphinx bases
"pathlib._local.Path": "pathlib.Path",
}
if target in mapping:
target = node["reftarget"] = mapping[target]
return super().resolve_xref(env, fromdocname, builder, type, target, node, contnode)
app.connect("autodoc-process-signature", process_signature, priority=400)
app.add_domain(PatchedPythonDomain, override=True)
tox_cfg = SourceFileLoader("tox_conf", str(here / "tox_conf.py")).load_module().ToxConfig
app.add_directive(tox_cfg.name, tox_cfg)
def check_uri(self: ExternalLinksChecker, refnode: reference) -> None:
if refnode.document is not None and refnode.document.attributes["source"].endswith("index.rst"):
return None # do not use for the index file
return prev_check(self, refnode)
prev_check = ExternalLinksChecker.check_uri
ExternalLinksChecker.check_uri = check_uri # ty: ignore[invalid-assignment] # monkey-patching instance method onto class
inject_into_ssl()
|