Example #1
0
def _unreachable_name_for(val_doc, docindex):
    assert isinstance(val_doc, ValueDoc)

    # [xx] (when) does this help?
    if (isinstance(val_doc, ModuleDoc) and len(val_doc.canonical_name) == 1
            and val_doc.package is None):
        for root_val in docindex.root:
            if root_val.canonical_name == val_doc.canonical_name:
                if root_val != val_doc:
                    log.error("Name conflict: %r vs %r" % (val_doc, root_val))
                break
        else:
            return val_doc.canonical_name, -1000

    # Assign it an 'unreachable' name:
    if (val_doc.pyval is not UNKNOWN and hasattr(val_doc.pyval, '__name__')):
        try:
            name = DottedName(DottedName.UNREACHABLE, val_doc.pyval.__name__)
        except DottedName.InvalidDottedName:
            name = DottedName(DottedName.UNREACHABLE)
    else:
        name = DottedName(DottedName.UNREACHABLE)

    # Uniquify the name.
    if name in _unreachable_names:
        n = 2
        while DottedName('%s-%s' % (name, n)) in _unreachable_names:
            n += 1
        name = DottedName('%s-%s' % (name, n))
    _unreachable_names.add(name)

    return name, -10000
Example #2
0
 def _write(self, write_func, directory, filename, *args):
     # Display our progress.
     self._files_written += 1
     log.progress(self._files_written/self._num_files, filename)
     
     path = os.path.join(directory, filename)
     if self._encoding == 'utf8':
         f = codecs.open(path, 'w', 'utf-8')
         write_func(f.write, *args)
         f.close()
     else:
         result = []
         write_func(result.append, *args)
         s = u''.join(result)
         try:
             s = s.encode(self._encoding)
         except UnicodeError:
             log.error("Output could not be represented with the "
                       "given encoding (%r).  Unencodable characters "
                       "will be displayed as '?'.  It is recommended "
                       "that you use a different output encoding (utf8, "
                       "if it's supported by latex on your system).")
             s = s.encode(self._encoding, 'replace')
         f = open(path, 'w')
         f.write(s)
         f.close()
Example #3
0
    def _write(self, write_func, directory, filename, *args):
        # Display our progress.
        self._files_written += 1
        log.progress(self._files_written / self._num_files, filename)

        path = os.path.join(directory, filename)
        if self._encoding == 'utf-8':
            f = codecs.open(path, 'w', 'utf-8')
            write_func(f.write, *args)
            f.close()
        else:
            result = []
            write_func(result.append, *args)
            s = u''.join(result)
            try:
                s = s.encode(self._encoding)
            except UnicodeError:
                log.error("Output could not be represented with the "
                          "given encoding (%r).  Unencodable characters "
                          "will be displayed as '?'.  It is recommended "
                          "that you use a different output encoding (utf-8, "
                          "if it's supported by latex on your system)." %
                          self._encoding)
                s = s.encode(self._encoding, 'replace')
            f = open(path, 'w')
            f.write(s)
            f.close()
Example #4
0
    def add_module(self, name, check=0):
        from epydoc.util import is_package_dir, is_pyname, is_module_file
        from epydoc.docintrospecter import get_value_from_name
        from epydoc.docintrospecter import get_value_from_filename

        if (os.path.isfile(name) or is_package_dir(name) or is_pyname(name)):
            # Check that it's a good module, if requested.
            if check:
                try:
                    if is_module_file(name) or is_package_dir(name):
                        get_value_from_filename(name)
                    elif os.path.isfile(name):
                        get_value_from_scriptname(name)
                    else:
                        get_value_from_name(name)
                except ImportError as e:
                    log.error(e)
                    self._update_messages()
                    self._root.bell()
                    return
            
            # Add the module to the list of modules.
            self._module_list.insert('end', name)
            self._module_list.yview('end')
        else:
            log.error("Couldn't find %r" % name)
            self._update_messages()
            self._root.bell()
Example #5
0
def _unreachable_name_for(val_doc, docindex):
    assert isinstance(val_doc, ValueDoc)
    
    # [xx] (when) does this help?
    if (isinstance(val_doc, ModuleDoc) and
        len(val_doc.canonical_name)==1 and val_doc.package is None):
        for root_val in docindex.root:
            if root_val.canonical_name == val_doc.canonical_name:
                if root_val != val_doc: 
                    log.error("Name conflict: %r vs %r" %
                              (val_doc, root_val))
                break
        else:
            return val_doc.canonical_name, -1000

    # Assign it an 'unreachable' name:
    if (val_doc.pyval is not UNKNOWN and
          hasattr(val_doc.pyval, '__name__')):
        try:
            name = DottedName(DottedName.UNREACHABLE,
                              val_doc.pyval.__name__)
        except DottedName.InvalidDottedName:
            name = DottedName(DottedName.UNREACHABLE)
    else:
        name = DottedName(DottedName.UNREACHABLE)

    # Uniquify the name.
    if name in _unreachable_names:
        n = 2
        while DottedName('%s-%s' % (name,n)) in _unreachable_names:
            n += 1
        name = DottedName('%s-%s' % (name,n))
    _unreachable_names.add(name)
    
    return name, -10000
Example #6
0
    def open(self, prjfile):
        from epydoc.docwriter.html_css import STYLESHEETS

        self._filename = prjfile
        try:
            opts = load(open(prjfile, "r"))

            modnames = list(opts.get("modules", []))
            modnames.sort()
            self._module_list.delete(0, "end")
            for name in modnames:
                self.add_module(name)
            self._module_entry.delete(0, "end")

            self._name_entry.delete(0, "end")
            if opts.get("prj_name"):
                self._name_entry.insert(0, opts["prj_name"])

            self._url_entry.delete(0, "end")
            if opts.get("prj_url"):
                self._url_entry.insert(0, opts["prj_url"])

            self._docformat_var.set(opts.get("docformat", "epytext"))
            self._inheritance_var.set(opts.get("inheritance", "grouped"))
            self._introspect_or_parse_var.set(opts.get("introspect_or_parse", "both"))

            self._help_entry.delete(0, "end")
            if opts.get("help") is None:
                self._help_var.set("default")
            else:
                self._help_var.set("-other-")
                self._help_entry.insert(0, opts.get("help"))

            self._out_entry.delete(0, "end")
            self._out_entry.insert(0, opts.get("target", "html"))

            self._frames_var.set(opts.get("frames", 1))
            self._private_var.set(opts.get("private", 1))
            self._imports_var.set(opts.get("show_imports", 0))

            self._css_entry.delete(0, "end")
            if opts.get("css", "default") in STYLESHEETS.keys():
                self._css_var.set(opts.get("css", "default"))
            else:
                self._css_var.set("-other-")
                self._css_entry.insert(0, opts.get("css", "default"))

            # if opts.get('private_css', 'default') in STYLESHEETS.keys():
            #    self._private_css_var.set(opts.get('private_css', 'default'))
            # else:
            #    self._private_css_var.set('-other-')
            #    self._css_entry.insert(0, opts.get('private_css', 'default'))

        except Exception, e:
            log.error("Error opening %s: %s" % (prjfile, e))
            self._root.bell()
Example #7
0
File: gui.py Project: B-Rich/epydoc
    def open(self, prjfile):
        from epydoc.docwriter.html_css import STYLESHEETS
        self._filename = prjfile
        try:
            opts = load(open(prjfile, 'r'))
            
            modnames = list(opts.get('modules', []))
            modnames.sort()
            self._module_list.delete(0, 'end')
            for name in modnames:
                self.add_module(name)
            self._module_entry.delete(0, 'end')
                
            self._name_entry.delete(0, 'end')
            if opts.get('prj_name'):
                self._name_entry.insert(0, opts['prj_name'])
                
            self._url_entry.delete(0, 'end')
            if opts.get('prj_url'):
                self._url_entry.insert(0, opts['prj_url'])

            self._docformat_var.set(opts.get('docformat', 'epytext'))
            self._inheritance_var.set(opts.get('inheritance', 'grouped'))
            self._introspect_or_parse_var.set(
                opts.get('introspect_or_parse', 'both'))

            self._help_entry.delete(0, 'end')
            if opts.get('help') is None:
                self._help_var.set('default')
            else:
                self._help_var.set('-other-')
                self._help_entry.insert(0, opts.get('help'))
                
            self._out_entry.delete(0, 'end')
            self._out_entry.insert(0, opts.get('target', 'html'))

            self._frames_var.set(opts.get('frames', 1))
            self._private_var.set(opts.get('private', 1))
            self._imports_var.set(opts.get('show_imports', 0))
            
            self._css_entry.delete(0, 'end')
            if opts.get('css', 'default') in list(STYLESHEETS.keys()):
                self._css_var.set(opts.get('css', 'default'))
            else:
                self._css_var.set('-other-')
                self._css_entry.insert(0, opts.get('css', 'default'))

            #if opts.get('private_css', 'default') in STYLESHEETS.keys():
            #    self._private_css_var.set(opts.get('private_css', 'default'))
            #else:
            #    self._private_css_var.set('-other-')
            #    self._css_entry.insert(0, opts.get('private_css', 'default'))
                                                   
        except Exception as e:
            log.error('Error opening %s: %s' % (prjfile, e))
            self._root.bell()
Example #8
0
    def open(self, prjfile):
        from epydoc.docwriter.html_css import STYLESHEETS
        self._filename = prjfile
        try:
            opts = load(open(prjfile, 'r'))

            modnames = list(opts.get('modules', []))
            modnames.sort()
            self._module_list.delete(0, 'end')
            for name in modnames:
                self.add_module(name)
            self._module_entry.delete(0, 'end')

            self._name_entry.delete(0, 'end')
            if opts.get('prj_name'):
                self._name_entry.insert(0, opts['prj_name'])

            self._url_entry.delete(0, 'end')
            if opts.get('prj_url'):
                self._url_entry.insert(0, opts['prj_url'])

            self._docformat_var.set(opts.get('docformat', 'epytext'))
            self._inheritance_var.set(opts.get('inheritance', 'grouped'))
            self._introspect_or_parse_var.set(
                opts.get('introspect_or_parse', 'both'))

            self._help_entry.delete(0, 'end')
            if opts.get('help') is None:
                self._help_var.set('default')
            else:
                self._help_var.set('-other-')
                self._help_entry.insert(0, opts.get('help'))

            self._out_entry.delete(0, 'end')
            self._out_entry.insert(0, opts.get('outdir', 'html'))

            self._frames_var.set(opts.get('frames', 1))
            self._private_var.set(opts.get('private', 1))
            self._imports_var.set(opts.get('show_imports', 0))

            self._css_entry.delete(0, 'end')
            if opts.get('css', 'default') in STYLESHEETS.keys():
                self._css_var.set(opts.get('css', 'default'))
            else:
                self._css_var.set('-other-')
                self._css_entry.insert(0, opts.get('css', 'default'))

            #if opts.get('private_css', 'default') in STYLESHEETS.keys():
            #    self._private_css_var.set(opts.get('private_css', 'default'))
            #else:
            #    self._private_css_var.set('-other-')
            #    self._css_entry.insert(0, opts.get('private_css', 'default'))

        except Exception, e:
            log.error('Error opening %s: %s' % (prjfile, e))
            self._root.bell()
