PageRenderTime 68ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/python/helpers/epydoc/docwriter/html.py

http://github.com/JetBrains/intellij-community
Python | 3491 lines | 3150 code | 99 blank | 242 comment | 188 complexity | 42cd7770ed9539825cbbc40e0712c977 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, MPL-2.0-no-copyleft-exception, MIT, EPL-1.0, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. #
  2. # epydoc -- HTML output generator
  3. # Edward Loper
  4. #
  5. # Created [01/30/01 05:18 PM]
  6. # $Id: html.py 1674 2008-01-29 06:03:36Z edloper $
  7. #
  8. """
  9. The HTML output generator for epydoc. The main interface provided by
  10. this module is the L{HTMLWriter} class.
  11. @todo: Add a cache to L{HTMLWriter.url()}?
  12. """
  13. __docformat__ = 'epytext en'
  14. import re, os, sys, codecs, sre_constants, pprint, base64
  15. import urllib
  16. import __builtin__
  17. from epydoc.apidoc import *
  18. import epydoc.docstringparser
  19. import time, epydoc, epydoc.markup, epydoc.markup.epytext
  20. from epydoc.docwriter.html_colorize import PythonSourceColorizer
  21. from epydoc.docwriter import html_colorize
  22. from epydoc.docwriter.html_css import STYLESHEETS
  23. from epydoc.docwriter.html_help import HTML_HELP
  24. from epydoc.docwriter.dotgraph import *
  25. from epydoc import log
  26. from epydoc.util import plaintext_to_html, is_src_filename
  27. from epydoc.compat import * # Backwards compatibility
  28. ######################################################################
  29. ## Template Compiler
  30. ######################################################################
  31. # The compile_template() method defined in this section is used to
  32. # define several of HTMLWriter's methods.
  33. def compile_template(docstring, template_string,
  34. output_function='out', debug=epydoc.DEBUG):
  35. """
  36. Given a template string containing inline python source code,
  37. return a python function that will fill in the template, and
  38. output the result. The signature for this function is taken from
  39. the first line of C{docstring}. Output is generated by making
  40. repeated calls to the output function with the given name (which
  41. is typically one of the function's parameters).
  42. The templating language used by this function passes through all
  43. text as-is, with three exceptions:
  44. - If every line in the template string is indented by at least
  45. M{x} spaces, then the first M{x} spaces are stripped from each
  46. line.
  47. - Any line that begins with '>>>' (with no indentation)
  48. should contain python code, and will be inserted as-is into
  49. the template-filling function. If the line begins a control
  50. block (such as 'if' or 'for'), then the control block will
  51. be closed by the first '>>>'-marked line whose indentation is
  52. less than or equal to the line's own indentation (including
  53. lines that only contain comments.)
  54. - In any other line, any expression between two '$' signs will
  55. be evaluated and inserted into the line (using C{str()} to
  56. convert the result to a string).
  57. Here is a simple example:
  58. >>> TEMPLATE = '''
  59. ... <book>
  60. ... <title>$book.title$</title>
  61. ... <pages>$book.count_pages()$</pages>
  62. ... >>> for chapter in book.chapters:
  63. ... <chaptername>$chapter.name$</chaptername>
  64. ... >>> #endfor
  65. ... </book>
  66. >>> write_book = compile_template('write_book(out, book)', TEMPLATE)
  67. @newfield acknowledgements: Acknowledgements
  68. @acknowledgements: The syntax used by C{compile_template} is
  69. loosely based on Cheetah.
  70. """
  71. # Extract signature from the docstring:
  72. signature = docstring.lstrip().split('\n',1)[0].strip()
  73. func_name = signature.split('(',1)[0].strip()
  74. # Regexp to search for inline substitutions:
  75. INLINE = re.compile(r'\$([^\$]+)\$')
  76. # Regexp to search for python statements in the template:
  77. COMMAND = re.compile(r'(^>>>.*)\n?', re.MULTILINE)
  78. # Strip indentation from the template.
  79. template_string = strip_indent(template_string)
  80. # If we're debugging, then we'll store the generated function,
  81. # so we can print it along with any tracebacks that depend on it.
  82. if debug:
  83. signature = re.sub(r'\)\s*$', ', __debug=__debug)', signature)
  84. # Funciton declaration line
  85. pysrc_lines = ['def %s:' % signature]
  86. indents = [-1]
  87. if debug:
  88. pysrc_lines.append(' try:')
  89. indents.append(-1)
  90. commands = COMMAND.split(template_string.strip()+'\n')
  91. for i, command in enumerate(commands):
  92. if command == '': continue
  93. # String literal segment:
  94. if i%2 == 0:
  95. pieces = INLINE.split(command)
  96. for j, piece in enumerate(pieces):
  97. if j%2 == 0:
  98. # String piece
  99. pysrc_lines.append(' '*len(indents)+
  100. '%s(%r)' % (output_function, piece))
  101. else:
  102. # Variable piece
  103. pysrc_lines.append(' '*len(indents)+
  104. '%s(unicode(%s))' % (output_function, piece))
  105. # Python command:
  106. else:
  107. srcline = command[3:].lstrip()
  108. # Update indentation
  109. indent = len(command)-len(srcline)
  110. while indent <= indents[-1]: indents.pop()
  111. # Add on the line.
  112. srcline = srcline.rstrip()
  113. pysrc_lines.append(' '*len(indents)+srcline)
  114. if srcline.endswith(':'):
  115. indents.append(indent)
  116. if debug:
  117. pysrc_lines.append(' except Exception,e:')
  118. pysrc_lines.append(' pysrc, func_name = __debug ')
  119. pysrc_lines.append(' lineno = sys.exc_info()[2].tb_lineno')
  120. pysrc_lines.append(' print ("Exception in template %s() on "')
  121. pysrc_lines.append(' "line %d:" % (func_name, lineno))')
  122. pysrc_lines.append(' print pysrc[lineno-1]')
  123. pysrc_lines.append(' raise')
  124. pysrc = '\n'.join(pysrc_lines)+'\n'
  125. #log.debug(pysrc)
  126. if debug: localdict = {'__debug': (pysrc_lines, func_name)}
  127. else: localdict = {}
  128. try: exec pysrc in globals(), localdict
  129. except SyntaxError:
  130. log.error('Error in script:\n' + pysrc + '\n')
  131. raise
  132. template_func = localdict[func_name]
  133. template_func.__doc__ = docstring
  134. return template_func
  135. def strip_indent(s):
  136. """
  137. Given a multiline string C{s}, find the minimum indentation for
  138. all non-blank lines, and return a new string formed by stripping
  139. that amount of indentation from all lines in C{s}.
  140. """
  141. # Strip indentation from the template.
  142. minindent = sys.maxint
  143. lines = s.split('\n')
  144. for line in lines:
  145. stripline = line.lstrip()
  146. if stripline:
  147. minindent = min(minindent, len(line)-len(stripline))
  148. return '\n'.join([l[minindent:] for l in lines])
  149. ######################################################################
  150. ## HTML Writer
  151. ######################################################################
  152. class HTMLWriter:
  153. #////////////////////////////////////////////////////////////
  154. # Table of Contents
  155. #////////////////////////////////////////////////////////////
  156. #
  157. # 1. Interface Methods
  158. #
  159. # 2. Page Generation -- write complete web page files
  160. # 2.1. Module Pages
  161. # 2.2. Class Pages
  162. # 2.3. Trees Page
  163. # 2.4. Indices Page
  164. # 2.5. Help Page
  165. # 2.6. Frames-based table of contents pages
  166. # 2.7. Homepage (index.html)
  167. # 2.8. CSS Stylesheet
  168. # 2.9. Javascript file
  169. # 2.10. Graphs
  170. # 2.11. Images
  171. #
  172. # 3. Page Element Generation -- write pieces of a web page file
  173. # 3.1. Page Header
  174. # 3.2. Page Footer
  175. # 3.3. Navigation Bar
  176. # 3.4. Breadcrumbs
  177. # 3.5. Summary Tables
  178. #
  179. # 4. Helper functions
  180. def __init__(self, docindex, **kwargs):
  181. """
  182. Construct a new HTML writer, using the given documentation
  183. index.
  184. @param docindex: The documentation index.
  185. @type prj_name: C{string}
  186. @keyword prj_name: The name of the project. Defaults to
  187. none.
  188. @type prj_url: C{string}
  189. @keyword prj_url: The target for the project hopeage link on
  190. the navigation bar. If C{prj_url} is not specified,
  191. then no hyperlink is created.
  192. @type prj_link: C{string}
  193. @keyword prj_link: The label for the project link on the
  194. navigation bar. This link can contain arbitrary HTML
  195. code (e.g. images). By default, a label is constructed
  196. from C{prj_name}.
  197. @type top_page: C{string}
  198. @keyword top_page: The top page for the documentation. This
  199. is the default page shown main frame, when frames are
  200. enabled. C{top} can be a URL, the name of a
  201. module, the name of a class, or one of the special
  202. strings C{"trees.html"}, C{"indices.html"}, or
  203. C{"help.html"}. By default, the top-level package or
  204. module is used, if there is one; otherwise, C{"trees"}
  205. is used.
  206. @type css: C{string}
  207. @keyword css: The CSS stylesheet file. If C{css} is a file
  208. name, then the specified file's conents will be used.
  209. Otherwise, if C{css} is the name of a CSS stylesheet in
  210. L{epydoc.docwriter.html_css}, then that stylesheet will
  211. be used. Otherwise, an error is reported. If no stylesheet
  212. is specified, then the default stylesheet is used.
  213. @type help_file: C{string}
  214. @keyword help_file: The name of the help file. If no help file is
  215. specified, then the default help file will be used.
  216. @type show_private: C{boolean}
  217. @keyword show_private: Whether to create documentation for
  218. private objects. By default, private objects are documented.
  219. @type show_frames: C{boolean})
  220. @keyword show_frames: Whether to create a frames-based table of
  221. contents. By default, it is produced.
  222. @type show_imports: C{boolean}
  223. @keyword show_imports: Whether or not to display lists of
  224. imported functions and classes. By default, they are
  225. not shown.
  226. @type variable_maxlines: C{int}
  227. @keyword variable_maxlines: The maximum number of lines that
  228. should be displayed for the value of a variable in the
  229. variable details section. By default, 8 lines are
  230. displayed.
  231. @type variable_linelength: C{int}
  232. @keyword variable_linelength: The maximum line length used for
  233. displaying the values of variables in the variable
  234. details sections. If a line is longer than this length,
  235. then it will be wrapped to the next line. The default
  236. line length is 70 characters.
  237. @type variable_summary_linelength: C{int}
  238. @keyword variable_summary_linelength: The maximum line length
  239. used for displaying the values of variables in the summary
  240. section. If a line is longer than this length, then it
  241. will be truncated. The default is 40 characters.
  242. @type variable_tooltip_linelength: C{int}
  243. @keyword variable_tooltip_linelength: The maximum line length
  244. used for tooltips for the values of variables. If a
  245. line is longer than this length, then it will be
  246. truncated. The default is 600 characters.
  247. @type property_function_linelength: C{int}
  248. @keyword property_function_linelength: The maximum line length
  249. used to dispaly property functions (C{fget}, C{fset}, and
  250. C{fdel}) that contain something other than a function
  251. object. The default length is 40 characters.
  252. @type inheritance: C{string}
  253. @keyword inheritance: How inherited objects should be displayed.
  254. If C{inheritance='grouped'}, then inherited objects are
  255. gathered into groups; if C{inheritance='listed'}, then
  256. inherited objects are listed in a short list at the
  257. end of their group; if C{inheritance='included'}, then
  258. inherited objects are mixed in with non-inherited
  259. objects. The default is 'grouped'.
  260. @type include_source_code: C{boolean}
  261. @keyword include_source_code: If true, then generate colorized
  262. source code files for each python module.
  263. @type include_log: C{boolean}
  264. @keyword include_log: If true, the the footer will include an
  265. href to the page 'epydoc-log.html'.
  266. @type src_code_tab_width: C{int}
  267. @keyword src_code_tab_width: Number of spaces to replace each tab
  268. with in source code listings.
  269. """
  270. self.docindex = docindex
  271. # Process keyword arguments.
  272. self._show_private = kwargs.get('show_private', 1)
  273. """Should private docs be included?"""
  274. self._prj_name = kwargs.get('prj_name', None)
  275. """The project's name (for the project link in the navbar)"""
  276. self._prj_url = kwargs.get('prj_url', None)
  277. """URL for the project link in the navbar"""
  278. self._prj_link = kwargs.get('prj_link', None)
  279. """HTML code for the project link in the navbar"""
  280. self._top_page = kwargs.get('top_page', None)
  281. """The 'main' page"""
  282. self._css = kwargs.get('css')
  283. """CSS stylesheet to use"""
  284. self._helpfile = kwargs.get('help_file', None)
  285. """Filename of file to extract help contents from"""
  286. self._frames_index = kwargs.get('show_frames', 1)
  287. """Should a frames index be created?"""
  288. self._show_imports = kwargs.get('show_imports', False)
  289. """Should imports be listed?"""
  290. self._propfunc_linelen = kwargs.get('property_function_linelength', 40)
  291. """[XXX] Not used!"""
  292. self._variable_maxlines = kwargs.get('variable_maxlines', 8)
  293. """Max lines for variable values"""
  294. self._variable_linelen = kwargs.get('variable_linelength', 70)
  295. """Max line length for variable values"""
  296. self._variable_summary_linelen = \
  297. kwargs.get('variable_summary_linelength', 65)
  298. """Max length for variable value summaries"""
  299. self._variable_tooltip_linelen = \
  300. kwargs.get('variable_tooltip_linelength', 600)
  301. """Max length for variable tooltips"""
  302. self._inheritance = kwargs.get('inheritance', 'listed')
  303. """How should inheritance be displayed? 'listed', 'included',
  304. or 'grouped'"""
  305. self._incl_sourcecode = kwargs.get('include_source_code', True)
  306. """Should pages be generated for source code of modules?"""
  307. self._mark_docstrings = kwargs.get('mark_docstrings', False)
  308. """Wrap <span class='docstring'>...</span> around docstrings?"""
  309. self._graph_types = kwargs.get('graphs', ()) or ()
  310. """Graphs that we should include in our output."""
  311. self._include_log = kwargs.get('include_log', False)
  312. """Are we generating an HTML log page?"""
  313. self._src_code_tab_width = kwargs.get('src_code_tab_width', 8)
  314. """Number of spaces to replace each tab with in source code
  315. listings."""
  316. self._callgraph_cache = {}
  317. """Map the callgraph L{uid<DotGraph.uid>} to their HTML
  318. representation."""
  319. self._redundant_details = kwargs.get('redundant_details', False)
  320. """If true, then include objects in the details list even if all
  321. info about them is already provided by the summary table."""
  322. # For use with select_variables():
  323. if self._show_private:
  324. self._public_filter = None
  325. else:
  326. self._public_filter = True
  327. # Make sure inheritance has a sane value.
  328. if self._inheritance not in ('listed', 'included', 'grouped'):
  329. raise ValueError, 'Bad value for inheritance'
  330. # Create the project homepage link, if it was not specified.
  331. if (self._prj_name or self._prj_url) and not self._prj_link:
  332. self._prj_link = plaintext_to_html(self._prj_name or
  333. 'Project Homepage')
  334. # Add a hyperlink to _prj_url, if _prj_link doesn't already
  335. # contain any hyperlinks.
  336. if (self._prj_link and self._prj_url and
  337. not re.search(r'<a[^>]*\shref', self._prj_link)):
  338. self._prj_link = ('<a class="navbar" target="_top" href="'+
  339. self._prj_url+'">'+self._prj_link+'</a>')
  340. # Precompute lists & sets of APIDoc objects that we're
  341. # interested in.
  342. self.valdocs = valdocs = sorted(docindex.reachable_valdocs(
  343. imports=False, packages=False, bases=False, submodules=False,
  344. subclasses=False, private=self._show_private))
  345. self.module_list = [d for d in valdocs if isinstance(d, ModuleDoc)]
  346. """The list of L{ModuleDoc}s for the documented modules."""
  347. self.module_set = set(self.module_list)
  348. """The set of L{ModuleDoc}s for the documented modules."""
  349. self.class_list = [d for d in valdocs if isinstance(d, ClassDoc)]
  350. """The list of L{ClassDoc}s for the documented classes."""
  351. self.class_set = set(self.class_list)
  352. """The set of L{ClassDoc}s for the documented classes."""
  353. self.routine_list = [d for d in valdocs if isinstance(d, RoutineDoc)]
  354. """The list of L{RoutineDoc}s for the documented routines."""
  355. self.indexed_docs = []
  356. """The list of L{APIDoc}s for variables and values that should
  357. be included in the index."""
  358. # URL for 'trees' page
  359. if self.module_list: self._trees_url = 'module-tree.html'
  360. else: self._trees_url = 'class-tree.html'
  361. # Construct the value for self.indexed_docs.
  362. self.indexed_docs += [d for d in valdocs
  363. if not isinstance(d, GenericValueDoc)]
  364. for doc in valdocs:
  365. if isinstance(doc, NamespaceDoc):
  366. # add any vars with generic values; but don't include
  367. # inherited vars.
  368. self.indexed_docs += [d for d in doc.variables.values() if
  369. isinstance(d.value, GenericValueDoc)
  370. and d.container == doc]
  371. self.indexed_docs.sort()
  372. # Figure out the url for the top page.
  373. self._top_page_url = self._find_top_page(self._top_page)
  374. # Decide whether or not to split the identifier index.
  375. self._split_ident_index = (len(self.indexed_docs) >=
  376. self.SPLIT_IDENT_INDEX_SIZE)
  377. # Figure out how many output files there will be (for progress
  378. # reporting).
  379. self.modules_with_sourcecode = set()
  380. for doc in self.module_list:
  381. if isinstance(doc, ModuleDoc) and is_src_filename(doc.filename):
  382. self.modules_with_sourcecode.add(doc)
  383. self._num_files = (len(self.class_list) + len(self.module_list) +
  384. 10 + len(self.METADATA_INDICES))
  385. if self._frames_index:
  386. self._num_files += len(self.module_list) + 3
  387. if self._incl_sourcecode:
  388. self._num_files += len(self.modules_with_sourcecode)
  389. if self._split_ident_index:
  390. self._num_files += len(self.LETTERS)
  391. def _find_top_page(self, pagename):
  392. """
  393. Find the top page for the API documentation. This page is
  394. used as the default page shown in the main frame, when frames
  395. are used. When frames are not used, this page is copied to
  396. C{index.html}.
  397. @param pagename: The name of the page, as specified by the
  398. keyword argument C{top} to the constructor.
  399. @type pagename: C{string}
  400. @return: The URL of the top page.
  401. @rtype: C{string}
  402. """
  403. # If a page name was specified, then we need to figure out
  404. # what it points to.
  405. if pagename:
  406. # If it's a URL, then use it directly.
  407. if pagename.lower().startswith('http:'):
  408. return pagename
  409. # If it's an object, then use that object's page.
  410. try:
  411. doc = self.docindex.get_valdoc(pagename)
  412. return self.url(doc)
  413. except:
  414. pass
  415. # Otherwise, give up.
  416. log.warning('Could not find top page %r; using %s '
  417. 'instead' % (pagename, self._trees_url))
  418. return self._trees_url
  419. # If no page name was specified, then try to choose one
  420. # automatically.
  421. else:
  422. root = [val_doc for val_doc in self.docindex.root
  423. if isinstance(val_doc, (ClassDoc, ModuleDoc))]
  424. if len(root) == 0:
  425. # No docs?? Try the trees page.
  426. return self._trees_url
  427. elif len(root) == 1:
  428. # One item in the root; use that.
  429. return self.url(root[0])
  430. else:
  431. # Multiple root items; if they're all in one package,
  432. # then use that. Otherwise, use self._trees_url
  433. root = sorted(root, key=lambda v:len(v.canonical_name))
  434. top = root[0]
  435. for doc in root[1:]:
  436. if not top.canonical_name.dominates(doc.canonical_name):
  437. return self._trees_url
  438. else:
  439. return self.url(top)
  440. #////////////////////////////////////////////////////////////
  441. #{ 1. Interface Methods
  442. #////////////////////////////////////////////////////////////
  443. def write(self, directory=None):
  444. """
  445. Write the documentation to the given directory.
  446. @type directory: C{string}
  447. @param directory: The directory to which output should be
  448. written. If no directory is specified, output will be
  449. written to the current directory. If the directory does
  450. not exist, it will be created.
  451. @rtype: C{None}
  452. @raise OSError: If C{directory} cannot be created.
  453. @raise OSError: If any file cannot be created or written to.
  454. """
  455. # For progress reporting:
  456. self._files_written = 0.
  457. # Set the default values for ValueDoc formatted representations.
  458. orig_valdoc_defaults = (ValueDoc.SUMMARY_REPR_LINELEN,
  459. ValueDoc.REPR_LINELEN,
  460. ValueDoc.REPR_MAXLINES)
  461. ValueDoc.SUMMARY_REPR_LINELEN = self._variable_summary_linelen
  462. ValueDoc.REPR_LINELEN = self._variable_linelen
  463. ValueDoc.REPR_MAXLINES = self._variable_maxlines
  464. # Use an image for the crarr symbol.
  465. from epydoc.markup.epytext import ParsedEpytextDocstring
  466. orig_crarr_html = ParsedEpytextDocstring.SYMBOL_TO_HTML['crarr']
  467. ParsedEpytextDocstring.SYMBOL_TO_HTML['crarr'] = (
  468. r'<span class="variable-linewrap">'
  469. r'<img src="crarr.png" alt="\" /></span>')
  470. # Keep track of failed xrefs, and report them at the end.
  471. self._failed_xrefs = {}
  472. # Create destination directories, if necessary
  473. if not directory: directory = os.curdir
  474. self._mkdir(directory)
  475. self._directory = directory
  476. # Write the CSS file.
  477. self._files_written += 1
  478. log.progress(self._files_written/self._num_files, 'epydoc.css')
  479. self.write_css(directory, self._css)
  480. # Write the Javascript file.
  481. self._files_written += 1
  482. log.progress(self._files_written/self._num_files, 'epydoc.js')
  483. self.write_javascript(directory)
  484. # Write images
  485. self.write_images(directory)
  486. # Build the indices.
  487. indices = {'ident': self.build_identifier_index(),
  488. 'term': self.build_term_index()}
  489. for (name, label, label2) in self.METADATA_INDICES:
  490. indices[name] = self.build_metadata_index(name)
  491. # Write the identifier index. If requested, split it into
  492. # separate pages for each letter.
  493. ident_by_letter = self._group_by_letter(indices['ident'])
  494. if not self._split_ident_index:
  495. self._write(self.write_link_index, directory,
  496. 'identifier-index.html', indices,
  497. 'Identifier Index', 'identifier-index.html',
  498. ident_by_letter)
  499. else:
  500. # Write a page for each section.
  501. for letter in self.LETTERS:
  502. filename = 'identifier-index-%s.html' % letter
  503. self._write(self.write_link_index, directory, filename,
  504. indices, 'Identifier Index', filename,
  505. ident_by_letter, [letter],
  506. 'identifier-index-%s.html')
  507. # Use the first non-empty section as the main index page.
  508. for letter in self.LETTERS:
  509. if letter in ident_by_letter:
  510. filename = 'identifier-index.html'
  511. self._write(self.write_link_index, directory, filename,
  512. indices, 'Identifier Index', filename,
  513. ident_by_letter, [letter],
  514. 'identifier-index-%s.html')
  515. break
  516. # Write the term index.
  517. if indices['term']:
  518. term_by_letter = self._group_by_letter(indices['term'])
  519. self._write(self.write_link_index, directory, 'term-index.html',
  520. indices, 'Term Definition Index',
  521. 'term-index.html', term_by_letter)
  522. else:
  523. self._files_written += 1 # (skipped)
  524. # Write the metadata indices.
  525. for (name, label, label2) in self.METADATA_INDICES:
  526. if indices[name]:
  527. self._write(self.write_metadata_index, directory,
  528. '%s-index.html' % name, indices, name,
  529. label, label2)
  530. else:
  531. self._files_written += 1 # (skipped)
  532. # Write the trees file (package & class hierarchies)
  533. if self.module_list:
  534. self._write(self.write_module_tree, directory, 'module-tree.html')
  535. else:
  536. self._files_written += 1 # (skipped)
  537. if self.class_list:
  538. self._write(self.write_class_tree, directory, 'class-tree.html')
  539. else:
  540. self._files_written += 1 # (skipped)
  541. # Write the help file.
  542. self._write(self.write_help, directory,'help.html')
  543. # Write the frames-based table of contents.
  544. if self._frames_index:
  545. self._write(self.write_frames_index, directory, 'frames.html')
  546. self._write(self.write_toc, directory, 'toc.html')
  547. self._write(self.write_project_toc, directory, 'toc-everything.html')
  548. for doc in self.module_list:
  549. filename = 'toc-%s' % urllib.unquote(self.url(doc))
  550. self._write(self.write_module_toc, directory, filename, doc)
  551. # Write the object documentation.
  552. for doc in self.module_list:
  553. filename = urllib.unquote(self.url(doc))
  554. self._write(self.write_module, directory, filename, doc)
  555. for doc in self.class_list:
  556. filename = urllib.unquote(self.url(doc))
  557. self._write(self.write_class, directory, filename, doc)
  558. # Write source code files.
  559. if self._incl_sourcecode:
  560. # Build a map from short names to APIDocs, used when
  561. # linking names in the source code.
  562. name_to_docs = {}
  563. for api_doc in self.indexed_docs:
  564. if (api_doc.canonical_name is not None and
  565. self.url(api_doc) is not None):
  566. name = api_doc.canonical_name[-1]
  567. name_to_docs.setdefault(name, []).append(api_doc)
  568. # Sort each entry of the name_to_docs list.
  569. for doc_list in name_to_docs.values():
  570. doc_list.sort()
  571. # Write the source code for each module.
  572. for doc in self.modules_with_sourcecode:
  573. filename = urllib.unquote(self.pysrc_url(doc))
  574. self._write(self.write_sourcecode, directory, filename, doc,
  575. name_to_docs)
  576. # Write the auto-redirect page.
  577. self._write(self.write_redirect_page, directory, 'redirect.html')
  578. # Write the mapping object name -> URL
  579. self._write(self.write_api_list, directory, 'api-objects.txt')
  580. # Write the index.html files.
  581. # (this must be done last, since it might copy another file)
  582. self._files_written += 1
  583. log.progress(self._files_written/self._num_files, 'index.html')
  584. self.write_homepage(directory)
  585. # Don't report references to builtins as missing
  586. for k in self._failed_xrefs.keys(): # have a copy of keys
  587. if hasattr(__builtin__, k):
  588. del self._failed_xrefs[k]
  589. # Report any failed crossreferences
  590. if self._failed_xrefs:
  591. estr = 'Failed identifier crossreference targets:\n'
  592. failed_identifiers = self._failed_xrefs.keys()
  593. failed_identifiers.sort()
  594. for identifier in failed_identifiers:
  595. names = self._failed_xrefs[identifier].keys()
  596. names.sort()
  597. estr += '- %s' % identifier
  598. estr += '\n'
  599. for name in names:
  600. estr += ' (from %s)\n' % name
  601. log.docstring_warning(estr)
  602. # [xx] testing:
  603. if self._num_files != int(self._files_written):
  604. log.debug("Expected to write %d files, but actually "
  605. "wrote %d files" %
  606. (self._num_files, int(self._files_written)))
  607. # Restore defaults that we changed.
  608. (ValueDoc.SUMMARY_REPR_LINELEN, ValueDoc.REPR_LINELEN,
  609. ValueDoc.REPR_MAXLINES) = orig_valdoc_defaults
  610. ParsedEpytextDocstring.SYMBOL_TO_HTML['crarr'] = orig_crarr_html
  611. def _write(self, write_func, directory, filename, *args):
  612. # Display our progress.
  613. self._files_written += 1
  614. log.progress(self._files_written/self._num_files, filename)
  615. path = os.path.join(directory, filename)
  616. f = codecs.open(path, 'w', 'ascii', errors='xmlcharrefreplace')
  617. write_func(f.write, *args)
  618. f.close()
  619. def _mkdir(self, directory):
  620. """
  621. If the given directory does not exist, then attempt to create it.
  622. @rtype: C{None}
  623. """
  624. if not os.path.isdir(directory):
  625. if os.path.exists(directory):
  626. raise OSError('%r is not a directory' % directory)
  627. os.mkdir(directory)
  628. #////////////////////////////////////////////////////////////
  629. #{ 2.1. Module Pages
  630. #////////////////////////////////////////////////////////////
  631. def write_module(self, out, doc):
  632. """
  633. Write an HTML page containing the API documentation for the
  634. given module to C{out}.
  635. @param doc: A L{ModuleDoc} containing the API documentation
  636. for the module that should be described.
  637. """
  638. longname = doc.canonical_name
  639. shortname = doc.canonical_name[-1]
  640. # Write the page header (incl. navigation bar & breadcrumbs)
  641. self.write_header(out, str(longname))
  642. self.write_navbar(out, doc)
  643. self.write_breadcrumbs(out, doc, self.url(doc))
  644. # Write the name of the module we're describing.
  645. if doc.is_package is True: typ = 'Package'
  646. else: typ = 'Module'
  647. if longname[0].startswith('script-'):
  648. shortname = str(longname)[7:]
  649. typ = 'Script'
  650. out('<!-- ==================== %s ' % typ.upper() +
  651. 'DESCRIPTION ==================== -->\n')
  652. out('<h1 class="epydoc">%s %s</h1>' % (typ, shortname))
  653. out('<p class="nomargin-top">%s</p>\n' % self.pysrc_link(doc))
  654. # If the module has a description, then list it.
  655. if doc.descr not in (None, UNKNOWN):
  656. out(self.descr(doc, 2)+'\n\n')
  657. # Write any standarad metadata (todo, author, etc.)
  658. if doc.metadata is not UNKNOWN and doc.metadata:
  659. out('<hr />\n')
  660. self.write_standard_fields(out, doc)
  661. # If it's a package, then list the modules it contains.
  662. if doc.is_package is True:
  663. self.write_module_list(out, doc)
  664. # Write summary tables describing the variables that the
  665. # module defines.
  666. self.write_summary_table(out, "Classes", doc, "class")
  667. self.write_summary_table(out, "Functions", doc, "function")
  668. self.write_summary_table(out, "Variables", doc, "other")
  669. # Write a list of all imported objects.
  670. if self._show_imports:
  671. self.write_imports(out, doc)
  672. # Write detailed descriptions of functions & variables defined
  673. # in this module.
  674. self.write_details_list(out, "Function Details", doc, "function")
  675. self.write_details_list(out, "Variables Details", doc, "other")
  676. # Write the page footer (including navigation bar)
  677. self.write_navbar(out, doc)
  678. self.write_footer(out)
  679. #////////////////////////////////////////////////////////////
  680. #{ 2.??. Source Code Pages
  681. #////////////////////////////////////////////////////////////
  682. def write_sourcecode(self, out, doc, name_to_docs):
  683. #t0 = time.time()
  684. filename = doc.filename
  685. name = str(doc.canonical_name)
  686. # Header
  687. self.write_header(out, name)
  688. self.write_navbar(out, doc)
  689. self.write_breadcrumbs(out, doc, self.pysrc_url(doc))
  690. # Source code listing
  691. out('<h1 class="epydoc">Source Code for %s</h1>\n' %
  692. self.href(doc, label='%s %s' % (self.doc_kind(doc), name)))
  693. out('<pre class="py-src">\n')
  694. out(PythonSourceColorizer(filename, name, self.docindex,
  695. self.url, name_to_docs,
  696. self._src_code_tab_width).colorize())
  697. out('</pre>\n<br />\n')
  698. # Footer
  699. self.write_navbar(out, doc)
  700. self.write_footer(out)
  701. #log.debug('[%6.2f sec] Wrote pysrc for %s' %
  702. # (time.time()-t0, name))
  703. #////////////////////////////////////////////////////////////
  704. #{ 2.2. Class Pages
  705. #////////////////////////////////////////////////////////////
  706. def write_class(self, out, doc):
  707. """
  708. Write an HTML page containing the API documentation for the
  709. given class to C{out}.
  710. @param doc: A L{ClassDoc} containing the API documentation
  711. for the class that should be described.
  712. """
  713. longname = doc.canonical_name
  714. shortname = doc.canonical_name[-1]
  715. # Write the page header (incl. navigation bar & breadcrumbs)
  716. self.write_header(out, str(longname))
  717. self.write_navbar(out, doc)
  718. self.write_breadcrumbs(out, doc, self.url(doc))
  719. # Write the name of the class we're describing.
  720. if doc.is_type(): typ = 'Type'
  721. elif doc.is_exception(): typ = 'Exception'
  722. else: typ = 'Class'
  723. out('<!-- ==================== %s ' % typ.upper() +
  724. 'DESCRIPTION ==================== -->\n')
  725. out('<h1 class="epydoc">%s %s</h1>' % (typ, shortname))
  726. out('<p class="nomargin-top">%s</p>\n' % self.pysrc_link(doc))
  727. if ((doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0) or
  728. (doc.subclasses not in (UNKNOWN,None) and len(doc.subclasses)>0)):
  729. # Display bases graphically, if requested.
  730. if 'umlclasstree' in self._graph_types:
  731. self.write_class_tree_graph(out, doc, uml_class_tree_graph)
  732. elif 'classtree' in self._graph_types:
  733. self.write_class_tree_graph(out, doc, class_tree_graph)
  734. # Otherwise, use ascii-art.
  735. else:
  736. # Write the base class tree.
  737. if doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0:
  738. out('<pre class="base-tree">\n%s</pre>\n\n' %
  739. self.base_tree(doc))
  740. # Write the known subclasses
  741. if (doc.subclasses not in (UNKNOWN, None) and
  742. len(doc.subclasses) > 0):
  743. out('<dl><dt>Known Subclasses:</dt>\n<dd>\n ')
  744. out(' <ul class="subclass-list">\n')
  745. for i, subclass in enumerate(doc.subclasses):
  746. href = self.href(subclass, context=doc)
  747. if self._val_is_public(subclass): css = ''
  748. else: css = ' class="private"'
  749. if i > 0: href = ', '+href
  750. out('<li%s>%s</li>' % (css, href))
  751. out(' </ul>\n')
  752. out('</dd></dl>\n\n')
  753. out('<hr />\n')
  754. # If the class has a description, then list it.
  755. if doc.descr not in (None, UNKNOWN):
  756. out(self.descr(doc, 2)+'\n\n')
  757. # Write any standarad metadata (todo, author, etc.)
  758. if doc.metadata is not UNKNOWN and doc.metadata:
  759. out('<hr />\n')
  760. self.write_standard_fields(out, doc)
  761. # Write summary tables describing the variables that the
  762. # class defines.
  763. self.write_summary_table(out, "Nested Classes", doc, "class")
  764. self.write_summary_table(out, "Instance Methods", doc,
  765. "instancemethod")
  766. self.write_summary_table(out, "Class Methods", doc, "classmethod")
  767. self.write_summary_table(out, "Static Methods", doc, "staticmethod")
  768. self.write_summary_table(out, "Class Variables", doc,
  769. "classvariable")
  770. self.write_summary_table(out, "Instance Variables", doc,
  771. "instancevariable")
  772. self.write_summary_table(out, "Properties", doc, "property")
  773. # Write a list of all imported objects.
  774. if self._show_imports:
  775. self.write_imports(out, doc)
  776. # Write detailed descriptions of functions & variables defined
  777. # in this class.
  778. # [xx] why group methods into one section but split vars into two?
  779. # seems like we should either group in both cases or split in both
  780. # cases.
  781. self.write_details_list(out, "Method Details", doc, "method")
  782. self.write_details_list(out, "Class Variable Details", doc,
  783. "classvariable")
  784. self.write_details_list(out, "Instance Variable Details", doc,
  785. "instancevariable")
  786. self.write_details_list(out, "Property Details", doc, "property")
  787. # Write the page footer (including navigation bar)
  788. self.write_navbar(out, doc)
  789. self.write_footer(out)
  790. def write_class_tree_graph(self, out, doc, graphmaker):
  791. """
  792. Write HTML code for a class tree graph of C{doc} (a classdoc),
  793. using C{graphmaker} to draw the actual graph. C{graphmaker}
  794. should be L{class_tree_graph()}, or L{uml_class_tree_graph()},
  795. or any other function with a compatible signature.
  796. If the given class has any private sublcasses (including
  797. recursive subclasses), then two graph images will be generated
  798. -- one to display when private values are shown, and the other
  799. to display when private values are hidden.
  800. """
  801. linker = _HTMLDocstringLinker(self, doc)
  802. private_subcls = self._private_subclasses(doc)
  803. if private_subcls:
  804. out('<center>\n'
  805. ' <div class="private">%s</div>\n'
  806. ' <div class="public" style="display:none">%s</div>\n'
  807. '</center>\n' %
  808. (self.render_graph(graphmaker(doc, linker, doc)),
  809. self.render_graph(graphmaker(doc, linker, doc,
  810. exclude=private_subcls))))
  811. else:
  812. out('<center>\n%s\n</center>\n' %
  813. self.render_graph(graphmaker(doc, linker, doc)))
  814. #////////////////////////////////////////////////////////////
  815. #{ 2.3. Trees pages
  816. #////////////////////////////////////////////////////////////
  817. def write_module_tree(self, out):
  818. # Header material
  819. self.write_treepage_header(out, 'Module Hierarchy', 'module-tree.html')
  820. out('<h1 class="epydoc">Module Hierarchy</h1>\n')
  821. # Write entries for all top-level modules/packages.
  822. out('<ul class="nomargin-top">\n')
  823. for doc in self.module_list:
  824. if (doc.package in (None, UNKNOWN) or
  825. doc.package not in self.module_set):
  826. self.write_module_tree_item(out, doc)
  827. out('</ul>\n')
  828. # Footer material
  829. self.write_navbar(out, 'trees')
  830. self.write_footer(out)
  831. def write_class_tree(self, out):
  832. """
  833. Write HTML code for a nested list showing the base/subclass
  834. relationships between all documented classes. Each element of
  835. the top-level list is a class with no (documented) bases; and
  836. under each class is listed all of its subclasses. Note that
  837. in the case of multiple inheritance, a class may appear
  838. multiple times.
  839. @todo: For multiple inheritance, don't repeat subclasses the
  840. second time a class is mentioned; instead, link to the
  841. first mention.
  842. """
  843. # [XX] backref for multiple inheritance?
  844. # Header material
  845. self.write_treepage_header(out, 'Class Hierarchy', 'class-tree.html')
  846. out('<h1 class="epydoc">Class Hierarchy</h1>\n')
  847. # Build a set containing all classes that we should list.
  848. # This includes everything in class_list, plus any of those
  849. # class' bases, but not undocumented subclasses.
  850. class_set = self.class_set.copy()
  851. for doc in self.class_list:
  852. if doc.bases != UNKNOWN:
  853. for base in doc.bases:
  854. if base not in class_set:
  855. if isinstance(base, ClassDoc):
  856. class_set.update(base.mro())
  857. else:
  858. # [XX] need to deal with this -- how?
  859. pass
  860. #class_set.add(base)
  861. out('<ul class="nomargin-top">\n')
  862. for doc in sorted(class_set, key=lambda c:c.canonical_name[-1]):
  863. if doc.bases != UNKNOWN and len(doc.bases)==0:
  864. self.write_class_tree_item(out, doc, class_set)
  865. out('</ul>\n')
  866. # Footer material
  867. self.write_navbar(out, 'trees')
  868. self.write_footer(out)
  869. def write_treepage_header(self, out, title, url):
  870. # Header material.
  871. self.write_header(out, title)
  872. self.write_navbar(out, 'trees')
  873. self.write_breadcrumbs(out, 'trees', url)
  874. if self.class_list and self.module_list:
  875. out('<center><b>\n')
  876. out(' [ <a href="module-tree.html">Module Hierarchy</a>\n')
  877. out(' | <a href="class-tree.html">Class Hierarchy</a> ]\n')
  878. out('</b></center><br />\n')
  879. #////////////////////////////////////////////////////////////
  880. #{ 2.4. Index pages
  881. #////////////////////////////////////////////////////////////
  882. SPLIT_IDENT_INDEX_SIZE = 3000
  883. """If the identifier index has more than this number of entries,
  884. then it will be split into separate pages, one for each
  885. alphabetical section."""
  886. LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'
  887. """The alphabetical sections that are used for link index pages."""
  888. def write_link_index(self, out, indices, title, url, index_by_section,
  889. sections=LETTERS, section_url='#%s'):
  890. # Header
  891. self.write_indexpage_header(out, indices, title, url)
  892. # Index title & links to alphabetical sections.
  893. out('<table border="0" width="100%">\n'
  894. '<tr valign="bottom"><td>\n')
  895. out('<h1 class="epydoc">%s</h1>\n</td><td>\n[\n' % title)
  896. for sec in self.LETTERS:
  897. if sec in index_by_section:
  898. out(' <a href="%s">%s</a>\n' % (section_url % sec, sec))
  899. else:
  900. out(' %s\n' % sec)
  901. out(']\n')
  902. out('</td></table>\n')
  903. # Alphabetical sections.
  904. sections = [s for s in sections if s in index_by_section]
  905. if sections:
  906. out('<table border="0" width="100%">\n')
  907. for section in sorted(sections):
  908. out('<tr valign="top"><td valign="top" width="1%">')
  909. out('<h2 class="epydoc"><a name="%s">%s</a></h2></td>\n' %
  910. (section, section))
  911. out('<td valign="top">\n')
  912. self.write_index_section(out, index_by_section[section], True)
  913. out('</td></tr>\n')
  914. out('</table>\n<br />')
  915. # Footer material.
  916. out('<br />')
  917. self.write_navbar(out, 'indices')
  918. self.write_footer(out)
  919. def write_metadata_index(self, out, indices, field, title, typ):
  920. """
  921. Write an HTML page containing a metadata index.
  922. """
  923. index = indices[field]
  924. # Header material.
  925. self.write_indexpage_header(out, indices, title,
  926. '%s-index.html' % field)
  927. # Page title.
  928. out('<h1 class="epydoc"><a name="%s">%s</a></h1>\n<br />\n' %
  929. (field, title))
  930. # Index (one section per arg)
  931. for arg in sorted(index):
  932. # Write a section title.
  933. if arg is not None:
  934. if len([1 for (doc, descrs) in index[arg] if
  935. not self._doc_or_ancestor_is_private(doc)]) == 0:
  936. out('<div class="private">')
  937. else:
  938. out('<div>')
  939. self.write_table_header(out, 'metadata-index', arg)
  940. out('</table>')
  941. # List every descr for this arg.
  942. for (doc, descrs) in index[arg]:
  943. if self._doc_or_ancestor_is_private(doc):
  944. out('<div class="private">\n')
  945. else:
  946. out('<div>\n')
  947. out('<table width="100%" class="metadata-index" '
  948. 'bgcolor="#e0e0e0"><tr><td class="metadata-index">')
  949. out('<b>%s in %s</b>' %
  950. (typ, self.href(doc, label=doc.canonical_name)))
  951. out(' <ul class="nomargin">\n')
  952. for descr in descrs:
  953. out(' <li>%s</li>\n' %
  954. self.docstring_to_html(descr,doc,4))
  955. out(' </ul>\n')
  956. out('</table></div>\n')
  957. # Footer material.
  958. out('<br />')
  959. self.write_navbar(out, 'indices')
  960. self.write_footer(out)
  961. def write_indexpage_header(self, out, indices, title, url):
  962. """
  963. A helper for the index page generation functions, which
  964. generates a header that can be used to navigate between the
  965. different indices.
  966. """
  967. self.write_header(out, title)
  968. self.write_navbar(out, 'indices')
  969. self.write_breadcrumbs(out, 'indices', url)
  970. if (indices['term'] or
  971. [1 for (name,l,l2) in self.METADATA_INDICES if indices[name]]):
  972. out('<center><b>[\n')
  973. out(' <a href="identifier-index.html">Identifiers</a>\n')
  974. if indices['term']:
  975. out('| <a href="term-index.html">Term Definitions</a>\n')
  976. for (name, label, label2) in self.METADATA_INDICES:
  977. if indices[name]:
  978. out('| <a href="%s-index.html">%s</a>\n' %
  979. (name, label2))
  980. out(']</b></center><br />\n')
  981. def write_index_section(self, out, items, add_blankline=False):
  982. out('<table class="link-index" width="100%" border="1">\n')
  983. num_rows = (len(items)+2)/3
  984. for row in range(num_rows):
  985. out('<tr>\n')
  986. for col in range(3):
  987. out('<td width="33%" class="link-index">')
  988. i = col*num_rows+row
  989. if i < len(items):
  990. name, url, container = items[col*num_rows+row]
  991. out('<a href="%s">%s</a>' % (url, name))
  992. if container is not None:
  993. out('<br />\n')
  994. if isinstance(container, ModuleDoc):
  995. label = container.canonical_name
  996. else:
  997. label = container.canonical_name[-1]
  998. out('<span class="index-where">(in&nbsp;%s)'
  999. '</span>' % self.href(container, label))
  1000. else:
  1001. out('&nbsp;')
  1002. out('</td>\n')
  1003. out('</tr>\n')
  1004. if add_blankline and num_rows == 1:
  1005. blank_cell = '<td class="link-index">&nbsp;</td>'
  1006. out('<tr>'+3*blank_cell+'</tr>\n')
  1007. out('</table>\n')
  1008. #////////////////////////////////////////////////////////////
  1009. #{ 2.5. Help Page
  1010. #////////////////////////////////////////////////////////////
  1011. def write_help(self, out):
  1012. """
  1013. Write an HTML help file to the given stream. If
  1014. C{self._helpfile} contains a help file, then use it;
  1015. otherwise, use the default helpfile from
  1016. L{epydoc.docwriter.html_help}.
  1017. """
  1018. # todo: optionally parse .rst etc

Large files files are truncated, but you can click here to view the full file