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