Example #9
0
 def _save(self, *e):
     if self._filename is None: return self._saveas()
     try:
         opts = self._getopts()
         dump(opts, open(self._filename, 'w'))
     except Exception, e:
         if self._filename is None:
             log.error('Error saving: %s' % e)
         else:
             log.error('Error saving %s: %s' % (self._filename, e))
         self._root.bell()
Example #10
0
File: gui.py Project: B-Rich/epydoc
 def _save(self, *e):
     if self._filename is None: return self._saveas()
     try:
         opts = self._getopts()
         dump(opts, open(self._filename, 'w'))
     except Exception as e:
         if self._filename is None:
             log.error('Error saving: %s' %  e)
         else:
             log.error('Error saving %s: %s' % (self._filename, e))
         self._root.bell()
Example #11
0
def _get_docs_from_pyobject(obj, introspect, parse, progress_estimator):
    progress_estimator.complete += 1
    log.progress(progress_estimator.progress(), ` obj `)

    if not introspect:
        log.error("Cannot get docs for Python objects without "
                  "introspecting them.")

    introspect_doc = parse_doc = None
    introspect_error = parse_error = None
    try:
        introspect_doc = introspect_docs(value=obj)
    except ImportError, e:
        log.error(e)
        return (None, None)
Example #12
0
def _get_docs_from_pyobject(obj, introspect, parse, progress_estimator):
    progress_estimator.complete += 1
    log.progress(progress_estimator.progress(), `obj`)
    
    if not introspect:
        log.error("Cannot get docs for Python objects without "
                  "introspecting them.")
            
    introspect_doc = parse_doc = None
    introspect_error = parse_error = None
    try:
        introspect_doc = introspect_docs(value=obj)
    except ImportError, e:
        log.error(e)
        return (None, None)
Example #13
0
def document(options, cancel, done):
    """
    Create the documentation for C{modules}, using the options
    specified by C{options}.  C{document} is designed to be started in
    its own thread by L{EpydocGUI._go}.

    @param options: The options to use for generating documentation.
        This includes keyword options that can be given to
        L{html.HTMLFormatter}, as well as the option C{outdir}, which
        controls where the output is written to.
    @type options: C{dictionary}
    """
    from epydoc.docwriter.html import HTMLWriter
    from epydoc.docbuilder import build_doc_index
    import epydoc.docstringparser

    # Set the default docformat.
    docformat = options.get('docformat', 'epytext')
    epydoc.docstringparser.DEFAULT_DOCFORMAT = docformat

    try:
        parse = options['introspect_or_parse'] in ('parse', 'both')
        introspect = options['introspect_or_parse'] in ('introspect', 'both')
        docindex = build_doc_index(options['modules'], parse, introspect)
        html_writer = HTMLWriter(docindex, **options)
        log.start_progress('Writing HTML docs to %r' % options['target'])
        html_writer.write(options['target'])
        log.end_progress()

        # We're done.
        log.warning('Finished!')
        done[0] = 'done'

    except SystemExit:
        # Cancel.
        log.error('Cancelled!')
        done[0] = 'cancel'
        raise
    except Exception, e:
        # We failed.
        log.error('Internal error: %s' % e)
        done[0] = 'cancel'
        raise
Example #14
0
def document(options, cancel, done):
    """
    Create the documentation for C{modules}, using the options
    specified by C{options}.  C{document} is designed to be started in
    its own thread by L{EpydocGUI._go}.

    @param options: The options to use for generating documentation.
        This includes keyword options that can be given to
        L{docwriter.html.HTMLWriter}, as well as the option C{target}, which
        controls where the output is written to.
    @type options: C{dictionary}
    """
    from epydoc.docwriter.html import HTMLWriter
    from epydoc.docbuilder import build_doc_index
    import epydoc.docstringparser

    # Set the default docformat.
    docformat = options.get('docformat', 'epytext')
    epydoc.docstringparser.DEFAULT_DOCFORMAT = docformat

    try:
        parse = options['introspect_or_parse'] in ('parse', 'both')
        introspect = options['introspect_or_parse'] in ('introspect', 'both')
        docindex = build_doc_index(options['modules'], parse, introspect)
        html_writer = HTMLWriter(docindex, **options)
        log.start_progress('Writing HTML docs to %r' % options['target'])
        html_writer.write(options['target'])
        log.end_progress()
    
        # We're done.
        log.warning('Finished!')
        done[0] = 'done'

    except SystemExit:
        # Cancel.
        log.error('Cancelled!')
        done[0] ='cancel'
        raise
    except Exception, e:
        # We failed.
        log.error('Internal error: %s' % e)
        done[0] ='cancel'
        raise
Example #15
0
def _get_docs_from_items(items, introspect, parse, add_submodules):
    # Start the progress bar.
    log.start_progress('Building documentation')
    progress_estimator = _ProgressEstimator(items)

    # Collect (introspectdoc, parsedoc) pairs for each item.
    doc_pairs = []
    for item in items:
        if isinstance(item, basestring):
            if is_module_file(item):
                doc_pairs.append(
                    _get_docs_from_module_file(item, introspect, parse,
                                               progress_estimator))
            elif is_package_dir(item):
                pkgfile = os.path.join(item, '__init__')
                doc_pairs.append(
                    _get_docs_from_module_file(pkgfile, introspect, parse,
                                               progress_estimator))
            elif os.path.isfile(item):
                doc_pairs.append(
                    _get_docs_from_pyscript(item, introspect, parse,
                                            progress_estimator))
            elif hasattr(__builtin__, item):
                val = getattr(__builtin__, item)
                doc_pairs.append(
                    _get_docs_from_pyobject(val, introspect, parse,
                                            progress_estimator))
            elif is_pyname(item):
                doc_pairs.append(
                    _get_docs_from_pyname(item, introspect, parse,
                                          progress_estimator))
            elif os.path.isdir(item):
                log.error("Directory %r is not a package" % item)
            elif os.path.isfile(item):
                log.error("File %s is not a Python module" % item)
            else:
                log.error("Could not find a file or object named %s" % item)
        else:
            doc_pairs.append(
                _get_docs_from_pyobject(item, introspect, parse,
                                        progress_estimator))

        # This will only have an effect if doc_pairs[-1] contains a
        # package's docs.  The 'not is_module_file(item)' prevents
        # us from adding subdirectories if they explicitly specify
        # a package's __init__.py file.
        if add_submodules and not is_module_file(item):
            doc_pairs += _get_docs_from_submodules(item, doc_pairs[-1],
                                                   introspect, parse,
                                                   progress_estimator)

    log.end_progress()
    return doc_pairs
Example #16
0
def _report_errors(name, introspect_doc, parse_doc,
                   introspect_error, parse_error):
    hdr = 'In %s:\n' % name
    if introspect_doc == parse_doc == None:
        log.start_block('%sNo documentation available!' % hdr)
        if introspect_error:
            log.error('Import failed:\n%s' % introspect_error)
        if parse_error:
            log.error('Source code parsing failed:\n%s' % parse_error)
        log.end_block()
    elif introspect_error:
        log.start_block('%sImport failed (but source code parsing '
                        'was successful).' % hdr)
        log.error(introspect_error)
        log.end_block()
    elif parse_error:
        log.start_block('%sSource code parsing failed (but '
                        'introspection was successful).' % hdr)
        log.error(parse_error)
        log.end_block()
Example #17
0
def _report_errors(name, introspect_doc, parse_doc, introspect_error,
                   parse_error):
    hdr = 'In %s:\n' % name
    if introspect_doc == parse_doc == None:
        log.start_block('%sNo documentation available!' % hdr)
        if introspect_error:
            log.error('Import failed:\n%s' % introspect_error)
        if parse_error:
            log.error('Source code parsing failed:\n%s' % parse_error)
        log.end_block()
    elif introspect_error:
        log.start_block('%sImport failed (but source code parsing '
                        'was successful).' % hdr)
        log.error(introspect_error)
        log.end_block()
    elif parse_error:
        log.start_block('%sSource code parsing failed (but '
                        'introspection was successful).' % hdr)
        log.error(parse_error)
        log.end_block()
Example #18
0
def _get_docs_from_items(items, introspect, parse, add_submodules):
    # Start the progress bar.
    log.start_progress('Building documentation')
    progress_estimator = _ProgressEstimator(items)

    # Collect (introspectdoc, parsedoc) pairs for each item.
    doc_pairs = []
    for item in items:
        if isinstance(item, basestring):
            if is_module_file(item):
                doc_pairs.append(_get_docs_from_module_file(
                    item, introspect, parse, progress_estimator))
            elif is_package_dir(item):
                pkgfile = os.path.join(item, '__init__')
                doc_pairs.append(_get_docs_from_module_file(
                    pkgfile, introspect, parse, progress_estimator))
            elif os.path.isfile(item):
                doc_pairs.append(_get_docs_from_pyscript(
                    item, introspect, parse, progress_estimator))
            elif hasattr(__builtin__, item):
                val = getattr(__builtin__, item)
                doc_pairs.append(_get_docs_from_pyobject(
                    val, introspect, parse, progress_estimator))
            elif is_pyname(item):
                doc_pairs.append(_get_docs_from_pyname(
                    item, introspect, parse, progress_estimator))
            elif os.path.isdir(item):
                log.error("Directory %r is not a package" % item)
            elif os.path.isfile(item):
                log.error("File %s is not a Python module" % item)
            else:
                log.error("Could not find a file or object named %s" %
                          item)
        else:
            doc_pairs.append(_get_docs_from_pyobject(
                item, introspect, parse, progress_estimator))

        # This will only have an effect if doc_pairs[-1] contains a
        # package's docs.  The 'not is_module_file(item)' prevents
        # us from adding subdirectories if they explicitly specify
        # a package's __init__.py file.
        if add_submodules and not is_module_file(item):
            doc_pairs += _get_docs_from_submodules(
                item, doc_pairs[-1], introspect, parse, progress_estimator)

    log.end_progress()
    return doc_pairs
Example #19
0
                        (parse_docstring, markup, e))
            import epydoc.markup.plaintext as plaintext
            return plaintext.parse_docstring(docstring, errors, **options)
        _markup_language_registry[markup] = parse_docstring

    # Keep track of which markup languages have been used so far.
    MARKUP_LANGUAGES_USED.add(markup)

    # Parse the docstring.
    try:
        parsed_docstring = parse_docstring(docstring, errors, **options)
    except KeyboardInterrupt:
        raise
    except Exception, e:
        if epydoc.DEBUG: raise
        log.error('Internal error while parsing a docstring: %s; '
                  'treating docstring as plaintext' % e)
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    # Check for fatal errors.
    fatal_errors = [e for e in errors if e.is_fatal()]
    if fatal_errors and raise_on_error: raise fatal_errors[0]
    if fatal_errors:
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    return parsed_docstring


