1   
   2   
   3   
   4   
   5   
   6   
   7   
   8   
   9  """ 
  10  The HTML output generator for epydoc.  The main interface provided by 
  11  this module is the L{HTMLWriter} class. 
  12  """ 
  13  __docformat__ = 'epytext en' 
  14   
  15  import re, os, sys, codecs, sre_constants, pprint 
  16  import urllib 
  17  from epydoc.apidoc import * 
  18  import epydoc.docstringparser 
  19  import time, epydoc, epydoc.markup 
  20  from epydoc.docwriter.html_colorize import colorize_re 
  21  from epydoc.docwriter.html_colorize import PythonSourceColorizer 
  22  from epydoc.docwriter import html_colorize 
  23  from epydoc.docwriter.html_css import STYLESHEETS 
  24  from epydoc.docwriter.html_help import HTML_HELP 
  25  from epydoc.docwriter.dotgraph import * 
  26  from epydoc import log 
  27  from epydoc.util import plaintext_to_html, is_src_filename 
  28  from epydoc.compat import *  
  29   
  30   
  31   
  32   
  33   
  34   
  35   
  38      """ 
  39      Given a template string containing inline python source code, 
  40      return a python function that will fill in the template, and 
  41      output the result.  The signature for this function is taken from 
  42      the first line of C{docstring}.  Output is generated by making 
  43      repeated calls to the output function with the given name (which 
  44      is typically one of the function's parameters). 
  45   
  46      The templating language used by this function passes through all 
  47      text as-is, with three exceptions: 
  48   
  49        - If every line in the template string is indented by at least 
  50          M{x} spaces, then the first M{x} spaces are stripped from each 
  51          line. 
  52   
  53        - Any line that begins with '>>>' (with no indentation) 
  54          should contain python code, and will be inserted as-is into 
  55          the template-filling function.  If the line begins a control 
  56          block (such as 'if' or 'for'), then the control block will 
  57          be closed by the first '>>>'-marked line whose indentation is 
  58          less than or equal to the line's own indentation (including 
  59          lines that only contain comments.) 
  60   
  61        - In any other line, any expression between two '$' signs will 
  62          be evaluated and inserted into the line (using C{str()} to 
  63          convert the result to a string). 
  64   
  65      Here is a simple example: 
  66   
  67          >>> TEMPLATE = ''' 
  68          ... <book> 
  69          ...   <title>$book.title$</title> 
  70          ...   <pages>$book.count_pages()$</pages> 
  71          ... >>> for chapter in book.chapters: 
  72          ...     <chaptername>$chapter.name$</chaptername> 
  73          ... >>> #endfor 
  74          ... </book> 
  75          >>> write_book = compile_template('write_book(out, book)', TEMPLATE) 
  76   
  77      @newfield acknowledgements: Acknowledgements 
  78      @acknowledgements: The syntax used by C{compile_template} is 
  79      loosely based on Cheetah. 
  80      """ 
  81       
  82      signature = docstring.lstrip().split('\n',1)[0].strip() 
  83      func_name = signature.split('(',1)[0].strip() 
  84   
  85       
  86      INLINE = re.compile(r'\$([^\$]+)\$') 
  87       
  88      COMMAND = re.compile(r'(^>>>.*)\n?', re.MULTILINE) 
  89   
  90       
  91      template_string = strip_indent(template_string) 
  92   
  93       
  94       
  95      if debug: 
  96          signature = re.sub(r'\)\s*$', ', __debug=__debug)', signature) 
  97   
  98       
  99      pysrc_lines = ['def %s:' % signature] 
 100      indents = [-1] 
 101   
 102      if debug: 
 103          pysrc_lines.append('    try:') 
 104          indents.append(-1) 
 105   
 106      commands = COMMAND.split(template_string.strip()+'\n') 
 107      for i, command in enumerate(commands): 
 108          if command == '': continue 
 109   
 110           
 111          if i%2 == 0: 
 112              pieces = INLINE.split(command) 
 113              for j, piece in enumerate(pieces): 
 114                  if j%2 == 0: 
 115                       
 116                      pysrc_lines.append('    '*len(indents)+ 
 117                                   '%s(%r)' % (output_function, piece)) 
 118                  else: 
 119                       
 120                      pysrc_lines.append('    '*len(indents)+ 
 121                                   '%s(unicode(%s))' % (output_function, piece)) 
 122   
 123           
 124          else: 
 125              srcline = command[3:].lstrip() 
 126               
 127              indent = len(command)-len(srcline) 
 128              while indent <= indents[-1]: indents.pop() 
 129               
 130              srcline = srcline.rstrip() 
 131              pysrc_lines.append('    '*len(indents)+srcline) 
 132              if srcline.endswith(':'): 
 133                  indents.append(indent) 
 134           
 135      if debug: 
 136          pysrc_lines.append('    except Exception,e:') 
 137          pysrc_lines.append('        pysrc, func_name = __debug ') 
 138          pysrc_lines.append('        lineno = sys.exc_info()[2].tb_lineno') 
 139          pysrc_lines.append('        print ("Exception in template %s() on "') 
 140          pysrc_lines.append('               "line %d:" % (func_name, lineno))') 
 141          pysrc_lines.append('        print pysrc[lineno-1]') 
 142          pysrc_lines.append('        raise') 
 143           
 144      pysrc = '\n'.join(pysrc_lines)+'\n' 
 145      if debug: localdict = {'__debug': (pysrc_lines, func_name)} 
 146      else: localdict = {} 
 147      try: exec pysrc in globals(), localdict 
 148      except SyntaxError: 
 149          log.error('Error in script:\n' + pysrc + '\n') 
 150          raise 
 151      template_func = localdict[func_name] 
 152      template_func.__doc__ = docstring 
 153      return template_func 
  154       
 156      """ 
 157      Given a multiline string C{s}, find the minimum indentation for 
 158      all non-blank lines, and return a new string formed by stripping 
 159      that amount of indentation from all lines in C{s}. 
 160      """ 
 161       
 162      minindent = sys.maxint 
 163      lines = s.split('\n') 
 164      for line in lines: 
 165          stripline = line.lstrip() 
 166          if stripline: 
 167              minindent = min(minindent, len(line)-len(stripline)) 
 168      return '\n'.join([l[minindent:] for l in lines]) 
  169   
 170   
 171   
 172   
 173   
 175       
 176       
 177       
 178       
 179       
 180       
 181       
 182       
 183       
 184       
 185       
 186       
 187       
 188       
 189       
 190       
 191       
 192       
 193       
 194       
 195       
 196       
 197       
 198       
 199       
 200   
 201 -    def __init__(self, docindex, **kwargs): 
  202          """ 
 203          Construct a new HTML writer, using the given documentation 
 204          index. 
 205           
 206          @param docmap: The documentation index. 
 207           
 208          @type prj_name: C{string} 
 209          @keyword prj_name: The name of the project.  Defaults to 
 210                none. 
 211          @type prj_url: C{string} 
 212          @keyword prj_url: The target for the project hopeage link on 
 213                the navigation bar.  If C{prj_url} is not specified, 
 214                then no hyperlink is created. 
 215          @type prj_link: C{string} 
 216          @keyword prj_link: The label for the project link on the 
 217                navigation bar.  This link can contain arbitrary HTML 
 218                code (e.g. images).  By default, a label is constructed 
 219                from C{prj_name}. 
 220          @type top_page: C{string} 
 221          @keyword top_page: The top page for the documentation.  This 
 222                is the default page shown main frame, when frames are 
 223                enabled.  C{top} can be a URL, the name of a 
 224                module, the name of a class, or one of the special 
 225                strings C{"trees.html"}, C{"indices.html"}, or 
 226                C{"help.html"}.  By default, the top-level package or 
 227                module is used, if there is one; otherwise, C{"trees"} 
 228                is used. 
 229          @type css: C{string} 
 230          @keyword css: The CSS stylesheet file.  If C{css} is a file 
 231                name, then the specified file's conents will be used. 
 232                Otherwise, if C{css} is the name of a CSS stylesheet in 
 233                L{epydoc.docwriter.html_css}, then that stylesheet will 
 234                be used.  Otherwise, an error is reported.  If no stylesheet  
 235                is specified, then the default stylesheet is used. 
 236          @type help_file: C{string} 
 237          @keyword help_file: The name of the help file.  If no help file is 
 238                specified, then the default help file will be used. 
 239          @type show_private: C{boolean} 
 240          @keyword show_private: Whether to create documentation for 
 241              private objects.  By default, private objects are documented. 
 242          @type show_frames: C{boolean}) 
 243          @keyword show_frames: Whether to create a frames-based table of 
 244                contents.  By default, it is produced. 
 245          @type show_imports: C{boolean} 
 246          @keyword show_imports: Whether or not to display lists of 
 247                imported functions and classes.  By default, they are 
 248                not shown. 
 249          @type variable_maxlines: C{int} 
 250          @keyword variable_maxlines: The maximum number of lines that 
 251                should be displayed for the value of a variable in the 
 252                variable details section.  By default, 8 lines are 
 253                displayed. 
 254          @type variable_linelength: C{int} 
 255          @keyword variable_linelength: The maximum line length used for 
 256                displaying the values of variables in the variable 
 257                details sections.  If a line is longer than this length, 
 258                then it will be wrapped to the next line.  The default 
 259                line length is 70 characters. 
 260          @type variable_summary_linelength: C{int} 
 261          @keyword variable_summary_linelength: The maximum line length 
 262                used for displaying the values of variables in the summary 
 263                section.  If a line is longer than this length, then it 
 264                will be truncated.  The default is 40 characters. 
 265          @type variable_tooltip_linelength: C{int} 
 266          @keyword variable_tooltip_linelength: The maximum line length 
 267                used for tooltips for the values of variables.  If a 
 268                line is longer than this length, then it will be 
 269                truncated.  The default is 600 characters. 
 270          @type property_function_linelength: C{int} 
 271          @keyword property_function_linelength: The maximum line length 
 272                used to dispaly property functions (C{fget}, C{fset}, and 
 273                C{fdel}) that contain something other than a function 
 274                object.  The default length is 40 characters. 
 275          @type inheritance: C{string} 
 276          @keyword inheritance: How inherited objects should be displayed. 
 277                If C{inheritance='grouped'}, then inherited objects are 
 278                gathered into groups; if C{inheritance='listed'}, then 
 279                inherited objects are listed in a short list at the 
 280                end of their group; if C{inheritance='included'}, then 
 281                inherited objects are mixed in with non-inherited 
 282                objects.  The default is 'grouped'. 
 283          @type include_sourcecode: C{boolean} 
 284          @param include_sourcecode: If true, then generate colorized 
 285                source code files for each python module. 
 286          """ 
 287          self.docindex = docindex 
 288           
 289           
 290          self._show_private = kwargs.get('show_private', 1) 
 291          """Should private docs be included?""" 
 292           
 293          self._prj_name = kwargs.get('prj_name', None) 
 294          """The project's name (for the project link in the navbar)""" 
 295           
 296          self._prj_url = kwargs.get('prj_url', None) 
 297          """URL for the project link in the navbar""" 
 298           
 299          self._prj_link = kwargs.get('prj_link', None) 
 300          """HTML code for the project link in the navbar""" 
 301           
 302          self._top_page = kwargs.get('top_page', None) 
 303          """The 'main' page""" 
 304   
 305          self._css = kwargs.get('css') 
 306          """CSS stylesheet to use""" 
 307           
 308          self._helpfile = kwargs.get('help_file', None) 
 309          """Filename of file to extract help contents from""" 
 310           
 311          self._frames_index = kwargs.get('show_frames', 1) 
 312          """Should a frames index be created?""" 
 313           
 314          self._show_imports = kwargs.get('show_imports', False) 
 315          """Should imports be listed?""" 
 316           
 317          self._propfunc_linelen = kwargs.get('property_function_linelength', 40) 
 318          """[XXX] Not used!""" 
 319           
 320          self._variable_maxlines = kwargs.get('variable_maxlines', 8) 
 321          """Max lines for variable values""" 
 322           
 323          self._variable_linelen = kwargs.get('variable_linelength', 70) 
 324          """Max line length for variable values""" 
 325           
 326          self._variable_summary_linelen = \ 
 327                           kwargs.get('variable_summary_linelength', 55) 
 328          """Max length for variable value summaries""" 
 329           
 330          self._variable_tooltip_linelen = \ 
 331                           kwargs.get('variable_tooltip_linelength', 600) 
 332          """Max length for variable tooltips""" 
 333           
 334          self._inheritance = kwargs.get('inheritance', 'listed') 
 335          """How should inheritance be displayed?  'listed', 'included', 
 336          or 'grouped'""" 
 337   
 338          self._incl_sourcecode = kwargs.get('include_source_code', True) 
 339          """Should pages be generated for source code of modules?""" 
 340   
 341          self._mark_docstrings = kwargs.get('mark_docstrings', False) 
 342          """Wrap <span class='docstring'>...</span> around docstrings?""" 
 343   
 344          self._graph_types = kwargs.get('graphs', ()) or () 
 345          """Graphs that we should include in our output.""" 
 346   
 347           
 348          if self._show_private: 
 349              self._public_filter = None 
 350          else: 
 351              self._public_filter = True 
 352           
 353           
 354          if self._inheritance not in ('listed', 'included', 'grouped'): 
 355              raise ValueError, 'Bad value for inheritance' 
 356   
 357           
 358          if (self._prj_name or self._prj_url) and not self._prj_link: 
 359              self._prj_link = plaintext_to_html(self._prj_name or 
 360                                                 'Project Homepage') 
 361   
 362           
 363           
 364          if (self._prj_link and self._prj_url and 
 365              not re.search(r'<a[^>]*\shref', self._prj_link)): 
 366              self._prj_link = ('<a class="navbar" target="_top" href="'+ 
 367                                self._prj_url+'">'+self._prj_link+'</a>') 
 368   
 369           
 370           
 371          self.valdocs = valdocs = sorted(docindex.reachable_valdocs( 
 372              imports=False, packages=False, bases=False, submodules=False,  
 373              subclasses=False, private=self._show_private)) 
 374          self.module_list = [d for d in valdocs if isinstance(d, ModuleDoc)] 
 375          """The list of L{ModuleDoc}s for the documented modules.""" 
 376          self.module_set = set(self.module_list) 
 377          """The set of L{ModuleDoc}s for the documented modules.""" 
 378          self.class_list = [d for d in valdocs if isinstance(d, ClassDoc)] 
 379          """The list of L{ClassDoc}s for the documented classes.""" 
 380          self.class_set = set(self.class_list) 
 381          """The set of L{ClassDoc}s for the documented classes.""" 
 382          self.routine_list = [d for d in valdocs if isinstance(d, RoutineDoc)] 
 383          """The list of L{RoutineDoc}s for the documented routines.""" 
 384          self.indexed_docs = [] 
 385          """The list of L{APIDoc}s for variables and values that should 
 386          be included in the index.""" 
 387   
 388           
 389          self.indexed_docs += [d for d in valdocs 
 390                                if not isinstance(d, GenericValueDoc)] 
 391          for doc in valdocs: 
 392              if isinstance(doc, NamespaceDoc): 
 393                  self.indexed_docs += [doc for doc in doc.variables.values() if 
 394                                        isinstance(doc.value, GenericValueDoc)] 
 395          self.indexed_docs.sort() 
 396   
 397           
 398          self._top_page_url = self._find_top_page(self._top_page) 
 399           
 400           
 401           
 402          self.modules_with_sourcecode = set() 
 403          for doc in self.module_list: 
 404              if isinstance(doc, ModuleDoc) and is_src_filename(doc.filename): 
 405                  self.modules_with_sourcecode.add(doc) 
 406          self._num_files = len(self.class_list) + 2*len(self.module_list) + 9 
 407          if self._incl_sourcecode: 
 408              self._num_files += len(self.modules_with_sourcecode) 
  409               
 410 -    def _find_top_page(self, pagename): 
  411          """ 
 412          Find the top page for the API documentation.  This page is 
 413          used as the default page shown in the main frame, when frames 
 414          are used.  When frames are not used, this page is copied to  
 415          C{index.html}. 
 416   
 417          @param pagename: The name of the page, as specified by the 
 418              keyword argument C{top} to the constructor. 
 419          @type pagename: C{string} 
 420          @return: The URL of the top page. 
 421          @rtype: C{string} 
 422          """ 
 423           
 424           
 425          if pagename: 
 426               
 427              if pagename.lower().startswith('http:'): 
 428                  return pagename 
 429   
 430               
 431              try: 
 432                  doc = self.docindex.get_valdoc(pagename) 
 433                  return self.url(doc) 
 434              except: 
 435                  pass 
 436   
 437               
 438              log.warning('Could not find top page %r; using trees.html ' 
 439                          'instead' % pagename) 
 440   
 441           
 442           
 443          else: 
 444              root = [val_doc for val_doc in self.docindex.root 
 445                      if isinstance(val_doc, (ClassDoc, ModuleDoc))] 
 446              if len(root) == 0: 
 447                   
 448                  return 'trees.html'  
 449              elif len(root) == 1: 
 450                   
 451                  return self.url(root[0])  
 452              else: 
 453                   
 454                   
 455                  root = sorted(root, key=lambda v:len(v.canonical_name)) 
 456                  top = root[0] 
 457                  for doc in root[1:]: 
 458                      if not top.canonical_name.dominates(doc.canonical_name): 
 459                          return 'trees.html' 
 460                  else: 
 461                      return self.url(top) 
  462       
 463       
 464       
 465       
 466   
 467 -    def write(self, directory=None): 
  468          """ 
 469          Write the documentation to the given directory. 
 470   
 471          @type directory: C{string} 
 472          @param directory: The directory to which output should be 
 473              written.  If no directory is specified, output will be 
 474              written to the current directory.  If the directory does 
 475              not exist, it will be created. 
 476          @rtype: C{None} 
 477          @raise OSError: If C{directory} cannot be created. 
 478          @raise OSError: If any file cannot be created or written to. 
 479          """ 
 480           
 481          self._files_written = 0. 
 482           
 483           
 484          self._failed_xrefs = {} 
 485   
 486           
 487          if not directory: directory = os.curdir 
 488          self._mkdir(directory) 
 489          self._directory = directory 
 490   
 491           
 492          self._files_written += 1 
 493          log.progress(self._files_written/self._num_files, 'epydoc.css') 
 494          self.write_css(directory, self._css) 
 495   
 496           
 497          self._files_written += 1 
 498          log.progress(self._files_written/self._num_files, 'epydoc.js') 
 499          self.write_javascript(directory) 
 500   
 501           
 502          self._write(self.write_indices, directory, 'indices.html') 
 503           
 504           
 505          self._write(self.write_trees, directory, 'trees.html') 
 506           
 507           
 508          self._write(self.write_help, directory,'help.html') 
 509           
 510           
 511          self._write(self.write_frames_index, directory, 'frames.html') 
 512          self._write(self.write_toc, directory, 'toc.html') 
 513          self._write(self.write_project_toc, directory, 'toc-everything.html') 
 514          for doc in self.module_list: 
 515              filename = 'toc-%s' % urllib.unquote(self.url(doc)) 
 516              self._write(self.write_module_toc, directory, filename, doc) 
 517   
 518           
 519          for doc in self.module_list: 
 520              filename = urllib.unquote(self.url(doc)) 
 521              self._write(self.write_module, directory, filename, doc) 
 522          for doc in self.class_list: 
 523              filename = urllib.unquote(self.url(doc)) 
 524              self._write(self.write_class, directory, filename, doc) 
 525   
 526           
 527          if self._incl_sourcecode: 
 528              for doc in self.modules_with_sourcecode: 
 529                  filename = urllib.unquote(self.pysrc_url(doc)) 
 530                  self._write(self.write_sourcecode, directory, filename, doc) 
 531   
 532           
 533           
 534          self._files_written += 1 
 535          log.progress(self._files_written/self._num_files, 'index.html') 
 536          self.write_homepage(directory) 
 537   
 538           
 539          if self._failed_xrefs: 
 540              estr = 'Failed identifier crossreference targets:\n' 
 541              failed_identifiers = self._failed_xrefs.keys() 
 542              failed_identifiers.sort() 
 543              for identifier in failed_identifiers: 
 544                  names = self._failed_xrefs[identifier].keys() 
 545                  names.sort() 
 546                  estr += '- %s' % identifier 
 547                  estr += '\n' 
 548                  for name in names: 
 549                      estr += '      (from %s)\n' % name 
 550              log.docstring_warning(estr) 
  551   
 552 -    def _write(self, write_func, directory, filename, *args): 
  561   
 563          """ 
 564          If the given directory does not exist, then attempt to create it. 
 565          @rtype: C{None} 
 566          """ 
 567          if not os.path.isdir(directory): 
 568              if os.path.exists(directory): 
 569                  raise OSError('%r is not a directory' % directory) 
 570              os.mkdir(directory) 
  571           
 572       
 573       
 574       
 575   
 577          """ 
 578          Write an HTML page containing the API documentation for the 
 579          given module to C{out}. 
 580           
 581          @param doc: A L{ModuleDoc} containing the API documentation 
 582          for the module that should be described. 
 583          """ 
 584          longname = doc.canonical_name 
 585          shortname = doc.canonical_name[-1] 
 586   
 587           
 588          self.write_header(out, str(longname)) 
 589          self.write_navbar(out, doc) 
 590          self.write_breadcrumbs(out, doc, self.url(doc)) 
 591   
 592           
 593          if doc.is_package is True: typ = 'Package' 
 594          else: typ = 'Module' 
 595          if longname[0].startswith('script-'): 
 596              shortname = str(longname)[7:] 
 597              typ = 'Script' 
 598          out('<!-- ==================== %s ' % typ.upper() + 
 599              'DESCRIPTION ==================== -->\n') 
 600          out('<h2 class="%s">%s %s' % (typ.lower(), typ, shortname)) 
 601          src_link = self.pysrc_link(doc) 
 602          if src_link: out('\n<br/>' + src_link) 
 603          out('</h2>\n') 
 604           
 605           
 606          if doc.descr not in (None, UNKNOWN): 
 607              out(self.descr(doc, 2)+'<br /><br />\n\n') 
 608   
 609           
 610          if doc.metadata is not UNKNOWN and doc.metadata: 
 611              out('<hr />\n') 
 612          self.write_standard_fields(out, doc) 
 613   
 614           
 615          if doc.is_package is True: 
 616              self.write_module_list(out, doc) 
 617   
 618           
 619           
 620          self.write_summary_table(out, "Classes", doc, "class") 
 621          self.write_summary_table(out, "Functions", doc, "function") 
 622          self.write_summary_table(out, "Variables", doc, "other") 
 623   
 624           
 625          if self._show_imports: 
 626              self.write_imports(out, doc) 
 627   
 628           
 629           
 630          self.write_details_list(out, "Function Details", doc, "function") 
 631          self.write_details_list(out, "Variables Details", doc, "other") 
 632   
 633           
 634          self.write_navbar(out, doc) 
 635          self.write_footer(out) 
  636   
 637       
 638       
 639       
 640   
 642          filename = doc.filename 
 643          name = str(doc.canonical_name) 
 644           
 645           
 646          self.write_header(out, name) 
 647          self.write_navbar(out, doc) 
 648          self.write_breadcrumbs(out, doc, self.pysrc_url(doc)) 
 649   
 650           
 651          out('<h2 class="py-src">Source Code for %s</h2>\n' % 
 652              self.href(doc, label='%s %s' % (self.doc_kind(doc), name))) 
 653          out('<div class="py-src">\n') 
 654          out('<pre class="py-src">\n') 
 655          out(PythonSourceColorizer(filename, name, self.docindex, 
 656                                    self.indexed_docs, self.url).colorize()) 
 657          out('</pre>\n</div>\n<br />\n') 
 658   
 659           
 660          self.write_navbar(out, doc) 
 661          self.write_footer(out) 
  662   
 663       
 664       
 665       
 666   
 668          """ 
 669          Write an HTML page containing the API documentation for the 
 670          given class to C{out}. 
 671           
 672          @param doc: A L{ClassDoc} containing the API documentation 
 673          for the class that should be described. 
 674          """ 
 675          longname = doc.canonical_name 
 676          shortname = doc.canonical_name[-1] 
 677   
 678           
 679          self.write_header(out, str(longname)) 
 680          self.write_navbar(out, doc) 
 681          self.write_breadcrumbs(out, doc, self.url(doc)) 
 682   
 683           
 684          if doc.is_type(): typ = 'Type' 
 685          elif doc.is_exception(): typ = 'Exception' 
 686          else: typ = 'Class' 
 687          out('<!-- ==================== %s ' % typ.upper() + 
 688              'DESCRIPTION ==================== -->\n') 
 689          out('<h2 class="%s">%s %s' % 
 690              (typ.lower(), typ, shortname)) 
 691          src_link = self.pysrc_link(doc) 
 692          if src_link: out('\n<br/>' + src_link) 
 693          out('</h2>\n') 
 694   
 695          if ((doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0) or 
 696              (doc.subclasses not in (UNKNOWN,None) and len(doc.subclasses)>0)): 
 697               
 698              if 'umlclasstree' in self._graph_types: 
 699                  linker = _HTMLDocstringLinker(self, doc) 
 700                  graph = uml_class_tree_graph(doc, linker, doc) 
 701                  out('<center>\n%s</center>\n' % self.render_graph(graph)) 
 702                   
 703              elif 'classtree' in self._graph_types: 
 704                  linker = _HTMLDocstringLinker(self, doc) 
 705                  graph = class_tree_graph([doc], linker, doc) 
 706                  out('<center>\n%s</center>\n' % self.render_graph(graph)) 
 707   
 708               
 709              else: 
 710                   
 711                  if doc.bases not in (UNKNOWN, None) and len(doc.bases) > 0: 
 712                      out('<pre class="base-tree">\n%s</pre>\n\n' % 
 713                          self.base_tree(doc)) 
 714   
 715                   
 716                  if (doc.subclasses not in (UNKNOWN, None) and 
 717                      len(doc.subclasses) > 0): 
 718                      out('<dl><dt>Known Subclasses:</dt>\n<dd>\n    ') 
 719                      out(',\n    '.join([self.href(c, context=doc) 
 720                                          for c in doc.subclasses])) 
 721                      out('\n</dd></dl>\n\n') 
 722   
 723              out('<hr />\n') 
 724           
 725           
 726          if doc.descr not in (None, UNKNOWN): 
 727              out(self.descr(doc, 2)+'<br /><br />\n\n') 
 728   
 729           
 730          if doc.metadata is not UNKNOWN and doc.metadata: 
 731              out('<hr />\n') 
 732          self.write_standard_fields(out, doc) 
 733   
 734           
 735           
 736          self.write_summary_table(out, "Nested Classes", doc, "class") 
 737          self.write_summary_table(out, "Instance Methods", doc, 
 738                                   "instancemethod") 
 739          self.write_summary_table(out, "Class Methods", doc, "classmethod") 
 740          self.write_summary_table(out, "Static Methods", doc, "staticmethod") 
 741          self.write_summary_table(out, "Class Variables", doc, 
 742                                   "classvariable") 
 743          self.write_summary_table(out, "Instance Variables", doc, 
 744                                   "instancevariable") 
 745          self.write_summary_table(out, "Properties", doc, "property") 
 746   
 747           
 748          if self._show_imports: 
 749              self.write_imports(out, doc) 
 750   
 751           
 752           
 753           
 754           
 755           
 756          self.write_details_list(out, "Method Details", doc, "method") 
 757          self.write_details_list(out, "Class Variable Details", doc, 
 758                                  "classvariable") 
 759          self.write_details_list(out, "Instance Variable Details", doc, 
 760                                  "instancevariable") 
 761          self.write_details_list(out, "Property Details", doc, "property") 
 762   
 763           
 764          self.write_navbar(out, doc) 
 765          self.write_footer(out) 
  766   
 767       
 768       
 769       
 770   
 772          """ 
 773          Write an HTML page containing the module and class hierarchies 
 774          to the given streams. 
 775          @param public: The output stream for the public version of the page. 
 776          @param private: The output stream for the private version of the page. 
 777          """ 
 778           
 779          self.write_header(out, 'Trees') 
 780          self.write_navbar(out, 'trees') 
 781          self.write_breadcrumbs(out, 'trees', 'trees.html') 
 782   
 783           
 784          out('<!-- ==================== '  
 785              'MODULE HIERARCHY ==================== -->\n') 
 786          out('<h2>Module Hierarchy</h2>\n') 
 787          self.write_module_tree(out) 
 788   
 789           
 790          defines_classes = len(self.class_list) > 0 
 791   
 792           
 793          if defines_classes: 
 794              out('<!-- ==================== ' 
 795                  'CLASS HIERARCHY ==================== -->\n') 
 796              out('<h2>Class Hierarchy</h2>\n') 
 797              self.write_class_tree(out) 
 798   
 799           
 800          self.write_navbar(out, 'trees') 
 801          self.write_footer(out) 
  802   
 803       
 804       
 805       
 806   
 808          """ 
 809          Write an HTML page containing the term and identifier indices 
 810          to the given streams. 
 811          @bug: If there are private indexed terms, but no public 
 812              indexed terms, then this function will still write a 
 813              header for the Term Index to the public stream. 
 814          @param public: The output stream for the public version of the page. 
 815          @param private: The output stream for the private version of the page. 
 816          """ 
 817           
 818          self.write_header(out, 'Index') 
 819          self.write_navbar(out, 'indices') 
 820          self.write_breadcrumbs(out, 'indices', 'indices.html') 
 821          out('<br />\n') 
 822   
 823          terms = self._extract_term_index() 
 824          if terms: 
 825              self.write_term_index(out, terms) 
 826   
 827           
 828           
 829          identifiers = [] 
 830          for doc in self.indexed_docs: 
 831              name = doc.canonical_name 
 832              if self.url(doc) is None: continue 
 833              key = name[-1].lower() 
 834              key = (key[:1] in 'abcdefghijklmnopqrstuvwxyz', key) 
 835              identifiers.append( (key, name, doc) ) 
 836               
 837          identifiers.sort() 
 838          if identifiers: 
 839              self.write_identifier_index(out, identifiers) 
 840   
 841           
 842          self.write_navbar(out, 'indices') 
 843          self.write_footer(out) 
  844   
 845      write_identifier_index_header = compile_template( 
 846          """ 
 847          write_identifier_index_header(self, out) 
 848          """, 
 849           
 850          ''' 
 851          <!-- ==================== IDENTIFIER INDEX ==================== --> 
 852          <table class="index" border="1" cellpadding="3" 
 853                 cellspacing="0" width="100%" bgcolor="white"> 
 854          <tr bgcolor="#70b0f0" class="index"><th colspan="2"> 
 855            <table border="0" cellpadding="0" cellspacing="0" width="100%"> 
 856              <tr><th class="index">Identifier Index</th> 
 857                <td width="100%" align="right"> [ 
 858                  <a href="#_">_</a> 
 859          >>> for c in "abcdefghijklmnopqrstuvwxyz": 
 860                  <a href="#$c$">$c$</a> 
 861          >>> #endfor 
 862                ] </td> 
 863              </tr></table> 
 864          </th></tr> 
 865          ''') 
 866           
 867       
 868      write_identifier_index = compile_template( 
 869          """ 
 870          write_identifier_index(self, out, index) 
 871          """, 
 872           
 873          ''' 
 874          >>> #self.write_table_header(out, "index", "Identifier Index") 
 875          >>> self.write_identifier_index_header(out) 
 876          >>> letters = "abcdefghijklmnopqrstuvwxyz" 
 877            <a name="_"></a> 
 878          >>> for sortkey, name, doc in index: 
 879          >>>     if self._doc_or_ancestor_is_private(doc): 
 880          >>>         if not self._show_private: continue 
 881            <tr class="private"><td width="15%"> 
 882          >>>     else: 
 883            <tr><td width="15%"> 
 884          >>>     #endif 
 885          >>>     while letters and letters[0] <= name[-1][:1].lower(): 
 886                    <a name="$letters[0]$"></a> 
 887          >>>       letters = letters[1:] 
 888          >>>     #endif 
 889                  $self.href(doc, name[-1])$ 
 890                </td> 
 891                <td>$self.doc_kind(doc)$ 
 892          >>>     container_name = name.container() 
 893          >>>     if container_name is not None: 
 894          >>>         container = self.docindex.get_valdoc(container_name) 
 895          >>>         if container is not None: 
 896                        in $self.doc_kind(container)$ $self.href(container)$ 
 897          >>>         #endif 
 898          >>>     #endif 
 899                </td> 
 900            </tr> 
 901          >>> #endfor 
 902          </table> 
 903          >>> for letter in letters: 
 904          <a name="$letter$"></a> 
 905          >>> #endfor 
 906          <br /> 
 907          ''') 
 908           
 909   
 910      write_term_index = compile_template( 
 911          """ 
 912          write_term_index(self, out, index) 
 913          """, 
 914           
 915          ''' 
 916          >>> if not index: return 
 917          >>> self.write_table_header(out, "index", "Term Index") 
 918          >>> for (key, term, links) in index: 
 919            <tr><td width="15%">$term.to_plaintext(None)$</td> 
 920                <td> 
 921          >>>     for link in links[:-1]: 
 922                  <em>$self.href(link)$</em>, 
 923          >>>     #endfor 
 924                  <em>$self.href(links[-1])$</em> 
 925                </td> 
 926            </tr> 
 927          >>> #endfor 
 928          </table> 
 929          <br /> 
 930          ''') 
 931           
 932   
 933       
 934       
 935       
 936   
 938          """ 
 939          Write an HTML help file to the given stream.  If 
 940          C{self._helpfile} contains a help file, then use it; 
 941          otherwise, use the default helpfile from 
 942          L{epydoc.docwriter.html_help}. 
 943           
 944          @param public: The output stream for the public version of the page. 
 945          @param private: The output stream for the private version of the page. 
 946          """ 
 947           
 948           
 949           
 950          if self._helpfile: 
 951              if os.path.exists(self._helpfile): 
 952                  try: help = open(self._helpfile).read() 
 953                  except: raise IOError("Can't open help file: %r" % 
 954                                        self._helpfile) 
 955              else: 
 956                  raise IOError("Can't find help file: %r" % self._helpfile) 
 957          else: 
 958              if self._prj_name: thisprj = self._prj_name 
 959              else: thisprj = 'this project' 
 960              help = HTML_HELP % {'this_project':thisprj} 
 961   
 962           
 963          self.write_header(out, 'Help') 
 964          self.write_navbar(out, 'help') 
 965          self.write_breadcrumbs(out, 'help', 'help.html') 
 966          out(help) 
 967          self.write_navbar(out, 'help') 
 968          self.write_footer(out) 
  969   
 970       
 971       
 972       
 973       
 974      write_frames_index = compile_template( 
 975          """ 
 976          write_frames_index(self, out) 
 977   
 978          Write the frames index file for the frames-based table of 
 979          contents to the given streams. 
 980          """, 
 981           
 982          ''' 
 983          <?xml version="1.0" encoding="iso-8859-1"?> 
 984          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" 
 985                    "DTD/xhtml1-frameset.dtd"> 
 986          <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
 987          <head> 
 988            <title> $self._prj_name or "API Documentation"$ </title> 
 989          </head> 
 990          <frameset cols="20%,80%"> 
 991            <frameset rows="30%,70%"> 
 992              <frame src="toc.html" name="moduleListFrame" 
 993                     id="moduleListFrame" /> 
 994              <frame src="toc-everything.html" name="moduleFrame" 
 995                     id="moduleFrame" /> 
 996            </frameset> 
 997            <frame src="$self._top_page_url$" name="mainFrame" id="mainFrame" /> 
 998          </frameset> 
 999          </html> 
1000          ''') 
1001           
1002       
1003      write_toc = compile_template( 
1004          """ 
1005          write_toc(self, out) 
1006          """, 
1007           
1008          ''' 
1009          >>> self.write_header(out, "Table of Contents") 
1010          <h1 class="tocheading">Table of Contents</h1> 
1011          <hr /> 
1012          <p class="toc"> 
1013            <a target="moduleFrame" href="toc-everything.html">Everything</a> 
1014          </p> 
1015          >>> self.write_toc_section(out, "Modules", self.module_list) 
1016          <hr /> 
1017          >>> if self._show_private: 
1018            $self.PRIVATE_LINK$ 
1019          >>> #endif 
1020          >>> self.write_footer(out, short=True) 
1021          ''') 
1022           
1023   
1025          if not docs: return 
1026   
1027           
1028          if fullname: 
1029              docs = [(str(d.canonical_name), d) for d in docs] 
1030          else: 
1031              docs = [(str(d.canonical_name[-1]), d) for d in docs] 
1032          docs.sort() 
1033   
1034          out('  <h2 class="tocheading">%s</h2>\n' % name) 
1035          for label, doc in docs: 
1036              doc_url = self.url(doc) 
1037              toc_url = 'toc-%s' % doc_url 
1038              is_private = self._doc_or_ancestor_is_private(doc) 
1039              if is_private: 
1040                  if not self._show_private: continue 
1041                  out('  <div class="private">\n') 
1042                   
1043              out('  <p class="toc">\n') 
1044              if isinstance(doc, ModuleDoc): 
1045                  out('    <a target="moduleFrame" href="%s"\n' 
1046                      '     onclick="setFrame(\'%s\',\'%s\');"' 
1047                      '     >%s</a></p>' % (toc_url, toc_url, doc_url, label)) 
1048              else: 
1049                  out('    <a target="mainFrame" href="%s"\n' 
1050                      '     >%s</a></p>' % (doc_url, label)) 
1051              if is_private: 
1052                  out('  </div>\n') 
 1053   
