Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e599386

Browse files
committedAug 15, 2024·
Add separate conf.py for the different docs types
The goal here is to allow building the `man` pages without all the additional requirements needed for the `html` docs, so that e.g. developers packaging `pip` can also package the man pages with minimal dependencies. Specifically, this should have no impact on the build output of `nox -s docs`, but does allow: sphinx-build \ -c docs/man \ -d docs/build/doctrees/man \ -b man \ docs/man \ docs/build/man to run with only `sphinx` dependency (in addition to `pip`s dependencies). While doing this I also used long-opts to `sphinx-build` in the `noxfile` since I found this more understandable at a glance An `__init__.py` was added under `docs/man` to satisfy `mypy`. If this wasn't added it would error: docs/man/conf.py: error: Duplicate module named "conf" (also at "docs/html/conf.py") docs/man/conf.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info docs/man/conf.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH Found 1 error in 1 file (errors prevented further checking) Adding an extra `__init__.py` under `docs/html` would result in a separate error since then the `html` module is local (and not the stdlib one) resulting in a error from `sphinx-build`: Extension error: Could not import extension sphinx.builders.linkcheck (exception: No module named 'html.parser') Issue: #12881 Avoid mypy ignore for docs by just adding one `__init__.py`
1 parent e98cc5c commit e599386

10 files changed

+112
-76
lines changed
 

‎.readthedocs.yml

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ sphinx:
1212
python:
1313
install:
1414
- requirements: docs/requirements.txt
15+
- requirements: docs/html/requirements.txt

‎MANIFEST.in

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ recursive-include src/pip/_vendor *COPYING*
1313

1414
include docs/docutils.conf
1515
include docs/requirements.txt
16+
include docs/html/requirements.txt
1617

1718
exclude .git-blame-ignore-revs
1819
exclude .coveragerc

‎docs/common_conf.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import os
2+
import re
3+
from typing import Tuple
4+
5+
6+
def read_version() -> Tuple[str, str]:
7+
# Find the version and release information.
8+
# We have a single source of truth for our version number: pip's __init__.py file.
9+
# This next bit of code reads from it.
10+
file_with_version = os.path.join(
11+
os.path.dirname(__file__), "..", "src", "pip", "__init__.py"
12+
)
13+
with open(file_with_version) as f:
14+
for line in f:
15+
m = re.match(r'__version__ = "(.*)"', line)
16+
if m:
17+
__version__ = m.group(1)
18+
# The short X.Y version.
19+
version = ".".join(__version__.split(".")[:2])
20+
# The full version, including alpha/beta/rc tags.
21+
release = __version__
22+
return version, release
23+
return "dev", "dev"
24+
25+
26+
# General information about the project.
27+
project = "pip"
28+
copyright = "The pip developers"
29+
version, release = read_version()

‎docs/html/conf.py

+4-62
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
"""Sphinx configuration file for pip's documentation."""
22

3-
import glob
43
import os
54
import pathlib
6-
import re
75
import sys
8-
from typing import List, Tuple
96

10-
# Add the docs/ directory to sys.path, because pip_sphinxext.py is there.
7+
# Add the docs/ directory to sys.path to load the common config,
8+
# and pip_sphinxext.py
119
docs_dir = os.path.dirname(os.path.dirname(__file__))
1210
sys.path.insert(0, docs_dir)
1311

12+
from common_conf import copyright, project, release, version # noqa: E402, F401
13+
1414
# -- General configuration ------------------------------------------------------------
1515

1616
extensions = [
@@ -28,27 +28,6 @@
2828
"sphinxcontrib.towncrier",
2929
]
3030

31-
# General information about the project.
32-
project = "pip"
33-
copyright = "The pip developers"
34-
35-
# Find the version and release information.
36-
# We have a single source of truth for our version number: pip's __init__.py file.
37-
# This next bit of code reads from it.
38-
file_with_version = os.path.join(docs_dir, "..", "src", "pip", "__init__.py")
39-
with open(file_with_version) as f:
40-
for line in f:
41-
m = re.match(r'__version__ = "(.*)"', line)
42-
if m:
43-
__version__ = m.group(1)
44-
# The short X.Y version.
45-
version = ".".join(__version__.split(".")[:2])
46-
# The full version, including alpha/beta/rc tags.
47-
release = __version__
48-
break
49-
else: # AKA no-break
50-
version = release = "dev"
51-
5231
print("pip version:", version)
5332
print("pip release:", release)
5433

@@ -95,43 +74,6 @@
9574
html_use_modindex = False
9675
html_use_index = False
9776

98-
# -- Options for Manual Pages ---------------------------------------------------------
99-
100-
101-
# List of manual pages generated
102-
def determine_man_pages() -> List[Tuple[str, str, str, str, int]]:
103-
"""Determine which man pages need to be generated."""
104-
105-
def to_document_name(path: str, base_dir: str) -> str:
106-
"""Convert a provided path to a Sphinx "document name"."""
107-
relative_path = os.path.relpath(path, base_dir)
108-
root, _ = os.path.splitext(relative_path)
109-
return root.replace(os.sep, "/")
110-
111-
# Crawl the entire man/commands/ directory and list every file with appropriate
112-
# name and details.
113-
man_dir = os.path.join(docs_dir, "man")
114-
raw_subcommands = glob.glob(os.path.join(man_dir, "commands/*.rst"))
115-
if not raw_subcommands:
116-
raise FileNotFoundError(
117-
"The individual subcommand manpages could not be found!"
118-
)
119-
120-
retval = [
121-
("index", "pip", "package manager for Python packages", "pip developers", 1),
122-
]
123-
for fname in raw_subcommands:
124-
fname_base = to_document_name(fname, man_dir)
125-
outname = "pip-" + fname_base.split("/")[1]
126-
description = "description of {} command".format(outname.replace("-", " "))
127-
128-
retval.append((fname_base, outname, description, "pip developers", 1))
129-
130-
return retval
131-
132-
133-
man_pages = determine_man_pages()
134-
13577
# -- Options for sphinx_copybutton ----------------------------------------------------
13678