# only issue each warning once:
_parse_warnings = {}
    def handle_line(self, line):
        """
        Render a single logical line from the module, and write the
        generated HTML to C{self.out}.

        @param line: A single logical line, encoded as a list of
            C{(toktype,tokttext)} pairs corresponding to the tokens in
            the line.
        """
        # def_name is the name of the function or class defined by
        # this line; or None if no funciton or class is defined.
        def_name = None

        # def_type is the type of the function or class defined by
        # this line; or None if no funciton or class is defined.
        def_type = None

        # does this line start a class/func def?
        starting_def_block = False

        in_base_list = False
        in_param_list = False
        in_param_default = 0
        at_module_top = (self.lineno == 1)

        ended_def_blocks = 0

        # The html output.
        if self.ADD_LINE_NUMBERS:
            s = self.lineno_to_html()
            self.lineno += 1
        else:
            s = ''
        s += '  <tt class="py-line">'

        # Loop through each token, and colorize it appropriately.
        for i, (toktype, toktext) in enumerate(line):
            if type(s) is not str:
                if type(s) is str:
                    log.error('While colorizing %s -- got unexpected '
                              'unicode string' % self.module_name)
                    s = s.encode('ascii', 'xmlcharrefreplace')
                else:
                    raise ValueError('Unexpected value for s -- %s' %
                                     type(s).__name__)

            # For each token, determine its css class and whether it
            # should link to a url.
            css_class = None
            url = None
            tooltip = None
            onclick = uid = targets = None  # these 3 are used together.

            # Is this token the class name in a class definition?  If
            # so, then make it a link back into the API docs.
            if i >= 2 and line[i - 2][1] == 'class':
                in_base_list = True
                css_class = self.CSS_CLASSES['DEFNAME']
                def_name = toktext
                def_type = 'class'
                if 'func' not in self.context_types:
                    cls_name = self.context_name(def_name)
                    url = self.name2url(cls_name)
                    s = self.mark_def(s, cls_name)
                    starting_def_block = True

            # Is this token the function name in a function def?  If
            # so, then make it a link back into the API docs.
            elif i >= 2 and line[i - 2][1] == 'def':
                in_param_list = True
                css_class = self.CSS_CLASSES['DEFNAME']
                def_name = toktext
                def_type = 'func'
                if 'func' not in self.context_types:
                    cls_name = self.context_name()
                    func_name = self.context_name(def_name)
                    url = self.name2url(cls_name, def_name)
                    s = self.mark_def(s, func_name)
                    starting_def_block = True

            # For each indent, update the indents list (which we use
            # to keep track of indentation strings) and the context
            # list.  If this indent is the start of a class or
            # function def block, then self.def_name will be its name;
            # otherwise, it will be None.
            elif toktype == token.INDENT:
                self.indents.append(toktext)
                self.context.append(self.def_name)
                self.context_types.append(self.def_type)

            # When we dedent, pop the last elements off the indents
            # list and the context list.  If the last context element
            # is a name, then we're ending a class or function def
            # block; so write an end-div tag.
            elif toktype == token.DEDENT:
                self.indents.pop()
                self.context_types.pop()
                if self.context.pop():
                    ended_def_blocks += 1

            # If this token contains whitespace, then don't bother to
            # give it a css tag.
            elif toktype in (None, tokenize.NL, token.NEWLINE,
                             token.ENDMARKER):
                css_class = None

            # Check if the token is a keyword.
            elif toktype == token.NAME and keyword.iskeyword(toktext):
                css_class = self.CSS_CLASSES['KEYWORD']

            elif in_base_list and toktype == token.NAME:
                css_class = self.CSS_CLASSES['BASECLASS']

            elif (in_param_list and toktype == token.NAME
                  and not in_param_default):
                css_class = self.CSS_CLASSES['PARAM']

            # Class/function docstring.
            elif (self.def_name and line[i - 1][0] == token.INDENT
                  and self.is_docstring(line, i)):
                css_class = self.CSS_CLASSES['DOCSTRING']

            # Module docstring.
            elif at_module_top and self.is_docstring(line, i):
                css_class = self.CSS_CLASSES['DOCSTRING']

            # check for decorators??
            elif (toktype == token.NAME and (
                (i > 0 and line[i - 1][1] == '@') or
                (i > 1 and line[i - 1][0] == None and line[i - 2][1] == '@'))):
                css_class = self.CSS_CLASSES['DECORATOR']
                self.has_decorators = True

            # If it's a name, try to link it.
            elif toktype == token.NAME:
                css_class = self.CSS_CLASSES['NAME']
                # If we have a variable named `toktext` in the current
                # context, then link to that.  Note that if we're inside
                # a function, then that function is our context, not
                # the namespace that contains it. [xx] this isn't always
                # the right thing to do.
                if (self.GUESS_LINK_TARGETS and self.docindex is not None
                        and self.url_func is not None):
                    context = [n for n in self.context if n is not None]
                    container = self.docindex.get_vardoc(
                        DottedName(self.module_name, *context))
                    if isinstance(container, NamespaceDoc):
                        doc = container.variables.get(toktext)
                        if doc is not None:
                            url = self.url_func(doc)
                            tooltip = str(doc.canonical_name)
                # Otherwise, check the name_to_docs index to see what
                # else this name might refer to.
                if (url is None and self.name_to_docs is not None
                        and self.url_func is not None):
                    docs = self.name_to_docs.get(toktext)
                    if docs:
                        tooltip = '\n'.join(
                            [str(d.canonical_name) for d in docs])
                        if len(docs) == 1 and self.GUESS_LINK_TARGETS:
                            url = self.url_func(docs[0])
                        else:
                            uid, onclick, targets = self.doclink(toktext, docs)

            # For all other tokens, look up the CSS class to use
            # based on the token's type.
            else:
                if toktype == token.OP and toktext in self.CSS_CLASSES:
                    css_class = self.CSS_CLASSES[toktext]
                elif token.tok_name[toktype] in self.CSS_CLASSES:
                    css_class = self.CSS_CLASSES[token.tok_name[toktype]]
                else:
                    css_class = None

            # update our status..
            if toktext == ':':
                in_base_list = False
                in_param_list = False
            if toktext == '=' and in_param_list:
                in_param_default = True
            if in_param_default:
                if toktext in ('(', '[', '{'): in_param_default += 1
                if toktext in (')', ']', '}'): in_param_default -= 1
                if toktext == ',' and in_param_default == 1:
                    in_param_default = 0

            # Write this token, with appropriate colorization.
            if tooltip and self.ADD_TOOLTIPS:
                tooltip_html = ' title="%s"' % tooltip
            else:
                tooltip_html = ''
            if css_class: css_class_html = ' class="%s"' % css_class
            else: css_class_html = ''
            if onclick:
                if targets: targets_html = ' targets="%s"' % targets
                else: targets_html = ''
                s += ('<tt id="%s"%s%s><a%s%s href="#" onclick="%s">' %
                      (uid, css_class_html, targets_html, tooltip_html,
                       css_class_html, onclick))
            elif url:
                if isinstance(url, str):
                    url = url.encode('ascii', 'xmlcharrefreplace')
                s += ('<a%s%s href="%s">' %
                      (tooltip_html, css_class_html, url))
            elif css_class_html or tooltip_html:
                s += '<tt%s%s>' % (tooltip_html, css_class_html)
            if i == len(line) - 1:
                s += ' </tt>'  # Closes <tt class="py-line">
                s += cgi.escape(toktext)
            else:
                try:
                    s += self.add_line_numbers(cgi.escape(toktext), css_class)
                except Exception as e:
                    print((toktext, css_class, toktext.encode('ascii')))
                    raise

            if onclick: s += "</a></tt>"
            elif url: s += '</a>'
            elif css_class_html or tooltip_html: s += '</tt>'

        if self.ADD_DEF_BLOCKS:
            for i in range(ended_def_blocks):
                self.out(self.END_DEF_BLOCK)

        # Strip any empty <tt>s.
        s = re.sub(r'<tt class="[\w+]"></tt>', '', s)

        # Write the line.
        self.out(s)

        if def_name and starting_def_block:
            self.out('</div>')

        # Add div's if we're starting a def block.
        if (self.ADD_DEF_BLOCKS and def_name and starting_def_block
                and (line[-2][1] == ':')):
            indentation = (''.join(self.indents) + '    ').replace(' ', '+')
            linenum_padding = '+' * self.linenum_size
            name = self.context_name(def_name)
            self.out(self.START_DEF_BLOCK %
                     (name, linenum_padding, indentation, name))

        self.def_name = def_name
        self.def_type = def_type
Example #21
0
        except ImportError, e:
            _parse_warn('Error importing %s for markup language %s: %s' %
                        (parse_docstring, markup, e))
            import epydoc.markup.plaintext as plaintext
            return plaintext.parse_docstring(docstring, errors, **options)
        _markup_language_registry[markup] = parse_docstring

    # Keep track of which markup languages have been used so far.
    MARKUP_LANGUAGES_USED.add(markup)

    # Parse the docstring.
    try: parsed_docstring = parse_docstring(docstring, errors, **options)
    except KeyboardInterrupt: raise
    except Exception, e:
        if epydoc.DEBUG: raise
        log.error('Internal error while parsing a docstring: %s; '
                  'treating docstring as plaintext' % e)
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    # Check for fatal errors.
    fatal_errors = [e for e in errors if e.is_fatal()]
    if fatal_errors and raise_on_error: raise fatal_errors[0]
    if fatal_errors:
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    return parsed_docstring