1055          self.write_header(out, "Everything") 
1056          out('<h1 class="tocheading">Everything</h1>\n') 
1057          out('<hr />\n') 
1058   
1059           
1060          self.write_toc_section(out, "All Classes", self.class_list) 
1061   
1062           
1063          funcs = [d for d in self.routine_list  
1064                   if not isinstance(self.docindex.container(d),  
1065                                     (ClassDoc, types.NoneType))] 
1066          self.write_toc_section(out, "All Functions", funcs) 
1067   
1068           
1069          vars = [] 
1070          for doc in self.module_list: 
1071              vars += doc.select_variables(value_type='other', 
1072                                           imported=False, 
1073                                           public=self._public_filter) 
1074          self.write_toc_section(out, "All Variables", vars) 
1075   
1076           
1077          out('<hr />\n') 
1078          if self._show_private: 
1079              out(self.PRIVATE_LINK+'\n') 
1080          self.write_footer(out, short=True) 
 1081   
1083          """ 
1084          Write an HTML page containing the table of contents page for 
1085          the given module to the given streams.  This page lists the 
1086          modules, classes, exceptions, functions, and variables defined 
1087          by the module. 
1088          @param public: The output stream for the public version of the page. 
1089          @param private: The output stream for the private version of the page. 
1090          """ 
1091          name = doc.canonical_name[-1] 
1092          self.write_header(out, name) 
1093          out('<h1 class="tocheading">Module %s</h1>\n' % name) 
1094          out('<hr />\n') 
1095   
1096   
1097           
1098          classes = doc.select_variables(value_type='class', imported=False, 
1099                                         public=self._public_filter) 
1100          self.write_toc_section(out, "Classes", classes, fullname=False) 
1101   
1102           
1103          funcs = doc.select_variables(value_type='function', imported=False, 
1104                                       public=self._public_filter) 
1105          self.write_toc_section(out, "Functions", funcs, fullname=False) 
1106   
1107           
1108          variables = doc.select_variables(value_type='other', imported=False, 
1109                                           public=self._public_filter) 
1110          self.write_toc_section(out, "Variables", variables, fullname=False) 
1111           
1112           
1113          out('<hr />\n') 
1114          if self._show_private: 
1115              out(self.PRIVATE_LINK+'\n') 
1116          self.write_footer(out, short=True) 
 1117   
