Skip to content

Commit 19541fb

Browse files
committed
Use Sphinx's argument parser
1 parent 88a1098 commit 19541fb

File tree

2 files changed

+63
-106
lines changed

2 files changed

+63
-106
lines changed

sphinx_autobuild/__main__.py

Lines changed: 63 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,146 +5,135 @@
55
import argparse
66
import os
77
import shlex
8+
import sys
89

910
import colorama
1011
from livereload import Server
1112

13+
# This isn't public API, but there aren't many better options
14+
from sphinx.cmd.build import get_parser as sphinx_get_parser
15+
1216
from sphinx_autobuild import __version__
13-
from sphinx_autobuild.build import SPHINX_BUILD_OPTIONS, Builder
17+
from sphinx_autobuild.build import Builder
1418
from sphinx_autobuild.ignore import Ignore
1519
from sphinx_autobuild.utils import find_free_port
1620

1721

18-
def _get_build_args(args):
19-
build_args = []
20-
arg_dict = vars(args) # Convert the args namespace to a dictionary
21-
for opt, meta in SPHINX_BUILD_OPTIONS:
22-
arg = opt.removeprefix("-") # remove leading '-'
23-
val = arg_dict.get(arg)
24-
if val is None:
25-
continue
26-
if meta is None:
27-
build_args.extend([opt] * val)
28-
else:
29-
for v in val:
30-
build_args.extend([opt, v])
22+
def _parse_args(argv):
23+
# Parse once with the Sphinx parser to emit errors
24+
# and capture the ``-d`` and ``-w`` options.
25+
# NOTE:
26+
# The Sphinx parser is not considered to be public API,
27+
# but as this is a first-party project, we can cheat a little bit.
28+
sphinx_args = _get_sphinx_build_parser().parse_args(argv.copy())
29+
print(f"{sphinx_args.filenames=}")
3130

32-
build_args.extend([os.path.realpath(args.sourcedir), os.path.realpath(args.outdir)])
33-
build_args.extend(args.filenames)
31+
# Parse a second time with just our parser
32+
parser = _get_parser()
33+
args, build_args = parser.parse_known_args(argv.copy())
3434

35-
return build_args
35+
# Copy needed settings
36+
args.sourcedir = sphinx_args.sourcedir
37+
args.outdir = sphinx_args.outputdir
38+
args.doctree_dir = sphinx_args.doctreedir
39+
args.warnings_file = sphinx_args.warnfile
3640

41+
return args, build_args
3742

38-
def get_parser():
39-
"""Get the application's argument parser.
4043

41-
Note: this also handles SPHINX_BUILD_OPTIONS, which later get forwarded to
42-
sphinx-build as-is.
43-
"""
44+
def _get_sphinx_build_parser():
45+
# NOTE:
46+
# sphinx.cmd.build.get_parser is not considered to be public API,
47+
# but as this is a first-party project, we can cheat a little bit.
48+
sphinx_build_parser = sphinx_get_parser()
49+
sphinx_build_parser.description = None
50+
sphinx_build_parser.epilog = None
51+
sphinx_build_parser.prog = "sphinx-autobuild"
52+
for action in sphinx_build_parser._actions:
53+
if hasattr(action, "version"):
54+
# Fix the version
55+
action.version = f"%(prog)s {__version__}"
56+
break
57+
_add_autobuild_arguments(sphinx_build_parser)
4458

45-
class RawTextArgumentDefaultsHelpFormatter(
46-
argparse.ArgumentDefaultsHelpFormatter, argparse.RawTextHelpFormatter
47-
):
48-
pass
59+
return sphinx_build_parser
4960