# only issue each warning once:
_parse_warnings = {}
def _parse_warn(estr):
Example #22
0
    def handle_line(self, line):
        """
        Render a single logical line from the module, and write the
        generated HTML to C{self.out}.

        @param line: A single logical line, encoded as a list of
            C{(toktype,tokttext)} pairs corresponding to the tokens in
            the line.
        """
        # def_name is the name of the function or class defined by
        # this line; or None if no funciton or class is defined.
        def_name = None

        # def_type is the type of the function or class defined by
        # this line; or None if no funciton or class is defined.
        def_type = None

        # does this line start a class/func def?
        starting_def_block = False 

        in_base_list = False
        in_param_list = False
        in_param_default = 0
        at_module_top = (self.lineno == 1)

        ended_def_blocks = 0

        # The html output.
        if self.ADD_LINE_NUMBERS:
            s = self.lineno_to_html()
            self.lineno += 1
        else:
            s = ''
        s += '  <tt class="py-line">'

        # Loop through each token, and colorize it appropriately.
        for i, (toktype, toktext) in enumerate(line):
            if type(s) is not str:
                if type(s) is str:
                    log.error('While colorizing %s -- got unexpected '
                              'unicode string' % self.module_name)
                    s = s.encode('ascii', 'xmlcharrefreplace')
                else:
                    raise ValueError('Unexpected value for s -- %s' % 
                                     type(s).__name__)

            # For each token, determine its css class and whether it
            # should link to a url.
            css_class = None
            url = None
            tooltip = None
            onclick = uid = targets = None # these 3 are used together.

            # Is this token the class name in a class definition?  If
            # so, then make it a link back into the API docs.
            if i>=2 and line[i-2][1] == 'class':
                in_base_list = True
                css_class = self.CSS_CLASSES['DEFNAME']
                def_name = toktext
                def_type = 'class'
                if 'func' not in self.context_types:
                    cls_name = self.context_name(def_name)
                    url = self.name2url(cls_name)
                    s = self.mark_def(s, cls_name)
                    starting_def_block = True

            # Is this token the function name in a function def?  If
            # so, then make it a link back into the API docs.
            elif i>=2 and line[i-2][1] == 'def':
                in_param_list = True
                css_class = self.CSS_CLASSES['DEFNAME']
                def_name = toktext
                def_type = 'func'
                if 'func' not in self.context_types:
                    cls_name = self.context_name()
                    func_name = self.context_name(def_name)
                    url = self.name2url(cls_name, def_name)
                    s = self.mark_def(s, func_name)
                    starting_def_block = True

            # For each indent, update the indents list (which we use
            # to keep track of indentation strings) and the context
            # list.  If this indent is the start of a class or
            # function def block, then self.def_name will be its name;
            # otherwise, it will be None.
            elif toktype == token.INDENT:
                self.indents.append(toktext)
                self.context.append(self.def_name)
                self.context_types.append(self.def_type)

            # When we dedent, pop the last elements off the indents
            # list and the context list.  If the last context element
            # is a name, then we're ending a class or function def
            # block; so write an end-div tag.
            elif toktype == token.DEDENT:
                self.indents.pop()
                self.context_types.pop()
                if self.context.pop():
                    ended_def_blocks += 1

            # If this token contains whitespace, then don't bother to
            # give it a css tag.
            elif toktype in (None, tokenize.NL, token.NEWLINE,
                             token.ENDMARKER):
                css_class = None

            # Check if the token is a keyword.
            elif toktype == token.NAME and keyword.iskeyword(toktext):
                css_class = self.CSS_CLASSES['KEYWORD']

            elif in_base_list and toktype == token.NAME:
                css_class = self.CSS_CLASSES['BASECLASS']

            elif (in_param_list and toktype == token.NAME and
                  not in_param_default):
                css_class = self.CSS_CLASSES['PARAM']

            # Class/function docstring.
            elif (self.def_name and line[i-1][0] == token.INDENT and
                  self.is_docstring(line, i)):
                css_class = self.CSS_CLASSES['DOCSTRING']

            # Module docstring.
            elif at_module_top and self.is_docstring(line, i):
                css_class = self.CSS_CLASSES['DOCSTRING']

            # check for decorators??
            elif (toktype == token.NAME and
                  ((i>0 and line[i-1][1]=='@') or
                   (i>1 and line[i-1][0]==None and line[i-2][1] == '@'))):
                css_class = self.CSS_CLASSES['DECORATOR']
                self.has_decorators = True

            # If it's a name, try to link it.
            elif toktype == token.NAME:
                css_class = self.CSS_CLASSES['NAME']
                # If we have a variable named `toktext` in the current
                # context, then link to that.  Note that if we're inside
                # a function, then that function is our context, not
                # the namespace that contains it. [xx] this isn't always
                # the right thing to do.
                if (self.GUESS_LINK_TARGETS and self.docindex is not None
                    and self.url_func is not None):
                    context = [n for n in self.context if n is not None]
                    container = self.docindex.get_vardoc(
                        DottedName(self.module_name, *context))
                    if isinstance(container, NamespaceDoc):
                        doc = container.variables.get(toktext)
                        if doc is not None:
                            url = self.url_func(doc)
                            tooltip = str(doc.canonical_name)
                # Otherwise, check the name_to_docs index to see what
                # else this name might refer to.
                if (url is None and self.name_to_docs is not None
                    and self.url_func is not None):
                    docs = self.name_to_docs.get(toktext)
                    if docs:
                        tooltip='\n'.join([str(d.canonical_name)
                                           for d in docs])
                        if len(docs) == 1 and self.GUESS_LINK_TARGETS:
                            url = self.url_func(docs[0])
                        else:
                            uid, onclick, targets = self.doclink(toktext, docs)

            # For all other tokens, look up the CSS class to use
            # based on the token's type.
            else:
                if toktype == token.OP and toktext in self.CSS_CLASSES:
                    css_class = self.CSS_CLASSES[toktext]
                elif token.tok_name[toktype] in self.CSS_CLASSES:
                    css_class = self.CSS_CLASSES[token.tok_name[toktype]]
                else:
                    css_class = None

            # update our status..
            if toktext == ':':
                in_base_list = False
                in_param_list = False
            if toktext == '=' and in_param_list:
                in_param_default = True
            if in_param_default:
                if toktext in ('(','[','{'): in_param_default += 1
                if toktext in (')',']','}'): in_param_default -= 1
                if toktext == ',' and in_param_default == 1:
                    in_param_default = 0
                
            # Write this token, with appropriate colorization.
            if tooltip and self.ADD_TOOLTIPS:
                tooltip_html = ' title="%s"' % tooltip
            else: tooltip_html = ''
            if css_class: css_class_html = ' class="%s"' % css_class
            else: css_class_html = ''
            if onclick:
                if targets: targets_html = ' targets="%s"' % targets
                else: targets_html = ''
                s += ('<tt id="%s"%s%s><a%s%s href="#" onclick="%s">' %
                      (uid, css_class_html, targets_html, tooltip_html,
                       css_class_html, onclick))
            elif url:
                if isinstance(url, str):
                    url = url.encode('ascii', 'xmlcharrefreplace')
                s += ('<a%s%s href="%s">' %
                      (tooltip_html, css_class_html, url))
            elif css_class_html or tooltip_html:
                s += '<tt%s%s>' % (tooltip_html, css_class_html)
            if i == len(line)-1:
                s += ' </tt>' # Closes <tt class="py-line">
                s += cgi.escape(toktext)
            else:
                try:
                    s += self.add_line_numbers(cgi.escape(toktext), css_class)
                except Exception as e:
                    print((toktext, css_class, toktext.encode('ascii')))
                    raise

            if onclick: s += "</a></tt>"
            elif url: s += '</a>'
            elif css_class_html or tooltip_html: s += '</tt>'

        if self.ADD_DEF_BLOCKS:
            for i in range(ended_def_blocks):
                self.out(self.END_DEF_BLOCK)

        # Strip any empty <tt>s.
        s = re.sub(r'<tt class="[\w+]"></tt>', '', s)

        # Write the line.
        self.out(s)

        if def_name and starting_def_block:
            self.out('</div>')

        # Add div's if we're starting a def block.
        if (self.ADD_DEF_BLOCKS and def_name and starting_def_block and
            (line[-2][1] == ':')):
            indentation = (''.join(self.indents)+'    ').replace(' ', '+')
            linenum_padding = '+'*self.linenum_size
            name=self.context_name(def_name)
            self.out(self.START_DEF_BLOCK % (name, linenum_padding,
                                             indentation, name))
            
        self.def_name = def_name
        self.def_type = def_type