1118       
1119       
1120       
1121   
1122 -    def write_homepage(self, directory): 
 1123          """ 
1124          Write an C{index.html} file in the given directory.  The 
1125          contents of this file are copied or linked from an existing 
1126          page, so this method must be called after all pages have been 
1127          written.  The page used is determined by L{_frames_index} and 
1128          L{_top_page}: 
1129              - If L{_frames_index} is true, then C{frames.html} is 
1130                copied. 
1131              - Otherwise, the page specified by L{_top_page} is 
1132                copied. 
1133          """ 
1134          filename = os.path.join(directory, 'index.html') 
1135          if self._frames_index: top = 'frames.html' 
1136          else: top = self._top_page_url 
1137   
1138           
1139          if top[:5] != 'http:' and '/' not in top: 
1140              try: 
1141                   
1142                  topfile = os.path.join(directory, top) 
1143                  s = open(topfile, 'r').read() 
1144   
1145                   
1146                  open(filename, 'w').write(s) 
1147                  return 
1148              except: 
1149                  log.error('Warning: error copying index; ' 
1150                            'using a redirect page') 
1151   
1152           
1153          name = self._prj_name or 'this project' 
1154          f = open(filename, 'w') 
1155          self.write_redirect_index(f.write, top, name) 
1156          f.close() 
 1157   
