mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
[format] Add ruff formating for apidoc/autosummary (#12447)
This commit is contained in:
parent
13b16c9b04
commit
ee92847a0a
27
.ruff.toml
27
.ruff.toml
@ -448,7 +448,32 @@ exclude = [
|
|||||||
"sphinx/directives/*",
|
"sphinx/directives/*",
|
||||||
"sphinx/domains/*",
|
"sphinx/domains/*",
|
||||||
"sphinx/environment/*",
|
"sphinx/environment/*",
|
||||||
"sphinx/ext/*",
|
"sphinx/ext/autodoc/__init__.py",
|
||||||
|
"sphinx/ext/autodoc/directive.py",
|
||||||
|
"sphinx/ext/autodoc/importer.py",
|
||||||
|
"sphinx/ext/autodoc/mock.py",
|
||||||
|
"sphinx/ext/autodoc/preserve_defaults.py",
|
||||||
|
"sphinx/ext/autodoc/type_comment.py",
|
||||||
|
"sphinx/ext/autodoc/typehints.py",
|
||||||
|
"sphinx/ext/autosectionlabel.py",
|
||||||
|
"sphinx/ext/autosummary/__init__.py",
|
||||||
|
"sphinx/ext/coverage.py",
|
||||||
|
"sphinx/ext/doctest.py",
|
||||||
|
"sphinx/ext/duration.py",
|
||||||
|
"sphinx/ext/extlinks.py",
|
||||||
|
"sphinx/ext/githubpages.py",
|
||||||
|
"sphinx/ext/graphviz.py",
|
||||||
|
"sphinx/ext/ifconfig.py",
|
||||||
|
"sphinx/ext/imgconverter.py",
|
||||||
|
"sphinx/ext/imgmath.py",
|
||||||
|
"sphinx/ext/inheritance_diagram.py",
|
||||||
|
"sphinx/ext/intersphinx/*",
|
||||||
|
"sphinx/ext/linkcode.py",
|
||||||
|
"sphinx/ext/mathjax.py",
|
||||||
|
"sphinx/ext/napoleon/__init__.py",
|
||||||
|
"sphinx/ext/napoleon/docstring.py",
|
||||||
|
"sphinx/ext/todo.py",
|
||||||
|
"sphinx/ext/viewcode.py",
|
||||||
"sphinx/pycode/*",
|
"sphinx/pycode/*",
|
||||||
"sphinx/pygments_styles.py",
|
"sphinx/pygments_styles.py",
|
||||||
"sphinx/registry.py",
|
"sphinx/registry.py",
|
||||||
|
@ -95,8 +95,9 @@ def write_file(name: str, text: str, opts: Any) -> None:
|
|||||||
f.write(text)
|
f.write(text)
|
||||||
|
|
||||||
|
|
||||||
def create_module_file(package: str | None, basename: str, opts: Any,
|
def create_module_file(
|
||||||
user_template_dir: str | None = None) -> None:
|
package: str | None, basename: str, opts: Any, user_template_dir: str | None = None
|
||||||
|
) -> None:
|
||||||
"""Build the text of the file and write the file."""
|
"""Build the text of the file and write the file."""
|
||||||
options = copy(OPTIONS)
|
options = copy(OPTIONS)
|
||||||
if opts.includeprivate and 'private-members' not in options:
|
if opts.includeprivate and 'private-members' not in options:
|
||||||
@ -117,24 +118,32 @@ def create_module_file(package: str | None, basename: str, opts: Any,
|
|||||||
write_file(qualname, text, opts)
|
write_file(qualname, text, opts)
|
||||||
|
|
||||||
|
|
||||||
def create_package_file(root: str, master_package: str | None, subroot: str,
|
def create_package_file(
|
||||||
py_files: list[str],
|
root: str,
|
||||||
opts: Any, subs: list[str], is_namespace: bool,
|
master_package: str | None,
|
||||||
excludes: Sequence[re.Pattern[str]] = (),
|
subroot: str,
|
||||||
user_template_dir: str | None = None,
|
py_files: list[str],
|
||||||
) -> None:
|
opts: Any,
|
||||||
|
subs: list[str],
|
||||||
|
is_namespace: bool,
|
||||||
|
excludes: Sequence[re.Pattern[str]] = (),
|
||||||
|
user_template_dir: str | None = None,
|
||||||
|
) -> None:
|
||||||
"""Build the text of the file and write the file."""
|
"""Build the text of the file and write the file."""
|
||||||
# build a list of sub packages (directories containing an __init__ file)
|
# build a list of sub packages (directories containing an __init__ file)
|
||||||
subpackages = [module_join(master_package, subroot, pkgname)
|
subpackages = [
|
||||||
for pkgname in subs
|
module_join(master_package, subroot, pkgname)
|
||||||
if not is_skipped_package(path.join(root, pkgname), opts, excludes)]
|
for pkgname in subs
|
||||||
|
if not is_skipped_package(path.join(root, pkgname), opts, excludes)
|
||||||
|
]
|
||||||
# build a list of sub modules
|
# build a list of sub modules
|
||||||
submodules = [sub.split('.')[0] for sub in py_files
|
submodules = [
|
||||||
if not is_skipped_module(path.join(root, sub), opts, excludes) and
|
sub.split('.')[0]
|
||||||
not is_initpy(sub)]
|
for sub in py_files
|
||||||
|
if not is_skipped_module(path.join(root, sub), opts, excludes) and not is_initpy(sub)
|
||||||
|
]
|
||||||
submodules = sorted(set(submodules))
|
submodules = sorted(set(submodules))
|
||||||
submodules = [module_join(master_package, subroot, modname)
|
submodules = [module_join(master_package, subroot, modname) for modname in submodules]
|
||||||
for modname in submodules]
|
|
||||||
options = copy(OPTIONS)
|
options = copy(OPTIONS)
|
||||||
if opts.includeprivate and 'private-members' not in options:
|
if opts.includeprivate and 'private-members' not in options:
|
||||||
options.append('private-members')
|
options.append('private-members')
|
||||||
@ -163,8 +172,9 @@ def create_package_file(root: str, master_package: str | None, subroot: str,
|
|||||||
create_module_file(None, submodule, opts, user_template_dir)
|
create_module_file(None, submodule, opts, user_template_dir)
|
||||||
|
|
||||||
|
|
||||||
def create_modules_toc_file(modules: list[str], opts: Any, name: str = 'modules',
|
def create_modules_toc_file(
|
||||||
user_template_dir: str | None = None) -> None:
|
modules: list[str], opts: Any, name: str = 'modules', user_template_dir: str | None = None
|
||||||
|
) -> None:
|
||||||
"""Create the module's index."""
|
"""Create the module's index."""
|
||||||
modules.sort()
|
modules.sort()
|
||||||
prev_module = ''
|
prev_module = ''
|
||||||
@ -188,8 +198,9 @@ def create_modules_toc_file(modules: list[str], opts: Any, name: str = 'modules'
|
|||||||
write_file(name, text, opts)
|
write_file(name, text, opts)
|
||||||
|
|
||||||
|
|
||||||
def is_skipped_package(dirname: str, opts: Any,
|
def is_skipped_package(
|
||||||
excludes: Sequence[re.Pattern[str]] = ()) -> bool:
|
dirname: str, opts: Any, excludes: Sequence[re.Pattern[str]] = ()
|
||||||
|
) -> bool:
|
||||||
"""Check if we want to skip this module."""
|
"""Check if we want to skip this module."""
|
||||||
if not path.isdir(dirname):
|
if not path.isdir(dirname):
|
||||||
return False
|
return False
|
||||||
@ -213,17 +224,22 @@ def is_skipped_module(filename: str, opts: Any, _excludes: Sequence[re.Pattern[s
|
|||||||
return path.basename(filename).startswith('_') and not opts.includeprivate
|
return path.basename(filename).startswith('_') and not opts.includeprivate
|
||||||
|
|
||||||
|
|
||||||
def walk(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any,
|
def walk(
|
||||||
) -> Iterator[tuple[str, list[str], list[str]]]:
|
rootpath: str,
|
||||||
|
excludes: Sequence[re.Pattern[str]],
|
||||||
|
opts: Any,
|
||||||
|
) -> Iterator[tuple[str, list[str], list[str]]]:
|
||||||
"""Walk through the directory and list files and subdirectories up."""
|
"""Walk through the directory and list files and subdirectories up."""
|
||||||
followlinks = getattr(opts, 'followlinks', False)
|
followlinks = getattr(opts, 'followlinks', False)
|
||||||
includeprivate = getattr(opts, 'includeprivate', False)
|
includeprivate = getattr(opts, 'includeprivate', False)
|
||||||
|
|
||||||
for root, subs, files in os.walk(rootpath, followlinks=followlinks):
|
for root, subs, files in os.walk(rootpath, followlinks=followlinks):
|
||||||
# document only Python module files (that aren't excluded)
|
# document only Python module files (that aren't excluded)
|
||||||
files = sorted(f for f in files
|
files = sorted(
|
||||||
if f.endswith(PY_SUFFIXES) and
|
f
|
||||||
not is_excluded(path.join(root, f), excludes))
|
for f in files
|
||||||
|
if f.endswith(PY_SUFFIXES) and not is_excluded(path.join(root, f), excludes)
|
||||||
|
)
|
||||||
|
|
||||||
# remove hidden ('.') and private ('_') directories, as well as
|
# remove hidden ('.') and private ('_') directories, as well as
|
||||||
# excluded dirs
|
# excluded dirs
|
||||||
@ -232,22 +248,27 @@ def walk(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any,
|
|||||||
else:
|
else:
|
||||||
exclude_prefixes = ('.', '_')
|
exclude_prefixes = ('.', '_')
|
||||||
|
|
||||||
subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and
|
subs[:] = sorted(
|
||||||
not is_excluded(path.join(root, sub), excludes))
|
sub
|
||||||
|
for sub in subs
|
||||||
|
if not sub.startswith(exclude_prefixes)
|
||||||
|
and not is_excluded(path.join(root, sub), excludes)
|
||||||
|
)
|
||||||
|
|
||||||
yield root, subs, files
|
yield root, subs, files
|
||||||
|
|
||||||
|
|
||||||
def has_child_module(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any) -> bool:
|
def has_child_module(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any) -> bool:
|
||||||
"""Check the given directory contains child module/s (at least one)."""
|
"""Check the given directory contains child module/s (at least one)."""
|
||||||
return any(
|
return any(files for _root, _subs, files in walk(rootpath, excludes, opts))
|
||||||
files
|
|
||||||
for _root, _subs, files in walk(rootpath, excludes, opts)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def recurse_tree(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any,
|
def recurse_tree(
|
||||||
user_template_dir: str | None = None) -> list[str]:
|
rootpath: str,
|
||||||
|
excludes: Sequence[re.Pattern[str]],
|
||||||
|
opts: Any,
|
||||||
|
user_template_dir: str | None = None,
|
||||||
|
) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Look for every file in the directory tree and create the corresponding
|
Look for every file in the directory tree and create the corresponding
|
||||||
ReST files.
|
ReST files.
|
||||||
@ -279,14 +300,21 @@ def recurse_tree(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any,
|
|||||||
if is_pkg or is_namespace:
|
if is_pkg or is_namespace:
|
||||||
# we are in a package with something to document
|
# we are in a package with something to document
|
||||||
if subs or len(files) > 1 or not is_skipped_package(root, opts):
|
if subs or len(files) > 1 or not is_skipped_package(root, opts):
|
||||||
subpackage = root[len(rootpath):].lstrip(path.sep).\
|
subpackage = root[len(rootpath) :].lstrip(path.sep).replace(path.sep, '.')
|
||||||
replace(path.sep, '.')
|
|
||||||
# if this is not a namespace or
|
# if this is not a namespace or
|
||||||
# a namespace and there is something there to document
|
# a namespace and there is something there to document
|
||||||
if not is_namespace or has_child_module(root, excludes, opts):
|
if not is_namespace or has_child_module(root, excludes, opts):
|
||||||
create_package_file(root, root_package, subpackage,
|
create_package_file(
|
||||||
files, opts, subs, is_namespace, excludes,
|
root,
|
||||||
user_template_dir)
|
root_package,
|
||||||
|
subpackage,
|
||||||
|
files,
|
||||||
|
opts,
|
||||||
|
subs,
|
||||||
|
is_namespace,
|
||||||
|
excludes,
|
||||||
|
user_template_dir,
|
||||||
|
)
|
||||||
toplevels.append(module_join(root_package, subpackage))
|
toplevels.append(module_join(root_package, subpackage))
|
||||||
else:
|
else:
|
||||||
# if we are at the root level, we don't require it to be a package
|
# if we are at the root level, we don't require it to be a package
|
||||||
@ -312,8 +340,7 @@ def is_excluded(root: str, excludes: Sequence[re.Pattern[str]]) -> bool:
|
|||||||
|
|
||||||
def get_parser() -> argparse.ArgumentParser:
|
def get_parser() -> argparse.ArgumentParser:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
usage='%(prog)s [OPTIONS] -o <OUTPUT_PATH> <MODULE_PATH> '
|
usage='%(prog)s [OPTIONS] -o <OUTPUT_PATH> <MODULE_PATH> ' '[EXCLUDE_PATTERN, ...]',
|
||||||
'[EXCLUDE_PATTERN, ...]',
|
|
||||||
epilog=__('For more information, visit <https://www.sphinx-doc.org/>.'),
|
epilog=__('For more information, visit <https://www.sphinx-doc.org/>.'),
|
||||||
description=__("""
|
description=__("""
|
||||||
Look recursively in <MODULE_PATH> for Python modules and packages and create
|
Look recursively in <MODULE_PATH> for Python modules and packages and create
|
||||||
@ -322,87 +349,196 @@ one reST file with automodule directives per package in the <OUTPUT_PATH>.
|
|||||||
The <EXCLUDE_PATTERN>s can be file and/or directory patterns that will be
|
The <EXCLUDE_PATTERN>s can be file and/or directory patterns that will be
|
||||||
excluded from generation.
|
excluded from generation.
|
||||||
|
|
||||||
Note: By default this script will not overwrite already created files."""))
|
Note: By default this script will not overwrite already created files."""),
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument('--version', action='version', dest='show_version',
|
parser.add_argument(
|
||||||
version='%%(prog)s %s' % __display_version__)
|
'--version',
|
||||||
|
action='version',
|
||||||
|
dest='show_version',
|
||||||
|
version='%%(prog)s %s' % __display_version__,
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument('module_path',
|
parser.add_argument('module_path', help=__('path to module to document'))
|
||||||
help=__('path to module to document'))
|
parser.add_argument(
|
||||||
parser.add_argument('exclude_pattern', nargs='*',
|
'exclude_pattern',
|
||||||
help=__('fnmatch-style file and/or directory patterns '
|
nargs='*',
|
||||||
'to exclude from generation'))
|
help=__('fnmatch-style file and/or directory patterns ' 'to exclude from generation'),
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument('-o', '--output-dir', action='store', dest='destdir',
|
parser.add_argument(
|
||||||
required=True,
|
'-o',
|
||||||
help=__('directory to place all output'))
|
'--output-dir',
|
||||||
parser.add_argument('-q', action='store_true', dest='quiet',
|
action='store',
|
||||||
help=__('no output on stdout, just warnings on stderr'))
|
dest='destdir',
|
||||||
parser.add_argument('-d', '--maxdepth', action='store', dest='maxdepth',
|
required=True,
|
||||||
type=int, default=4,
|
help=__('directory to place all output'),
|
||||||
help=__('maximum depth of submodules to show in the TOC '
|
)
|
||||||
'(default: 4)'))
|
parser.add_argument(
|
||||||
parser.add_argument('-f', '--force', action='store_true', dest='force',
|
'-q',
|
||||||
help=__('overwrite existing files'))
|
action='store_true',
|
||||||
parser.add_argument('-l', '--follow-links', action='store_true',
|
dest='quiet',
|
||||||
dest='followlinks', default=False,
|
help=__('no output on stdout, just warnings on stderr'),
|
||||||
help=__('follow symbolic links. Powerful when combined '
|
)
|
||||||
'with collective.recipe.omelette.'))
|
parser.add_argument(
|
||||||
parser.add_argument('-n', '--dry-run', action='store_true', dest='dryrun',
|
'-d',
|
||||||
help=__('run the script without creating files'))
|
'--maxdepth',
|
||||||
parser.add_argument('-e', '--separate', action='store_true',
|
action='store',
|
||||||
dest='separatemodules',
|
dest='maxdepth',
|
||||||
help=__('put documentation for each module on its own page'))
|
type=int,
|
||||||
parser.add_argument('-P', '--private', action='store_true',
|
default=4,
|
||||||
dest='includeprivate',
|
help=__('maximum depth of submodules to show in the TOC ' '(default: 4)'),
|
||||||
help=__('include "_private" modules'))
|
)
|
||||||
parser.add_argument('--tocfile', action='store', dest='tocfile', default='modules',
|
parser.add_argument(
|
||||||
help=__("filename of table of contents (default: modules)"))
|
'-f', '--force', action='store_true', dest='force', help=__('overwrite existing files')
|
||||||
parser.add_argument('-T', '--no-toc', action='store_false', dest='tocfile',
|
)
|
||||||
help=__("don't create a table of contents file"))
|
parser.add_argument(
|
||||||
parser.add_argument('-E', '--no-headings', action='store_true',
|
'-l',
|
||||||
dest='noheadings',
|
'--follow-links',
|
||||||
help=__("don't create headings for the module/package "
|
action='store_true',
|
||||||
"packages (e.g. when the docstrings already "
|
dest='followlinks',
|
||||||
"contain them)"))
|
default=False,
|
||||||
parser.add_argument('-M', '--module-first', action='store_true',
|
help=__(
|
||||||
dest='modulefirst',
|
'follow symbolic links. Powerful when combined ' 'with collective.recipe.omelette.'
|
||||||
help=__('put module documentation before submodule '
|
),
|
||||||
'documentation'))
|
)
|
||||||
parser.add_argument('--implicit-namespaces', action='store_true',
|
parser.add_argument(
|
||||||
dest='implicit_namespaces',
|
'-n',
|
||||||
help=__('interpret module paths according to PEP-0420 '
|
'--dry-run',
|
||||||
'implicit namespaces specification'))
|
action='store_true',
|
||||||
parser.add_argument('-s', '--suffix', action='store', dest='suffix',
|
dest='dryrun',
|
||||||
default='rst',
|
help=__('run the script without creating files'),
|
||||||
help=__('file suffix (default: rst)'))
|
)
|
||||||
parser.add_argument('-F', '--full', action='store_true', dest='full',
|
parser.add_argument(
|
||||||
help=__('generate a full project with sphinx-quickstart'))
|
'-e',
|
||||||
parser.add_argument('-a', '--append-syspath', action='store_true',
|
'--separate',
|
||||||
dest='append_syspath',
|
action='store_true',
|
||||||
help=__('append module_path to sys.path, used when --full is given'))
|
dest='separatemodules',
|
||||||
parser.add_argument('-H', '--doc-project', action='store', dest='header',
|
help=__('put documentation for each module on its own page'),
|
||||||
help=__('project name (default: root module name)'))
|
)
|
||||||
parser.add_argument('-A', '--doc-author', action='store', dest='author',
|
parser.add_argument(
|
||||||
help=__('project author(s), used when --full is given'))
|
'-P',
|
||||||
parser.add_argument('-V', '--doc-version', action='store', dest='version',
|
'--private',
|
||||||
help=__('project version, used when --full is given'))
|
action='store_true',
|
||||||
parser.add_argument('-R', '--doc-release', action='store', dest='release',
|
dest='includeprivate',
|
||||||
help=__('project release, used when --full is given, '
|
help=__('include "_private" modules'),
|
||||||
'defaults to --doc-version'))
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--tocfile',
|
||||||
|
action='store',
|
||||||
|
dest='tocfile',
|
||||||
|
default='modules',
|
||||||
|
help=__('filename of table of contents (default: modules)'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-T',
|
||||||
|
'--no-toc',
|
||||||
|
action='store_false',
|
||||||
|
dest='tocfile',
|
||||||
|
help=__("don't create a table of contents file"),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-E',
|
||||||
|
'--no-headings',
|
||||||
|
action='store_true',
|
||||||
|
dest='noheadings',
|
||||||
|
help=__(
|
||||||
|
"don't create headings for the module/package "
|
||||||
|
'packages (e.g. when the docstrings already '
|
||||||
|
'contain them)'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-M',
|
||||||
|
'--module-first',
|
||||||
|
action='store_true',
|
||||||
|
dest='modulefirst',
|
||||||
|
help=__('put module documentation before submodule ' 'documentation'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--implicit-namespaces',
|
||||||
|
action='store_true',
|
||||||
|
dest='implicit_namespaces',
|
||||||
|
help=__(
|
||||||
|
'interpret module paths according to PEP-0420 ' 'implicit namespaces specification'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-s',
|
||||||
|
'--suffix',
|
||||||
|
action='store',
|
||||||
|
dest='suffix',
|
||||||
|
default='rst',
|
||||||
|
help=__('file suffix (default: rst)'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-F',
|
||||||
|
'--full',
|
||||||
|
action='store_true',
|
||||||
|
dest='full',
|
||||||
|
help=__('generate a full project with sphinx-quickstart'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-a',
|
||||||
|
'--append-syspath',
|
||||||
|
action='store_true',
|
||||||
|
dest='append_syspath',
|
||||||
|
help=__('append module_path to sys.path, used when --full is given'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-H',
|
||||||
|
'--doc-project',
|
||||||
|
action='store',
|
||||||
|
dest='header',
|
||||||
|
help=__('project name (default: root module name)'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-A',
|
||||||
|
'--doc-author',
|
||||||
|
action='store',
|
||||||
|
dest='author',
|
||||||
|
help=__('project author(s), used when --full is given'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-V',
|
||||||
|
'--doc-version',
|
||||||
|
action='store',
|
||||||
|
dest='version',
|
||||||
|
help=__('project version, used when --full is given'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-R',
|
||||||
|
'--doc-release',
|
||||||
|
action='store',
|
||||||
|
dest='release',
|
||||||
|
help=__('project release, used when --full is given, ' 'defaults to --doc-version'),
|
||||||
|
)
|
||||||
|
|
||||||
group = parser.add_argument_group(__('extension options'))
|
group = parser.add_argument_group(__('extension options'))
|
||||||
group.add_argument('--extensions', metavar='EXTENSIONS', dest='extensions',
|
group.add_argument(
|
||||||
action='append', help=__('enable arbitrary extensions'))
|
'--extensions',
|
||||||
|
metavar='EXTENSIONS',
|
||||||
|
dest='extensions',
|
||||||
|
action='append',
|
||||||
|
help=__('enable arbitrary extensions'),
|
||||||
|
)
|
||||||
for ext in EXTENSIONS:
|
for ext in EXTENSIONS:
|
||||||
group.add_argument('--ext-%s' % ext, action='append_const',
|
group.add_argument(
|
||||||
const='sphinx.ext.%s' % ext, dest='extensions',
|
'--ext-%s' % ext,
|
||||||
help=__('enable %s extension') % ext)
|
action='append_const',
|
||||||
|
const='sphinx.ext.%s' % ext,
|
||||||
|
dest='extensions',
|
||||||
|
help=__('enable %s extension') % ext,
|
||||||
|
)
|
||||||
|
|
||||||
group = parser.add_argument_group(__('Project templating'))
|
group = parser.add_argument_group(__('Project templating'))
|
||||||
group.add_argument('-t', '--templatedir', metavar='TEMPLATEDIR',
|
group.add_argument(
|
||||||
dest='templatedir',
|
'-t',
|
||||||
help=__('template directory for template files'))
|
'--templatedir',
|
||||||
|
metavar='TEMPLATEDIR',
|
||||||
|
dest='templatedir',
|
||||||
|
help=__('template directory for template files'),
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -436,6 +572,7 @@ def main(argv: Sequence[str] = (), /) -> int:
|
|||||||
|
|
||||||
if args.full:
|
if args.full:
|
||||||
from sphinx.cmd import quickstart as qs
|
from sphinx.cmd import quickstart as qs
|
||||||
|
|
||||||
modules.sort()
|
modules.sort()
|
||||||
prev_module = ''
|
prev_module = ''
|
||||||
text = ''
|
text = ''
|
||||||
@ -455,8 +592,7 @@ def main(argv: Sequence[str] = (), /) -> int:
|
|||||||
'suffix': '.' + args.suffix,
|
'suffix': '.' + args.suffix,
|
||||||
'master': 'index',
|
'master': 'index',
|
||||||
'epub': True,
|
'epub': True,
|
||||||
'extensions': ['sphinx.ext.autodoc', 'sphinx.ext.viewcode',
|
'extensions': ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.todo'],
|
||||||
'sphinx.ext.todo'],
|
|
||||||
'makefile': True,
|
'makefile': True,
|
||||||
'batchfile': True,
|
'batchfile': True,
|
||||||
'make_mode': True,
|
'make_mode': True,
|
||||||
@ -477,8 +613,7 @@ def main(argv: Sequence[str] = (), /) -> int:
|
|||||||
d['extensions'].extend(ext.split(','))
|
d['extensions'].extend(ext.split(','))
|
||||||
|
|
||||||
if not args.dryrun:
|
if not args.dryrun:
|
||||||
qs.generate(d, silent=True, overwrite=args.force,
|
qs.generate(d, silent=True, overwrite=args.force, templatedir=args.templatedir)
|
||||||
templatedir=args.templatedir)
|
|
||||||
elif args.tocfile:
|
elif args.tocfile:
|
||||||
create_modules_toc_file(modules, args, args.tocfile, args.templatedir)
|
create_modules_toc_file(modules, args, args.tocfile, args.templatedir)
|
||||||
|
|
||||||
@ -486,5 +621,5 @@ def main(argv: Sequence[str] = (), /) -> int:
|
|||||||
|
|
||||||
|
|
||||||
# So program can be started with "python -m sphinx.apidoc ..."
|
# So program can be started with "python -m sphinx.apidoc ..."
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
raise SystemExit(main(sys.argv[1:]))
|
raise SystemExit(main(sys.argv[1:]))
|
||||||
|
@ -65,7 +65,7 @@ class DummyApplication:
|
|||||||
self.config = Config()
|
self.config = Config()
|
||||||
self.registry = SphinxComponentRegistry()
|
self.registry = SphinxComponentRegistry()
|
||||||
self.messagelog: list[str] = []
|
self.messagelog: list[str] = []
|
||||||
self.srcdir = "/"
|
self.srcdir = '/'
|
||||||
self.translator = translator
|
self.translator = translator
|
||||||
self.verbosity = 0
|
self.verbosity = 0
|
||||||
self._warncount = 0
|
self._warncount = 0
|
||||||
@ -98,10 +98,17 @@ def setup_documenters(app: Any) -> None:
|
|||||||
ModuleDocumenter,
|
ModuleDocumenter,
|
||||||
PropertyDocumenter,
|
PropertyDocumenter,
|
||||||
)
|
)
|
||||||
|
|
||||||
documenters: list[type[Documenter]] = [
|
documenters: list[type[Documenter]] = [
|
||||||
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
|
ModuleDocumenter,
|
||||||
FunctionDocumenter, MethodDocumenter,
|
ClassDocumenter,
|
||||||
AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,
|
ExceptionDocumenter,
|
||||||
|
DataDocumenter,
|
||||||
|
FunctionDocumenter,
|
||||||
|
MethodDocumenter,
|
||||||
|
AttributeDocumenter,
|
||||||
|
DecoratorDocumenter,
|
||||||
|
PropertyDocumenter,
|
||||||
]
|
]
|
||||||
for documenter in documenters:
|
for documenter in documenters:
|
||||||
app.registry.add_documenter(documenter.objtype, documenter)
|
app.registry.add_documenter(documenter.objtype, documenter)
|
||||||
@ -123,8 +130,9 @@ class AutosummaryRenderer:
|
|||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
system_templates_path = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')]
|
system_templates_path = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')]
|
||||||
loader = SphinxTemplateLoader(app.srcdir, app.config.templates_path,
|
loader = SphinxTemplateLoader(
|
||||||
system_templates_path)
|
app.srcdir, app.config.templates_path, system_templates_path
|
||||||
|
)
|
||||||
|
|
||||||
self.env = SandboxedEnvironment(loader=loader)
|
self.env = SandboxedEnvironment(loader=loader)
|
||||||
self.env.filters['escape'] = rst.escape
|
self.env.filters['escape'] = rst.escape
|
||||||
@ -132,7 +140,7 @@ class AutosummaryRenderer:
|
|||||||
self.env.filters['underline'] = _underline
|
self.env.filters['underline'] = _underline
|
||||||
|
|
||||||
if app.translator:
|
if app.translator:
|
||||||
self.env.add_extension("jinja2.ext.i18n")
|
self.env.add_extension('jinja2.ext.i18n')
|
||||||
# ``install_gettext_translations`` is injected by the ``jinja2.ext.i18n`` extension
|
# ``install_gettext_translations`` is injected by the ``jinja2.ext.i18n`` extension
|
||||||
self.env.install_gettext_translations(app.translator) # type: ignore[attr-defined]
|
self.env.install_gettext_translations(app.translator) # type: ignore[attr-defined]
|
||||||
|
|
||||||
@ -168,17 +176,17 @@ def _split_full_qualified_name(name: str) -> tuple[str | None, str]:
|
|||||||
parts = name.split('.')
|
parts = name.split('.')
|
||||||
for i, _part in enumerate(parts, 1):
|
for i, _part in enumerate(parts, 1):
|
||||||
try:
|
try:
|
||||||
modname = ".".join(parts[:i])
|
modname = '.'.join(parts[:i])
|
||||||
importlib.import_module(modname)
|
importlib.import_module(modname)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if parts[:i - 1]:
|
if parts[: i - 1]:
|
||||||
return ".".join(parts[:i - 1]), ".".join(parts[i - 1:])
|
return '.'.join(parts[: i - 1]), '.'.join(parts[i - 1 :])
|
||||||
else:
|
else:
|
||||||
return None, ".".join(parts)
|
return None, '.'.join(parts)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return name, ""
|
return name, ''
|
||||||
|
|
||||||
|
|
||||||
# -- Generating output ---------------------------------------------------------
|
# -- Generating output ---------------------------------------------------------
|
||||||
@ -194,12 +202,19 @@ class ModuleScanner:
|
|||||||
|
|
||||||
def is_skipped(self, name: str, value: Any, objtype: str) -> bool:
|
def is_skipped(self, name: str, value: Any, objtype: str) -> bool:
|
||||||
try:
|
try:
|
||||||
return self.app.emit_firstresult('autodoc-skip-member', objtype,
|
return self.app.emit_firstresult(
|
||||||
name, value, False, {})
|
'autodoc-skip-member', objtype, name, value, False, {}
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(__('autosummary: failed to determine %r to be documented, '
|
logger.warning(
|
||||||
'the following exception was raised:\n%s'),
|
__(
|
||||||
name, exc, type='autosummary')
|
'autosummary: failed to determine %r to be documented, '
|
||||||
|
'the following exception was raised:\n%s'
|
||||||
|
),
|
||||||
|
name,
|
||||||
|
exc,
|
||||||
|
type='autosummary',
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def scan(self, imported_members: bool) -> list[str]:
|
def scan(self, imported_members: bool) -> list[str]:
|
||||||
@ -257,12 +272,19 @@ def members_of(obj: Any, conf: Config) -> Sequence[str]:
|
|||||||
return getall(obj) or dir(obj)
|
return getall(obj) or dir(obj)
|
||||||
|
|
||||||
|
|
||||||
def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
def generate_autosummary_content(
|
||||||
template: AutosummaryRenderer, template_name: str,
|
name: str,
|
||||||
imported_members: bool, app: Any,
|
obj: Any,
|
||||||
recursive: bool, context: dict,
|
parent: Any,
|
||||||
modname: str | None = None,
|
template: AutosummaryRenderer,
|
||||||
qualname: str | None = None) -> str:
|
template_name: str,
|
||||||
|
imported_members: bool,
|
||||||
|
app: Any,
|
||||||
|
recursive: bool,
|
||||||
|
context: dict,
|
||||||
|
modname: str | None = None,
|
||||||
|
qualname: str | None = None,
|
||||||
|
) -> str:
|
||||||
doc = get_documenter(app, obj, parent)
|
doc = get_documenter(app, obj, parent)
|
||||||
|
|
||||||
ns: dict[str, Any] = {}
|
ns: dict[str, Any] = {}
|
||||||
@ -275,23 +297,25 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
respect_module_all = not app.config.autosummary_ignore_module_all
|
respect_module_all = not app.config.autosummary_ignore_module_all
|
||||||
imported_members = imported_members or ('__all__' in dir(obj) and respect_module_all)
|
imported_members = imported_members or ('__all__' in dir(obj) and respect_module_all)
|
||||||
|
|
||||||
ns['functions'], ns['all_functions'] = \
|
ns['functions'], ns['all_functions'] = _get_members(
|
||||||
_get_members(doc, app, obj, {'function'}, imported=imported_members)
|
doc, app, obj, {'function'}, imported=imported_members
|
||||||
ns['classes'], ns['all_classes'] = \
|
)
|
||||||
_get_members(doc, app, obj, {'class'}, imported=imported_members)
|
ns['classes'], ns['all_classes'] = _get_members(
|
||||||
ns['exceptions'], ns['all_exceptions'] = \
|
doc, app, obj, {'class'}, imported=imported_members
|
||||||
_get_members(doc, app, obj, {'exception'}, imported=imported_members)
|
)
|
||||||
ns['attributes'], ns['all_attributes'] = \
|
ns['exceptions'], ns['all_exceptions'] = _get_members(
|
||||||
_get_module_attrs(name, ns['members'])
|
doc, app, obj, {'exception'}, imported=imported_members
|
||||||
|
)
|
||||||
|
ns['attributes'], ns['all_attributes'] = _get_module_attrs(name, ns['members'])
|
||||||
ispackage = hasattr(obj, '__path__')
|
ispackage = hasattr(obj, '__path__')
|
||||||
if ispackage and recursive:
|
if ispackage and recursive:
|
||||||
# Use members that are not modules as skip list, because it would then mean
|
# Use members that are not modules as skip list, because it would then mean
|
||||||
# that module was overwritten in the package namespace
|
# that module was overwritten in the package namespace
|
||||||
skip = (
|
skip = (
|
||||||
ns["all_functions"]
|
ns['all_functions']
|
||||||
+ ns["all_classes"]
|
+ ns['all_classes']
|
||||||
+ ns["all_exceptions"]
|
+ ns['all_exceptions']
|
||||||
+ ns["all_attributes"]
|
+ ns['all_attributes']
|
||||||
)
|
)
|
||||||
|
|
||||||
# If respect_module_all and module has a __all__ attribute, first get
|
# If respect_module_all and module has a __all__ attribute, first get
|
||||||
@ -301,40 +325,44 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
#
|
#
|
||||||
# Otherwise, use get_modules method normally
|
# Otherwise, use get_modules method normally
|
||||||
if respect_module_all and '__all__' in dir(obj):
|
if respect_module_all and '__all__' in dir(obj):
|
||||||
imported_modules, all_imported_modules = \
|
imported_modules, all_imported_modules = _get_members(
|
||||||
_get_members(doc, app, obj, {'module'}, imported=True)
|
doc, app, obj, {'module'}, imported=True
|
||||||
|
)
|
||||||
skip += all_imported_modules
|
skip += all_imported_modules
|
||||||
imported_modules = [name + '.' + modname for modname in imported_modules]
|
imported_modules = [name + '.' + modname for modname in imported_modules]
|
||||||
all_imported_modules = \
|
all_imported_modules = [
|
||||||
[name + '.' + modname for modname in all_imported_modules]
|
name + '.' + modname for modname in all_imported_modules
|
||||||
|
]
|
||||||
public_members = getall(obj)
|
public_members = getall(obj)
|
||||||
else:
|
else:
|
||||||
imported_modules, all_imported_modules = [], []
|
imported_modules, all_imported_modules = [], []
|
||||||
public_members = None
|
public_members = None
|
||||||
|
|
||||||
modules, all_modules = _get_modules(obj, skip=skip, name=name,
|
modules, all_modules = _get_modules(
|
||||||
public_members=public_members)
|
obj, skip=skip, name=name, public_members=public_members
|
||||||
|
)
|
||||||
ns['modules'] = imported_modules + modules
|
ns['modules'] = imported_modules + modules
|
||||||
ns["all_modules"] = all_imported_modules + all_modules
|
ns['all_modules'] = all_imported_modules + all_modules
|
||||||
elif doc.objtype == 'class':
|
elif doc.objtype == 'class':
|
||||||
ns['members'] = dir(obj)
|
ns['members'] = dir(obj)
|
||||||
ns['inherited_members'] = \
|
ns['inherited_members'] = set(dir(obj)) - set(obj.__dict__.keys())
|
||||||
set(dir(obj)) - set(obj.__dict__.keys())
|
ns['methods'], ns['all_methods'] = _get_members(
|
||||||
ns['methods'], ns['all_methods'] = \
|
doc, app, obj, {'method'}, include_public={'__init__'}
|
||||||
_get_members(doc, app, obj, {'method'}, include_public={'__init__'})
|
)
|
||||||
ns['attributes'], ns['all_attributes'] = \
|
ns['attributes'], ns['all_attributes'] = _get_members(
|
||||||
_get_members(doc, app, obj, {'attribute', 'property'})
|
doc, app, obj, {'attribute', 'property'}
|
||||||
|
)
|
||||||
|
|
||||||
if modname is None or qualname is None:
|
if modname is None or qualname is None:
|
||||||
modname, qualname = _split_full_qualified_name(name)
|
modname, qualname = _split_full_qualified_name(name)
|
||||||
|
|
||||||
if doc.objtype in ('method', 'attribute', 'property'):
|
if doc.objtype in ('method', 'attribute', 'property'):
|
||||||
ns['class'] = qualname.rsplit(".", 1)[0]
|
ns['class'] = qualname.rsplit('.', 1)[0]
|
||||||
|
|
||||||
if doc.objtype == 'class':
|
if doc.objtype == 'class':
|
||||||
shortname = qualname
|
shortname = qualname
|
||||||
else:
|
else:
|
||||||
shortname = qualname.rsplit(".", 1)[-1]
|
shortname = qualname.rsplit('.', 1)[-1]
|
||||||
|
|
||||||
ns['fullname'] = name
|
ns['fullname'] = name
|
||||||
ns['module'] = modname
|
ns['module'] = modname
|
||||||
@ -352,12 +380,17 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
|
|
||||||
def _skip_member(app: Sphinx, obj: Any, name: str, objtype: str) -> bool:
|
def _skip_member(app: Sphinx, obj: Any, name: str, objtype: str) -> bool:
|
||||||
try:
|
try:
|
||||||
return app.emit_firstresult('autodoc-skip-member', objtype, name,
|
return app.emit_firstresult('autodoc-skip-member', objtype, name, obj, False, {})
|
||||||
obj, False, {})
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning(__('autosummary: failed to determine %r to be documented, '
|
logger.warning(
|
||||||
'the following exception was raised:\n%s'),
|
__(
|
||||||
name, exc, type='autosummary')
|
'autosummary: failed to determine %r to be documented, '
|
||||||
|
'the following exception was raised:\n%s'
|
||||||
|
),
|
||||||
|
name,
|
||||||
|
exc,
|
||||||
|
type='autosummary',
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -384,9 +417,15 @@ def _get_all_members(doc: type[Documenter], app: Sphinx, obj: Any) -> dict[str,
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def _get_members(doc: type[Documenter], app: Sphinx, obj: Any, types: set[str], *,
|
def _get_members(
|
||||||
include_public: Set[str] = frozenset(),
|
doc: type[Documenter],
|
||||||
imported: bool = True) -> tuple[list[str], list[str]]:
|
app: Sphinx,
|
||||||
|
obj: Any,
|
||||||
|
types: set[str],
|
||||||
|
*,
|
||||||
|
include_public: Set[str] = frozenset(),
|
||||||
|
imported: bool = True,
|
||||||
|
) -> tuple[list[str], list[str]]:
|
||||||
items: list[str] = []
|
items: list[str] = []
|
||||||
public: list[str] = []
|
public: list[str] = []
|
||||||
|
|
||||||
@ -423,20 +462,16 @@ def _get_module_attrs(name: str, members: Any) -> tuple[list[str], list[str]]:
|
|||||||
if not attr_name.startswith('_'):
|
if not attr_name.startswith('_'):
|
||||||
public.append(attr_name)
|
public.append(attr_name)
|
||||||
except PycodeError:
|
except PycodeError:
|
||||||
pass # give up if ModuleAnalyzer fails to parse code
|
pass # give up if ModuleAnalyzer fails to parse code
|
||||||
return public, attrs
|
return public, attrs
|
||||||
|
|
||||||
|
|
||||||
def _get_modules(
|
def _get_modules(
|
||||||
obj: Any,
|
obj: Any, *, skip: Sequence[str], name: str, public_members: Sequence[str] | None = None
|
||||||
*,
|
) -> tuple[list[str], list[str]]:
|
||||||
skip: Sequence[str],
|
|
||||||
name: str,
|
|
||||||
public_members: Sequence[str] | None = None) -> tuple[list[str], list[str]]:
|
|
||||||
items: list[str] = []
|
items: list[str] = []
|
||||||
public: list[str] = []
|
public: list[str] = []
|
||||||
for _, modname, _ispkg in pkgutil.iter_modules(obj.__path__):
|
for _, modname, _ispkg in pkgutil.iter_modules(obj.__path__):
|
||||||
|
|
||||||
if modname in skip:
|
if modname in skip:
|
||||||
# module was overwritten in __init__.py, so not accessible
|
# module was overwritten in __init__.py, so not accessible
|
||||||
continue
|
continue
|
||||||
@ -458,17 +493,20 @@ def _get_modules(
|
|||||||
return public, items
|
return public, items
|
||||||
|
|
||||||
|
|
||||||
def generate_autosummary_docs(sources: list[str],
|
def generate_autosummary_docs(
|
||||||
output_dir: str | os.PathLike[str] | None = None,
|
sources: list[str],
|
||||||
suffix: str = '.rst',
|
output_dir: str | os.PathLike[str] | None = None,
|
||||||
base_path: str | os.PathLike[str] | None = None,
|
suffix: str = '.rst',
|
||||||
imported_members: bool = False, app: Any = None,
|
base_path: str | os.PathLike[str] | None = None,
|
||||||
overwrite: bool = True, encoding: str = 'utf-8') -> None:
|
imported_members: bool = False,
|
||||||
|
app: Any = None,
|
||||||
|
overwrite: bool = True,
|
||||||
|
encoding: str = 'utf-8',
|
||||||
|
) -> None:
|
||||||
showed_sources = sorted(sources)
|
showed_sources = sorted(sources)
|
||||||
if len(showed_sources) > 20:
|
if len(showed_sources) > 20:
|
||||||
showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:]
|
showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:]
|
||||||
logger.info(__('[autosummary] generating autosummary for: %s'),
|
logger.info(__('[autosummary] generating autosummary for: %s'), ', '.join(showed_sources))
|
||||||
', '.join(showed_sources))
|
|
||||||
|
|
||||||
if output_dir:
|
if output_dir:
|
||||||
logger.info(__('[autosummary] writing to %s'), output_dir)
|
logger.info(__('[autosummary] writing to %s'), output_dir)
|
||||||
@ -501,30 +539,43 @@ def generate_autosummary_docs(sources: list[str],
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
name, obj, parent, modname = import_by_name(entry.name)
|
name, obj, parent, modname = import_by_name(entry.name)
|
||||||
qualname = name.replace(modname + ".", "")
|
qualname = name.replace(modname + '.', '')
|
||||||
except ImportExceptionGroup as exc:
|
except ImportExceptionGroup as exc:
|
||||||
try:
|
try:
|
||||||
# try to import as an instance attribute
|
# try to import as an instance attribute
|
||||||
name, obj, parent, modname = import_ivar_by_name(entry.name)
|
name, obj, parent, modname = import_ivar_by_name(entry.name)
|
||||||
qualname = name.replace(modname + ".", "")
|
qualname = name.replace(modname + '.', '')
|
||||||
except ImportError as exc2:
|
except ImportError as exc2:
|
||||||
if exc2.__cause__:
|
if exc2.__cause__:
|
||||||
exceptions: list[BaseException] = [*exc.exceptions, exc2.__cause__]
|
exceptions: list[BaseException] = [*exc.exceptions, exc2.__cause__]
|
||||||
else:
|
else:
|
||||||
exceptions = [*exc.exceptions, exc2]
|
exceptions = [*exc.exceptions, exc2]
|
||||||
|
|
||||||
errors = list({f"* {type(e).__name__}: {e}" for e in exceptions})
|
errors = list({f'* {type(e).__name__}: {e}' for e in exceptions})
|
||||||
logger.warning(__('[autosummary] failed to import %s.\nPossible hints:\n%s'),
|
logger.warning(
|
||||||
entry.name, '\n'.join(errors))
|
__('[autosummary] failed to import %s.\nPossible hints:\n%s'),
|
||||||
|
entry.name,
|
||||||
|
'\n'.join(errors),
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
context: dict[str, Any] = {}
|
context: dict[str, Any] = {}
|
||||||
if app:
|
if app:
|
||||||
context.update(app.config.autosummary_context)
|
context.update(app.config.autosummary_context)
|
||||||
|
|
||||||
content = generate_autosummary_content(name, obj, parent, template, entry.template,
|
content = generate_autosummary_content(
|
||||||
imported_members, app, entry.recursive, context,
|
name,
|
||||||
modname, qualname)
|
obj,
|
||||||
|
parent,
|
||||||
|
template,
|
||||||
|
entry.template,
|
||||||
|
imported_members,
|
||||||
|
app,
|
||||||
|
entry.recursive,
|
||||||
|
context,
|
||||||
|
modname,
|
||||||
|
qualname,
|
||||||
|
)
|
||||||
|
|
||||||
filename = os.path.join(path, filename_map.get(name, name) + suffix)
|
filename = os.path.join(path, filename_map.get(name, name) + suffix)
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
@ -544,14 +595,20 @@ def generate_autosummary_docs(sources: list[str],
|
|||||||
|
|
||||||
# descend recursively to new files
|
# descend recursively to new files
|
||||||
if new_files:
|
if new_files:
|
||||||
generate_autosummary_docs(new_files, output_dir=output_dir,
|
generate_autosummary_docs(
|
||||||
suffix=suffix, base_path=base_path,
|
new_files,
|
||||||
imported_members=imported_members, app=app,
|
output_dir=output_dir,
|
||||||
overwrite=overwrite)
|
suffix=suffix,
|
||||||
|
base_path=base_path,
|
||||||
|
imported_members=imported_members,
|
||||||
|
app=app,
|
||||||
|
overwrite=overwrite,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# -- Finding documented entries in files ---------------------------------------
|
# -- Finding documented entries in files ---------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def find_autosummary_in_files(filenames: list[str]) -> list[AutosummaryEntry]:
|
def find_autosummary_in_files(filenames: list[str]) -> list[AutosummaryEntry]:
|
||||||
"""Find out what items are documented in source/*.rst.
|
"""Find out what items are documented in source/*.rst.
|
||||||
|
|
||||||
@ -566,7 +623,8 @@ def find_autosummary_in_files(filenames: list[str]) -> list[AutosummaryEntry]:
|
|||||||
|
|
||||||
|
|
||||||
def find_autosummary_in_docstring(
|
def find_autosummary_in_docstring(
|
||||||
name: str, filename: str | None = None,
|
name: str,
|
||||||
|
filename: str | None = None,
|
||||||
) -> list[AutosummaryEntry]:
|
) -> list[AutosummaryEntry]:
|
||||||
"""Find out what items are documented in the given object's docstring.
|
"""Find out what items are documented in the given object's docstring.
|
||||||
|
|
||||||
@ -579,16 +637,21 @@ def find_autosummary_in_docstring(
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
except ImportExceptionGroup as exc:
|
except ImportExceptionGroup as exc:
|
||||||
errors = '\n'.join({f"* {type(e).__name__}: {e}" for e in exc.exceptions})
|
errors = '\n'.join({f'* {type(e).__name__}: {e}' for e in exc.exceptions})
|
||||||
logger.warning(f'Failed to import {name}.\nPossible hints:\n{errors}') # NoQA: G004
|
logger.warning(f'Failed to import {name}.\nPossible hints:\n{errors}') # NoQA: G004
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
logger.warning("Failed to import '%s'; the module executes module level "
|
logger.warning(
|
||||||
'statement and it might call sys.exit().', name)
|
"Failed to import '%s'; the module executes module level "
|
||||||
|
'statement and it might call sys.exit().',
|
||||||
|
name,
|
||||||
|
)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def find_autosummary_in_lines(
|
def find_autosummary_in_lines(
|
||||||
lines: list[str], module: str | None = None, filename: str | None = None,
|
lines: list[str],
|
||||||
|
module: str | None = None,
|
||||||
|
filename: str | None = None,
|
||||||
) -> list[AutosummaryEntry]:
|
) -> list[AutosummaryEntry]:
|
||||||
"""Find out what items appear in autosummary:: directives in the
|
"""Find out what items appear in autosummary:: directives in the
|
||||||
given lines.
|
given lines.
|
||||||
@ -601,10 +664,8 @@ def find_autosummary_in_lines(
|
|||||||
corresponding options set.
|
corresponding options set.
|
||||||
"""
|
"""
|
||||||
autosummary_re = re.compile(r'^(\s*)\.\.\s+autosummary::\s*')
|
autosummary_re = re.compile(r'^(\s*)\.\.\s+autosummary::\s*')
|
||||||
automodule_re = re.compile(
|
automodule_re = re.compile(r'^\s*\.\.\s+automodule::\s*([A-Za-z0-9_.]+)\s*$')
|
||||||
r'^\s*\.\.\s+automodule::\s*([A-Za-z0-9_.]+)\s*$')
|
module_re = re.compile(r'^\s*\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$')
|
||||||
module_re = re.compile(
|
|
||||||
r'^\s*\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$')
|
|
||||||
autosummary_item_re = re.compile(r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?')
|
autosummary_item_re = re.compile(r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?')
|
||||||
recursive_arg_re = re.compile(r'^\s+:recursive:\s*$')
|
recursive_arg_re = re.compile(r'^\s+:recursive:\s*$')
|
||||||
toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$')
|
toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$')
|
||||||
@ -617,7 +678,7 @@ def find_autosummary_in_lines(
|
|||||||
template = ''
|
template = ''
|
||||||
current_module = module
|
current_module = module
|
||||||
in_autosummary = False
|
in_autosummary = False
|
||||||
base_indent = ""
|
base_indent = ''
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if in_autosummary:
|
if in_autosummary:
|
||||||
@ -630,8 +691,7 @@ def find_autosummary_in_lines(
|
|||||||
if m:
|
if m:
|
||||||
toctree = m.group(1)
|
toctree = m.group(1)
|
||||||
if filename:
|
if filename:
|
||||||
toctree = os.path.join(os.path.dirname(filename),
|
toctree = os.path.join(os.path.dirname(filename), toctree)
|
||||||
toctree)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
m = template_arg_re.match(line)
|
m = template_arg_re.match(line)
|
||||||
@ -647,13 +707,12 @@ def find_autosummary_in_lines(
|
|||||||
name = m.group(1).strip()
|
name = m.group(1).strip()
|
||||||
if name.startswith('~'):
|
if name.startswith('~'):
|
||||||
name = name[1:]
|
name = name[1:]
|
||||||
if current_module and \
|
if current_module and not name.startswith(current_module + '.'):
|
||||||
not name.startswith(current_module + '.'):
|
name = f'{current_module}.{name}'
|
||||||
name = f"{current_module}.{name}"
|
|
||||||
documented.append(AutosummaryEntry(name, toctree, template, recursive))
|
documented.append(AutosummaryEntry(name, toctree, template, recursive))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not line.strip() or line.startswith(base_indent + " "):
|
if not line.strip() or line.startswith(base_indent + ' '):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
in_autosummary = False
|
in_autosummary = False
|
||||||
@ -671,8 +730,7 @@ def find_autosummary_in_lines(
|
|||||||
if m:
|
if m:
|
||||||
current_module = m.group(1).strip()
|
current_module = m.group(1).strip()
|
||||||
# recurse into the automodule docstring
|
# recurse into the automodule docstring
|
||||||
documented.extend(find_autosummary_in_docstring(
|
documented.extend(find_autosummary_in_docstring(current_module, filename=filename))
|
||||||
current_module, filename=filename))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
m = module_re.match(line)
|
m = module_re.match(line)
|
||||||
@ -698,33 +756,62 @@ The format of the autosummary directive is documented in the
|
|||||||
``sphinx.ext.autosummary`` Python module and can be read using::
|
``sphinx.ext.autosummary`` Python module and can be read using::
|
||||||
|
|
||||||
pydoc sphinx.ext.autosummary
|
pydoc sphinx.ext.autosummary
|
||||||
"""))
|
"""),
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument('--version', action='version', dest='show_version',
|
parser.add_argument(
|
||||||
version='%%(prog)s %s' % __display_version__)
|
'--version',
|
||||||
|
action='version',
|
||||||
|
dest='show_version',
|
||||||
|
version='%%(prog)s %s' % __display_version__,
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument('source_file', nargs='+',
|
parser.add_argument(
|
||||||
help=__('source files to generate rST files for'))
|
'source_file', nargs='+', help=__('source files to generate rST files for')
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument('-o', '--output-dir', action='store',
|
parser.add_argument(
|
||||||
dest='output_dir',
|
'-o',
|
||||||
help=__('directory to place all output in'))
|
'--output-dir',
|
||||||
parser.add_argument('-s', '--suffix', action='store', dest='suffix',
|
action='store',
|
||||||
default='rst',
|
dest='output_dir',
|
||||||
help=__('default suffix for files (default: '
|
help=__('directory to place all output in'),
|
||||||
'%(default)s)'))
|
)
|
||||||
parser.add_argument('-t', '--templates', action='store', dest='templates',
|
parser.add_argument(
|
||||||
default=None,
|
'-s',
|
||||||
help=__('custom template directory (default: '
|
'--suffix',
|
||||||
'%(default)s)'))
|
action='store',
|
||||||
parser.add_argument('-i', '--imported-members', action='store_true',
|
dest='suffix',
|
||||||
dest='imported_members', default=False,
|
default='rst',
|
||||||
help=__('document imported members (default: '
|
help=__('default suffix for files (default: ' '%(default)s)'),
|
||||||
'%(default)s)'))
|
)
|
||||||
parser.add_argument('-a', '--respect-module-all', action='store_true',
|
parser.add_argument(
|
||||||
dest='respect_module_all', default=False,
|
'-t',
|
||||||
help=__('document exactly the members in module __all__ attribute. '
|
'--templates',
|
||||||
'(default: %(default)s)'))
|
action='store',
|
||||||
|
dest='templates',
|
||||||
|
default=None,
|
||||||
|
help=__('custom template directory (default: ' '%(default)s)'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-i',
|
||||||
|
'--imported-members',
|
||||||
|
action='store_true',
|
||||||
|
dest='imported_members',
|
||||||
|
default=False,
|
||||||
|
help=__('document imported members (default: ' '%(default)s)'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-a',
|
||||||
|
'--respect-module-all',
|
||||||
|
action='store_true',
|
||||||
|
dest='respect_module_all',
|
||||||
|
default=False,
|
||||||
|
help=__(
|
||||||
|
'document exactly the members in module __all__ attribute. '
|
||||||
|
'(default: %(default)s)'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -740,12 +827,15 @@ def main(argv: Sequence[str] = (), /) -> None:
|
|||||||
|
|
||||||
if args.templates:
|
if args.templates:
|
||||||
app.config.templates_path.append(path.abspath(args.templates))
|
app.config.templates_path.append(path.abspath(args.templates))
|
||||||
app.config.autosummary_ignore_module_all = (not args.respect_module_all)
|
app.config.autosummary_ignore_module_all = not args.respect_module_all
|
||||||
|
|
||||||
generate_autosummary_docs(args.source_file, args.output_dir,
|
generate_autosummary_docs(
|
||||||
'.' + args.suffix,
|
args.source_file,
|
||||||
imported_members=args.imported_members,
|
args.output_dir,
|
||||||
app=app)
|
'.' + args.suffix,
|
||||||
|
imported_members=args.imported_members,
|
||||||
|
app=app,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
Reference in New Issue
Block a user