Example #23
0
def parse(docstring, markup='plaintext', errors=None, **options):
    """
    Parse the given docstring, and use it to construct a
    C{ParsedDocstring}.  If any fatal C{ParseError}s are encountered
    while parsing the docstring, then the docstring will be rendered
    as plaintext, instead.

    @type docstring: C{string}
    @param docstring: The docstring to encode.
    @type markup: C{string}
    @param markup: The name of the markup language that is used by
        the docstring.  If the markup language is not supported, then
        the docstring will be treated as plaintext.  The markup name
        is case-insensitive.
    @param errors: A list where any errors generated during parsing
        will be stored.  If no list is specified, then fatal errors
        will generate exceptions, and non-fatal errors will be
        ignored.
    @type errors: C{list} of L{ParseError}
    @rtype: L{ParsedDocstring}
    @return: A L{ParsedDocstring} that encodes the contents of
        C{docstring}.
    @raise ParseError: If C{errors} is C{None} and an error is
        encountered while parsing.
    """
    # Initialize errors list.
    raise_on_error = (errors is None)
    if errors == None: errors = []

    # Normalize the markup language name.
    markup = markup.lower()

    # Is the markup language valid?
    if not re.match(r'\w+', markup):
        _parse_warn('Bad markup language name %r.  Treating '
                    'docstrings as plaintext.' % markup)
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    # Is the markup language supported?
    if markup not in _markup_language_registry:
        _parse_warn('Unsupported markup language %r.  Treating '
                    'docstrings as plaintext.' % markup)
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    # Get the parse function.
    parse_docstring = _markup_language_registry[markup]

    # If it's a string, then it names a function to import.
    if isinstance(parse_docstring, str):
        try: exec('from %s import parse_docstring' % parse_docstring)
        except ImportError as e:
            _parse_warn('Error importing %s for markup language %s: %s' %
                        (parse_docstring, markup, e))
            import epydoc.markup.plaintext as plaintext
            return plaintext.parse_docstring(docstring, errors, **options)
        _markup_language_registry[markup] = parse_docstring

    # Keep track of which markup languages have been used so far.
    MARKUP_LANGUAGES_USED.add(markup)

    # Parse the docstring.
    try: parsed_docstring = parse_docstring(docstring, errors, **options)
    except KeyboardInterrupt: raise
    except Exception as e:
        if epydoc.DEBUG: raise
        log.error('Internal error while parsing a docstring: %s; '
                  'treating docstring as plaintext' % e)
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    # Check for fatal errors.
    fatal_errors = [e for e in errors if e.is_fatal()]
    if fatal_errors and raise_on_error: raise fatal_errors[0]
    if fatal_errors:
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    return parsed_docstring
Example #24
0
def _colorize_re(tree, noparen=0):
    """
    Recursively descend the given regexp parse tree to produce the
    HTML code for a colorized version of the regexp.

    @param tree: The regexp parse tree for the regexp that should be
        colorized.
    @type tree: L{sre_parse.SubPattern}
    @param noparen: If true, then don't include parenthases around the
        expression in C{tree}, even if it contains multiple elements.
    @type noparen: C{boolean}
    @return: The HTML code for a colorized version of C{tree}
    @rtype: C{string}
    """
    result = []
    out = result.append
    
    if len(tree) > 1 and not noparen:
        out('<span class="%s">(</span>' % PAREN_TAG)
    for elt in tree:
        op = elt[0]
        args = elt[1]

        if op == sre_constants.LITERAL:
            c = unichr(args)
            if c == '\t': out(r'<span class="%s">\t</span>' % ESCAPE_TAG)
            elif c == '\n': out(r'<span class="%s">\n</span>' % ESCAPE_TAG)
            elif c == '\r': out(r'<span class="%s">\r</span>' % ESCAPE_TAG)
            elif c == '\f': out(r'<span class="%s">\f</span>' % ESCAPE_TAG)
            elif c == '\v': out(r'<span class="%s">\v</span>' % ESCAPE_TAG)
            elif ord(c)<32 or ord(c)>=127:
                if c < 256: template = r'<span class="%s">\x%02x</span>'
                else: template = r'<span class="%s">\u%04x</span>'
                out(template % (ESCAPE_TAG,ord(c)))
            elif c in '.^$\\*+?{}[]|()':
                out(r'<span class="%s">\%c</span>' % (ESCAPE_TAG, c))
            else: out(plaintext_to_html(unichr(args)))
            continue
        
        elif op == sre_constants.ANY:
            out('<span class="%s">.</span>' % ANY_TAG)
            
        elif op == sre_constants.BRANCH:
            if args[0] is not None:
                raise ValueError('Branch expected None arg but got %s'
                                 % args[0])
            VBAR = '<span class="%s">|</span>' % BRANCH_TAG
            out(VBAR.join([_colorize_re(item,1) for item in args[1]]))
            
        elif op == sre_constants.IN:
            if (len(args) == 1 and args[0][0] == sre_constants.CATEGORY):
                out(_colorize_re(args))
            else:
                out('<span class="%s">[</span>' % CHOICE_TAG)
                out(_colorize_re(args, 1))
                out('<span class="%s">]</span>' % CHOICE_TAG)
                
        elif op == sre_constants.CATEGORY:
            out('<span class="%s">' % CATEGORY_TAG)
            if args == sre_constants.CATEGORY_DIGIT: out(r'\d')
            elif args == sre_constants.CATEGORY_NOT_DIGIT: out(r'\D')
            elif args == sre_constants.CATEGORY_SPACE: out(r'\s')
            elif args == sre_constants.CATEGORY_NOT_SPACE: out(r'\S')
            elif args == sre_constants.CATEGORY_WORD: out(r'\w')
            elif args == sre_constants.CATEGORY_NOT_WORD: out(r'\W')
            else: raise ValueError('Unknown category %s' % args)
            out('</span>')
            
        elif op == sre_constants.AT:
            out('<span class="%s">' % AT_TAG)
            if args == sre_constants.AT_BEGINNING_STRING: out(r'\A')
            elif args == sre_constants.AT_BEGINNING: out(r'^')
            elif args == sre_constants.AT_END: out(r'$')
            elif args == sre_constants.AT_BOUNDARY: out(r'\b')
            elif args == sre_constants.AT_NON_BOUNDARY: out(r'\B')
            elif args == sre_constants.AT_END_STRING: out(r'\Z')
            else: raise ValueError('Unknown position %s' % args)
            out('</span>')
            
        elif op == sre_constants.MAX_REPEAT:
            min = args[0]
            max = args[1]
            if max == sre_constants.MAXREPEAT:
                if min == 0:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">*</span>' % STAR_TAG)
                elif min == 1:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">+</span>' % PLUS_TAG)
                else:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">{%d,}</span>' % (RNG_TAG, min))
            elif min == 0:
                if max == 1:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">?</span>' % QMRK_TAG)
                else:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">{,%d}</span>' % (RNG_TAG, max))
            elif min == max:
                out(_colorize_re(args[2]))
                out('<span class="%s">{%d}</span>' % (RNG_TAG, max))
            else:
                out(_colorize_re(args[2]))
                out('<span class="%s">{%d,%d}</span>' % (RNG_TAG, min, max))

        elif op == sre_constants.MIN_REPEAT:
            min = args[0]
            max = args[1]
            if max == sre_constants.MAXREPEAT:
                if min == 0:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">*?</span>' % STAR_TAG)
                elif min == 1:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">+?</span>' % PLUS_TAG)
                else:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">{%d,}?</span>' % (RNG_TAG, min))
            elif min == 0:
                if max == 1:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">??</span>' % QMRK_TAG)
                else:
                    out(_colorize_re(args[2]))
                    out('<span class="%s">{,%d}?</span>' % (RNG_TAG, max))
            elif min == max:
                out(_colorize_re(args[2]))
                out('<span class="%s">{%d}?</span>' % (RNG_TAG, max))
            else:
                out(_colorize_re(args[2]))
                out('<span class="%s">{%d,%d}?</span>'%(RNG_TAG, min, max))

        elif op == sre_constants.SUBPATTERN:
            if args[0] is None:
                out('<span class="%s">(?:</span>' % PAREN_TAG)
            elif isinstance(args[0], (int, long)):
                # This is cheating:
                out('<span class="%s">(</span>' % PAREN_TAG)
            else:
                out('<span class="%s">(?P&lt;</span>' % PAREN_TAG)
                out('<span class="%s">%s</span>' %
                    (REF_TAG, plaintext_to_html(args[0])))
                out('<span class="%s">&gt;</span>' % PAREN_TAG)
            out(_colorize_re(args[1], 1))
            out('<span class="%s">)</span>' % PAREN_TAG)

        elif op == sre_constants.GROUPREF:
            out('<span class="%s">\\%d</span>' % (REF_TAG, args))

        elif op == sre_constants.RANGE:
            start = _colorize_re( ((sre_constants.LITERAL, args[0]),) )
            end = _colorize_re( ((sre_constants.LITERAL, args[1]),) )
            out('%s<span class="%s">-</span>%s' % (start, CHOICE_TAG, end))
            
        elif op == sre_constants.NEGATE:
            out('<span class="%s">^</span>' % CHOICE_TAG)

        elif op == sre_constants.ASSERT:
            if args[0]: out('<span class="%s">(?=</span>' % ASSERT_TAG)
            else: out('<span class="%s">(?&lt;=</span>' % ASSERT_TAG)
            out(''.join(_colorize_re(args[1], 1)))
            out('<span class="%s">)</span>' % ASSERT_TAG)
                           
        elif op == sre_constants.ASSERT_NOT:
            if args[0]: out('<span class="%s">(?!</span>' % ASSERT_TAG)
            else: out('<span class="%s">(?&lt;!</span>' % ASSERT_TAG)
            out(''.join(_colorize_re(args[1], 1)))
            out('<span class="%s">)</span>' % ASSERT_TAG)

        elif op == sre_constants.NOT_LITERAL:
            lit = _colorize_re( ((sre_constants.LITERAL, args),) )
            out('<span class="%s">[^</span>%s<span class="%s">]</span>' %
                (CHOICE_TAG, lit, CHOICE_TAG))
        else:
            log.error("Error colorizing regexp: unknown elt %r" % elt)
    if len(tree) > 1 and not noparen: 
        out('<span class="%s">)</span>' % PAREN_TAG)
    return u''.join(result)
Example #25
0
def write_latex(docindex, options, format):
    from epydoc.docwriter.latex import LatexWriter
    latex_writer = LatexWriter(docindex, **options.__dict__)
    log.start_progress('Writing LaTeX docs')
    latex_writer.write(options.target)
    log.end_progress()
    # If we're just generating the latex, and not any output format,
    # then we're done.
    if format == 'latex': return
    
    if format == 'dvi': steps = 4
    elif format == 'ps': steps = 5
    elif format == 'pdf': steps = 6
    
    log.start_progress('Processing LaTeX docs')
    oldpath = os.path.abspath(os.curdir)
    running = None # keep track of what we're doing.
    try:
        try:
            os.chdir(options.target)

            # Clear any old files out of the way.
            for ext in 'tex aux log out idx ilg toc ind'.split():
                if os.path.exists('apidoc.%s' % ext):
                    os.remove('apidoc.%s' % ext)

            # The first pass generates index files.
            running = 'latex'
            log.progress(0./steps, 'LaTeX: First pass')
            run_subprocess('latex api.tex')

            # Build the index.
            running = 'makeindex'
            log.progress(1./steps, 'LaTeX: Build index')
            run_subprocess('makeindex api.idx')

            # The second pass generates our output.
            running = 'latex'
            log.progress(2./steps, 'LaTeX: Second pass')
            out, err = run_subprocess('latex api.tex')
            
            # The third pass is only necessary if the second pass
            # changed what page some things are on.
            running = 'latex'
            if _RERUN_LATEX_RE.match(out):
                log.progress(3./steps, 'LaTeX: Third pass')
                out, err = run_subprocess('latex api.tex')
 
            # A fourth path should (almost?) never be necessary.
            running = 'latex'
            if _RERUN_LATEX_RE.match(out):
                log.progress(3./steps, 'LaTeX: Fourth pass')
                run_subprocess('latex api.tex')

            # If requested, convert to postscript.
            if format in ('ps', 'pdf'):
                running = 'dvips'
                log.progress(4./steps, 'dvips')
                run_subprocess('dvips api.dvi -o api.ps -G0 -Ppdf')

            # If requested, convert to pdf.
            if format in ('pdf'):
                running = 'ps2pdf'
                log.progress(5./steps, 'ps2pdf')
                run_subprocess(
                    'ps2pdf -sPAPERSIZE=letter -dMaxSubsetPct=100 '
                    '-dSubsetFonts=true -dCompatibilityLevel=1.2 '
                    '-dEmbedAllFonts=true api.ps api.pdf')
        except RunSubprocessError, e:
            if running == 'latex':
                e.out = re.sub(r'(?sm)\A.*?!( LaTeX Error:)?', r'', e.out)
                e.out = re.sub(r'(?sm)\s*Type X to quit.*', '', e.out)
                e.out = re.sub(r'(?sm)^! Emergency stop.*', '', e.out)
            log.error("%s failed: %s" % (running, (e.out+e.err).lstrip()))
        except OSError, e:
            log.error("%s failed: %s" % (running, e))
Example #26
0
def parse(docstring, markup='plaintext', errors=None, **options):
    """
    Parse the given docstring, and use it to construct a
    C{ParsedDocstring}.  If any fatal C{ParseError}s are encountered
    while parsing the docstring, then the docstring will be rendered
    as plaintext, instead.

    @type docstring: C{string}
    @param docstring: The docstring to encode.
    @type markup: C{string}
    @param markup: The name of the markup language that is used by
        the docstring.  If the markup language is not supported, then
        the docstring will be treated as plaintext.  The markup name
        is case-insensitive.
    @param errors: A list where any errors generated during parsing
        will be stored.  If no list is specified, then fatal errors
        will generate exceptions, and non-fatal errors will be
        ignored.
    @type errors: C{list} of L{ParseError}
    @rtype: L{ParsedDocstring}
    @return: A L{ParsedDocstring} that encodes the contents of
        C{docstring}.
    @raise ParseError: If C{errors} is C{None} and an error is
        encountered while parsing.
    """
    # Initialize errors list.
    raise_on_error = (errors is None)
    if errors == None: errors = []

    # Normalize the markup language name.
    markup = markup.lower()

    # Is the markup language valid?
    if not re.match(r'\w+', markup):
        _parse_warn('Bad markup language name %r.  Treating '
                    'docstrings as plaintext.' % markup)
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    # Is the markup language supported?
    if markup not in _markup_language_registry:
        _parse_warn('Unsupported markup language %r.  Treating '
                    'docstrings as plaintext.' % markup)
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    # Get the parse function.
    parse_docstring = _markup_language_registry[markup]

    # If it's a string, then it names a function to import.
    if isinstance(parse_docstring, str):
        try:
            exec('from %s import parse_docstring' % parse_docstring)
        except ImportError as e:
            _parse_warn('Error importing %s for markup language %s: %s' %
                        (parse_docstring, markup, e))
            import epydoc.markup.plaintext as plaintext
            return plaintext.parse_docstring(docstring, errors, **options)
        _markup_language_registry[markup] = parse_docstring

    # Keep track of which markup languages have been used so far.
    MARKUP_LANGUAGES_USED.add(markup)

    # Parse the docstring.
    try:
        parsed_docstring = parse_docstring(docstring, errors, **options)
    except KeyboardInterrupt:
        raise
    except Exception as e:
        if epydoc.DEBUG: raise
        log.error('Internal error while parsing a docstring: %s; '
                  'treating docstring as plaintext' % e)
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    # Check for fatal errors.
    fatal_errors = [e for e in errors if e.is_fatal()]
    if fatal_errors and raise_on_error: raise fatal_errors[0]
    if fatal_errors:
        import epydoc.markup.plaintext as plaintext
        return plaintext.parse_docstring(docstring, errors, **options)

    return parsed_docstring