1158      write_redirect_index = compile_template( 
1159          """ 
1160          write_redirect_index(self, out, top, name) 
1161          """, 
1162           
1163          ''' 
1164          <?xml version="1.0" encoding="iso-8859-1"?> 
1165          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
1166                    "DTD/xhtml1-strict.dtd"> 
1167          <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
1168          <head> 
1169            <title> Redirect </title> 
1170            <meta http-equiv="refresh" content="1;url=$top$" /> 
1171            <link rel="stylesheet" href="epydoc.css" type="text/css"></link> 
1172          </head> 
1173          <body> 
1174            <p>Redirecting to the API documentation for 
1175              <a href="$top$">$self._prj_name or "this project"$</a>...</p> 
1176          </body> 
1177          </html> 
1178          ''') 
1179           
1180   
1181       
1182       
1183       
1184   
1186          """ 
1187          Write the CSS stylesheet in the given directory.  If 
1188          C{cssname} contains a stylesheet file or name (from 
1189          L{epydoc.docwriter.html_css}), then use that stylesheet; 
1190          otherwise, use the default stylesheet. 
1191   
1192          @rtype: C{None} 
1193          """ 
1194          filename = os.path.join(directory, 'epydoc.css') 
1195           
1196           
1197          if cssname is None: 
1198              css = STYLESHEETS['default'][0] 
1199          else: 
1200              if os.path.exists(cssname): 
1201                  try: css = open(cssname).read() 
1202                  except: raise IOError("Can't open CSS file: %r" % cssname) 
1203              elif STYLESHEETS.has_key(cssname): 
1204                  css = STYLESHEETS[cssname][0] 
1205              else: 
1206                  raise IOError("Can't find CSS file: %r" % cssname) 
1207   
1208           
1209          cssfile = open(filename, 'w') 
1210          cssfile.write(css) 
1211          cssfile.close() 
 1212   
1213       
1214       
1215       
1216   
1226   
1227       
1228       
1229       
1230       
1231      TOGGLE_PRIVATE_JS = ''' 
1232        function toggle_private() { 
1233          // Search for any private/public links on this page.  Store 
1234          // their old text in "cmd," so we will know what action to 
1235          // take; and change their text to the opposite action. 
1236          var cmd = "?"; 
1237          var elts = document.getElementsByTagName("a"); 
1238          for(var i=0; i<elts.length; i++) { 
1239            if (elts[i].className == "privatelink") { 
1240              cmd = elts[i].innerHTML; 
1241              elts[i].innerHTML = ((cmd=="show private")?"hide private": 
1242                                                         "show private"); 
1243            } 
1244          } 
1245          // Update all DIVs containing private objects. 
1246          var elts = document.getElementsByTagName("div"); 
1247          for(var i=0; i<elts.length; i++) { 
1248            if (elts[i].className == "private") { 
1249              elts[i].style.display = ((cmd=="hide private")?"none":"block"); 
1250            } 
1251          } 
1252          // Update all table rowss containing private objects.  Note, we 
1253          // use "" instead of "block" becaue IE & firefox disagree on what 
1254          // this should be (block vs table-row), and "" just gives the 
1255          // default for both browsers. 
1256          var elts = document.getElementsByTagName("tr"); 
1257          for(var i=0; i<elts.length; i++) { 
1258            if (elts[i].className == "private") { 
1259              elts[i].style.display = ((cmd=="hide private")?"none":""); 
1260            } 
1261          } 
1262          // Update all list items containing private objects. 
1263          var elts = document.getElementsByTagName("li"); 
1264          for(var i=0; i<elts.length; i++) { 
1265            if (elts[i].className == "private") { 
1266              elts[i].style.display = ((cmd=="hide private")?"none":"list-item"); 
1267            } 
1268          } 
1269          // Update all list items containing private objects. 
1270          var elts = document.getElementsByTagName("ul"); 
1271          for(var i=0; i<elts.length; i++) { 
1272            if (elts[i].className == "private") { 
1273              elts[i].style.display = ((cmd=="hide private")?"none":"block"); 
1274            } 
1275          } 
1276          // Set a cookie to remember the current option. 
1277          document.cookie = "EpydocPrivate="+cmd; 
1278        } 
1279        '''.strip() 
1280   
1281       
1282       
1283       
1284      GET_COOKIE_JS = ''' 
1285        function getCookie(name) { 
1286          var dc = document.cookie; 
1287          var prefix = name + "="; 
1288          var begin = dc.indexOf("; " + prefix); 
1289          if (begin == -1) { 
1290            begin = dc.indexOf(prefix); 
1291            if (begin != 0) return null; 
1292          } else 
1293          { begin += 2; } 
1294          var end = document.cookie.indexOf(";", begin); 
1295          if (end == -1) 
1296          { end = dc.length; } 
1297          return unescape(dc.substring(begin + prefix.length, end)); 
1298        } 
1299        '''.strip() 
1300   
1301       
1302       
1303       
1304       
1305      SET_FRAME_JS = ''' 
1306        function setFrame(url1, url2) { 
1307            parent.frames[1].location.href = url1; 
1308            parent.frames[2].location.href = url2; 
1309        } 
1310      '''.strip() 
1311   
1312       
1313       
1314       
1315      HIDE_PRIVATE_JS = ''' 
1316        function checkCookie() { 
1317          var cmd=getCookie("EpydocPrivate"); 
1318          if (cmd!="show private" && location.href.indexOf("#_") < 0) 
1319              toggle_private(); 
1320        } 
1321      '''.strip() 
1322   
1323      TOGGLE_CALLGRAPH_JS = ''' 
1324        function toggleCallGraph(id) { 
1325          var elt = document.getElementById(id); 
1326          if (elt.style.display == "none") 
1327              elt.style.display = "block"; 
1328          else 
1329              elt.style.display = "none"; 
1330        } 
1331      '''.strip() 
1332   
1333       
1334       
1335       
1336   
1337       
1339          if graph is None: return '' 
1340          graph.caption = graph.title = None 
1341          image_url = '%s.gif' % graph.uid 
1342          image_file = os.path.join(self._directory, image_url) 
1343          return graph.to_html(image_file, image_url) 
 1344       
1346          graph_html = self.render_graph(callgraph, css='graph-with-title') 
1347          if graph_html == '': return '' 
1348          return ('<div style="display:none" id="%s-div"><center>\n' 
1349                  '<table border="0" cellpadding="0" cellspacing="0">\n' 
1350                  '  <tr><td>%s</td></tr>\n' 
1351                  '  <tr><th>Call Graph</th></tr>\n' 
1352                  '</table><br />\n</center></div>\n' % 
1353                  (callgraph.uid, graph_html)) 
 1354   
