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