Package epydoc :: Package docwriter :: Module latex |
[hide private]
[frames] | no frames]

# Source Code for Module epydoc.docwriter.latex

       1  #
       2  # epydoc.py: epydoc LaTeX output generator
       3  # Edward Loper
       4  #
       5  # Created [01/30/01 05:18 PM]
       6  # $Id: latex.py 1621 2007-09-23 18:54:23Z edloper $
       7  #
       8
       9  """
      10  The LaTeX output generator for epydoc.  The main interface provided by
      11  this module is the L{LatexWriter} class.
      12
      13  @todo: Inheritance=listed
      14  """
      15  __docformat__ = 'epytext en'
      16
      17  import os.path, sys, time, re, textwrap, codecs
      18
      19  from epydoc.apidoc import *
      20  from epydoc.compat import *
      21  import epydoc
      22  from epydoc import log
      23  from epydoc import markup
      24  from epydoc.util import plaintext_to_latex
      25  import epydoc.markup
      26
      27 -class LatexWriter:
      28      PREAMBLE = [
      29          "\\documentclass{article}",
      30          "\\usepackage{alltt, parskip, fancyhdr, boxedminipage}",
      31          "\\usepackage{makeidx, multirow, longtable, tocbibind, amssymb}",
      32          "\\usepackage{fullpage}",
      33          "\\usepackage[usenames]{color}",
      34          # Fix the heading position -- without this, the headings generated
      35          # by the fancyheadings package sometimes overlap the text.
      36          "\\setlength{\\headheight}{16pt}",
      37          "\\setlength{\\headsep}{24pt}",
      38          "\\setlength{\\topmargin}{-\\headsep}",
      39          # By default, do not indent paragraphs.
      40          "\\setlength{\\parindent}{0ex}",
      41          "\\setlength{\\parskip}{2ex}",
      42          # Double the standard size boxedminipage outlines.
      43          "\\setlength{\\fboxrule}{2\\fboxrule}",
      44          # Create a 'base class' length named BCL for use in base trees.
      45          "\\newlength{\\BCL} % base class length, for base trees.",
      46          # Display the section & subsection names in a header.
      47          "\\pagestyle{fancy}",
      48          "\\renewcommand{\\sectionmark}[1]{\\markboth{#1}{}}",
      49          "\\renewcommand{\\subsectionmark}[1]{\\markright{#1}}",
      50          # Colorization for python source code
      51          "\\definecolor{py@keywordcolour}{rgb}{1,0.45882,0}",
      52          "\\definecolor{py@stringcolour}{rgb}{0,0.666666,0}",
      53          "\\definecolor{py@commentcolour}{rgb}{1,0,0}",
      54          "\\definecolor{py@ps1colour}{rgb}{0.60784,0,0}",
      55          "\\definecolor{py@ps2colour}{rgb}{0.60784,0,1}",
      56          "\\definecolor{py@inputcolour}{rgb}{0,0,0}",
      57          "\\definecolor{py@outputcolour}{rgb}{0,0,1}",
      58          "\\definecolor{py@exceptcolour}{rgb}{1,0,0}",
      59          "\\definecolor{py@defnamecolour}{rgb}{1,0.5,0.5}",
      60          "\\definecolor{py@builtincolour}{rgb}{0.58039,0,0.58039}",
      61          "\\definecolor{py@identifiercolour}{rgb}{0,0,0}",
      62          "\\definecolor{py@linenumcolour}{rgb}{0.4,0.4,0.4}",
      63          "\\definecolor{py@inputcolour}{rgb}{0,0,0}",
      64          "% Prompt",
      65          "\\newcommand{\\pysrcprompt}[1]{\\textcolor{py@ps1colour}"
      66              "{\\small\\textbf{#1}}}",
      67          "\\newcommand{\\pysrcmore}[1]{\\textcolor{py@ps2colour}"
      68              "{\\small\\textbf{#1}}}",
      69          "% Source code",
      70          "\\newcommand{\\pysrckeyword}[1]{\\textcolor{py@keywordcolour}"
      71              "{\\small\\textbf{#1}}}",
      72          "\\newcommand{\\pysrcbuiltin}[1]{\\textcolor{py@builtincolour}"
      73              "{\\small\\textbf{#1}}}",
      74          "\\newcommand{\\pysrcstring}[1]{\\textcolor{py@stringcolour}"
      75              "{\\small\\textbf{#1}}}",
      76          "\\newcommand{\\pysrcdefname}[1]{\\textcolor{py@defnamecolour}"
      77              "{\\small\\textbf{#1}}}",
      78          "\\newcommand{\\pysrcother}[1]{\\small\\textbf{#1}}",
      79          "% Comments",
      80          "\\newcommand{\\pysrccomment}[1]{\\textcolor{py@commentcolour}"
      81              "{\\small\\textbf{#1}}}",
      82          "% Output",
      83          "\\newcommand{\\pysrcoutput}[1]{\\textcolor{py@outputcolour}"
      84              "{\\small\\textbf{#1}}}",
      85          "% Exceptions",
      86          "\\newcommand{\\pysrcexcept}[1]{\\textcolor{py@exceptcolour}"
      87              "{\\small\\textbf{#1}}}",
      88          # Size of the function description boxes.
      89          "\\newlength{\\funcindent}",
      90          "\\newlength{\\funcwidth}",
      91          "\\setlength{\\funcindent}{1cm}",
      92          "\\setlength{\\funcwidth}{\\textwidth}",
      93          "\\addtolength{\\funcwidth}{-2\\funcindent}",
      94          # Size of the var description tables.
      95          "\\newlength{\\varindent}",
      96          "\\newlength{\\varnamewidth}",
      97          "\\newlength{\\vardescrwidth}",
      98          "\\newlength{\\varwidth}",
      99          "\\setlength{\\varindent}{1cm}",
     100          "\\setlength{\\varnamewidth}{.3\\textwidth}",
     101          "\\setlength{\\varwidth}{\\textwidth}",
     102          "\\addtolength{\\varwidth}{-4\\tabcolsep}",
     103          "\\addtolength{\\varwidth}{-3\\arrayrulewidth}",
     104          "\\addtolength{\\varwidth}{-2\\varindent}",
     105          "\\setlength{\\vardescrwidth}{\\varwidth}",
     106          "\\addtolength{\\vardescrwidth}{-\\varnamewidth}",
     107          # Define new environment for displaying parameter lists.
     108          textwrap.dedent("""\
     109          \\newenvironment{Ventry}[1]%
     110           {\\begin{list}{}{%
     111             \\renewcommand{\\makelabel}[1]{\\texttt{##1:}\\hfil}%
     112             \\settowidth{\\labelwidth}{\\texttt{#1:}}%
     113             \\setlength{\\leftmargin}{\\labelsep}%
     114             \\addtolength{\\leftmargin}{\\labelwidth}}}%
     115           {\\end{list}}"""),
     116          ]
     117
     118      HRULE = '\\rule{\\textwidth}{0.5\\fboxrule}\n\n'
     119
     120      SECTIONS = ['\\part{%s}', '\\chapter{%s}', '\\section{%s}',
     121                  '\\subsection{%s}', '\\subsubsection{%s}',
     122                  '\\textbf{%s}']
     123
     124      STAR_SECTIONS = ['\\part*{%s}', '\\chapter*{%s}', '\\section*{%s}',
     125                       '\\subsection*{%s}', '\\subsubsection*{%s}',
     126                       '\\textbf{%s}']
     127
     128 -    def __init__(self, docindex, **kwargs):
     129          self.docindex = docindex
     130          # Process keyword arguments
     131          self._show_private = kwargs.get('private', 0)
     132          self._prj_name = kwargs.get('prj_name', None) or 'API Documentation'
     133          self._crossref = kwargs.get('crossref', 1)
     134          self._index = kwargs.get('index', 1)
     135          self._list_classes_separately=kwargs.get('list_classes_separately',0)
     136          self._inheritance = kwargs.get('inheritance', 'listed')
     137          self._exclude = kwargs.get('exclude', 1)
     138          self._top_section = 2
     139          self._index_functions = 1
     140          self._hyperref = 1
     141
     142          #: The Python representation of the encoding.
     143          #: Update L{latex_encodings} in case of mismatch between it and
     144          #: the C{inputenc} LaTeX package.
     145          self._encoding = kwargs.get('encoding', 'utf-8')
     146
     147          self.valdocs = valdocs = sorted(docindex.reachable_valdocs(
     148              imports=False, packages=False, bases=False, submodules=False,
     149              subclasses=False, private=self._show_private))
     150          self._num_files = self.num_files()
     151          # For use with select_variables():
     152          if self._show_private: self._public_filter = None
     153          else: self._public_filter = True
     154
     155          self.class_list = [d for d in valdocs if isinstance(d, ClassDoc)]
     156          """The list of L{ClassDoc}s for the documented classes."""
     157          self.class_set = set(self.class_list)
     158          """The set of L{ClassDoc}s for the documented classes."""
     159
     160 -    def write(self, directory=None):
     161          """
     162          Write the API documentation for the entire project to the
     163          given directory.
     164
     165          @type directory: C{string}
     166          @param directory: The directory to which output should be
     167              written.  If no directory is specified, output will be
     168              written to the current directory.  If the directory does
     169              not exist, it will be created.
     170          @rtype: C{None}
     171          @raise OSError: If C{directory} cannot be created,
     172          @raise OSError: If any file cannot be created or written to.
     173          """
     174          # For progress reporting:
     175          self._files_written = 0.
     176
     177          # Set the default values for ValueDoc formatted representations.
     178          orig_valdoc_defaults = (ValueDoc.SUMMARY_REPR_LINELEN,
     179                                  ValueDoc.REPR_LINELEN,
     180                                  ValueDoc.REPR_MAXLINES)
     181          ValueDoc.SUMMARY_REPR_LINELEN = 60
     182          ValueDoc.REPR_LINELEN = 52
     183          ValueDoc.REPR_MAXLINES = 5
     184
     185          # Create destination directories, if necessary
     186          if not directory: directory = os.curdir
     187          self._mkdir(directory)
     188          self._directory = directory
     189
     190          # Write the top-level file.
     191          self._write(self.write_topfile, directory, 'api.tex')
     192
     193          # Write the module & class files.
     194          for val_doc in self.valdocs:
     195              if isinstance(val_doc, ModuleDoc):
     196                  filename = '%s-module.tex' % val_doc.canonical_name
     197                  self._write(self.write_module, directory, filename, val_doc)
     198              elif (isinstance(val_doc, ClassDoc) and
     199                    self._list_classes_separately):
     200                  filename = '%s-class.tex' % val_doc.canonical_name
     201                  self._write(self.write_class, directory, filename, val_doc)
     202
     203          # Restore defaults that we changed.
     204          (ValueDoc.SUMMARY_REPR_LINELEN, ValueDoc.REPR_LINELEN,
     205           ValueDoc.REPR_MAXLINES) = orig_valdoc_defaults
     206
     207 -    def _write(self, write_func, directory, filename, *args):
     208          # Display our progress.
     209          self._files_written += 1
     210          log.progress(self._files_written/self._num_files, filename)
     211
     212          path = os.path.join(directory, filename)
     213          if self._encoding == 'utf-8':
     214              f = codecs.open(path, 'w', 'utf-8')
     215              write_func(f.write, *args)
     216              f.close()
     217          else:
     218              result = []
     219              write_func(result.append, *args)
     220              s = u''.join(result)
     221              try:
     222                  s = s.encode(self._encoding)
     223              except UnicodeError:
     224                  log.error("Output could not be represented with the "
     225                            "given encoding (%r).  Unencodable characters "
     226                            "will be displayed as '?'.  It is recommended "
     227                            "that you use a different output encoding (utf-8, "
     228                            "if it's supported by latex on your system)."
     229                            % self._encoding)
     230                  s = s.encode(self._encoding, 'replace')
     231              f = open(path, 'w')
     232              f.write(s)
     233              f.close()
     234
     235 -    def num_files(self):
     236          """
     237          @return: The number of files that this C{LatexFormatter} will
     238              generate.
     239          @rtype: C{int}
     240          """
     241          n = 1
     242          for doc in self.valdocs:
     243              if isinstance(doc, ModuleDoc): n += 1
     244              if isinstance(doc, ClassDoc) and self._list_classes_separately:
     245                  n += 1
     246          return n
     247
     248 -    def _mkdir(self, directory):
     249          """
     250          If the given directory does not exist, then attempt to create it.
     251          @rtype: C{None}
     252          """
     253          if not os.path.isdir(directory):
     254              if os.path.exists(directory):
     255                  raise OSError('%r is not a directory' % directory)
     256              os.mkdir(directory)
     257
     258      #////////////////////////////////////////////////////////////
     259      #{ Main Doc File
     260      #////////////////////////////////////////////////////////////
     261
     262 -    def write_topfile(self, out):
     263          self.write_header(out, 'Include File')
     264          self.write_preamble(out)
     265          out('\n\\begin{document}\n\n')
     266          self.write_start_of(out, 'Header')
     267
     268          # Write the title.
     269          self.write_start_of(out, 'Title')
     270          out('\\title{%s}\n' % plaintext_to_latex(self._prj_name, 1))
     271          out('\\author{API Documentation}\n')
     272          out('\\maketitle\n')
     273
     274          # Add a table of contents.
     275          self.write_start_of(out, 'Table of Contents')
     276          out('\\addtolength{\\parskip}{-2ex}\n')
     277          out('\\tableofcontents\n')
     278          out('\\addtolength{\\parskip}{2ex}\n')
     279
     280          # Include documentation files.
     281          self.write_start_of(out, 'Includes')
     282          for val_doc in self.valdocs:
     283              if isinstance(val_doc, ModuleDoc):
     284                  out('\\include{%s-module}\n' % val_doc.canonical_name)
     285
     286          # If we're listing classes separately, put them after all the
     287          # modules.
     288          if self._list_classes_separately:
     289              for val_doc in self.valdocs:
     290                  if isinstance(val_doc, ClassDoc):
     291                      out('\\include{%s-class}\n' % val_doc.canonical_name)
     292
     293          # Add the index, if requested.
     294          if self._index:
     295              self.write_start_of(out, 'Index')
     296              out('\\printindex\n\n')
     297
     298          # Add the footer.
     299          self.write_start_of(out, 'Footer')
     300          out('\\end{document}\n\n')
     301
     302 -    def write_preamble(self, out):
     303          out('\n'.join(self.PREAMBLE))
     304          out('\n')
     305
     306          # Set the encoding.
     307          out('\\usepackage[%s]{inputenc}\n' % self.get_latex_encoding())
     308
     309          # If we're generating hyperrefs, add the appropriate packages.
     310          if self._hyperref:
     311              out('\\definecolor{UrlColor}{rgb}{0,0.08,0.45}\n')
     312              out('\\usepackage[dvips, pagebackref, pdftitle={%s}, '
     313                  'pdfcreator={epydoc %s}, bookmarks=true, '
     314                  'bookmarksopen=false, pdfpagemode=UseOutlines, '
     315                  'colorlinks=true, linkcolor=black, anchorcolor=black, '
     316                  'citecolor=black, filecolor=black, menucolor=black, '
     317                  'pagecolor=black, urlcolor=UrlColor]{hyperref}\n' %
     318                  (self._prj_name or '', epydoc.__version__))
     319
     320          # If we're generating an index, add it to the preamble.
     321          if self._index:
     322              out("\\makeindex\n")
     323
     324          # If restructuredtext was used, then we need to extend
     325          # the prefix to include LatexTranslator.head_prefix.
     326          if 'restructuredtext' in epydoc.markup.MARKUP_LANGUAGES_USED:
     327              from epydoc.markup import restructuredtext
     328              rst_head = restructuredtext.latex_head_prefix()
     329              rst_head = ''.join(rst_head).split('\n')
     330              for line in rst_head[1:]:
     331                  m = re.match(r'\\usepackage(\[.*?\])?{(.*?)}', line)
     332                  if m and m.group(2) in (
     333                      'babel', 'hyperref', 'color', 'alltt', 'parskip',
     334                      'fancyhdr', 'boxedminipage', 'makeidx',
     335                      'multirow', 'longtable', 'tocbind', 'assymb',
     336                      'fullpage', 'inputenc'):
     337                      pass
     338                  else:
     339                      out(line+'\n')
     340
     341
     342      #////////////////////////////////////////////////////////////
     343      #{ Chapters
     344      #////////////////////////////////////////////////////////////
     345
     346 -    def write_module(self, out, doc):
     347          self.write_header(out, doc)
     348          self.write_start_of(out, 'Module Description')
     349
     350          # Add this module to the index.
     351          out('    ' + self.indexterm(doc, 'start'))
     352
     353          # Add a section marker.
     354          out(self.section('%s %s' % (self.doc_kind(doc),
     355                                      doc.canonical_name)))
     356
     357          # Label our current location.
     358          out('    \\label{%s}\n' % self.label(doc))
     359
     360          # Add the module's description.
     361          if doc.descr not in (None, UNKNOWN):
     362              out(self.docstring_to_latex(doc.descr))
     363
     364          # Add version, author, warnings, requirements, notes, etc.
     365          self.write_standard_fields(out, doc)
     366
     367          # If it's a package, list the sub-modules.
     368          if doc.submodules != UNKNOWN and doc.submodules:
     369              self.write_module_list(out, doc)
     370
     371          # Contents.
     372          if self._list_classes_separately:
     373              self.write_class_list(out, doc)
     374          self.write_func_list(out, 'Functions', doc, 'function')
     375          self.write_var_list(out, 'Variables', doc, 'other')
     376
     377          # Class list.
     378          if not self._list_classes_separately:
     379              classes = doc.select_variables(imported=False, value_type='class',
     380                                             public=self._public_filter)
     381              for var_doc in classes:
     382                  self.write_class(out, var_doc.value)
     383
     384          # Mark the end of the module (for the index)
     385          out('    ' + self.indexterm(doc, 'end'))
     386
     387 -    def write_class(self, out, doc):
     388          if self._list_classes_separately:
     389              self.write_header(out, doc)
     390          self.write_start_of(out, 'Class Description')
     391
     392          # Add this class to the index.
     393          out('    ' + self.indexterm(doc, 'start'))
     394
     395          # Add a section marker.
     396          if self._list_classes_separately:
     397              seclevel = 0
     398              out(self.section('%s %s' % (self.doc_kind(doc),
     399                                          doc.canonical_name), seclevel))
     400          else:
     401              seclevel = 1
     402              out(self.section('%s %s' % (self.doc_kind(doc),
     403                                          doc.canonical_name[-1]), seclevel))
     404
     405          # Label our current location.
     406          out('    \\label{%s}\n' % self.label(doc))
     407
     408          # Add our base list.
     409          if doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0:
     410              out(self.base_tree(doc))
     411
     412          # The class's known subclasses
     413          if doc.subclasses not in (UNKNOWN, None) and len(doc.subclasses) > 0:
     414              sc_items = [plaintext_to_latex('%s' % sc.canonical_name)
     415                          for sc in doc.subclasses]
     416              out(self._descrlist(sc_items, 'Known Subclasses', short=1))
     417
     418          # The class's description.
     419          if doc.descr not in (None, UNKNOWN):
     420              out(self.docstring_to_latex(doc.descr))
     421
     422          # Version, author, warnings, requirements, notes, etc.
     423          self.write_standard_fields(out, doc)
     424
     425          # Contents.
     426          self.write_func_list(out, 'Methods', doc, 'method',
     427                               seclevel+1)
     428          self.write_var_list(out, 'Properties', doc,
     429                              'property', seclevel+1)
     430          self.write_var_list(out, 'Class Variables', doc,
     431                              'classvariable', seclevel+1)
     432          self.write_var_list(out, 'Instance Variables', doc,
     433                              'instancevariable', seclevel+1)
     434
     435          # Mark the end of the class (for the index)
     436          out('    ' + self.indexterm(doc, 'end'))
     437
     438      #////////////////////////////////////////////////////////////
     439      #{ Module hierarchy trees
     440      #////////////////////////////////////////////////////////////
     441
     442 -    def write_module_tree(self, out):
     443          modules = [doc for doc in self.valdocs
     444                     if isinstance(doc, ModuleDoc)]
     445          if not modules: return
     446
     447          # Write entries for all top-level modules/packages.
     448          out('\\begin{itemize}\n')
     449          out('\\setlength{\\parskip}{0ex}\n')
     450          for doc in modules:
     451              if (doc.package in (None, UNKNOWN) or
     452                  doc.package not in self.valdocs):
     453                  self.write_module_tree_item(out, doc)
     454          return s +'\\end{itemize}\n'
     455
     456 -    def write_module_list(self, out, doc):
     457          if len(doc.submodules) == 0: return
     458          self.write_start_of(out, 'Modules')
     459
     460          out(self.section('Modules', 1))
     461          out('\\begin{itemize}\n')
     462          out('\\setlength{\\parskip}{0ex}\n')
     463
     464          for group_name in doc.group_names():
     465              if not doc.submodule_groups[group_name]: continue
     466              if group_name:
     467                  out('  \\item \\textbf{%s}\n' % group_name)
     468                  out('  \\begin{itemize}\n')
     469              for submodule in doc.submodule_groups[group_name]:
     470                  self.write_module_tree_item(out, submodule)
     471              if group_name:
     472                  out('  \end{itemize}\n')
     473
     474          out('\\end{itemize}\n\n')
     475
     476 -    def write_module_tree_item(self, out, doc, depth=0):
     477          """
     478          Helper function for L{write_module_tree} and L{write_module_list}.
     479
     480          @rtype: C{string}
     481          """
     482          out(' '*depth + '\\item \\textbf{')
     483          out(plaintext_to_latex(doc.canonical_name[-1]) +'}')
     484          if doc.summary not in (None, UNKNOWN):
     485              out(': %s\n' % self.docstring_to_latex(doc.summary))
     486          if self._crossref:
     487              out('\n  \\textit{(Section \\ref{%s}' % self.label(doc))
     488              out(', p.~\\pageref{%s})}\n\n' % self.label(doc))
     489          if doc.submodules != UNKNOWN and doc.submodules:
     490              out(' '*depth + '  \\begin{itemize}\n')
     491              out(' '*depth + '\\setlength{\\parskip}{0ex}\n')
     492              for submodule in doc.submodules:
     493                  self.write_module_tree_item(out, submodule, depth+4)
     494              out(' '*depth + '  \\end{itemize}\n')
     495
     496      #////////////////////////////////////////////////////////////
     497      #{ Base class trees
     498      #////////////////////////////////////////////////////////////
     499
     500 -    def base_tree(self, doc, width=None, linespec=None):
     501          if width is None:
     502              width = self._find_tree_width(doc)+2
     503              linespec = []
     504              s = ('&'*(width-4)+'\\multicolumn{2}{l}{\\textbf{%s}}\n' %
     505                     plaintext_to_latex('%s'%self._base_name(doc)))
     506              s += '\\end{tabular}\n\n'
     507              top = 1
     508          else:
     509              s = self._base_tree_line(doc, width, linespec)
     510              top = 0
     511
     512          if isinstance(doc, ClassDoc):
     513              for i in range(len(doc.bases)-1, -1, -1):
     514                  base = doc.bases[i]
     515                  spec = (i > 0)
     516                  s = self.base_tree(base, width, [spec]+linespec) + s
     517
     518          if top:
     519              s = '\\begin{tabular}{%s}\n' % (width*'c') + s
     520
     521          return s
     522
     523 -    def _base_name(self, doc):
     524          if doc.canonical_name is None:
     525              if doc.parse_repr is not None:
     526                  return doc.parse_repr
     527              else:
     528                  return '??'
     529          else:
     530              return '%s' % doc.canonical_name
     531
     532 -    def _find_tree_width(self, doc):
     533          if not isinstance(doc, ClassDoc): return 2
     534          width = 2
     535          for base in doc.bases:
     536              width = max(width, self._find_tree_width(base)+2)
     537          return width
     538
     539 -    def _base_tree_line(self, doc, width, linespec):
     540          base_name = plaintext_to_latex(self._base_name(doc))
     541
     542          # linespec is a list of booleans.
     543          s = '%% Line for %s, linespec=%s\n' % (base_name, linespec)
     544
     545          labelwidth = width-2*len(linespec)-2
     546
     547          # The base class name.
     548          s += ('\\multicolumn{%s}{r}{' % labelwidth)
     549          s += '\\settowidth{\\BCL}{%s}' % base_name
     550          s += '\\multirow{2}{\\BCL}{%s}}\n' % base_name
     551
     552          # The vertical bars for other base classes (top half)
     553          for vbar in linespec:
     554              if vbar: s += '&&\\multicolumn{1}{|c}{}\n'
     555              else: s += '&&\n'
     556
     557          # The horizontal line.
     558          s += '  \\\\\\cline{%s-%s}\n' % (labelwidth+1, labelwidth+1)
     559
     560          # The vertical bar for this base class.
     561          s += '  ' + '&'*labelwidth
     562          s += '\\multicolumn{1}{c|}{}\n'
     563
     564          # The vertical bars for other base classes (bottom half)
     565          for vbar in linespec:
     566              if vbar: s += '&\\multicolumn{1}{|c}{}&\n'
     567              else: s += '&&\n'
     568          s += '  \\\\\n'
     569
     570          return s
     571
     572      #////////////////////////////////////////////////////////////
     573      #{ Class List
     574      #////////////////////////////////////////////////////////////
     575
     576 -    def write_class_list(self, out, doc):
     577          groups = [(plaintext_to_latex(group_name),
     578                     doc.select_variables(group=group_name, imported=False,
     579                                          value_type='class',
     580                                          public=self._public_filter))
     581                    for group_name in doc.group_names()]
     582
     583          # Discard any empty groups; and return if they're all empty.
     584          groups = [(g,vars) for (g,vars) in groups if vars]
     585          if not groups: return
     586
     587          # Write a header.
     588          self.write_start_of(out, 'Classes')
     589          out(self.section('Classes', 1))
     590          out('\\begin{itemize}')
     591          out('  \\setlength{\\parskip}{0ex}\n')
     592
     593          for name, var_docs in groups:
     594              if name:
     595                  out('  \\item \\textbf{%s}\n' % name)
     596                  out('  \\begin{itemize}\n')
     597              # Add the lines for each class
     598              for var_doc in var_docs:
     599                  self.write_class_list_line(out, var_doc)
     600              if name:
     601                  out('  \\end{itemize}\n')
     602
     603          out('\\end{itemize}\n')
     604
     605 -    def write_class_list_line(self, out, var_doc):
     606          if var_doc.value in (None, UNKNOWN): return # shouldn't happen
     607          doc = var_doc.value
     608          out('  ' + '\\item \\textbf{')
     609          out(plaintext_to_latex(var_doc.name) + '}')
     610          if doc.summary not in (None, UNKNOWN):
     611              out(': %s\n' % self.docstring_to_latex(doc.summary))
     612          if self._crossref:
     613              out(('\n  \\textit{(Section \\ref{%s}' % self.label(doc)))
     614              out((', p.~\\pageref{%s})}\n\n' % self.label(doc)))
     615
     616      #////////////////////////////////////////////////////////////
     617      #{ Function List
     618      #////////////////////////////////////////////////////////////
     619      _FUNC_GROUP_HEADER = '\n\\large{\\textbf{\\textit{%s}}}\n\n'
     620
     621 -    def write_func_list(self, out, heading, doc, value_type, seclevel=1):
     622          # Divide all public variables of the given type into groups.
     623          groups = [(plaintext_to_latex(group_name),
     624                     doc.select_variables(group=group_name, imported=False,
     625                                          value_type=value_type,
     626                                          public=self._public_filter))
     627                    for group_name in doc.group_names()]
     628
     629          # Discard any empty groups; and return if they're all empty.
     630          groups = [(g,vars) for (g,vars) in groups if vars]
     631          if not groups: return
     632
     633          # Write a header.
     634          self.write_start_of(out, heading)
     635          out('  '+self.section(heading, seclevel))
     636
     637          # Write a section for each group.
     638          grouped_inh_vars = {}
     639          for name, var_docs in groups:
     640              self.write_func_group(out, doc, name, var_docs, grouped_inh_vars)
     641
     642          # Write a section for each inheritance pseudo-group (used if
     643          # inheritance=='grouped')
     644          if grouped_inh_vars:
     645              for base in doc.mro():
     646                  if base in grouped_inh_vars:
     647                      hdr = ('Inherited from %s' %
     648                             plaintext_to_latex('%s' % base.canonical_name))
     649                      if self._crossref and base in self.class_set:
     650                          hdr += ('\\textit{(Section \\ref{%s})}' %
     651                                  self.label(base))
     652                      out(self._FUNC_GROUP_HEADER % (hdr))
     653                      for var_doc in grouped_inh_vars[base]:
     654                          self.write_func_list_box(out, var_doc)
     655
     656 -    def write_func_group(self, out, doc, name, var_docs, grouped_inh_vars):
     657          # Split up the var_docs list, according to the way each var
     658          # should be displayed:
     659          #   - listed_inh_vars -- for listed inherited variables.
     660          #   - grouped_inh_vars -- for grouped inherited variables.
     661          #   - normal_vars -- for all other variables.
     662          listed_inh_vars = {}
     663          normal_vars = []
     664          for var_doc in var_docs:
     665              if var_doc.container != doc:
     666                  base = var_doc.container
     667                  if (base not in self.class_set or
     668                      self._inheritance == 'listed'):
     669                      listed_inh_vars.setdefault(base,[]).append(var_doc)
     670                  elif self._inheritance == 'grouped':
     671                      grouped_inh_vars.setdefault(base,[]).append(var_doc)
     672                  else:
     673                      normal_vars.append(var_doc)
     674              else:
     675                  normal_vars.append(var_doc)
     676
     677          # Write a header for the group.
     678          if name:
     679              out(self._FUNC_GROUP_HEADER % name)
     680          # Write an entry for each normal var:
     681          for var_doc in normal_vars:
     682              self.write_func_list_box(out, var_doc)
     683          # Write a subsection for inherited vars:
     684          if listed_inh_vars:
     685              self.write_func_inheritance_list(out, doc, listed_inh_vars)
     686
     687 -    def write_func_inheritance_list(self, out, doc, listed_inh_vars):
     688          for base in doc.mro():
     689              if base not in listed_inh_vars: continue
     690              #if str(base.canonical_name) == 'object': continue
     691              var_docs = listed_inh_vars[base]
     692              if self._public_filter:
     693                  var_docs = [v for v in var_docs if v.is_public]
     694              if var_docs:
     695                  hdr = ('Inherited from %s' %
     696                         plaintext_to_latex('%s' % base.canonical_name))
     697                  if self._crossref and base in self.class_set:
     698                      hdr += ('\\textit{(Section \\ref{%s})}' %
     699                              self.label(base))
     700                  out(self._FUNC_GROUP_HEADER % hdr)
     701                  out('\\begin{quote}\n')
     702                  out('%s\n' % ', '.join(
     703                      ['%s()' % plaintext_to_latex(var_doc.name)
     704                       for var_doc in var_docs]))
     705                  out('\\end{quote}\n')
     706
     707 -    def write_func_list_box(self, out, var_doc):
     708          func_doc = var_doc.value
     709          is_inherited = (var_doc.overrides not in (None, UNKNOWN))
     710
     711          # nb: this gives the containing section, not a reference
     712          # directly to the function.
     713          if not is_inherited:
     714              out('    \\label{%s}\n' % self.label(func_doc))
     715              out('    %s\n' % self.indexterm(func_doc))
     716
     717          # Start box for this function.
     718          out('    \\vspace{0.5ex}\n\n')
     719          out('\\hspace{.8\\funcindent}')
     720          out('\\begin{boxedminipage}{\\funcwidth}\n\n')
     721
     722          # Function signature.
     723          out('    %s\n\n' % self.function_signature(var_doc))
     724
     725          if (func_doc.docstring not in (None, UNKNOWN) and
     726              func_doc.docstring.strip() != ''):
     727              out('    \\vspace{-1.5ex}\n\n')
     728              out('    \\rule{\\textwidth}{0.5\\fboxrule}\n')
     729
     730          # Description
     731          out("\\setlength{\\parskip}{2ex}\n")
     732          if func_doc.descr not in (None, UNKNOWN):
     733              out(self.docstring_to_latex(func_doc.descr, 4))
     734
     735          # Parameters
     736          out("\\setlength{\\parskip}{1ex}\n")
     737          if func_doc.arg_descrs or func_doc.arg_types:
     738              # Find the longest name.
     739              longest = max([0]+[len(n) for n in func_doc.arg_types])
     740              for names, descrs in func_doc.arg_descrs:
     741                  longest = max([longest]+[len(n) for n in names])
     742              # Table header.
     743              out(' '*6+'\\textbf{Parameters}\n')
     744              out('      \\vspace{-1ex}\n\n')
     745              out(' '*6+'\\begin{quote}\n')
     746              out('        \\begin{Ventry}{%s}\n\n' % (longest*'x'))
     747              # Add params that have @type but not @param info:
     748              arg_descrs = list(func_doc.arg_descrs)
     749              args = set()
     750              for arg_names, arg_descr in arg_descrs:
     751                  args.update(arg_names)
     752              for arg in var_doc.value.arg_types:
     753                  if arg not in args:
     754                      arg_descrs.append( ([arg],None) )
     755              # Display params
     756              for (arg_names, arg_descr) in arg_descrs:
     757                  arg_name = plaintext_to_latex(', '.join(arg_names))
     758                  out('%s\\item[%s]\n\n' % (' '*10, arg_name))
     759                  if arg_descr:
     760                      out(self.docstring_to_latex(arg_descr, 10))
     761                  for arg_name in arg_names:
     762                      arg_typ = func_doc.arg_types.get(arg_name)
     763                      if arg_typ is not None:
     764                          if len(arg_names) == 1:
     765                              lhs = 'type'
     766                          else:
     767                              lhs = 'type of %s' % arg_name
     768                          rhs = self.docstring_to_latex(arg_typ).strip()
     769                          out('%s{\\it (%s=%s)}\n\n' % (' '*12, lhs, rhs))
     770              out('        \\end{Ventry}\n\n')
     771              out(' '*6+'\\end{quote}\n\n')
     772
     773          # Returns
     774          rdescr = func_doc.return_descr
     775          rtype = func_doc.return_type
     776          if rdescr not in (None, UNKNOWN) or rtype not in (None, UNKNOWN):
     777              out(' '*6+'\\textbf{Return Value}\n')
     778              out('    \\vspace{-1ex}\n\n')
     779              out(' '*6+'\\begin{quote}\n')
     780              if rdescr not in (None, UNKNOWN):
     781                  out(self.docstring_to_latex(rdescr, 6))
     782                  if rtype not in (None, UNKNOWN):
     783                      out(' '*6+'{\\it (type=%s)}\n\n' %
     784                          self.docstring_to_latex(rtype, 6).strip())
     785              elif rtype not in (None, UNKNOWN):
     786                  out(self.docstring_to_latex(rtype, 6))
     787              out(' '*6+'\\end{quote}\n\n')
     788
     789          # Raises
     790          if func_doc.exception_descrs not in (None, UNKNOWN, [], ()):
     791              out(' '*6+'\\textbf{Raises}\n')
     792              out('    \\vspace{-1ex}\n\n')
     793              out(' '*6+'\\begin{quote}\n')
     794              out('        \\begin{description}\n\n')
     795              for name, descr in func_doc.exception_descrs:
     796                  out(' '*10+'\\item[\\texttt{%s}]\n\n' %
     797                      plaintext_to_latex('%s' % name))
     798                  out(self.docstring_to_latex(descr, 10))
     799              out('        \\end{description}\n\n')
     800              out(' '*6+'\\end{quote}\n\n')
     801
     802          ## Overrides
     803          if var_doc.overrides not in (None, UNKNOWN):
     804              out('      Overrides: ' +
     805                  plaintext_to_latex('%s'%var_doc.overrides.canonical_name))
     806              if (func_doc.docstring in (None, UNKNOWN) and
     807                  var_doc.overrides.value.docstring not in (None, UNKNOWN)):
     808                  out(' \textit{(inherited documentation)}')
     809              out('\n\n')
     810
     811          # Add version, author, warnings, requirements, notes, etc.
     812          self.write_standard_fields(out, func_doc)
     813
     814          out('    \\end{boxedminipage}\n\n')
     815
     816 -    def function_signature(self, var_doc):
     817          func_doc = var_doc.value
     818          func_name = var_doc.name
     819
     820          # This should never happen, but just in case:
     821          if func_doc in (None, UNKNOWN):
     822              return ('\\raggedright \\textbf{%s}(...)' %
     823                      plaintext_to_latex(func_name))
     824
     825          if func_doc.posargs == UNKNOWN:
     826              args = ['...']
     827          else:
     828              args = [self.func_arg(name, default) for (name, default)
     829                      in zip(func_doc.posargs, func_doc.posarg_defaults)]
     830          if func_doc.vararg:
     831              if func_doc.vararg == '...':
     832                  args.append('\\textit{...}')
     833              else:
     834                  args.append('*\\textit{%s}' %
     835                              plaintext_to_latex(func_doc.vararg))
     836          if func_doc.kwarg:
     837              args.append('**\\textit{%s}' %
     838                          plaintext_to_latex(func_doc.kwarg))
     839          return ('\\raggedright \\textbf{%s}(%s)' %
     840                  (plaintext_to_latex(func_name), ', '.join(args)))
     841
     842 -    def func_arg(self, name, default):
     843          s = '\\textit{%s}' % plaintext_to_latex(self._arg_name(name))
     844          if default is not None:
     845              s += '={\\tt %s}' % default.summary_pyval_repr().to_latex(None)
     846          return s
     847
     848 -    def _arg_name(self, arg):
     849          if isinstance(arg, basestring):
     850              return arg
     851          elif len(arg) == 1:
     852              return '(%s,)' % self._arg_name(arg[0])
     853          else:
     854              return '(%s)' % (', '.join([self._arg_name(a) for a in arg]))
     855
     856      #////////////////////////////////////////////////////////////
     857      #{ Variable List
     858      #////////////////////////////////////////////////////////////
     859      _VAR_GROUP_HEADER = '\\multicolumn{2}{|l|}{\\textit{%s}}\\\\\n'
     860
     861      # Also used for the property list.
     862 -    def write_var_list(self, out, heading, doc, value_type, seclevel=1):
     863          groups = [(plaintext_to_latex(group_name),
     864                     doc.select_variables(group=group_name, imported=False,
     865                                          value_type=value_type,
     866                                          public=self._public_filter))
     867                    for group_name in doc.group_names()]
     868
     869          # Discard any empty groups; and return if they're all empty.
     870          groups = [(g,vars) for (g,vars) in groups if vars]
     871          if not groups: return
     872
     873          # Write a header.
     874          self.write_start_of(out, heading)
     875          out('  '+self.section(heading, seclevel))
     876
     877          # [xx] without this, there's a huge gap before the table -- why??
     878          out('    \\vspace{-1cm}\n')
     879
     880          out('\\hspace{\\varindent}')
     881          out('\\begin{longtable}')
     882          out('{|p{\\varnamewidth}|')
     883          out('p{\\vardescrwidth}|l}\n')
     884          out('\\cline{1-2}\n')
     885
     886          # Set up the headers & footer (this makes the table span
     887          # multiple pages in a happy way).
     888          out('\\cline{1-2} ')
     889          out('\\centering \\textbf{Name} & ')
     890          out('\\centering \\textbf{Description}& \\\\\n')
     891          out('\\cline{1-2}\n')
     892          out('\\endhead')
     893          out('\\cline{1-2}')
     894          out('\\multicolumn{3}{r}{\\small\\textit{')
     895          out('continued on next page}}\\\\')
     896          out('\\endfoot')
     897          out('\\cline{1-2}\n')
     898          out('\\endlastfoot')
     899
     900          # Write a section for each group.
     901          grouped_inh_vars = {}
     902          for name, var_docs in groups:
     903              self.write_var_group(out, doc, name, var_docs, grouped_inh_vars)
     904
     905          # Write a section for each inheritance pseudo-group (used if
     906          # inheritance=='grouped')
     907          if grouped_inh_vars:
     908              for base in doc.mro():
     909                  if base in grouped_inh_vars:
     910                      hdr = ('Inherited from %s' %
     911                             plaintext_to_latex('%s' % base.canonical_name))
     912                      if self._crossref and base in self.class_set:
     913                          hdr += (' \\textit{(Section \\ref{%s})}' %
     914                                  self.label(base))
     915                      out(self._VAR_GROUP_HEADER % (hdr))
     916                      out('\\cline{1-2}\n')
     917                      for var_doc in grouped_inh_vars[base]:
     918                          if isinstance(var_doc.value3, PropertyDoc):
     919                              self.write_property_list_line(out, var_doc)
     920                          else:
     921                              self.write_var_list_line(out, var_doc)
     922
     923          out('\\end{longtable}\n\n')
     924
     925 -    def write_var_group(self, out, doc, name, var_docs, grouped_inh_vars):
     926          # Split up the var_docs list, according to the way each var
     927          # should be displayed:
     928          #   - listed_inh_vars -- for listed inherited variables.
     929          #   - grouped_inh_vars -- for grouped inherited variables.
     930          #   - normal_vars -- for all other variables.
     931          listed_inh_vars = {}
     932          normal_vars = []
     933          for var_doc in var_docs:
     934              if var_doc.container != doc:
     935                  base = var_doc.container
     936                  if (base not in self.class_set or
     937                      self._inheritance == 'listed'):
     938                      listed_inh_vars.setdefault(base,[]).append(var_doc)
     939                  elif self._inheritance == 'grouped':
     940                      grouped_inh_vars.setdefault(base,[]).append(var_doc)
     941                  else:
     942                      normal_vars.append(var_doc)
     943              else:
     944                  normal_vars.append(var_doc)
     945
     946          # Write a header for the group.
     947          if name:
     948              out(self._VAR_GROUP_HEADER % name)
     949              out('\\cline{1-2}\n')
     950          # Write an entry for each normal var:
     951          for var_doc in normal_vars:
     952              if isinstance(var_doc.value, PropertyDoc):
     953                  self.write_property_list_line(out, var_doc)
     954              else:
     955                  self.write_var_list_line(out, var_doc)
     956          # Write a subsection for inherited vars:
     957          if listed_inh_vars:
     958              self.write_var_inheritance_list(out, doc, listed_inh_vars)
     959
     960 -    def write_var_inheritance_list(self, out, doc, listed_inh_vars):
     961          for base in doc.mro():
     962              if base not in listed_inh_vars: continue
     963              #if str(base.canonical_name) == 'object': continue
     964              var_docs = listed_inh_vars[base]
     965              if self._public_filter:
     966                  var_docs = [v for v in var_docs if v.is_public]
     967              if var_docs:
     968                  hdr = ('Inherited from %s' %
     969                         plaintext_to_latex('%s' % base.canonical_name))
     970                  if self._crossref and base in self.class_set:
     971                      hdr += (' \\textit{(Section \\ref{%s})}' %
     972                              self.label(base))
     973                  out(self._VAR_GROUP_HEADER % hdr)
     974                  out('\\multicolumn{2}{|p{\\varwidth}|}{'
     975                      '\\raggedright %s}\\\\\n' %
     976                      ', '.join(['%s' % plaintext_to_latex(var_doc.name)
     977                                 for var_doc in var_docs]))
     978                  out('\\cline{1-2}\n')
     979
     980
     981 -    def write_var_list_line(self, out, var_doc):
     982          out('\\raggedright ')
     983          out(plaintext_to_latex(var_doc.name, nbsp=True, breakany=True))
     984          out(' & ')
     985          has_descr = var_doc.descr not in (None, UNKNOWN)
     986          has_type = var_doc.type_descr not in (None, UNKNOWN)
     987          has_value = var_doc.value is not UNKNOWN
     988          if has_type or has_value:
     989              out('\\raggedright ')
     990          if has_descr:
     991              out(self.docstring_to_latex(var_doc.descr, 10).strip())
     992              if has_type or has_value: out('\n\n')
     993          if has_value:
     994              out('\\textbf{Value:} \n{\\tt %s}' %
     995                  var_doc.value.summary_pyval_repr().to_latex(None))
     996          if has_type:
     997              ptype = self.docstring_to_latex(var_doc.type_descr, 12).strip()
     998              out('%s{\\it (type=%s)}' % (' '*12, ptype))
     999          out('&\\\\\n')
    1000          out('\\cline{1-2}\n')
    1001
    1002 -    def write_property_list_line(self, out, var_doc):
    1003          prop_doc = var_doc.value
    1004          out('\\raggedright ')
    1005          out(plaintext_to_latex(var_doc.name, nbsp=True, breakany=True))
    1006          out(' & ')
    1007          has_descr = prop_doc.descr not in (None, UNKNOWN)
    1008          has_type = prop_doc.type_descr not in (None, UNKNOWN)
    1009          if has_descr or has_type:
    1010              out('\\raggedright ')
    1011          if has_descr:
    1012              out(self.docstring_to_latex(prop_doc.descr, 10).strip())
    1013              if has_type: out('\n\n')
    1014          if has_type:
    1015              ptype = self.docstring_to_latex(prop_doc.type_descr, 12).strip()
    1016              out('%s{\\it (type=%s)}' % (' '*12, ptype))
    1017          # [xx] List the fget/fset/fdel functions?
    1018          out('&\\\\\n')
    1019          out('\\cline{1-2}\n')
    1020
    1021      #////////////////////////////////////////////////////////////
    1022      #{ Standard Fields
    1023      #////////////////////////////////////////////////////////////
    1024
    1025      # Copied from HTMLWriter:
    1026 -    def write_standard_fields(self, out, doc):
    1027          fields = []
    1028          field_values = {}
    1029
    1030          #if _sort_fields: fields = STANDARD_FIELD_NAMES [XX]
    1031
    1032          for (field, arg, descr) in doc.metadata:
    1033              if field not in field_values:
    1034                  fields.append(field)
    1035              if field.takes_arg:
    1036                  subfields = field_values.setdefault(field,{})
    1037                  subfields.setdefault(arg,[]).append(descr)
    1038              else:
    1039                  field_values.setdefault(field,[]).append(descr)
    1040
    1041          for field in fields:
    1042              if field.takes_arg:
    1043                  for arg, descrs in field_values[field].items():
    1044                      self.write_standard_field(out, doc, field, descrs, arg)
    1045
    1046              else:
    1047                  self.write_standard_field(out, doc, field, field_values[field])
    1048
    1049 -    def write_standard_field(self, out, doc, field, descrs, arg=''):
    1050          singular = field.singular
    1051          plural = field.plural
    1052          if arg:
    1053              singular += ' (%s)' % arg
    1054              plural += ' (%s)' % arg
    1055          out(self._descrlist([self.docstring_to_latex(d) for d in descrs],
    1056                              field.singular, field.plural, field.short))
    1057
    1058 -    def _descrlist(self, items, singular, plural=None, short=0):
    1059          if plural is None: plural = singular
    1060          if len(items) == 0: return ''
    1061          if len(items) == 1 and singular is not None:
    1062              return '\\textbf{%s:} %s\n\n' % (singular, items[0])
    1063          if short:
    1064              s = '\\textbf{%s:}\n' % plural
    1065              items = [item.strip() for item in items]
    1066              return s + ',\n    '.join(items) + '\n\n'
    1067          else:
    1068              s = '\\textbf{%s:}\n' % plural
    1069              s += '\\begin{quote}\n'
    1070              s += '  \\begin{itemize}\n\n  \item\n'
    1071              s += '    \\setlength{\\parskip}{0.6ex}\n'
    1072              s += '\n\n  \item '.join(items)
    1073              return s + '\n\n\\end{itemize}\n\n\\end{quote}\n\n'
    1074
    1075
    1076      #////////////////////////////////////////////////////////////
    1077      #{ Docstring -> LaTeX Conversion
    1078      #////////////////////////////////////////////////////////////
    1079
    1080      # We only need one linker, since we don't use context:
    1081 -    class _LatexDocstringLinker(markup.DocstringLinker):
    1082 -        def translate_indexterm(self, indexterm):
    1083              indexstr = re.sub(r'["!|@]', r'"\1', indexterm.to_latex(self))
    1084              return ('\\index{%s}\\textit{%s}' % (indexstr, indexstr))
    1085 -        def translate_identifier_xref(self, identifier, label=None):
    1086              if label is None: label = markup.plaintext_to_latex(identifier)
    1087              return '\\texttt{%s}' % label
    1088      _docstring_linker = _LatexDocstringLinker()
    1089
    1090 -    def docstring_to_latex(self, docstring, indent=0, breakany=0):
    1091          if docstring is None: return ''
    1092          return docstring.to_latex(self._docstring_linker, indent=indent,
    1093                                    hyperref=self._hyperref)
    1094
    1095      #////////////////////////////////////////////////////////////
    1096      #{ Helpers
    1097      #////////////////////////////////////////////////////////////
    1098
    1099 -    def write_header(self, out, where):
    1100          out('%\n% API Documentation')
    1101          if self._prj_name: out(' for %s' % self._prj_name)
    1102          if isinstance(where, APIDoc):
    1103              out('\n%% %s %s' % (self.doc_kind(where), where.canonical_name))
    1104          else:
    1105              out('\n%% %s' % where)
    1106          out('\n%%\n%% Generated by epydoc %s\n' % epydoc.__version__)
    1107          out('%% [%s]\n%%\n' % time.asctime(time.localtime(time.time())))
    1108
    1109 -    def write_start_of(self, out, section_name):
    1110          out('\n' + 75*'%' + '\n')
    1111          out('%%' + ((71-len(section_name))/2)*' ')
    1112          out(section_name)
    1113          out(((72-len(section_name))/2)*' ' + '%%\n')
    1114          out(75*'%' + '\n\n')
    1115
    1116 -    def section(self, title, depth=0):
    1117          sec = self.SECTIONS[depth+self._top_section]
    1118          return (('%s\n\n' % sec) % plaintext_to_latex(title))
    1119
    1120 -    def sectionstar(self, title, depth):
    1121          sec = self.STARSECTIONS[depth+self._top_section]
    1122          return (('%s\n\n' % sec) % plaintext_to_latex(title))
    1123
    1124 -    def doc_kind(self, doc):
    1125          if isinstance(doc, ModuleDoc) and doc.is_package == True:
    1126              return 'Package'
    1127          elif (isinstance(doc, ModuleDoc) and
    1128                doc.canonical_name[0].startswith('script')):
    1129              return 'Script'
    1130          elif isinstance(doc, ModuleDoc):
    1131              return 'Module'
    1132          elif isinstance(doc, ClassDoc):
    1133              return 'Class'
    1134          elif isinstance(doc, ClassMethodDoc):
    1135              return 'Class Method'
    1136          elif isinstance(doc, StaticMethodDoc):
    1137              return 'Static Method'
    1138          elif isinstance(doc, RoutineDoc):
    1139              if isinstance(self.docindex.container(doc), ClassDoc):
    1140                  return 'Method'
    1141              else:
    1142                  return 'Function'
    1143          else:
    1144              return 'Variable'
    1145
    1146 -    def indexterm(self, doc, pos='only'):
    1147          """Mark a term or section for inclusion in the index."""
    1148          if not self._index: return ''
    1149          if isinstance(doc, RoutineDoc) and not self._index_functions:
    1150              return ''
    1151
    1152          pieces = []
    1153          while doc is not None:
    1154              if doc.canonical_name == UNKNOWN:
    1155                  return '' # Give up.
    1156              pieces.append('%s \\textit{(%s)}' %
    1157                            (plaintext_to_latex('%s'%doc.canonical_name),
    1158                             self.doc_kind(doc).lower()))
    1159              doc = self.docindex.container(doc)
    1160              if doc == UNKNOWN:
    1161                  return '' # Give up.
    1162
    1163          pieces.reverse()
    1164          if pos == 'only':
    1165              return '\\index{%s}\n' % '!'.join(pieces)
    1166          elif pos == 'start':
    1167              return '\\index{%s|(}\n' % '!'.join(pieces)
    1168          elif pos == 'end':
    1169              return '\\index{%s|)}\n' % '!'.join(pieces)
    1170          else:
    1171              raise AssertionError('Bad index position %s' % pos)
    1172
    1173 -    def label(self, doc):
    1174          return ':'.join(doc.canonical_name)
    1175
    1176      #: Map the Python encoding representation into mismatching LaTeX ones.
    1177      latex_encodings = {
    1178          'utf-8': 'utf8',
    1179      }
    1180
    1181 -    def get_latex_encoding(self):
    1182          """
    1183          @return: The LaTeX representation of the selected encoding.
    1184          @rtype: C{str}
    1185          """
    1186          enc = self._encoding.lower()
    1187          return self.latex_encodings.get(enc, enc)
    1188