/usr/lib/python3/dist-packages/sphinx/apidoc.py is in python3-sphinx 1.4.9-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | # -*- coding: utf-8 -*-
"""
sphinx.apidoc
~~~~~~~~~~~~~
Parses a directory tree looking for Python modules and packages and creates
ReST files appropriately to create code documentation with Sphinx. It also
creates a modules index (named modules.<suffix>).
This is derived from the "sphinx-autopackage" script, which is:
Copyright 2008 Société des arts technologiques (SAT),
http://www.sat.qc.ca/
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function
import os
import sys
import optparse
from os import path
from six import binary_type
from sphinx.util.osutil import walk
from sphinx import __display_version__
# automodule options
if 'SPHINX_APIDOC_OPTIONS' in os.environ:
OPTIONS = os.environ['SPHINX_APIDOC_OPTIONS'].split(',')
else:
OPTIONS = [
'members',
'undoc-members',
# 'inherited-members', # disabled because there's a bug in sphinx
'show-inheritance',
]
INITPY = '__init__.py'
PY_SUFFIXES = set(['.py', '.pyx'])
def makename(package, module):
"""Join package and module with a dot."""
# Both package and module can be None/empty.
if package:
name = package
if module:
name += '.' + module
else:
name = module
return name
def write_file(name, text, opts):
"""Write the output file for module/package <name>."""
fname = path.join(opts.destdir, '%s.%s' % (name, opts.suffix))
if opts.dryrun:
print('Would create file %s.' % fname)
return
if not opts.force and path.isfile(fname):
print('File %s already exists, skipping.' % fname)
else:
print('Creating file %s.' % fname)
f = open(fname, 'w')
try:
f.write(text)
finally:
f.close()
def format_heading(level, text):
"""Create a heading of <level> [1, 2 or 3 supported]."""
underlining = ['=', '-', '~', ][level - 1] * len(text)
return '%s\n%s\n\n' % (text, underlining)
def format_directive(module, package=None):
"""Create the automodule directive and add the options."""
directive = '.. automodule:: %s\n' % makename(package, module)
for option in OPTIONS:
directive += ' :%s:\n' % option
return directive
def create_module_file(package, module, opts):
"""Build the text of the file and write the file."""
if not opts.noheadings:
text = format_heading(1, '%s module' % module)
else:
text = ''
# text += format_heading(2, ':mod:`%s` Module' % module)
text += format_directive(module, package)
write_file(makename(package, module), text, opts)
def create_package_file(root, master_package, subroot, py_files, opts, subs):
"""Build the text of the file and write the file."""
text = format_heading(1, '%s package' % makename(master_package, subroot))
if opts.modulefirst:
text += format_directive(subroot, master_package)
text += '\n'
# build a list of directories that are szvpackages (contain an INITPY file)
subs = [sub for sub in subs if path.isfile(path.join(root, sub, INITPY))]
# if there are some package directories, add a TOC for theses subpackages
if subs:
text += format_heading(2, 'Subpackages')
text += '.. toctree::\n\n'
for sub in subs:
text += ' %s.%s\n' % (makename(master_package, subroot), sub)
text += '\n'
submods = [path.splitext(sub)[0] for sub in py_files
if not shall_skip(path.join(root, sub), opts) and
sub != INITPY]
if submods:
text += format_heading(2, 'Submodules')
if opts.separatemodules:
text += '.. toctree::\n\n'
for submod in submods:
modfile = makename(master_package, makename(subroot, submod))
text += ' %s\n' % modfile
# generate separate file for this module
if not opts.noheadings:
filetext = format_heading(1, '%s module' % modfile)
else:
filetext = ''
filetext += format_directive(makename(subroot, submod),
master_package)
write_file(modfile, filetext, opts)
else:
for submod in submods:
modfile = makename(master_package, makename(subroot, submod))
if not opts.noheadings:
text += format_heading(2, '%s module' % modfile)
text += format_directive(makename(subroot, submod),
master_package)
text += '\n'
text += '\n'
if not opts.modulefirst:
text += format_heading(2, 'Module contents')
text += format_directive(subroot, master_package)
write_file(makename(master_package, subroot), text, opts)
def create_modules_toc_file(modules, opts, name='modules'):
"""Create the module's index."""
text = format_heading(1, '%s' % opts.header)
text += '.. toctree::\n'
text += ' :maxdepth: %s\n\n' % opts.maxdepth
modules.sort()
prev_module = ''
for module in modules:
# look if the module is a subpackage and, if yes, ignore it
if module.startswith(prev_module + '.'):
continue
prev_module = module
text += ' %s\n' % module
write_file(name, text, opts)
def shall_skip(module, opts):
"""Check if we want to skip this module."""
# skip it if there is nothing (or just \n or \r\n) in the file
if path.getsize(module) <= 2:
return True
# skip if it has a "private" name and this is selected
filename = path.basename(module)
if filename != '__init__.py' and filename.startswith('_') and \
not opts.includeprivate:
return True
return False
def recurse_tree(rootpath, excludes, opts):
"""
Look for every file in the directory tree and create the corresponding
ReST files.
"""
# check if the base directory is a package and get its name
if INITPY in os.listdir(rootpath):
root_package = rootpath.split(path.sep)[-1]
else:
# otherwise, the base is a directory with packages
root_package = None
toplevels = []
followlinks = getattr(opts, 'followlinks', False)
includeprivate = getattr(opts, 'includeprivate', False)
for root, subs, files in walk(rootpath, followlinks=followlinks):
# document only Python module files (that aren't excluded)
py_files = sorted(f for f in files
if path.splitext(f)[1] in PY_SUFFIXES and
not is_excluded(path.join(root, f), excludes))
is_pkg = INITPY in py_files
if is_pkg:
py_files.remove(INITPY)
py_files.insert(0, INITPY)
elif root != rootpath:
# only accept non-package at toplevel
del subs[:]
continue
# remove hidden ('.') and private ('_') directories, as well as
# excluded dirs
if includeprivate:
exclude_prefixes = ('.',)
else:
exclude_prefixes = ('.', '_')
subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and
not is_excluded(path.join(root, sub), excludes))
if is_pkg:
# we are in a package with something to document
if subs or len(py_files) > 1 or not \
shall_skip(path.join(root, INITPY), opts):
subpackage = root[len(rootpath):].lstrip(path.sep).\
replace(path.sep, '.')
create_package_file(root, root_package, subpackage,
py_files, opts, subs)
toplevels.append(makename(root_package, subpackage))
else:
# if we are at the root level, we don't require it to be a package
assert root == rootpath and root_package is None
for py_file in py_files:
if not shall_skip(path.join(rootpath, py_file), opts):
module = path.splitext(py_file)[0]
create_module_file(root_package, module, opts)
toplevels.append(module)
return toplevels
def normalize_excludes(rootpath, excludes):
"""Normalize the excluded directory list."""
return [path.abspath(exclude) for exclude in excludes]
def is_excluded(root, excludes):
"""Check if the directory is in the exclude list.
Note: by having trailing slashes, we avoid common prefix issues, like
e.g. an exlude "foo" also accidentally excluding "foobar".
"""
for exclude in excludes:
if root == exclude:
return True
return False
def main(argv=sys.argv):
"""Parse and check the command line arguments."""
parser = optparse.OptionParser(
usage="""\
usage: %prog [options] -o <output_path> <module_path> [exclude_path, ...]
Look recursively in <module_path> for Python modules and packages and create
one reST file with automodule directives per package in the <output_path>.
The <exclude_path>s can be files and/or directories that will be excluded
from generation.
Note: By default this script will not overwrite already created files.""")
parser.add_option('-o', '--output-dir', action='store', dest='destdir',
help='Directory to place all output', default='')
parser.add_option('-d', '--maxdepth', action='store', dest='maxdepth',
help='Maximum depth of submodules to show in the TOC '
'(default: 4)', type='int', default=4)
parser.add_option('-f', '--force', action='store_true', dest='force',
help='Overwrite existing files')
parser.add_option('-l', '--follow-links', action='store_true',
dest='followlinks', default=False,
help='Follow symbolic links. Powerful when combined '
'with collective.recipe.omelette.')
parser.add_option('-n', '--dry-run', action='store_true', dest='dryrun',
help='Run the script without creating files')
parser.add_option('-e', '--separate', action='store_true',
dest='separatemodules',
help='Put documentation for each module on its own page')
parser.add_option('-P', '--private', action='store_true',
dest='includeprivate',
help='Include "_private" modules')
parser.add_option('-T', '--no-toc', action='store_true', dest='notoc',
help='Don\'t create a table of contents file')
parser.add_option('-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_option('-M', '--module-first', action='store_true',
dest='modulefirst',
help='Put module documentation before submodule '
'documentation')
parser.add_option('-s', '--suffix', action='store', dest='suffix',
help='file suffix (default: rst)', default='rst')
parser.add_option('-F', '--full', action='store_true', dest='full',
help='Generate a full project with sphinx-quickstart')
parser.add_option('-H', '--doc-project', action='store', dest='header',
help='Project name (default: root module name)')
parser.add_option('-A', '--doc-author', action='store', dest='author',
type='str',
help='Project author(s), used when --full is given')
parser.add_option('-V', '--doc-version', action='store', dest='version',
help='Project version, used when --full is given')
parser.add_option('-R', '--doc-release', action='store', dest='release',
help='Project release, used when --full is given, '
'defaults to --doc-version')
parser.add_option('--version', action='store_true', dest='show_version',
help='Show version information and exit')
(opts, args) = parser.parse_args(argv[1:])
if opts.show_version:
print('Sphinx (sphinx-apidoc) %s' % __display_version__)
return 0
if not args:
parser.error('A package path is required.')
rootpath, excludes = args[0], args[1:]
if not opts.destdir:
parser.error('An output directory is required.')
if opts.header is None:
opts.header = path.abspath(rootpath).split(path.sep)[-1]
if opts.suffix.startswith('.'):
opts.suffix = opts.suffix[1:]
if not path.isdir(rootpath):
print('%s is not a directory.' % rootpath, file=sys.stderr)
sys.exit(1)
if not path.isdir(opts.destdir):
if not opts.dryrun:
os.makedirs(opts.destdir)
rootpath = path.abspath(rootpath)
excludes = normalize_excludes(rootpath, excludes)
modules = recurse_tree(rootpath, excludes, opts)
if opts.full:
from sphinx import quickstart as qs
modules.sort()
prev_module = ''
text = ''
for module in modules:
if module.startswith(prev_module + '.'):
continue
prev_module = module
text += ' %s\n' % module
d = dict(
path = opts.destdir,
sep = False,
dot = '_',
project = opts.header,
author = opts.author or 'Author',
version = opts.version or '',
release = opts.release or opts.version or '',
suffix = '.' + opts.suffix,
master = 'index',
epub = True,
ext_autodoc = True,
ext_viewcode = True,
ext_todo = True,
makefile = True,
batchfile = True,
mastertocmaxdepth = opts.maxdepth,
mastertoctree = text,
language = 'en',
)
if isinstance(opts.header, binary_type):
d['project'] = d['project'].decode('utf-8')
if isinstance(opts.author, binary_type):
d['author'] = d['author'].decode('utf-8')
if isinstance(opts.version, binary_type):
d['version'] = d['version'].decode('utf-8')
if isinstance(opts.release, binary_type):
d['release'] = d['release'].decode('utf-8')
if not opts.dryrun:
qs.generate(d, silent=True, overwrite=opts.force)
elif not opts.notoc:
create_modules_toc_file(modules, opts)
# So program can be started with "python -m sphinx.apidoc ..."
if __name__ == "__main__":
main()
|