13779
copybutton_prompt_text = r"\$ | C\:\> "

‎docs/html/requirements.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# currently incompatible with sphinxcontrib-towncrier
2+
# https://github.com/sphinx-contrib/sphinxcontrib-towncrier/issues/92
3+
towncrier < 24
4+
furo
5+
myst_parser
6+
sphinx-copybutton
7+
sphinx-inline-tabs
8+
sphinxcontrib-towncrier >= 0.2.0a0

‎docs/man/__init__.py

Whitespace-only changes.

‎docs/man/conf.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import glob
2+
import os
3+
import sys
4+
from typing import List, Tuple
5+
6+
# Add the docs/ directory to sys.path to load the common config
7+
docs_dir = os.path.dirname(os.path.dirname(__file__))
8+
sys.path.insert(0, docs_dir)
9+
10+
from common_conf import copyright, project, release, version # noqa: E402, F401
11+
12+
extensions = [
13+
# our extensions
14+
"pip_sphinxext",
15+
]
16+
17+
print("pip version:", version)
18+
print("pip release:", release)
19+
20+
21+
# List of manual pages generated
22+
def determine_man_pages() -> List[Tuple[str, str, str, str, int]]:
23+
"""Determine which man pages need to be generated."""
24+
25+
def to_document_name(path: str, base_dir: str) -> str:
26+
"""Convert a provided path to a Sphinx "document name"."""
27+
relative_path = os.path.relpath(path, base_dir)
28+
root, _ = os.path.splitext(relative_path)
29+
return root.replace(os.sep, "/")
30+
31+
# Crawl the entire man/commands/ directory and list every file with appropriate
32+
# name and details.
33+
man_dir = os.path.join(docs_dir, "man")
34+
raw_subcommands = glob.glob(os.path.join(man_dir, "commands/*.rst"))
35+
if not raw_subcommands:
36+
raise FileNotFoundError(
37+
"The individual subcommand manpages could not be found!"
38+
)
39+
40+
retval = [
41+
("index", "pip", "package manager for Python packages", "pip developers", 1),
42+
]
43+
for fname in raw_subcommands:
44+
fname_base = to_document_name(fname, man_dir)
45+
outname = "pip-" + fname_base.split("/")[1]
46+
description = "description of {} command".format(outname.replace("-", " "))
47+
48+
retval.append((fname_base, outname, description, "pip developers", 1))
49+
50+
return retval
51+
52+
53+
man_pages = determine_man_pages()

‎docs/requirements.txt

-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
11
sphinx ~= 7.0
2-
# currently incompatible with sphinxcontrib-towncrier
3-
# https://github.com/sphinx-contrib/sphinxcontrib-towncrier/issues/92
4-
towncrier < 24
5-
furo
6-
myst_parser
7-
sphinx-copybutton
8-
sphinx-inline-tabs
9-
sphinxcontrib-towncrier >= 0.2.0a0
102

113
# `docs.pipext` uses pip's internals to generate documentation. So, we install
124
# the current directory to make it work.

‎news/a75401cc-cba6-4eb2-ac22-5225ed3bf448.trivial.rst

Whitespace-only changes.

‎noxfile.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
}
2727
REQUIREMENTS = {
2828
"docs": "docs/requirements.txt",
29+
"docs-html": "docs/html/requirements.txt",
2930
"tests": "tests/requirements.txt",
3031
"common-wheels": "tests/requirements-common_wheels.txt",
3132
}
@@ -131,18 +132,21 @@ def docs(session: nox.Session) -> None:
131132
session.install("-r", REQUIREMENTS["docs"])
132133

133134
def get_sphinx_build_command(kind: str) -> List[str]:
134-
# Having the conf.py in the docs/html is weird but needed because we
135+
req_file = REQUIREMENTS.get(f"docs-{kind}")
136+
if req_file is not None:
137+
session.install("--requirement", req_file)
138+
# Having the conf.py in the docs/{html,man} is weird but needed because we
135139
# can not use a different configuration directory vs source directory
136140
# on RTD currently. So, we'll pass "-c docs/html" here.
137141
# See https://github.com/rtfd/readthedocs.org/issues/1543.
138142
# fmt: off
139143
return [
140144
"sphinx-build",
141145
"--keep-going",
142-
"-W",
143-
"-c", "docs/html", # see note above
144-
"-d", "docs/build/doctrees/" + kind,
145-
"-b", kind,
146+
"--fail-on-warning",
147+
"--conf-dir", "docs/" + kind, # see note above
148+
"--doctree-dir", "docs/build/doctrees/" + kind,
149+
"--builder", kind,
146150
"docs/" + kind,
147151
"docs/build/" + kind,
148152
]
@@ -155,7 +159,13 @@ def get_sphinx_build_command(kind: str) -> List[str]:
155159
@nox.session(name="docs-live")
156160
def docs_live(session: nox.Session) -> None:
157161
session.install("-e", ".")
158-
session.install("-r", REQUIREMENTS["docs"], "sphinx-autobuild")
162+
session.install(
163+
"-r",
164+
REQUIREMENTS["docs"],
165+
"-r",
166+
REQUIREMENTS["docs-html"],
167+
"sphinx-autobuild",
168+
)
159169

160170
session.run(
161171
"sphinx-autobuild",

0 commit comments

Comments
 (0)
Please sign in to comment.