1356          if callgraph is None: return '' 
1357          return ('<br /><span class="codelink"><a href="javascript: void(0);" ' 
1358                  'onclick="toggleCallGraph(\'%s-div\');return false;">' 
1359                  'call graph</a></span> ' % callgraph.uid) 
1360   
1361       
1362       
1363       
1364   
1365      write_header = compile_template( 
1366          """ 
1367          write_header(self, out, title) 
1368   
1369          Generate HTML code for the standard page header, and write it 
1370          to C{out}.  C{title} is a string containing the page title. 
1371          It should be appropriately escaped/encoded. 
1372          """, 
1373           
1374          ''' 
1375          <?xml version="1.0" encoding="ascii"?> 
1376          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
1377                    "DTD/xhtml1-transitional.dtd"> 
1378          <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
1379          <head> 
1380            <title>$title$</title> 
1381            <link rel="stylesheet" href="epydoc.css" type="text/css" /> 
1382            <script type="text/javascript" src="epydoc.js"></script> 
1383          </head> 
1384           
1385          <body bgcolor="white" text="black" link="blue" vlink="#204080" 
1386                alink="#204080"> 
1387          ''') 
1388           
1389   
1390       
1391       
1392       
1393   
1394      write_footer = compile_template( 
1395          """ 
1396          write_footer(self, out, short=False) 
1397   
1398          Generate HTML code for the standard page footer, and write it 
1399          to C{out}. 
1400          """, 
1401           
1402          ''' 
1403          >>> if not short: 
1404          <table border="0" cellpadding="0" cellspacing="0" width="100%%"> 
1405            <tr> 
1406              <td align="left" class="footer">Generated by Epydoc 
1407                  $epydoc.__version__$ on $time.asctime()$</td> 
1408              <td align="right" class="footer"> 
1409                <a href="http://epydoc.sourceforge.net">http://epydoc.sf.net</a> 
1410              </td> 
1411            </tr> 
1412          </table> 
1413          >>> #endif 
1414   
1415          <script type="text/javascript"> 
1416            <!-- 
1417            // Private objects are initially displayed (because if 
1418            // javascript is turned off then we want them to be 
1419            // visible); but by default, we want to hide them.  So hide 
1420            // them unless we have a cookie that says to show them. 
1421            checkCookie() 
1422            // --> 
1423          </script> 
1424             
1425          </body> 
1426          </html> 
1427          ''') 
1428           
1429   
1430       
1431       
1432       
1433   
1434      write_navbar = compile_template( 
1435          """ 
1436          write_navbar(self, out, context) 
1437   
1438          Generate HTML code for the navigation bar, and write it to 
1439          C{out}.  The navigation bar typically looks like:: 
1440   
1441               [ Home Trees Index Help             Project ] 
1442   
1443          @param context: A value indicating what page we're generating 
1444          a navigation bar for.  If we're generating an API 
1445          documentation page for an object, then C{context} is a 
1446          L{ValueDoc} containing the documentation for that object; 
1447          otherwise, C{context} is a string name for the page.  The 
1448          following string names are recognized: C{'tree'}, C{'index'}, 
1449          and C{'help'}. 
1450          """, 
1451           
1452          ''' 
1453          <!-- ==================== NAVIGATION BAR ==================== --> 
1454          <table class="navbar" border="0" width="100%" cellpadding="0" 
1455                 bgcolor="#a0c0ff" cellspacing="0"> 
1456            <tr valign="middle"> 
1457          >>> if self._top_page_url not in ("trees.html", "indices.html", "help.html"): 
1458            <!-- Home link --> 
1459          >>>   if (isinstance(context, ValueDoc) and 
1460          >>>       self._top_page_url == self.url(context.canonical_name)): 
1461                <th bgcolor="#70b0f0" class="navselect" 
1462                    >   Home   </th> 
1463          >>>   else: 
1464                <th class="navbar">   <a class="navbar" 
1465                  href="$self._top_page_url$">Home</a>   </th> 
1466          >>> #endif 
1467           
1468            <!-- Tree link --> 
1469          >>> if context == "trees": 
1470                <th bgcolor="#70b0f0" class="navselect" 
1471                    >   Trees   </th> 
1472          >>> else: 
1473                <th class="navbar">   <a class="navbar" 
1474                  href="trees.html">Trees</a>   </th> 
1475          >>> #endif 
1476           
1477            <!-- Index link --> 
1478          >>> if context == "indices": 
1479                <th bgcolor="#70b0f0" class="navselect" 
1480                    >   Index   </th> 
1481          >>> else: 
1482                <th class="navbar">   <a class="navbar" 
1483                  href="indices.html">Index</a>   </th> 
1484          >>> #endif 
1485           
1486            <!-- Help link --> 
1487          >>> if context == "help": 
1488                <th bgcolor="#70b0f0" class="navselect" 
1489                    >   Help   </th> 
1490          >>> else: 
1491                <th class="navbar">   <a class="navbar" 
1492                  href="help.html">Help</a>   </th> 
1493          >>> #endif 
1494           
1495          >>> if self._prj_link: 
1496            <!-- Project homepage --> 
1497                <th class="navbar" align="right" width="100%"> 
1498                  <table border="0" cellpadding="0" cellspacing="0"> 
1499                    <tr><th class="navbar" align="center"> 
1500                      <p class="nomargin"> 
1501                        $self._prj_link$ 
1502                </p></th></tr></table></th> 
1503          >>> else: 
1504                <th class="navbar" width="100%"></th> 
1505          >>> #endif 
1506            </tr> 
1507          </table> 
1508          ''') 
1509           
1510   
1511       
1512       
1513       
1514   
1515      write_breadcrumbs = compile_template( 
1516          """ 
1517          write_breadcrumbs(self, out, context, context_url) 
1518   
1519          Generate HTML for the breadcrumbs line, and write it to 
1520          C{out}.  The breadcrumbs line is an invisible table with a 
1521          list of pointers to the current object's ancestors on the 
1522          left; and the show/hide private selector and the 
1523          frames/noframes selector on the right. 
1524   
1525          @param context: The API documentation for the object whose 
1526          breadcrumbs we should generate. 
1527          @type context: L{ValueDoc} 
1528          """, 
1529           
1530          ''' 
1531          <table width="100%" cellpadding="0" cellspacing="0"> 
1532            <tr valign="top"> 
1533          >>> if isinstance(context, APIDoc): 
1534              <td width="100%"> 
1535                <span class="breadcrumbs"> 
1536          >>>   crumbs = self.breadcrumbs(context) 
1537          >>>   for crumb in crumbs[:-1]: 
1538                  $crumb$ :: 
1539          >>>   #endfor 
1540                  $crumbs[-1]$ 
1541                </span> 
1542              </td> 
1543          >>> else: 
1544              <td width="100%"> </td> 
1545          >>> #endif 
1546              <td> 
1547                <table cellpadding="0" cellspacing="0"> 
1548                  <!-- hide/show private --> 
1549          >>> if self._show_private: 
1550                  <tr><td align="right">$self.PRIVATE_LINK$</td></tr> 
1551          >>> #endif 
1552                  <tr><td align="right"><span class="options" 
1553                      >[<a href="frames.html" target="_top">frames</a 
1554                      >] | <a href="$context_url$" 
1555                      target="_top">no frames</a>]</span></td></tr> 
1556                </table> 
1557              </td> 
1558            </tr> 
1559          </table> 
1560          ''') 
1561           
1562   
1582           
1588   
1589       
1590       
1591       
1592   
1594          """ 
1595          Generate HTML code for a summary table, and write it to 
1596          C{out}.  A summary table is a table that includes a one-row 
1597          description for each variable (of a given type) in a module 
1598          or class. 
1599   
1600          @param heading: The heading for the summary table; typically, 
1601              this indicates what kind of value the table describes 
1602              (e.g., functions or classes). 
1603          @param doc: A L{ValueDoc} object containing the API 
1604              documentation for the module or class whose variables 
1605              we should summarize. 
1606          @param value_type: A string indicating what type of value 
1607              should be listed in this summary table.  This value 
1608              is passed on to C{doc}'s C{select_variables()} method. 
1609          """ 
1610           
1611           
1612           
1613           
1614          grouped_inh_vars = {} 
1615   
1616           
1617          groups = [(plaintext_to_html(group_name), 
1618                     doc.select_variables(group=group_name, imported=False, 
1619                                          value_type=value_type, 
1620                                          public=self._public_filter)) 
1621                    for group_name in doc.group_names()] 
1622                   
1623           
1624          groups = [(g,vars) for (g,vars) in groups if vars] 
1625          if not groups: return 
1626   
1627           
1628          self.write_table_header(out, "summary", heading) 
1629   
1630           
1631          for name, var_docs in groups: 
1632              self.write_summary_group(out, doc, name, 
1633                                       var_docs, grouped_inh_vars) 
1634   
1635           
1636           
1637          if grouped_inh_vars: 
1638              for base in doc.mro(): 
1639                  if base in grouped_inh_vars: 
1640                      hdr = 'Inherited from %s' % self.href(base, context=doc) 
1641                      tr_class = '' 
1642                      if len([v for v in grouped_inh_vars[base] 
1643                              if v.is_public]) == 0: 
1644                          tr_class = ' class="private"' 
1645                      self.write_group_header(out, hdr, tr_class) 
1646                      for var_doc in grouped_inh_vars[base]: 
1647                          self.write_summary_line(out, var_doc, doc) 
1648   
1649           
1650          out(self.TABLE_FOOTER) 
1651          out('\n<br />\n') 
 1652   
1654           
1655           
1656           
1657           
1658           
1659          listed_inh_vars = {} 
1660          normal_vars = [] 
1661          for var_doc in var_docs: 
1662              if var_doc.container != doc: 
1663                  base = var_doc.container 
1664                  if (base not in self.class_set or 
1665                      self._inheritance == 'listed'): 
1666                      listed_inh_vars.setdefault(base,[]).append(var_doc) 
1667                  elif self._inheritance == 'grouped': 
1668                      grouped_inh_vars.setdefault(base,[]).append(var_doc) 
1669                  else: 
1670                      normal_vars.append(var_doc) 
1671              else: 
1672                  normal_vars.append(var_doc) 
1673               
1674           
1675          if name != '': 
1676              tr_class = '' 
1677              if len([v for v in var_docs if v.is_public]) == 0: 
1678                  tr_class = ' class="private"' 
1679              self.write_group_header(out, name, tr_class) 
1680   
1681           
1682          for var_doc in normal_vars: 
1683              self.write_summary_line(out, var_doc, doc) 
1684           
1685          if listed_inh_vars: 
1686              self.write_inheritance_list(out, doc, listed_inh_vars) 
 1687   
1689          out('  <tr>\n    <td colspan="2">\n') 
1690          for base in doc.mro(): 
1691              if base not in listed_inh_vars: continue 
1692              public_vars = [v for v in listed_inh_vars[base] 
1693                             if v.is_public] 
1694              private_vars = [v for v in listed_inh_vars[base] 
1695                              if not v.is_public] 
1696              if public_vars: 
1697                  out('    <p class="varlist">' 
1698                      '<span class="varlist-header">Inherited ' 
1699                      'from <code>%s</code></span>:\n' % 
1700                      self.href(base, context=doc)) 
1701                  self.write_var_list(out, public_vars) 
1702                  out('      </p>\n') 
1703              if private_vars and self._show_private: 
1704                  out('    <div class="private">') 
1705                  out('    <p class="varlist">' 
1706                      '<span class="varlist-header">Inherited ' 
1707                      'from <code>%s</code></span> (private):\n' % 
1708                      self.href(base, context=doc)) 
1709                  self.write_var_list(out, private_vars) 
1710                  out('      </p></div>\n') 
1711          out('    </td>\n  </tr>\n') 
 1712       
1714          out('      ') 
1715          out(',\n      '.join(['<code>%s</code>' % self.href(v,v.name) 
1716                                for v in vardocs])+'\n') 
 1717   
1719          """ 
1720          Generate HTML code for a single line of a summary table, and 
1721          write it to C{out}.  See L{write_summary_table} for more 
1722          information. 
1723           
1724          @param var_doc: The API documentation for the variable that 
1725              should be described by this line of the summary table. 
1726          @param container: The API documentation for the class or 
1727              module whose summary table we're writing. 
1728          """ 
1729           
1730          if var_doc.is_public: tr_class = '' 
1731          else: tr_class = ' class="private"' 
1732   
1733           
1734          summary = self.summary(var_doc, indent=6) 
1735   
1736           
1737          if var_doc.container != container and self._inheritance=="included": 
1738              summary += ("\n      <em>(Inherited from " + 
1739                          self.href(var_doc.container) + ")</em>") 
1740               
1741          if isinstance(var_doc.value, RoutineDoc): 
1742              if summary: summary = '<br />'+summary 
1743              self.write_function_summary_line(out, var_doc, tr_class, summary) 
1744          else: 
1745               
1746              self.write_variable_summary_line(out, var_doc, tr_class, summary) 
 1747   
1748      write_function_summary_line = compile_template( 
1749          """ 
1750          write_function_summary_line(self, out, var_doc, tr_class, summary) 
1751   
1752          Generate HTML code for a single line of a summary table, 
1753          describing a variable whose value is a function, and write 
1754          it to C{out}. 
1755           
1756          @param var_doc: The API documentation for the variable that 
1757              should be described by this line of the summary table. 
1758          @param container: The API documentation for the class or 
1759              module whose summary table we're writing. 
1760          """, 
1761           
1762          ''' 
1763            <tr$tr_class$> 
1764              <td width="15%" align="right" valign="top" class="rtype"> 
1765                $self.rtype(var_doc, indent=6) or " "$ 
1766               </td> 
1767              <td> 
1768                $self.function_signature(var_doc, link_name=True)$ 
1769                $summary$ 
1770              </td> 
1771            </tr> 
1772          ''') 
1773           
1774   
1775      write_variable_summary_line = compile_template( 
1776          ''' 
1777          write_variable_summary_line(self, out, var_doc, tr_class, summary) 
1778          ''', 
1779           
1780          ''' 
1781            <tr$tr_class$> 
1782              <td width="15%"> 
1783                <strong>$self.href(var_doc)$</strong></td> 
1784              <td>$summary or " "$</td> 
1785            </tr> 
1786          ''') 
1787           
1788   
1789       
1790       
1791       
1792   
1794           
1795          if isinstance(doc, ClassDoc): 
1796              var_docs = doc.select_variables(value_type=value_type, 
1797                                              imported=False, inherited=False, 
1798                                              public=self._public_filter) 
1799          else: 
1800              var_docs = doc.select_variables(value_type=value_type, 
1801                                              imported=False, 
1802                                              public=self._public_filter) 
1803          if not var_docs: return 
1804   
1805           
1806          self.write_table_header(out, "details", heading) 
1807          out(self.TABLE_FOOTER) 
1808   
1809          for var_doc in var_docs: 
1810              self.write_details_entry(out, var_doc) 
1811   
1812          out('<br />\n') 
 1813   
1814 -    def write_details_entry(self, out, var_doc): 
 1815          descr = self.descr(var_doc, indent=2) 
1816          if var_doc.is_public: div_class = '' 
1817          else: div_class = ' class="private"' 
1818   
1819           
1820          if isinstance(var_doc.value, RoutineDoc): 
1821              rtype = self.rtype(var_doc, indent=10) 
1822              rdescr = self.return_descr(var_doc, indent=10) 
1823              arg_descrs = [] 
1824               
1825               
1826              for (arg_names, arg_descr) in var_doc.value.arg_descrs: 
1827                  lhs = ', '.join([self.arg_name_to_html(var_doc.value, n) 
1828                                   for n in arg_names]) 
1829                  rhs = self.docstring_to_html(arg_descr, var_doc.value, 10) 
1830                  arg_descrs.append( (lhs, rhs) ) 
1831               
1832              if 'callgraph' in self._graph_types: 
1833                  linker = _HTMLDocstringLinker(self, var_doc.value) 
1834                  callgraph = call_graph([var_doc.value], self.docindex, 
1835                                         linker, var_doc, add_callers=True,  
1836                                         add_callees=True) 
1837                  if callgraph is not None and len(callgraph.nodes) == 0: 
1838                      callgraph = None 
1839              else: 
1840                  callgraph = None 
1841              self.write_function_details_entry(out, var_doc, descr, callgraph, 
1842                                                rtype, rdescr, arg_descrs, 
1843                                                div_class) 
1844   
1845           
1846          elif isinstance(var_doc.value, PropertyDoc): 
1847              prop_doc = var_doc.value 
1848              accessors = [(name, self.property_accessor_to_html(val_doc), 
1849                            self.summary(val_doc)) for (name, val_doc) in 
1850                           [('Get', prop_doc.fget), ('Set', prop_doc.fset), 
1851                            ('Delete', prop_doc.fdel)]] 
1852              self.write_property_details_entry(out, var_doc, descr, 
1853                                                accessors, div_class) 
1854           
1855           
1856          else: 
1857              self.write_variable_details_entry(out, var_doc, descr, div_class) 
 1858   