Example #27
0
def build_doc_index(items, introspect=True, parse=True,
                    add_submodules=True):
    """
    Build API documentation for the given list of items, and
    return it in the form of a L{DocIndex}.

    @rtype: L{DocIndex}
    @param items: The items to document, specified using any of the
        following:
          - A string, naming a python package directory
            (e.g., C{'epydoc/markup'})
          - A string, naming a python file
            (e.g., C{'epydoc/docparser.py'})
          - A string, naming a python object
            (e.g., C{'epydoc.docparser.DocParser'})
          - Any (non-string) python object
            (e.g., C{list.append})
    @param introspect: If true, then use introspection to examine the
        specified items.  Otherwise, just use parsing.
    @param parse: If true, then use parsing to examine the specified
        items.  Otherwise, just use introspection.
    """
    # Get the basic docs for each item.
    doc_pairs = _get_docs_from_items(items, introspect, parse, add_submodules)

    # Merge the introspection & parse docs.
    if parse and introspect:
        log.start_progress('Merging parsed & introspected information')
        docs = []
        for i, (introspect_doc, parse_doc) in enumerate(doc_pairs):
            if introspect_doc is not None and parse_doc is not None:
                if introspect_doc.canonical_name not in (None, UNKNOWN):
                    name = introspect_doc.canonical_name
                else:
                    name = parse_doc.canonical_name
                log.progress(float(i)/len(doc_pairs), name)
                docs.append(merge_docs(introspect_doc, parse_doc))
            elif introspect_doc is not None:
                docs.append(introspect_doc)
            elif parse_doc is not None:
                docs.append(parse_doc)
        log.end_progress()
    elif introspect:
        docs = [doc_pair[0] for doc_pair in doc_pairs if doc_pair[0]]
    else:
        docs = [doc_pair[1] for doc_pair in doc_pairs if doc_pair[1]]

    if len(docs) == 0:
        log.error('Nothing left to document!')
        return None

    # Collect the docs into a single index.
    docindex = DocIndex(docs)

    # Replace any proxy valuedocs that we got from importing with
    # their targets.
    if parse:
        log.start_progress('Linking imported variables')
        valdocs = docindex.reachable_valdocs(sort_by_name=True, imports=False,
                                             submodules=False, packages=False,
                                             subclasses=False)
        for i, val_doc in enumerate(valdocs):
            _report_valdoc_progress(i, val_doc, valdocs)
            link_imports(val_doc, docindex)
        log.end_progress()

    # Assign canonical names.
    log.start_progress('Indexing documentation')
    for i, val_doc in enumerate(docindex.root):
        log.progress(float(i)/len(docindex.root), val_doc.canonical_name)
        assign_canonical_names(val_doc, val_doc.canonical_name, docindex)
    log.end_progress()

    # Parse the docstrings for each object.
    log.start_progress('Parsing docstrings')
    valdocs = docindex.reachable_valdocs(sort_by_name=True, imports=False,
                                         submodules=False, packages=False,
                                         subclasses=False)
    for i, val_doc in enumerate(valdocs):
        _report_valdoc_progress(i, val_doc, valdocs)
        # the value's docstring
        parse_docstring(val_doc, docindex)
        # the value's variables' docstrings
        if (isinstance(val_doc, NamespaceDoc) and
            val_doc.variables not in (None, UNKNOWN)):
            for var_doc in val_doc.variables.values():
                parse_docstring(var_doc, docindex)
    log.end_progress()

    # Take care of inheritance.
    log.start_progress('Inheriting documentation')
    for i, val_doc in enumerate(valdocs):
        if isinstance(val_doc, ClassDoc):
            percent = float(i)/len(valdocs)
            log.progress(percent, val_doc.canonical_name)
            inherit_docs(val_doc)
    log.end_progress()

    # Initialize the groups & sortedvars attributes.
    log.start_progress('Sorting & Grouping')
    for i, val_doc in enumerate(valdocs):
        if isinstance(val_doc, NamespaceDoc):
            percent = float(i)/len(valdocs)
            log.progress(percent, val_doc.canonical_name)
            val_doc.init_sorted_variables()
            val_doc.init_variable_groups()
            if isinstance(val_doc, ModuleDoc):
                val_doc.init_submodule_groups()
    log.end_progress()

    return docindex
Example #28
0
        log.warning('Finished!')
        done[0] = 'done'

    except SystemExit:
        # Cancel.
        log.error('Cancelled!')
        done[0] ='cancel'
        raise
    except Exception, e:
        # We failed.
        log.error('Internal error: %s' % e)
        done[0] ='cancel'
        raise
    except:
        # We failed.
        log.error('Internal error!')
        done[0] ='cancel'
        raise
    
##/////////////////////////////////////////////////////////////////////////
## GUI
##/////////////////////////////////////////////////////////////////////////

class EpydocGUI:
    """
    A graphical user interace to epydoc.
    """
    def __init__(self):
        self._afterid = 0
        self._progress = [None]
        self._cancel = [0]
Example #29
0
        log.warning('Finished!')
        done[0] = 'done'

    except SystemExit:
        # Cancel.
        log.error('Cancelled!')
        done[0] ='cancel'
        raise
    except Exception, e:
        # We failed.
        log.error('Internal error: %s' % e)
        done[0] ='cancel'
        raise
    except:
        # We failed.
        log.error('Internal error!')
        done[0] ='cancel'
        raise
    
##/////////////////////////////////////////////////////////////////////////
## GUI
##/////////////////////////////////////////////////////////////////////////

class EpydocGUI:
    """
    A graphical user interace to epydoc.
    """
    def __init__(self):
        self._afterid = 0
        self._progress = [None]
        self._cancel = [0]
Example #30
0
def main(options, names):
    if options.action == 'text':
        if options.parse and options.introspect:
            options.parse = False

    # Set up the logger
    if options.action == 'text':
        logger = None # no logger for text output.
    elif options.verbosity > 1:
        logger = ConsoleLogger(options.verbosity)
        log.register_logger(logger)
    else:
        # Each number is a rough approximation of how long we spend on
        # that task, used to divide up the unified progress bar.
        stages = [40,  # Building documentation
                  7,   # Merging parsed & introspected information
                  1,   # Linking imported variables
                  3,   # Indexing documentation
                  30,  # Parsing Docstrings
                  1,   # Inheriting documentation
                  2]   # Sorting & Grouping
        if options.action == 'html': stages += [100]
        elif options.action == 'text': stages += [30]
        elif options.action == 'latex': stages += [60]
        elif options.action == 'dvi': stages += [60,30]
        elif options.action == 'ps': stages += [60,40]
        elif options.action == 'pdf': stages += [60,50]
        elif options.action == 'check': stages += [10]
        else: raise ValueError, '%r not supported' % options.action
        if options.parse and not options.introspect:
            del stages[1] # no merging
        if options.introspect and not options.parse:
            del stages[1:3] # no merging or linking
        logger = UnifiedProgressConsoleLogger(options.verbosity, stages)
        log.register_logger(logger)

    # check the output directory.
    if options.action != 'text':
        if os.path.exists(options.target):
            if not os.path.isdir(options.target):
                return log.error("%s is not a directory" % options.target)

    # Set the default docformat
    from epydoc import docstringparser
    docstringparser.DEFAULT_DOCFORMAT = options.docformat

    # Set the dot path
    if options.dotpath:
        from epydoc import dotgraph
        dotgraph.DOT_PATH = options.dotpath

    # Build docs for the named values.
    from epydoc.docbuilder import build_doc_index
    docindex = build_doc_index(names, options.introspect, options.parse,
                               add_submodules=(options.action!='text'))

    if docindex is None:
        return # docbuilder already logged an error.

    # Load profile information, if it was given.
    if options.pstat_files:
        try:
            profile_stats = pstats.Stats(options.pstat_files[0])
            for filename in options.pstat_files[1:]:
                profile_stats.add(filename)
        except KeyboardInterrupt: raise
        except Exception, e:
            log.error("Error reading pstat file: %s" % e)
            profile_stats = None
        if profile_stats is not None:
            docindex.read_profiling_info(profile_stats)
    def handle_line(self, line):
        """
        Render a single logical line from the module, and write the
        generated HTML to C{self.out}.

        @param line: A single logical line, encoded as a list of
            C{(toktype,tokttext)} pairs corresponding to the tokens in
            the line.
        """
        # def_name is the name of the function or class defined by
        # this line; or None if no funciton or class is defined.
        def_name = None

        # def_type is the type of the function or class defined by
        # this line; or None if no funciton or class is defined.
        def_type = None

        # does this line start a class/func def?
        starting_def_block = False

        in_base_list = False
        in_param_list = False
        in_param_default = 0
        at_module_top = self.lineno == 1

        ended_def_blocks = 0

        # The html output.
        if self.ADD_LINE_NUMBERS:
            s = self.lineno_to_html()
            self.lineno += 1
        else:
            s = ""
        s += '  <tt class="py-line">'

        # Loop through each token, and colorize it appropriately.
        for i, (toktype, toktext) in enumerate(line):
            if type(s) is not str:
                if type(s) is unicode:
                    log.error("While colorizing %s -- got unexpected " "unicode string" % self.module_name)
                    s = s.encode("ascii", "xmlcharrefreplace")
                else:
                    raise ValueError("Unexpected value for s -- %s" % type(s).__name__)

            # For each token, determine its css class and whether it
            # should link to a url.
            css_class = None
            url = None
            tooltip = None
            onclick = uid = targets = None  # these 3 are used together.

            # Is this token the class name in a class definition?  If
            # so, then make it a link back into the API docs.
            if i >= 2 and line[i - 2][1] == "class":
                in_base_list = True
                css_class = self.CSS_CLASSES["DEFNAME"]
                def_name = toktext
                def_type = "class"
                if "func" not in self.context_types:
                    cls_name = self.context_name(def_name)
                    url = self.name2url(cls_name)
                    s = self.mark_def(s, cls_name)
                    starting_def_block = True

            # Is this token the function name in a function def?  If
            # so, then make it a link back into the API docs.
            elif i >= 2 and line[i - 2][1] == "def":
                in_param_list = True
                css_class = self.CSS_CLASSES["DEFNAME"]
                def_name = toktext
                def_type = "func"
                if "func" not in self.context_types:
                    cls_name = self.context_name()
                    func_name = self.context_name(def_name)
                    url = self.name2url(cls_name, def_name)
                    s = self.mark_def(s, func_name)
                    starting_def_block = True

            # For each indent, update the indents list (which we use
            # to keep track of indentation strings) and the context
            # list.  If this indent is the start of a class or
            # function def block, then self.def_name will be its name;
            # otherwise, it will be None.
            elif toktype == token.INDENT:
                self.indents.append(toktext)
                self.context.append(self.def_name)
                self.context_types.append(self.def_type)

            # When we dedent, pop the last elements off the indents
            # list and the context list.  If the last context element
            # is a name, then we're ending a class or function def
            # block; so write an end-div tag.
            elif toktype == token.DEDENT:
                self.indents.pop()
                self.context_types.pop()
                if self.context.pop():
                    ended_def_blocks += 1

            # If this token contains whitespace, then don't bother to
            # give it a css tag.
            elif toktype in (None, tokenize.NL, token.NEWLINE, token.ENDMARKER):
                css_class = None

            # Check if the token is a keyword.
            elif toktype == token.NAME and keyword.iskeyword(toktext):
                css_class = self.CSS_CLASSES["KEYWORD"]

            elif in_base_list and toktype == token.NAME:
                css_class = self.CSS_CLASSES["BASECLASS"]

            elif in_param_list and toktype == token.NAME and not in_param_default:
                css_class = self.CSS_CLASSES["PARAM"]

            # Class/function docstring.
            elif self.def_name and line[i - 1][0] == token.INDENT and self.is_docstring(line, i):
                css_class = self.CSS_CLASSES["DOCSTRING"]

            # Module docstring.
            elif at_module_top and self.is_docstring(line, i):
                css_class = self.CSS_CLASSES["DOCSTRING"]

            # check for decorators??
            elif toktype == token.NAME and (
                (i > 0 and line[i - 1][1] == "@") or (i > 1 and line[i - 1][0] == None and line[i - 2][1] == "@")
            ):
                css_class = self.CSS_CLASSES["DECORATOR"]

            # If it's a name, try to link it.
            elif toktype == token.NAME:
                css_class = self.CSS_CLASSES["NAME"]
                # If we have a variable named `toktext` in the current
                # context, then link to that.  Note that if we're inside
                # a function, then that function is our context, not
                # the namespace that contains it. [xx] this isn't always
                # the right thing to do.
                if self.GUESS_LINK_TARGETS and self.docindex is not None and self.url_func is not None:
                    context = [n for n in self.context if n is not None]
                    container = self.docindex.get_vardoc(DottedName(self.module_name, *context))
                    if isinstance(container, NamespaceDoc):
                        doc = container.variables.get(toktext)
                        if doc is not None:
                            url = self.url_func(doc)
                            tooltip = str(doc.canonical_name)
                # Otherwise, check the name_to_docs index to see what
                # else this name might refer to.
                if url is None and self.name_to_docs is not None and self.url_func is not None:
                    docs = self.name_to_docs.get(toktext)
                    if docs:
                        tooltip = "\n".join([str(d.canonical_name) for d in docs])
                        if len(docs) == 1 and self.GUESS_LINK_TARGETS:
                            url = self.url_func(docs[0])
                        else:
                            uid, onclick, targets = self.doclink(toktext, docs)

            # For all other tokens, look up the CSS class to use
            # based on the token's type.
            else:
                if toktype == token.OP and toktext in self.CSS_CLASSES:
                    css_class = self.CSS_CLASSES[toktext]
                elif token.tok_name[toktype] in self.CSS_CLASSES:
                    css_class = self.CSS_CLASSES[token.tok_name[toktype]]
                else:
                    css_class = None

            # update our status..
            if toktext == ":":
                in_base_list = False
                in_param_list = False
            if toktext == "=" and in_param_list:
                in_param_default = True
            if in_param_default:
                if toktext in ("(", "[", "{"):
                    in_param_default += 1
                if toktext in (")", "]", "}"):
                    in_param_default -= 1
                if toktext == "," and in_param_default == 1:
                    in_param_default = 0

            # Write this token, with appropriate colorization.
            if tooltip and self.ADD_TOOLTIPS:
                tooltip_html = ' title="%s"' % tooltip
            else:
                tooltip_html = ""
            if css_class:
                css_class_html = ' class="%s"' % css_class
            else:
                css_class_html = ""
            if onclick:
                if targets:
                    targets_html = ' targets="%s"' % targets
                else:
                    targets_html = ""
                s += '<tt id="%s"%s%s><a%s%s href="#" onclick="%s">' % (
                    uid,
                    css_class_html,
                    targets_html,
                    tooltip_html,
                    css_class_html,
                    onclick,
                )
            elif url:
                if isinstance(url, unicode):
                    url = url.encode("ascii", "xmlcharrefreplace")
                s += '<a%s%s href="%s">' % (tooltip_html, css_class_html, url)
            elif css_class_html or tooltip_html:
                s += "<tt%s%s>" % (tooltip_html, css_class_html)
            if i == len(line) - 1:
                s += " </tt>"  # Closes <tt class="py-line">
                s += cgi.escape(toktext)
            else:
                try:
                    s += self.add_line_numbers(cgi.escape(toktext), css_class)
                except Exception, e:
                    print(toktext, css_class, toktext.encode("ascii"))
                    raise

            if onclick:
                s += "</a></tt>"
            elif url:
                s += "</a>"
            elif css_class_html or tooltip_html:
                s += "</tt>"