50-
parser = argparse.ArgumentParser(
51-
formatter_class=RawTextArgumentDefaultsHelpFormatter
52-
)
61+
62+
def _get_parser():
63+
"""Get the application's argument parser."""
64+
65+
parser = argparse.ArgumentParser(allow_abbrev=False)
5366
parser.add_argument(
67+
"--version", action="version", version=f"sphinx-autobuild {__version__}"
68+
)
69+
_add_autobuild_arguments(parser)
70+
71+
return parser
72+
73+
74+
def _add_autobuild_arguments(parser):
75+
group = parser.add_argument_group('autobuild options')
76+
group.add_argument(
5477
"--port",
5578
type=int,
5679
default=8000,
5780
help="port to serve documentation on. 0 means find and use a free port",
5881
)
59-
parser.add_argument(
82+
group.add_argument(
6083
"--host",
6184
type=str,
6285
default="127.0.0.1",
6386
help="hostname to serve documentation on",
6487
)
65-
parser.add_argument(
88+
group.add_argument(
6689
"--re-ignore",
6790
action="append",
6891
default=[],
6992
help="regular expression for files to ignore, when watching for changes",
7093
)
71-
parser.add_argument(
94+
group.add_argument(
7295
"--ignore",
7396
action="append",
7497
default=[],
7598
help="glob expression for files to ignore, when watching for changes",
7699
)
77-
parser.add_argument(
100+
group.add_argument(
78101
"--no-initial",
79102
dest="no_initial_build",
80103
action="store_true",
81104
default=False,
82105
help="skip the initial build",
83106
)
84-
parser.add_argument(
107+
group.add_argument(
85108
"--open-browser",
86109
dest="openbrowser",
87110
action="store_true",
88111
default=False,
89112
help="open the browser after building documentation",
90113
)
91-
parser.add_argument(
114+
group.add_argument(
92115
"--delay",
93116
dest="delay",
94117
type=int,
95118
default=5,
96119
help="how long to wait before opening the browser",
97120
)
98-
parser.add_argument(
121+
group.add_argument(
99122
"--watch",
100123
action="append",
101124
metavar="DIR",
102125
default=[],
103126
help="additional directories to watch",
104127
dest="additional_watched_dirs",
105128
)
106-
parser.add_argument(
129+
group.add_argument(
107130
"--pre-build",
108131
action="append",
109132
metavar="COMMAND",
110133
default=[],
111134
help="additional command(s) to run prior to building the documentation",
112135
)
113-
parser.add_argument(
114-
"--version", action="version", version=f"sphinx-autobuild {__version__}"
115-
)
116-
117-
sphinx_arguments = ", ".join(
118-
arg if meta is None else f"{arg}={meta}"
119-
for arg, meta in SPHINX_BUILD_OPTIONS
120-
)
121-
sphinx_parser = parser.add_argument_group(
122-
"sphinx's arguments",
123-
(
124-
"The following arguments are forwarded as-is to Sphinx. Please look at "
125-
f"`sphinx --help` for more information.\n {sphinx_arguments}"
126-
),
127-
)
128-
129-
for arg, meta in SPHINX_BUILD_OPTIONS:
130-
if meta is None:
131-
sphinx_parser.add_argument(
132-
arg, action="count", help=argparse.SUPPRESS
133-
)
134-
else:
135-
sphinx_parser.add_argument(
136-
arg,
137-
action="append",
138-
help=argparse.SUPPRESS,
139-
metavar=meta,
140-
)
141-
142-
parser.add_argument("sourcedir", help="source directory")
143-
parser.add_argument("outdir", help="output directory for built documentation")
144-
parser.add_argument(
145-
"filenames", nargs="*", help="specific files to rebuild on each run"
146-
)
147-
return parser
136+
return group
148137

149138

150139
def _get_ignore_handler(ignore, regex_based, out_dir, doctree_dir, warnings_file):
@@ -162,8 +151,7 @@ def main():
162151
"""Actual application logic."""
163152
colorama.init()
164153

165-
parser = get_parser()
166-
args = parser.parse_args()
154+
args, build_args = _parse_args(sys.argv[1:])
167155

168156
srcdir = os.path.realpath(args.sourcedir)
169157
outdir = os.path.realpath(args.outdir)
@@ -173,7 +161,6 @@ def main():
173161
port_num = args.port or find_free_port()
174162
server = Server()
175163

176-
build_args = _get_build_args(args)
177164
pre_build_commands = list(map(shlex.split, args.pre_build))
178165
builder = Builder(
179166
server.watcher,
@@ -184,7 +171,7 @@ def main():
184171
)
185172

186173
ignore_handler = _get_ignore_handler(args.ignore, args.re_ignore, outdir,
187-
args.w, args.d)
174+
args.warnings_file, args.doctree_dir)
188175
server.watch(srcdir, builder, ignore=ignore_handler)
189176
for dirpath in args.additional_watched_dirs:
190177
dirpath = os.path.realpath(dirpath)

sphinx_autobuild/build.py

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,6 @@
66

77
from colorama import Fore, Style
88

9-
SPHINX_BUILD_OPTIONS = (
10-
# general options
11-
("-b", "builder"),
12-
("-a", None),
13-
("-E", None),
14-
("-j", "N"),
15-
("--jobs", "N"),
16-
# path options
17-
("-d", "path"),
18-
("-c", "path"),
19-
# build configuration options
20-
("-C", None),
21-
("-D", "setting=value"),
22-
("-A", "name=value"),
23-
("-t", "tag"),
24-
("-n", None),
25-
# console output options
26-
("-v", None),
27-
("-q", None),
28-
("-Q", None),
29-
("--color", None),
30-
("-N", None),
31-
# warning control options
32-
("-w", "file"),
33-
("--keep-going", None),
34-
("-W", None),
35-
("-T", None),
36-
("-P", None),
37-
)
38-
399

4010
def _log(text, *, colour):
4111
print(f"{Fore.GREEN}[sphinx-autobuild] {colour}{text}{Style.RESET_ALL}")

0 commit comments

Comments
 (0)