1860           
1861           
1862           
1863          m = re.match(r'^<p( [^>]+)?>', rhs) 
1864          if m: 
1865              lhs = m.group() + lhs 
1866              rhs = rhs[m.end():] 
1867   
1868          return '<li>%s - %s</li>' % (lhs, rhs) 
1869   
1888           
1890          """ 
1891          A helper function used to format an argument name, for use in 
1892          the argument description list under a routine's details entry. 
1893          This just wraps strong & code tags around the arg name; and if 
1894          the arg name is associated with a type, then adds it 
1895          parenthetically after the name. 
1896          """ 
1897          s = '<strong class="pname"><code>%s</code></strong>' % arg_name 
1898          if arg_name in func_doc.arg_types: 
1899              typ = func_doc.arg_types[arg_name] 
1900              typ_html = self.docstring_to_html(typ, func_doc, 10) 
1901              s += " (<code>%s</code>)" % typ_html 
1902          return s 
 1903   
1904      write_function_details_entry = compile_template( 
1905          ''' 
1906          write_function_details_entry(self, out, var_doc, descr, callgraph, \ 
1907                                       rtype, rdescr, arg_descrs, div_class) 
1908          ''', 
1909           
1910          ''' 
1911          >>> func_doc = var_doc.value 
1912          <a name="$var_doc.name$"></a> 
1913          <div$div_class$> 
1914          <table width="100%" class="func-details" bgcolor="#e0e0e0"><tr><td> 
1915            <table width="100%" cellpadding="0" cellspacing="0" border="0"> 
1916            <tr valign="top"><td> 
1917            <h3>$self.function_signature(var_doc)$ 
1918          >>> if var_doc.name in self.SPECIAL_METHODS: 
1919              <br /><em class="fname">($self.SPECIAL_METHODS[var_doc.name]$)</em> 
1920          >>> #endif 
1921            </h3> 
1922            </td><td align="right" valign="top" 
1923              >$self.pysrc_link(func_doc)$ </span 
1924              >$self.callgraph_link(callgraph)$</td> 
1925            </table> 
1926            $self.render_callgraph(callgraph)$ 
1927            $descr$ 
1928            <dl><dt></dt><dd> 
1929          >>> # === parameters === 
1930          >>> if arg_descrs: 
1931              <dl><dt>Parameters:</dt></dl> 
1932              <ul> 
1933          >>>   for lhs, rhs in arg_descrs: 
1934                  $self.labelled_list_item(lhs, rhs)$ 
1935          >>>   #endfor 
1936              </ul> 
1937          >>> #endif 
1938          >>> # === return type === 
1939          >>> if rdescr and rtype: 
1940              <dl><dt>Returns: <code>$rtype$</code></dt> 
1941                  <dd>$rdescr$</dd></dl> 
1942          >>> elif rdescr: 
1943              <dl><dt>Returns:</dt> 
1944                  <dd>$rdescr$</dd></dl> 
1945          >>> elif rtype: 
1946              <dl><dt>Returns: <code>$rtype$</code></dt></dl> 
1947          >>> #endif 
1948          >>> # === exceptions === 
1949          >>> if func_doc.exception_descrs not in (None, UNKNOWN, (), []): 
1950              <dl><dt>Raises:</dt></dl> 
1951              <ul> 
1952          >>>   for name, descr in func_doc.exception_descrs: 
1953                  $self.labelled_list_item( 
1954                      "<code><strong class=\'fraise\'>" + 
1955                      self.href(name) + "</strong></code>", 
1956                      self.docstring_to_html(descr, func_doc, 8))$ 
1957          >>>   #endfor 
1958              </ul> 
1959          >>> #endif 
1960          >>> # === overrides === 
1961          >>> if var_doc.overrides not in (None, UNKNOWN): 
1962              <dl><dt>Overrides: 
1963                $self.href(var_doc.overrides.value, context=var_doc)$ 
1964          >>>   if (func_doc.docstring in (None, UNKNOWN) and 
1965          >>>       var_doc.overrides.value.docstring not in (None, UNKNOWN)): 
1966                  <dd><em class="note">(inherited documentation)</em></dd> 
1967          >>>   #endif 
1968              </dt></dl> 
1969          >>> #endif 
1970          >>> # === metadata === 
1971          >>> self.write_standard_fields(out, func_doc) 
1972            </dd></dl> 
1973          </td></tr></table> 
1974          </div> 
1975          ''') 
1976           
1977   
1978       
1979      SPECIAL_METHODS ={ 
1980      '__init__': 'Constructor', 
1981      '__del__': 'Destructor', 
1982      '__add__': 'Addition operator', 
1983      '__sub__': 'Subtraction operator', 
1984      '__and__': 'And operator', 
1985      '__or__': 'Or operator', 
1986      '__repr__': 'Representation operator', 
1987      '__call__': 'Call operator', 
1988      '__getattr__': 'Qualification operator', 
1989      '__getitem__': 'Indexing operator', 
1990      '__setitem__': 'Index assignment operator', 
1991      '__delitem__': 'Index deletion operator', 
1992      '__delslice__': 'Slice deletion operator', 
1993      '__setslice__': 'Slice assignment operator', 
1994      '__getslice__': 'Slicling operator', 
1995      '__len__': 'Length operator', 
1996      '__cmp__': 'Comparison operator', 
1997      '__eq__': 'Equality operator', 
1998      '__in__': 'Containership operator', 
1999      '__gt__': 'Greater-than operator', 
2000      '__lt__': 'Less-than operator', 
2001      '__ge__': 'Greater-than-or-equals operator', 
2002      '__le__': 'Less-than-or-equals operator', 
2003      '__radd__': 'Right-side addition operator', 
2004      '__hash__': 'Hashing function', 
2005      '__contains__': 'In operator', 
2006      '__nonzero__': 'Boolean test operator', 
2007      '__str__': 'Informal representation operator', 
2008      } 
2009   
2010      write_property_details_entry = compile_template( 
2011          ''' 
2012          write_property_details_entry(self, out, var_doc, descr, \ 
2013                                       accessors, div_class) 
2014          ''', 
2015           
2016          ''' 
2017          >>> prop_doc = var_doc.value 
2018          <a name="$var_doc.name$"></a> 
2019          <div$div_class$> 
2020          <table width="100%" class="prop-details" bgcolor="#e0e0e0"><tr><td> 
2021            <h3>$var_doc.name$</h3> 
2022            $descr$ 
2023            <dl><dt></dt><dd> 
2024          >>> if prop_doc.type_descr not in (None, UNKNOWN): 
2025              <dl><dt>Type:</dt> 
2026                <dd>$self.type_descr(var_doc, indent=6)$</dd></dl> 
2027          >>> #endif 
2028          >>> for (name, val, summary) in accessors: 
2029              <dt>$name$ Method:</dt> 
2030              <dd>$val$ 
2031          >>>     if summary: 
2032                  - $summary$ 
2033          >>>     #endif 
2034              </dd> 
2035          >>> #endfor 
2036            </dd></dl> 
2037          </td></tr></table> 
2038          </div> 
2039          ''') 
2040           
2041           
2042      write_variable_details_entry = compile_template( 
2043          ''' 
2044          write_variable_details_entry(self, out, var_doc, descr, div_class) 
2045          ''', 
2046           
2047          ''' 
2048          <a name="$var_doc.name$"></a> 
2049          <div$div_class$> 
2050          <table width="100%" class="var-details" bgcolor="#e0e0e0"><tr><td> 
2051            <h3>$var_doc.name$</h3> 
2052            $descr$ 
2053            <dl><dt></dt><dd> 
2054          >>> if var_doc.type_descr not in (None, UNKNOWN): 
2055              <dl><dt>Type:</dt> 
2056                <dd>$self.type_descr(var_doc, indent=6)$</dd></dl> 
2057          >>> #endif 
2058          >>> tooltip = self.variable_tooltip(var_doc) 
2059          >>> if var_doc.value is not UNKNOWN: 
2060              <dl$tooltip$><dt>Value:</dt> 
2061                <dd><table><tr><td><pre class="variable"> 
2062          $self.pprint_value(var_doc.value)$ 
2063                </pre></td></tr></table></dd> 
2064              </dl> 
2065          >>> #endif 
2066            </dd></dl> 
2067          </td></tr></table> 
2068          </div> 
2069          ''') 
2070           
2071   
2072      _variable_linelen = 70 
2073      _variable_maxlines = 3 
2074      _variable_tooltip_linelen = 70 
2090   
2091 -    def pprint_value(self, val_doc, multiline=True, summary_linelen=0): 
 2101   
2102 -    def pprint_pyval(self, pyval, multiline=True, summary_linelen=0): 
 2103           
2104           
2105           
2106           
2107           
2108          if (type(pyval) is types.IntType or type(pyval) is types.FloatType or 
2109              type(pyval) is types.NoneType or type(pyval) is types.ComplexType): 
2110               
2111              vstr = repr(pyval) 
2112              return vstr + ' ' * (self._variable_linelen-len(vstr)) 
2113   
2114           
2115           
2116          elif type(pyval) is types.StringType: 
2117              vstr = repr(pyval) 
2118              if vstr.find(r'\n') >= 0 and multiline: 
2119                  body = vstr[1:-1].replace(r'\n', '\n') 
2120                  vstr = ('<span class="variable-quote">'+vstr[0]*3+'</span>'+ 
2121                          plaintext_to_html(body) + 
2122                         '<span class="variable-quote">'+vstr[0]*3+'</span>') 
2123                        
2124              else: 
2125                  vstr = ('<span class="variable-quote">'+vstr[0]+'</span>'+ 
2126                          plaintext_to_html(vstr[1:-1])+ 
2127                         '<span class="variable-quote">'+vstr[0]+'</span>') 
2128   
2129           
2130           
2131           
2132          elif type(pyval) is types.TupleType or type(pyval) is types.ListType: 
2133              try: vstr = repr(pyval) 
2134              except: vstr = '...' 
2135              if multiline and len(vstr) > self._variable_linelen: 
2136                  vstr = pprint.pformat(pyval[:self._variable_maxlines+1]) 
2137              vstr = plaintext_to_html(vstr) 
2138          elif type(pyval) is type({}): 
2139              try: vstr = repr(pyval) 
2140              except: vstr = '...' 
2141              if multiline and len(vstr) > self._variable_linelen: 
2142                  if len(pyval) < self._variable_maxlines+50: 
2143                      vstr = pprint.pformat(pyval) 
2144                  else: 
2145                      shortval = {} 
2146                      for (k,v) in pyval.items()[:self._variable_maxlines+1]: 
2147                          shortval[k]=v 
2148                      vstr = pprint.pformat(shortval) 
2149              vstr = plaintext_to_html(vstr) 
2150   
2151           
2152          elif type(pyval).__name__ == 'SRE_Pattern': 
2153              try: vstr = colorize_re(pyval) 
2154              except TypeError, sre_constants.error: 
2155                  try: vstr = plaintext_to_html(repr(pyval)) 
2156                  except: vstr = '...' 
2157              
2158           
2159          else: 
2160              try: vstr = plaintext_to_html(repr(pyval)) 
2161              except: vstr = '...' 
2162   
2163           
2164           
2165          if not multiline: 
2166              vstr = vstr.replace('\n', '') 
2167               
2168              vstr = vstr.replace(' ', ' ') 
2169              vstr = vstr.replace('<span ', '<span ') 
2170              vstr = self._linewrap_html(vstr, summary_linelen, 1) 
2171              return '<code>%s</code>\n' % vstr 
2172   
2173           
2174          return self._linewrap_html(vstr, self._variable_linelen, 
2175                                     self._variable_maxlines) 
 2176   