Example #32
0
        log.warning('Finished!')
        done[0] = 'done'

    except SystemExit:
        # Cancel.
        log.error('Cancelled!')
        done[0] = 'cancel'
        raise
    except Exception, e:
        # We failed.
        log.error('Internal error: %s' % e)
        done[0] = 'cancel'
        raise
    except:
        # We failed.
        log.error('Internal error!')
        done[0] = 'cancel'
        raise


##/////////////////////////////////////////////////////////////////////////
## GUI
##/////////////////////////////////////////////////////////////////////////


class EpydocGUI:
    """
    A graphical user interace to epydoc.
    """
    def __init__(self):
        self._afterid = 0
Example #33
0
def main(options, names):
    if options.action == 'text':
        if options.parse and options.introspect:
            options.parse = False

    # Set up the logger
    if options.action == 'text':
        logger = None  # no logger for text output.
    elif options.verbosity > 1:
        logger = ConsoleLogger(options.verbosity)
        log.register_logger(logger)
    else:
        # Each number is a rough approximation of how long we spend on
        # that task, used to divide up the unified progress bar.
        stages = [
            40,  # Building documentation
            7,  # Merging parsed & introspected information
            1,  # Linking imported variables
            3,  # Indexing documentation
            30,  # Parsing Docstrings
            1,  # Inheriting documentation
            2
        ]  # Sorting & Grouping
        if options.action == 'html': stages += [100]
        elif options.action == 'text': stages += [30]
        elif options.action == 'latex': stages += [60]
        elif options.action == 'dvi': stages += [60, 30]
        elif options.action == 'ps': stages += [60, 40]
        elif options.action == 'pdf': stages += [60, 50]
        elif options.action == 'check': stages += [10]
        else: raise ValueError, '%r not supported' % options.action
        if options.parse and not options.introspect:
            del stages[1]  # no merging
        if options.introspect and not options.parse:
            del stages[1:3]  # no merging or linking
        logger = UnifiedProgressConsoleLogger(options.verbosity, stages)
        log.register_logger(logger)

    # check the output directory.
    if options.action != 'text':
        if os.path.exists(options.target):
            if not os.path.isdir(options.target):
                return log.error("%s is not a directory" % options.target)

    # Set the default docformat
    from epydoc import docstringparser
    docstringparser.DEFAULT_DOCFORMAT = options.docformat

    # Set the dot path
    if options.dotpath:
        from epydoc import dotgraph
        dotgraph.DOT_PATH = options.dotpath

    # Build docs for the named values.
    from epydoc.docbuilder import build_doc_index
    docindex = build_doc_index(names,
                               options.introspect,
                               options.parse,
                               add_submodules=(options.action != 'text'))

    if docindex is None:
        return  # docbuilder already logged an error.

    # Load profile information, if it was given.
    if options.pstat_files:
        try:
            profile_stats = pstats.Stats(options.pstat_files[0])
            for filename in options.pstat_files[1:]:
                profile_stats.add(filename)
        except KeyboardInterrupt:
            raise
        except Exception, e:
            log.error("Error reading pstat file: %s" % e)
            profile_stats = None
        if profile_stats is not None:
            docindex.read_profiling_info(profile_stats)
Example #34
0
def write_latex(docindex, options, format):
    from epydoc.docwriter.latex import LatexWriter
    latex_writer = LatexWriter(docindex, **options.__dict__)
    log.start_progress('Writing LaTeX docs')
    latex_writer.write(options.target)
    log.end_progress()
    # If we're just generating the latex, and not any output format,
    # then we're done.
    if format == 'latex': return

    if format == 'dvi': steps = 4
    elif format == 'ps': steps = 5
    elif format == 'pdf': steps = 6

    log.start_progress('Processing LaTeX docs')
    oldpath = os.path.abspath(os.curdir)
    running = None  # keep track of what we're doing.
    try:
        try:
            os.chdir(options.target)

            # Clear any old files out of the way.
            for ext in 'tex aux log out idx ilg toc ind'.split():
                if os.path.exists('apidoc.%s' % ext):
                    os.remove('apidoc.%s' % ext)

            # The first pass generates index files.
            running = 'latex'
            log.progress(0. / steps, 'LaTeX: First pass')
            run_subprocess('latex api.tex')

            # Build the index.
            running = 'makeindex'
            log.progress(1. / steps, 'LaTeX: Build index')
            run_subprocess('makeindex api.idx')

            # The second pass generates our output.
            running = 'latex'
            log.progress(2. / steps, 'LaTeX: Second pass')
            out, err = run_subprocess('latex api.tex')

            # The third pass is only necessary if the second pass
            # changed what page some things are on.
            running = 'latex'
            if _RERUN_LATEX_RE.match(out):
                log.progress(3. / steps, 'LaTeX: Third pass')
                out, err = run_subprocess('latex api.tex')

            # A fourth path should (almost?) never be necessary.
            running = 'latex'
            if _RERUN_LATEX_RE.match(out):
                log.progress(3. / steps, 'LaTeX: Fourth pass')
                run_subprocess('latex api.tex')

            # If requested, convert to postscript.
            if format in ('ps', 'pdf'):
                running = 'dvips'
                log.progress(4. / steps, 'dvips')
                run_subprocess('dvips api.dvi -o api.ps -G0 -Ppdf')

            # If requested, convert to pdf.
            if format in ('pdf'):
                running = 'ps2pdf'
                log.progress(5. / steps, 'ps2pdf')
                run_subprocess('ps2pdf -sPAPERSIZE=letter -dMaxSubsetPct=100 '
                               '-dSubsetFonts=true -dCompatibilityLevel=1.2 '
                               '-dEmbedAllFonts=true api.ps api.pdf')
        except RunSubprocessError, e:
            if running == 'latex':
                e.out = re.sub(r'(?sm)\A.*?!( LaTeX Error:)?', r'', e.out)
                e.out = re.sub(r'(?sm)\s*Type X to quit.*', '', e.out)
                e.out = re.sub(r'(?sm)^! Emergency stop.*', '', e.out)
            log.error("%s failed: %s" % (running, (e.out + e.err).lstrip()))
        except OSError, e:
            log.error("%s failed: %s" % (running, e))
