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