2178          """ 
2179          Add line-wrapping to the HTML string C{s}.  Line length is 
2180          determined by C{linelen}; and the maximum number of 
2181          lines to display is determined by C{maxlines}.  This 
2182          function treats HTML entities (e.g., C{&}) as single 
2183          characters; and ignores HTML tags (e.g., C{<p>}). 
2184          """ 
2185          LINEWRAP_MARKER = r'<span class="variable-linewrap">\</span>' 
2186          ELLIPSIS_MARKER = r'<span class="variable-ellipsis">...</span>' 
2187          
2188          open_elements = []  
2189          lines = [] 
2190          start = end = cnum = 0 
2191          while len(lines) <= maxlines and end < len(s): 
2192               
2193              if s[end] == '<': 
2194                  newend = s.find('>', end) 
2195                  tag = s[end+1:newend] 
2196                  if tag[-1]!="/": 
2197                       
2198                      tagname = tag.split(None,1)[0] 
2199                      if tagname[0] == "/": 
2200                          open_elements.pop() 
2201                      else: 
2202                          open_elements.append(tagname) 
2203                  end = newend 
2204                  cnum -= 1 
2205   
2206               
2207              elif s[end] == '&': 
2208                  end = s.find(';', end) 
2209   
2210               
2211              cnum += 1 
2212              end += 1 
2213   
2214               
2215              if s[end-1] == '\n': 
2216                  lines.append(s[start:end-1]) 
2217                  cnum = 0 
2218                  start = end 
2219   
2220               
2221              if cnum == linelen and end<len(s) and s[end] != '\n': 
2222                  if maxlines == 1: 
2223                      closing_tags = "" 
2224                      for tag in open_elements: 
2225                          closing_tags += "</%s>" % (tag,) 
2226                      return s[start:end]+closing_tags+ELLIPSIS_MARKER 
2227                  lines.append(s[start:end]+LINEWRAP_MARKER) 
2228                  cnum = 0 
2229                  start = end 
2230   
2231           
2232          if end == len(s): 
2233              lines.append(s[start:end]) 
2234   
2235           
2236          if len(lines) > maxlines: 
2237              closing_tags = "" 
2238              for tag in open_elements: 
2239                  closing_tags += "</%s>" % (tag,) 
2240              lines[-1] = closing_tags+ELLIPSIS_MARKER 
2241              cnum = 3 
2242   
2243           
2244          lines[-1] += ' '*(linelen-cnum+1) 
2245   
2246          return ('\n').join(lines) 
 2247   
2248       
2249       
2250       
2251   
2252 -    def base_tree(self, doc, width=None, postfix='', context=None): 
 2253          """ 
2254          @return: The HTML code for a class's base tree.  The tree is 
2255              drawn 'upside-down' and right justified, to allow for 
2256              multiple inheritance. 
2257          @rtype: C{string} 
2258          """ 
2259          if context is None: 
2260              context = doc 
2261          if width == None: width = self.find_tree_width(doc, context) 
2262          if isinstance(doc, ClassDoc) and doc.bases != UNKNOWN: 
2263              bases = doc.bases 
2264          else: 
2265              bases = [] 
2266           
2267          if postfix == '': 
2268               
2269              s = (' '*(width-2) + '<strong class="uidshort">'+ 
2270                     self.contextual_label(doc, context)+'</strong>\n') 
2271          else: s = '' 
2272          for i in range(len(bases)-1, -1, -1): 
2273              base = bases[i] 
2274              label = self.contextual_label(base, context) 
2275              s = (' '*(width-4-len(label)) + self.href(base, label) 
2276                     +' --+'+postfix+'\n' +  
2277                     ' '*(width-4) + 
2278                     '   |'+postfix+'\n' + 
2279                     s) 
2280              if i != 0: 
2281                  s = (self.base_tree(base, width-4, '   |'+postfix)+s) 
2282              else: 
2283                  s = (self.base_tree(base, width-4, '    '+postfix)+s) 
2284          return s 
 2285   
2287          """ 
2288          Helper function for L{base_tree}. 
2289          @return: The width of a base tree, when drawn 
2290              right-justified.  This is used by L{base_tree} to 
2291              determine how far to indent lines of the base tree. 
2292          @rtype: C{int} 
2293          """ 
2294          if not isinstance(doc, ClassDoc): return 2 
2295          if doc.bases == UNKNOWN: return 2 
2296          width = 2 
2297          for base in doc.bases: 
2298              width = max(width, len(self.contextual_label(base, context))+4, 
2299                          self.find_tree_width(base, context)+4) 
2300          return width 
 2301   
2302 -    def contextual_label(self, doc, context): 
 2303          """ 
2304          Return the label for L{doc} to be shown in C{context}. 
2305          """ 
2306          context = context.canonical_name 
2307          if context is not UNKNOWN: 
2308              context = context.container() 
2309               
2310          return str(doc.canonical_name.contextualize(context)) 
 2311           
2312       
2313       
2314       
2315   
2318           
2319          if isinstance(api_doc, VariableDoc): 
2320              func_doc = api_doc.value 
2321               
2322              if api_doc.value in (None, UNKNOWN): 
2323                  return (('<span class="%s"><span class="%s-name">%s'+ 
2324                           '</span>(...)</span>') % 
2325                          (css_class, css_class, api_doc.name)) 
2326               
2327              if link_name: 
2328                  name = self.href(api_doc, css_class=css_class+'-name') 
2329              else: 
2330                  name = ('<span class="%s-name">%s</span>' % 
2331                          (css_class, api_doc.name)) 
2332          else: 
2333              func_doc = api_doc 
2334              name = self.href(api_doc, css_class=css_class+'-name') 
2335               
2336          if func_doc.posargs == UNKNOWN: 
2337              args = ['...'] 
2338          else: 
2339              args = [self.func_arg(n, d, css_class) for (n, d) 
2340                      in zip(func_doc.posargs, func_doc.posarg_defaults)] 
2341          if func_doc.vararg: 
2342              if func_doc.vararg == '...': 
2343                  args.append('<span class="%s-arg">...</span>' % css_class) 
2344              else: 
2345                  args.append('<span class="%s-arg">*%s</span>' % 
2346                              (css_class, func_doc.vararg)) 
2347          if func_doc.kwarg: 
2348              args.append('<span class="%s-arg">**%s</span>' % 
2349                          (css_class, func_doc.kwarg)) 
2350   
2351          return ('<span class="%s">%s(%s)</span>' % 
2352                  (css_class, name, ',\n        '.join(args))) 
 2353   
2354       
2355 -    def func_arg(self, name, default, css_class): 
 2370   
2372          if isinstance(arg, basestring): 
2373              return arg 
2374          elif len(arg) == 1: 
2375              return '(%s,)' % self._arg_name(arg[0]) 
2376          else: 
2377              return '(%s)' % (', '.join([self._arg_name(a) for a in arg])) 
 2378   
2379   
2380       
2381   
2382       
2383       
2384       
2385           
2387          assert isinstance(doc, NamespaceDoc) 
2388          imports = doc.select_variables(imported=True, 
2389                                         public=self._public_filter) 
2390          if not imports: return 
2391   
2392          out('<p class="imports">') 
2393          out('<span class="varlist-header">Imports:</span>\n  ') 
2394          out(',\n  '.join([self._import(v, doc) for v in imports])) 
2395          out('\n</p>\n') 
 2396   
2397 -    def _import(self, var_doc, context): 
 2405               
2406       
2407       
2408       
2409           
2410       
2411       
2412       
2413   
2415          if not self.module_list: return 
2416   
2417           
2418          out('<ul>\n') 
2419          for doc in self.module_list: 
2420              if (doc.package in (None, UNKNOWN) or 
2421                  doc.package not in self.module_set): 
2422                  self.write_module_tree_item(out, doc) 
2423          out('</ul>\n') 
 2424       
2439   
2459   
2460       
2461       
2462       
2463   
2464   
2466          """ 
2467          Write HTML code for a nested list showing the base/subclass 
2468          relationships between all documented classes.  Each element of 
2469          the top-level list is a class with no (documented) bases; and 
2470          under each class is listed all of its subclasses.  Note that 
2471          in the case of multiple inheritance, a class may appear 
2472          multiple times.  This is used by L{write_trees} to write 
2473          the class hierarchy. 
2474           
2475          @todo: For multiple inheritance, don't repeat subclasses the 
2476              second time a class is mentioned; instead, link to the 
2477              first mention. 
2478          """ 
2479           
2480          if not self.class_list: return 
2481           
2482           
2483           
2484           
2485          class_set = self.class_set.copy() 
2486          for doc in self.class_list: 
2487              if doc.bases != UNKNOWN: 
2488                  for base in doc.bases: 
2489                      if base not in class_set: 
2490                          if isinstance(base, ClassDoc): 
2491                              class_set.update(base.mro()) 
2492                          else: 
2493                               
2494                              pass 
2495                               
2496    
2497          out('<ul>\n') 
2498          for doc in sorted(class_set): 
2499              if doc.bases != UNKNOWN and len(doc.bases)==0: 
2500                  self.write_class_tree_item(out, doc, class_set) 
2501          out('</ul>\n') 
 2502   
2503      write_class_tree_item = compile_template( 
2504          ''' 
2505          write_class_tree_item(self, out, doc, class_set) 
2506          ''', 
2507           
2508          ''' 
2509          >>> if doc.summary in (None, UNKNOWN): 
2510              <li> <strong class="uidlink">$self.href(doc)$</strong> 
2511          >>> else: 
2512              <li> <strong class="uidlink">$self.href(doc)$</strong>: 
2513                <em class="summary">$self.description(doc.summary, doc, 8)$</em> 
2514          >>> # endif 
2515          >>> if doc.subclasses: 
2516              <ul> 
2517          >>>   for subclass in set(doc.subclasses): 
2518          >>>     if subclass in class_set: 
2519          >>>       self.write_class_tree_item(out, subclass, class_set) 
2520          >>>     #endif 
2521          >>>   #endfor 
2522              </ul> 
2523          >>> #endif 
2524              </li> 
2525          ''') 
2526           
2527       
2528       
2529       
2530       
2531   
2533          """ 
2534          Write HTML code containing descriptions of any standard markup 
2535          fields that are defined by the given L{APIDoc} object (such as 
2536          C{@author} and C{@todo} fields). 
2537   
2538          @param doc: The L{APIDoc} object containing the API documentation 
2539              for the object whose standard markup fields should be 
2540              described. 
2541          """ 
2542          fields = [] 
2543          field_values = {} 
2544           
2545           
2546           
2547          for (field, arg, descr) in doc.metadata: 
2548              if field not in field_values: 
2549                  fields.append(field) 
2550              if field.takes_arg: 
2551                  subfields = field_values.setdefault(field,{}) 
2552                  subfields.setdefault(arg,[]).append(descr) 
2553              else: 
2554                  field_values.setdefault(field,[]).append(descr) 
2555   
2556          for field in fields: 
2557              if field.takes_arg: 
2558                  for arg, descrs in field_values[field].items(): 
2559                      self.write_standard_field(out, doc, field, descrs, arg) 
2560                                                 
2561              else: 
2562                  self.write_standard_field(out, doc, field, field_values[field]) 
 2563   
2564      write_standard_field = compile_template( 
2565          """ 
2566          write_standard_field(self, out, doc, field, descrs, arg='') 
2567           
2568          """, 
2569           
2570          """ 
2571          >>> if arg: arglabel = ' (%s)' % arg 
2572          >>> else: arglabel = '' 
2573          >>>   if len(descrs) == 1: 
2574                <p><strong>$field.singular+arglabel$:</strong> 
2575                  $self.description(descrs[0], doc, 8)$ 
2576                </p> 
2577          >>>   elif field.short: 
2578                <dl><dt>$field.plural+arglabel$:</dt> 
2579                  <dd> 
2580          >>>     for descr in descrs[:-1]: 
2581                    $self.description(descr, doc, 10)$, 
2582          >>>     # end for 
2583                    $self.description(descrs[-1], doc, 10)$ 
2584                  </dd> 
2585                </dl> 
2586          >>>   else: 
2587                <p><strong>$field.plural+arglabel$:</strong> 
2588                <ul> 
2589          >>>     for descr in descrs: 
2590                  <li> 
2591                  $self.description(descr, doc, 8)$ 
2592                  </li> 
2593          >>>   # end for 
2594                </ul> 
2595          >>>   # end else 
2596          >>> # end for 
2597          """) 
2598           
2599   
2600       
2601       
2602       
2603       
2605          """ 
2606          A helper function for L{_extract_term_index}. 
2607           
2608          For each index term M{t} with key M{k} in C{parsed_docstring}, 
2609          modify C{terms} and C{links} as follows: 
2610            - Set C{terms[M{k}] = t} (if C{terms[M{k}]} doesn't exist). 
2611            - Append C{link} to C{links[M{k}]}. 
2612          """ 
2613          if parsed_docstring in (None, UNKNOWN): return 
2614          for term in parsed_docstring.index_terms(): 
2615              key = self._term_index_to_anchor(term) 
2616              if not terms.has_key(key): 
2617                  terms[key] = term 
2618                  links[key] = [] 
2619              links[key].append(link) 
 2620   
2622          """ 
2623          Given the name of an inline index item, construct a URI anchor. 
2624          These anchors are used to create links from the index page to each 
2625          index item. 
2626          """ 
2627           
2628           
2629          s = re.sub(r'\s\s+', '-', term.to_plaintext(None)) 
2630          return "index-"+re.sub("[^a-zA-Z0-9]", "_", s) 
 2631   