Example #35
0
def build_doc_index(items, introspect=True, parse=True, add_submodules=True):
    """
    Build API documentation for the given list of items, and
    return it in the form of a L{DocIndex}.

    @rtype: L{DocIndex}
    @param items: The items to document, specified using any of the
        following:
          - A string, naming a python package directory
            (e.g., C{'epydoc/markup'})
          - A string, naming a python file
            (e.g., C{'epydoc/docparser.py'})
          - A string, naming a python object
            (e.g., C{'epydoc.docparser.DocParser'})
          - Any (non-string) python object
            (e.g., C{list.append})
    @param introspect: If true, then use introspection to examine the
        specified items.  Otherwise, just use parsing.
    @param parse: If true, then use parsing to examine the specified
        items.  Otherwise, just use introspection.
    """
    # Get the basic docs for each item.
    doc_pairs = _get_docs_from_items(items, introspect, parse, add_submodules)

    # Merge the introspection & parse docs.
    if parse and introspect:
        log.start_progress('Merging parsed & introspected information')
        docs = []
        for i, (introspect_doc, parse_doc) in enumerate(doc_pairs):
            if introspect_doc is not None and parse_doc is not None:
                if introspect_doc.canonical_name not in (None, UNKNOWN):
                    name = introspect_doc.canonical_name
                else:
                    name = parse_doc.canonical_name
                log.progress(float(i) / len(doc_pairs), name)
                docs.append(merge_docs(introspect_doc, parse_doc))
            elif introspect_doc is not None:
                docs.append(introspect_doc)
            elif parse_doc is not None:
                docs.append(parse_doc)
        log.end_progress()
    elif introspect:
        docs = [doc_pair[0] for doc_pair in doc_pairs if doc_pair[0]]
    else:
        docs = [doc_pair[1] for doc_pair in doc_pairs if doc_pair[1]]

    if len(docs) == 0:
        log.error('Nothing left to document!')
        return None

    # Collect the docs into a single index.
    docindex = DocIndex(docs)

    # Replace any proxy valuedocs that we got from importing with
    # their targets.
    if parse:
        log.start_progress('Linking imported variables')
        valdocs = docindex.reachable_valdocs(sort_by_name=True,
                                             imports=False,
                                             submodules=False,
                                             packages=False,
                                             subclasses=False)
        for i, val_doc in enumerate(valdocs):
            _report_valdoc_progress(i, val_doc, valdocs)
            link_imports(val_doc, docindex)
        log.end_progress()

    # Assign canonical names.
    log.start_progress('Indexing documentation')
    for i, val_doc in enumerate(docindex.root):
        log.progress(float(i) / len(docindex.root), val_doc.canonical_name)
        assign_canonical_names(val_doc, val_doc.canonical_name, docindex)
    log.end_progress()

    # Parse the docstrings for each object.
    log.start_progress('Parsing docstrings')
    valdocs = docindex.reachable_valdocs(sort_by_name=True,
                                         imports=False,
                                         submodules=False,
                                         packages=False,
                                         subclasses=False)
    for i, val_doc in enumerate(valdocs):
        _report_valdoc_progress(i, val_doc, valdocs)
        # the value's docstring
        parse_docstring(val_doc, docindex)
        # the value's variables' docstrings
        if (isinstance(val_doc, NamespaceDoc)
                and val_doc.variables not in (None, UNKNOWN)):
            for var_doc in val_doc.variables.values():
                parse_docstring(var_doc, docindex)
    log.end_progress()

    # Take care of inheritance.
    log.start_progress('Inheriting documentation')
    for i, val_doc in enumerate(valdocs):
        if isinstance(val_doc, ClassDoc):
            percent = float(i) / len(valdocs)
            log.progress(percent, val_doc.canonical_name)
            inherit_docs(val_doc)
    log.end_progress()

    # Initialize the groups & sortedvars attributes.
    log.start_progress('Sorting & Grouping')
    for i, val_doc in enumerate(valdocs):
        if isinstance(val_doc, NamespaceDoc):
            percent = float(i) / len(valdocs)
            log.progress(percent, val_doc.canonical_name)
            val_doc.init_sorted_variables()
            val_doc.init_variable_groups()
            if isinstance(val_doc, ModuleDoc):
                val_doc.init_submodule_groups()
    log.end_progress()

    return docindex
Example #36
0
 def _colorize_re_tree(self, tree, state, noparen, groups):
     assert noparen in (True, False)
     if len(tree) > 1 and not noparen:
         self._output('(', self.RE_GROUP_TAG, state)
     for elt in tree:
         op = elt[0]
         args = elt[1]
 
         if op == sre_constants.LITERAL:
             c = unichr(args)
             # Add any appropriate escaping.
             if c in '.^$\\*+?{}[]|()\'': c = '\\'+c
             elif c == '\t': c = '\\t'
             elif c == '\r': c = '\\r'
             elif c == '\n': c = '\\n'
             elif c == '\f': c = '\\f'
             elif c == '\v': c = '\\v'
             elif ord(c) > 0xffff: c = r'\U%08x' % ord(c)
             elif ord(c) > 0xff: c = r'\u%04x' % ord(c)
             elif ord(c)<32 or ord(c)>=127: c = r'\x%02x' % ord(c)
             self._output(c, self.RE_CHAR_TAG, state)
         
         elif op == sre_constants.ANY:
             self._output('.', self.RE_CHAR_TAG, state)
             
         elif op == sre_constants.BRANCH:
             if args[0] is not None:
                 raise ValueError('Branch expected None arg but got %s'
                                  % args[0])
             for i, item in enumerate(args[1]):
                 if i > 0:
                     self._output('|', self.RE_OP_TAG, state)
                 self._colorize_re_tree(item, state, True, groups)
             
         elif op == sre_constants.IN:
             if (len(args) == 1 and args[0][0] == sre_constants.CATEGORY):
                 self._colorize_re_tree(args, state, False, groups)
             else:
                 self._output('[', self.RE_GROUP_TAG, state)
                 self._colorize_re_tree(args, state, True, groups)
                 self._output(']', self.RE_GROUP_TAG, state)
                 
         elif op == sre_constants.CATEGORY:
             if args == sre_constants.CATEGORY_DIGIT: val = r'\d'
             elif args == sre_constants.CATEGORY_NOT_DIGIT: val = r'\D'
             elif args == sre_constants.CATEGORY_SPACE: val = r'\s'
             elif args == sre_constants.CATEGORY_NOT_SPACE: val = r'\S'
             elif args == sre_constants.CATEGORY_WORD: val = r'\w'
             elif args == sre_constants.CATEGORY_NOT_WORD: val = r'\W'
             else: raise ValueError('Unknown category %s' % args)
             self._output(val, self.RE_CHAR_TAG, state)
             
         elif op == sre_constants.AT:
             if args == sre_constants.AT_BEGINNING_STRING: val = r'\A'
             elif args == sre_constants.AT_BEGINNING: val = r'^'
             elif args == sre_constants.AT_END: val = r'$'
             elif args == sre_constants.AT_BOUNDARY: val = r'\b'
             elif args == sre_constants.AT_NON_BOUNDARY: val = r'\B'
             elif args == sre_constants.AT_END_STRING: val = r'\Z'
             else: raise ValueError('Unknown position %s' % args)
             self._output(val, self.RE_CHAR_TAG, state)
             
         elif op in (sre_constants.MAX_REPEAT, sre_constants.MIN_REPEAT):
             minrpt = args[0]
             maxrpt = args[1]
             if maxrpt == sre_constants.MAXREPEAT:
                 if minrpt == 0:   val = '*'
                 elif minrpt == 1: val = '+'
                 else: val = '{%d,}' % (minrpt)
             elif minrpt == 0:
                 if maxrpt == 1: val = '?'
                 else: val = '{,%d}' % (maxrpt)
             elif minrpt == maxrpt:
                 val = '{%d}' % (maxrpt)
             else:
                 val = '{%d,%d}' % (minrpt, maxrpt)
             if op == sre_constants.MIN_REPEAT:
                 val += '?'
                 
             self._colorize_re_tree(args[2], state, False, groups)
             self._output(val, self.RE_OP_TAG, state)
             
         elif op == sre_constants.SUBPATTERN:
             if args[0] is None:
                 self._output('(?:', self.RE_GROUP_TAG, state)
             elif args[0] in groups:
                 self._output('(?P<', self.RE_GROUP_TAG, state)
                 self._output(groups[args[0]], self.RE_REF_TAG, state)
                 self._output('>', self.RE_GROUP_TAG, state)
             elif isinstance(args[0], (int, long)):
                 # This is cheating:
                 self._output('(', self.RE_GROUP_TAG, state)
             else:
                 self._output('(?P<', self.RE_GROUP_TAG, state)
                 self._output(args[0], self.RE_REF_TAG, state)
                 self._output('>', self.RE_GROUP_TAG, state)
             self._colorize_re_tree(args[1], state, True, groups)
             self._output(')', self.RE_GROUP_TAG, state)
 
         elif op == sre_constants.GROUPREF:
             self._output('\\%d' % args, self.RE_REF_TAG, state)
 
         elif op == sre_constants.RANGE:
             self._colorize_re_tree( ((sre_constants.LITERAL, args[0]),),
                                     state, False, groups )
             self._output('-', self.RE_OP_TAG, state)
             self._colorize_re_tree( ((sre_constants.LITERAL, args[1]),),
                                     state, False, groups )
             
         elif op == sre_constants.NEGATE:
             self._output('^', self.RE_OP_TAG, state)
 
         elif op == sre_constants.ASSERT:
             if args[0] > 0:
                 self._output('(?=', self.RE_GROUP_TAG, state)
             else:
                 self._output('(?<=', self.RE_GROUP_TAG, state)
             self._colorize_re_tree(args[1], state, True, groups)
             self._output(')', self.RE_GROUP_TAG, state)
                            
         elif op == sre_constants.ASSERT_NOT:
             if args[0] > 0:
                 self._output('(?!', self.RE_GROUP_TAG, state)
             else:
                 self._output('(?<!', self.RE_GROUP_TAG, state)
             self._colorize_re_tree(args[1], state, True, groups)
             self._output(')', self.RE_GROUP_TAG, state)
 
         elif op == sre_constants.NOT_LITERAL:
             self._output('[^', self.RE_GROUP_TAG, state)
             self._colorize_re_tree( ((sre_constants.LITERAL, args),),
                                     state, False, groups )
             self._output(']', self.RE_GROUP_TAG, state)
         else:
             log.error("Error colorizing regexp: unknown elt %r" % elt)
     if len(tree) > 1 and not noparen: 
         self._output(')', self.RE_GROUP_TAG, state)
Example #37
0
        log.warning("Finished!")
        done[0] = "done"

    except SystemExit:
        # Cancel.
        log.error("Cancelled!")
        done[0] = "cancel"
        raise
    except Exception, e:
        # We failed.
        log.error("Internal error: %s" % e)
        done[0] = "cancel"
        raise
    except:
        # We failed.
        log.error("Internal error!")
        done[0] = "cancel"
        raise


##/////////////////////////////////////////////////////////////////////////
## GUI
##/////////////////////////////////////////////////////////////////////////


class EpydocGUI:
    """
    A graphical user interace to epydoc.
    """

    def __init__(self):