PageRenderTime 45ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/documentor/libraries/Sphinx-1.1.3-py3.2/sphinx/ext/autosummary/generate.py

https://github.com/tictactatic/Superdesk
Python | 319 lines | 296 code | 4 blank | 19 comment | 1 complexity | 6ff2a718afba7a36cb5b86abfcca16cb MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-3.0, GPL-2.0
  1. # -*- coding: utf-8 -*-
  2. """
  3. sphinx.ext.autosummary.generate
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. Usable as a library or script to generate automatic RST source files for
  6. items referred to in autosummary:: directives.
  7. Each generated RST file contains a single auto*:: directive which
  8. extracts the docstring of the referred item.
  9. Example Makefile rule::
  10. generate:
  11. sphinx-autogen -o source/generated source/*.rst
  12. :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
  13. :license: BSD, see LICENSE for details.
  14. """
  15. import os
  16. import re
  17. import sys
  18. import pydoc
  19. import optparse
  20. from jinja2 import FileSystemLoader, TemplateNotFound
  21. from jinja2.sandbox import SandboxedEnvironment
  22. from sphinx import package_dir
  23. from sphinx.ext.autosummary import import_by_name, get_documenter
  24. from sphinx.jinja2glue import BuiltinTemplateLoader
  25. from sphinx.util.osutil import ensuredir
  26. from sphinx.util.inspect import safe_getattr
  27. def main(argv=sys.argv):
  28. usage = """%prog [OPTIONS] SOURCEFILE ..."""
  29. p = optparse.OptionParser(usage.strip())
  30. p.add_option("-o", "--output-dir", action="store", type="string",
  31. dest="output_dir", default=None,
  32. help="Directory to place all output in")
  33. p.add_option("-s", "--suffix", action="store", type="string",
  34. dest="suffix", default="rst",
  35. help="Default suffix for files (default: %default)")
  36. p.add_option("-t", "--templates", action="store", type="string",
  37. dest="templates", default=None,
  38. help="Custom template directory (default: %default)")
  39. options, args = p.parse_args(argv[1:])
  40. if len(args) < 1:
  41. p.error('no input files given')
  42. generate_autosummary_docs(args, options.output_dir,
  43. "." + options.suffix,
  44. template_dir=options.templates)
  45. def _simple_info(msg):
  46. print(msg)
  47. def _simple_warn(msg):
  48. print('WARNING: ' + msg, file=sys.stderr)
  49. # -- Generating output ---------------------------------------------------------
  50. def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
  51. warn=_simple_warn, info=_simple_info,
  52. base_path=None, builder=None, template_dir=None):
  53. showed_sources = list(sorted(sources))
  54. if len(showed_sources) > 20:
  55. showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:]
  56. info('[autosummary] generating autosummary for: %s' %
  57. ', '.join(showed_sources))
  58. if output_dir:
  59. info('[autosummary] writing to %s' % output_dir)
  60. if base_path is not None:
  61. sources = [os.path.join(base_path, filename) for filename in sources]
  62. # create our own templating environment
  63. template_dirs = [os.path.join(package_dir, 'ext',
  64. 'autosummary', 'templates')]
  65. if builder is not None:
  66. # allow the user to override the templates
  67. template_loader = BuiltinTemplateLoader()
  68. template_loader.init(builder, dirs=template_dirs)
  69. else:
  70. if template_dir:
  71. template_dirs.insert(0, template_dir)
  72. template_loader = FileSystemLoader(template_dirs)
  73. template_env = SandboxedEnvironment(loader=template_loader)
  74. # read
  75. items = find_autosummary_in_files(sources)
  76. # remove possible duplicates
  77. items = list(dict([(item, True) for item in items]).keys())
  78. # keep track of new files
  79. new_files = []
  80. # write
  81. for name, path, template_name in sorted(items):
  82. if path is None:
  83. # The corresponding autosummary:: directive did not have
  84. # a :toctree: option
  85. continue
  86. path = output_dir or os.path.abspath(path)
  87. ensuredir(path)
  88. try:
  89. name, obj, parent = import_by_name(name)
  90. except ImportError as e:
  91. warn('[autosummary] failed to import %r: %s' % (name, e))
  92. continue
  93. fn = os.path.join(path, name + suffix)
  94. # skip it if it exists
  95. if os.path.isfile(fn):
  96. continue
  97. new_files.append(fn)
  98. f = open(fn, 'w')
  99. try:
  100. doc = get_documenter(obj, parent)
  101. if template_name is not None:
  102. template = template_env.get_template(template_name)
  103. else:
  104. try:
  105. template = template_env.get_template('autosummary/%s.rst'
  106. % doc.objtype)
  107. except TemplateNotFound:
  108. template = template_env.get_template('autosummary/base.rst')
  109. def get_members(obj, typ, include_public=[]):
  110. items = []
  111. for name in dir(obj):
  112. try:
  113. documenter = get_documenter(safe_getattr(obj, name),
  114. obj)
  115. except AttributeError:
  116. continue
  117. if documenter.objtype == typ:
  118. items.append(name)
  119. public = [x for x in items
  120. if x in include_public or not x.startswith('_')]
  121. return public, items
  122. ns = {}
  123. if doc.objtype == 'module':
  124. ns['members'] = dir(obj)
  125. ns['functions'], ns['all_functions'] = \
  126. get_members(obj, 'function')
  127. ns['classes'], ns['all_classes'] = \
  128. get_members(obj, 'class')
  129. ns['exceptions'], ns['all_exceptions'] = \
  130. get_members(obj, 'exception')
  131. elif doc.objtype == 'class':
  132. ns['members'] = dir(obj)
  133. ns['methods'], ns['all_methods'] = \
  134. get_members(obj, 'method', ['__init__'])
  135. ns['attributes'], ns['all_attributes'] = \
  136. get_members(obj, 'attribute')
  137. parts = name.split('.')
  138. if doc.objtype in ('method', 'attribute'):
  139. mod_name = '.'.join(parts[:-2])
  140. cls_name = parts[-2]
  141. obj_name = '.'.join(parts[-2:])
  142. ns['class'] = cls_name
  143. else:
  144. mod_name, obj_name = '.'.join(parts[:-1]), parts[-1]
  145. ns['fullname'] = name
  146. ns['module'] = mod_name
  147. ns['objname'] = obj_name
  148. ns['name'] = parts[-1]
  149. ns['objtype'] = doc.objtype
  150. ns['underline'] = len(name) * '='
  151. rendered = template.render(**ns)
  152. f.write(rendered)
  153. finally:
  154. f.close()
  155. # descend recursively to new files
  156. if new_files:
  157. generate_autosummary_docs(new_files, output_dir=output_dir,
  158. suffix=suffix, warn=warn, info=info,
  159. base_path=base_path, builder=builder,
  160. template_dir=template_dir)
  161. # -- Finding documented entries in files ---------------------------------------
  162. def find_autosummary_in_files(filenames):
  163. """Find out what items are documented in source/*.rst.
  164. See `find_autosummary_in_lines`.
  165. """
  166. documented = []
  167. for filename in filenames:
  168. f = open(filename, 'r')
  169. lines = f.read().splitlines()
  170. documented.extend(find_autosummary_in_lines(lines, filename=filename))
  171. f.close()
  172. return documented
  173. def find_autosummary_in_docstring(name, module=None, filename=None):
  174. """Find out what items are documented in the given object's docstring.
  175. See `find_autosummary_in_lines`.
  176. """
  177. try:
  178. real_name, obj, parent = import_by_name(name)
  179. lines = pydoc.getdoc(obj).splitlines()
  180. return find_autosummary_in_lines(lines, module=name, filename=filename)
  181. except AttributeError:
  182. pass
  183. except ImportError as e:
  184. print("Failed to import '%s': %s" % (name, e))
  185. return []
  186. def find_autosummary_in_lines(lines, module=None, filename=None):
  187. """Find out what items appear in autosummary:: directives in the
  188. given lines.
  189. Returns a list of (name, toctree, template) where *name* is a name
  190. of an object and *toctree* the :toctree: path of the corresponding
  191. autosummary directive (relative to the root of the file name), and
  192. *template* the value of the :template: option. *toctree* and
  193. *template* ``None`` if the directive does not have the
  194. corresponding options set.
  195. """
  196. autosummary_re = re.compile(r'^(\s*)\.\.\s+autosummary::\s*')
  197. automodule_re = re.compile(
  198. r'^\s*\.\.\s+automodule::\s*([A-Za-z0-9_.]+)\s*$')
  199. module_re = re.compile(
  200. r'^\s*\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$')
  201. autosummary_item_re = re.compile(r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?')
  202. toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$')
  203. template_arg_re = re.compile(r'^\s+:template:\s*(.*?)\s*$')
  204. documented = []
  205. toctree = None
  206. template = None
  207. current_module = module
  208. in_autosummary = False
  209. base_indent = ""
  210. for line in lines:
  211. if in_autosummary:
  212. m = toctree_arg_re.match(line)
  213. if m:
  214. toctree = m.group(1)
  215. if filename:
  216. toctree = os.path.join(os.path.dirname(filename),
  217. toctree)
  218. continue
  219. m = template_arg_re.match(line)
  220. if m:
  221. template = m.group(1).strip()
  222. continue
  223. if line.strip().startswith(':'):
  224. continue # skip options
  225. m = autosummary_item_re.match(line)
  226. if m:
  227. name = m.group(1).strip()
  228. if name.startswith('~'):
  229. name = name[1:]
  230. if current_module and \
  231. not name.startswith(current_module + '.'):
  232. name = "%s.%s" % (current_module, name)
  233. documented.append((name, toctree, template))
  234. continue
  235. if not line.strip() or line.startswith(base_indent + " "):
  236. continue
  237. in_autosummary = False
  238. m = autosummary_re.match(line)
  239. if m:
  240. in_autosummary = True
  241. base_indent = m.group(1)
  242. toctree = None
  243. template = None
  244. continue
  245. m = automodule_re.search(line)
  246. if m:
  247. current_module = m.group(1).strip()
  248. # recurse into the automodule docstring
  249. documented.extend(find_autosummary_in_docstring(
  250. current_module, filename=filename))
  251. continue
  252. m = module_re.match(line)
  253. if m:
  254. current_module = m.group(2)
  255. continue
  256. return documented
  257. if __name__ == '__main__':
  258. main()