2633          """ 
2634          Extract the set of terms that should be indexed from all 
2635          documented docstrings.  Return the extracted set as a 
2636          list of tuples of the form C{(key, term, [links])}. 
2637          This list is used by L{write_indices()} to construct the 
2638          term index. 
2639          @rtype: C{list} of C{(string, ParsedDocstring, list of ValueDoc)} 
2640          """ 
2641          terms = {} 
2642          links = {} 
2643          for doc in self.valdocs: 
2644              self._get_index_terms(doc.descr, doc, terms, links) 
2645              if doc.metadata not in (None, UNKNOWN): 
2646                  for (field, arg, descr) in doc.metadata: 
2647                      self._get_index_terms(descr, doc, terms, links) 
2648               
2649              if isinstance(doc, NamespaceDoc): 
2650                  for var in doc.variables.values(): 
2651                      self._get_index_terms(var.descr, var, terms, links) 
2652                      for (field, arg, descr) in var.metadata: 
2653                          self._get_index_terms(descr, var, terms, links) 
2654              elif isinstance(doc, RoutineDoc): 
2655                  self._get_index_terms(doc.return_descr, doc, terms, links) 
2656                  self._get_index_terms(doc.return_type, doc, terms, links) 
2657                  if doc.arg_descrs not in (None, UNKNOWN): 
2658                      for arg, descr in doc.arg_descrs: 
2659                          self._get_index_terms(descr, doc, terms, links) 
2660                  if doc.arg_types not in (None, UNKNOWN): 
2661                      for arg, descr in doc.arg_types.items(): 
2662                          self._get_index_terms(descr, doc, terms, links) 
2663                  if doc.exception_descrs not in (None, UNKNOWN): 
2664                      for excname, descr in doc.exception_descrs: 
2665                          self._get_index_terms(descr, doc, terms, links) 
2666              elif isinstance(doc, PropertyDoc): 
2667                  self._get_index_terms(doc.type_descr, doc, terms, links) 
2668                       
2669           
2670          keys = terms.keys() 
2671          keys.sort() 
2672          return [(k, terms[k], links[k]) for k in keys] 
 2673                       
2674       
2675       
2676       
2677   
2678       
2679       
2680       
2681      write_table_header = compile_template( 
2682          ''' 
2683          write_table_header(self, out, css_class, heading=None, \ 
2684                             private_link=True) 
2685          ''', 
2686           
2687          ''' 
2688          >>> if heading is not None: 
2689          >>>     anchor = "section-%s" % re.sub("\W", "", heading) 
2690          <!-- ==================== $heading.upper()$ ==================== --> 
2691          <a name="$anchor$"></a> 
2692          >>> #endif 
2693          <table class="$css_class$" border="1" cellpadding="3" 
2694                 cellspacing="0" width="100%" bgcolor="white"> 
2695          >>> if heading is not None: 
2696          <tr bgcolor="#70b0f0" class="$css_class$"> 
2697          >>>     if private_link: 
2698            <td colspan="2"> 
2699              <table border="0" cellpadding="0" cellspacing="0" width="100%"> 
2700                <tr valign="top"> 
2701                  <th align="left" class="$css_class$">$heading$</th> 
2702                  <td align="right" valign="top" 
2703                   ><span class="options">[<a href="#$anchor$" 
2704                   class="privatelink" onclick="toggle_private();" 
2705                   >hide private</a>]</span></td> 
2706                </tr> 
2707              </table> 
2708            </td> 
2709          >>>     else: 
2710            <th align="left" colspan="2" class="$css_class$">$heading$</th> 
2711          >>>     #endif 
2712          </tr> 
2713          >>> #endif 
2714          ''') 
2715           
2716   
2717      TABLE_FOOTER = '</table>\n' 
2718   
2719      PRIVATE_LINK = ''' 
2720      <span class="options">[<a href="javascript: void(0);" class="privatelink" 
2721      onclick="toggle_private();">hide private</a>]</span> 
2722      '''.strip() 
2723   
2724      write_group_header = compile_template( 
2725          ''' 
2726          write_group_header(self, out, group, tr_class='') 
2727          ''', 
2728           
2729          ''' 
2730          <tr bgcolor="#e8f0f8" $tr_class$> 
2731            <th colspan="2" class="group" 
2732              >    $group$</th></tr> 
2733          ''') 
2734           
2735   
2736 -    def url(self, obj): 
 2737          """ 
2738          Return the URL for the given object, which can be a 
2739          C{VariableDoc}, a C{ValueDoc}, or a C{DottedName}. 
2740          """ 
2741           
2742          if isinstance(obj, ModuleDoc): 
2743              if obj not in self.module_set: return None 
2744              return urllib.quote('%s'%obj.canonical_name) + '-module.html' 
2745           
2746          elif isinstance(obj, ClassDoc): 
2747              if obj not in self.class_set: return None 
2748              return urllib.quote('%s'%obj.canonical_name) + '-class.html' 
2749           
2750          elif isinstance(obj, VariableDoc): 
2751              val_doc = obj.value 
2752              if isinstance(val_doc, (ModuleDoc, ClassDoc)): 
2753                  return self.url(val_doc) 
2754              elif obj.container in (None, UNKNOWN): 
2755                  if val_doc in (None, UNKNOWN): return None 
2756                  return self.url(val_doc) 
2757              elif obj.is_imported == True: 
2758                  if obj.imported_from is not UNKNOWN: 
2759                      return self.url(obj.imported_from) 
2760                  else: 
2761                      return None 
2762              else: 
2763                  container_url = self.url(obj.container) 
2764                  if container_url is None: return None 
2765                  return '%s#%s' % (container_url, urllib.quote('%s'%obj.name)) 
2766           
2767          elif isinstance(obj, ValueDoc): 
2768              container = self.docindex.container(obj) 
2769              if container is None: 
2770                  return None  
2771              else: 
2772                  container_url = self.url(container) 
2773                  if container_url is None: return None 
2774                  anchor = urllib.quote('%s'%obj.canonical_name[-1]) 
2775                  return '%s#%s' % (container_url, anchor) 
2776           
2777          elif isinstance(obj, DottedName): 
2778              val_doc = self.docindex.get_valdoc(obj) 
2779              if val_doc is None: return None 
2780              return self.url(val_doc) 
2781           
2782          elif obj == 'indices': 
2783              return 'indices.html' 
2784          elif obj == 'help': 
2785              return 'help.html' 
2786          elif obj == 'trees': 
2787              return 'trees.html' 
2788          else: 
2789              raise ValueError, "Don't know what to do with %r" % obj 
 2790   
2792          if not self._incl_sourcecode: 
2793              return '' 
2794          url = self.pysrc_url(api_doc) 
2795          if url is not None:  
2796              return ('<span class="codelink"><a href="%s">source ' 
2797                      'code</a></span>' % url) 
2798          else: 
2799              return '' 
 2800       
2802          if isinstance(api_doc, VariableDoc): 
2803              if api_doc.value not in (None, UNKNOWN): 
2804                  return pysrc_link(api_doc.value) 
2805              else: 
2806                  return None 
2807          elif isinstance(api_doc, ModuleDoc): 
2808              if api_doc in self.modules_with_sourcecode: 
2809                  return ('%s-pysrc.html' % 
2810                         urllib.quote('%s' % api_doc.canonical_name)) 
2811              else: 
2812                  return None 
2813          else: 
2814              module = api_doc.defining_module 
2815              if module == UNKNOWN: return None 
2816              module_pysrc_url = self.pysrc_url(module) 
2817              if module_pysrc_url is None: return None 
2818              module_name = module.canonical_name 
2819              if not module_name.dominates(api_doc.canonical_name, True): 
2820                  log.debug('%r is in %r but name does not dominate' % 
2821                            (api_doc, module)) 
2822                  return module_pysrc_url 
2823              mname_len = len(module.canonical_name) 
2824              anchor = '%s' % api_doc.canonical_name[mname_len:] 
2825              return '%s#%s' % (module_pysrc_url, urllib.quote(anchor)) 
2826           
2827           
2828          return None 
 2829   
2830       
2831 -    def href(self, target, label=None, css_class=None, context=None): 
 2832          """ 
2833          Return the HTML code for an HREF link to the given target 
2834          (which can be a C{VariableDoc}, a C{ValueDoc}, or a 
2835          C{DottedName}. 
2836          If a C{NamespaceDoc} C{context} is specified, the target label is 
2837          contextualized to it. 
2838          """ 
2839          assert isinstance(target, (APIDoc, DottedName)) 
2840   
2841           
2842          if label is None: 
2843              if isinstance(target, VariableDoc): 
2844                  label = target.name 
2845              elif (isinstance(target, ValueDoc) and 
2846                    target.canonical_name is not UNKNOWN): 
2847                  label = target.canonical_name 
2848              elif isinstance(target, DottedName): 
2849                  label = target 
2850              else: 
2851                  raise ValueError("Unable to find a label for %r" % target) 
2852                   
2853              if context is not None and isinstance(label, DottedName): 
2854                  label = label.contextualize(context.canonical_name.container()) 
2855                   
2856              label = plaintext_to_html(str(label)) 
2857               
2858               
2859              if label.startswith('script-'): 
2860                  label = label[7:] + ' (script)' 
2861              if label.startswith('??'): 
2862                  label = '<i>unreachable</i>' + label[2:] 
2863                  label = re.sub(r'-\d+$', '', label) 
2864   
2865           
2866          url = self.url(target) 
2867          if url is None: return label 
2868   
2869           
2870          if css_class is None: 
2871              css = '' 
2872          else: 
2873              css = ' class="%s"' % css_class 
2874   
2875          return '<a href="%s"%s>%s</a>' % (url, css, label) 
 2876   
2877 -    def summary(self, api_doc, indent=0): 
 2885           
2886 -    def descr(self, api_doc, indent=0): 
 2894   
2903   
2904 -    def rtype(self, api_doc, indent=0): 
 2911   
2919   
2921          if parsed_docstring in (None, UNKNOWN): return '' 
2922          linker = _HTMLDocstringLinker(self, where) 
2923          s = parsed_docstring.to_html(linker, indent=indent, 
2924                                       directory=self._directory, 
2925                                       docindex=self.docindex, 
2926                                       context=where).strip() 
2927          if self._mark_docstrings: 
2928              s = '<span class="docstring">%s</span><!--end docstring-->' % s 
2929          return s 
 2930   
2931       
2932 -    def description(self, parsed_docstring, where=None, indent=0): 
 2933          assert isinstance(where, (APIDoc, type(None))) 
2934          if parsed_docstring in (None, UNKNOWN): return '' 
2935          linker = _HTMLDocstringLinker(self, where) 
2936          descr = parsed_docstring.to_html(linker, indent=indent, 
2937                                           directory=self._directory, 
2938                                           docindex=self.docindex, 
2939                                           context=where).strip() 
2940          if descr == '': return ' ' 
2941          return descr 
 2942   
2943       
2945          if isinstance(doc, ModuleDoc) and doc.is_package == True: 
2946              return 'Package' 
2947          elif (isinstance(doc, ModuleDoc) and 
2948                doc.canonical_name[0].startswith('script')): 
2949              return 'Script' 
2950          elif isinstance(doc, ModuleDoc): 
2951              return 'Module' 
2952          elif isinstance(doc, ClassDoc): 
2953              return 'Class' 
2954          elif isinstance(doc, ClassMethodDoc): 
2955              return 'Class Method' 
2956          elif isinstance(doc, StaticMethodDoc): 
2957              return 'Static Method' 
2958          elif isinstance(doc, RoutineDoc): 
2959              if isinstance(self.docindex.container(doc), ClassDoc): 
2960                  return 'Method' 
2961              else: 
2962                  return 'Function' 
2963          else: 
2964              return 'Variable' 
 2965           
 2973   
2975 -    def __init__(self, htmlwriter, container): 
 2976          self.htmlwriter = htmlwriter 
2977          self.docindex = htmlwriter.docindex 
2978          self.container = container 
 2979           
2984       
2986           
2987          if label is None: label = plaintext_to_html(identifier) 
2988   
2989           
2990          doc = self.docindex.find(identifier, self.container) 
2991   
2992           
2993          if doc is None: 
2994              return '<code class="link">%s</code>' % label 
2995          else: 
2996              return self.htmlwriter.href(doc, label, 'link') 
 2997   
2998       
3000          if isinstance(identifier, (basestring, DottedName)): 
3001              doc = self.docindex.find(identifier, self.container) 
3002              if doc: 
3003                  return self.htmlwriter.url(doc) 
3004              else: 
3005                   
3006                   
3007                  failed_xrefs = self.htmlwriter._failed_xrefs 
3008                  context = self.container.canonical_name 
3009                  failed_xrefs.setdefault(identifier,{})[context] = 1 
3010               
3011          elif isinstance(identifier, APIDoc): 
3012              return self.htmlwriter.url(identifier) 
3013              doc = identifier 
3014               
3015          else: 
3016              raise TypeError('Expected string or APIDoc') 
  3017