def report_errors(api_doc, docindex, parse_errors, field_warnings):
    """A helper function for L{parse_docstring()} that reports any
    markup warnings and field warnings that we encountered while
    processing C{api_doc}'s docstring."""
    if not parse_errors and not field_warnings: return

    # Get the name of the item containing the error, and the
    # filename of its containing module.
    name = api_doc.canonical_name
    module = api_doc.defining_module
    if module is not UNKNOWN and module.filename not in (None, UNKNOWN):
        try:
            filename = py_src_filename(module.filename)
        except:
            filename = module.filename
    else:
        filename = '??'

    # [xx] Don't report markup errors for standard builtins.
    # n.b. that we must use 'is' to compare pyvals here -- if we use
    # 'in' or '==', then a user __cmp__ method might raise an
    # exception, or lie.
    if isinstance(api_doc, ValueDoc) and api_doc != module:
        if module not in (None, UNKNOWN):
            return
        for builtin_val in builtins.__dict__.values():
            if builtin_val is api_doc.pyval:
                return

    # Get the start line of the docstring containing the error.
    startline = api_doc.docstring_lineno
    if startline in (None, UNKNOWN):
        startline = introspect_docstring_lineno(api_doc)
        if startline in (None, UNKNOWN):
            startline = None

    # Display a block header.
    header = 'File %s, ' % filename
    if startline is not None:
        header += 'line %d, ' % startline
    header += 'in %s' % name
    log.start_block(header)

    # Display all parse errors.  But first, combine any errors
    # with duplicate description messages.
    if startline is None:
        # remove dups, but keep original order:
        dups = {}
        for error in parse_errors:
            message = error.descr()
            if message not in dups:
                log.docstring_warning(message)
                dups[message] = 1
    else:
        # Combine line number fields for dup messages:
        messages = {}  # maps message -> list of linenum
        for error in parse_errors:
            error.set_linenum_offset(startline)
            message = error.descr()
            messages.setdefault(message, []).append(error.linenum())
        message_items = sorted(messages.items(), key=lambda a: min(a[1]))
        for message, linenums in message_items:
            linenums = [n for n in linenums if n is not None]
            if len(linenums) == 0:
                log.docstring_warning(message)
            elif len(linenums) == 1:
                log.docstring_warning("Line %s: %s" % (linenums[0], message))
            else:
                linenums = ', '.join(['%s' % l for l in linenums])
                log.docstring_warning("Lines %s: %s" % (linenums, message))

    # Display all field warnings.
    for warning in field_warnings:
        log.docstring_warning(warning)

    # End the message block.
    log.end_block()
    def __init__(self,
                 module_filename,
                 module_name,
                 docindex=None,
                 url_func=None,
                 name_to_docs=None,
                 tab_width=8):
        """
        Create a new HTML colorizer for the specified module.

        @param module_filename: The name of the file containing the
            module; its text will be loaded from this file.
        @param module_name: The dotted name of the module; this will
            be used to create links back into the API source
            documentation.
        """
        # Get the source version, if possible.
        try:
            module_filename = py_src_filename(module_filename)
        except:
            pass

        #: The filename of the module we're colorizing.
        self.module_filename = module_filename

        #: The dotted name of the module we're colorizing.
        self.module_name = module_name

        #: A docindex, used to create href links from identifiers to
        #: the API documentation for their values.
        self.docindex = docindex

        #: A mapping from short names to lists of ValueDoc, used to
        #: decide which values an identifier might map to when creating
        #: href links from identifiers to the API docs for their values.
        self.name_to_docs = name_to_docs

        #: A function that maps APIDoc -> URL, used to create href
        #: links from identifiers to the API documentation for their
        #: values.
        self.url_func = url_func

        #: The index in C{text} of the last character of the last
        #: token we've processed.
        self.pos = 0

        #: A list that maps line numbers to character offsets in
        #: C{text}.  In particular, line C{M{i}} begins at character
        #: C{line_offset[i]} in C{text}.  Since line numbers begin at
        #: 1, the first element of C{line_offsets} is C{None}.
        self.line_offsets = []

        #: A list of C{(toktype, toktext)} for all tokens on the
        #: logical line that we are currently processing.  Once a
        #: complete line of tokens has been collected in C{cur_line},
        #: it is sent to L{handle_line} for processing.
        self.cur_line = []

        #: A list of the names of the class or functions that include
        #: the current block.  C{context} has one element for each
        #: level of indentation; C{context[i]} is the name of the class
        #: or function defined by the C{i}th level of indentation, or
        #: C{None} if that level of indentation doesn't correspond to a
        #: class or function definition.
        self.context = []

        #: A list, corresponding one-to-one with L{self.context},
        #: indicating the type of each entry.  Each element of
        #: C{context_types} is one of: C{'func'}, C{'class'}, C{None}.
        self.context_types = []

        #: A list of indentation strings for each of the current
        #: block's indents.  I.e., the current total indentation can
        #: be found by taking C{''.join(self.indents)}.
        self.indents = []

        #: The line number of the line we're currently processing.
        self.lineno = 0

        #: The name of the class or function whose definition started
        #: on the previous logical line, or C{None} if the previous
        #: logical line was not a class or function definition.
        self.def_name = None

        #: The type of the class or function whose definition started
        #: on the previous logical line, or C{None} if the previous
        #: logical line was not a class or function definition.
        #: Can be C{'func'}, C{'class'}, C{None}.
        self.def_type = None

        #: The number of spaces to replace each tab in source code with
        self.tab_width = tab_width
Beispiel #3
0
def report_errors(api_doc, docindex, parse_errors, field_warnings):
    """A helper function for L{parse_docstring()} that reports any
    markup warnings and field warnings that we encountered while
    processing C{api_doc}'s docstring."""
    if not parse_errors and not field_warnings: return

    # Get the name of the item containing the error, and the
    # filename of its containing module.
    name = api_doc.canonical_name
    module = api_doc.defining_module
    if module is not UNKNOWN and module.filename not in (None, UNKNOWN):
        try: filename = py_src_filename(module.filename)
        except: filename = module.filename
    else:
        filename = '??'

    # [xx] Don't report markup errors for standard builtins.
    # n.b. that we must use 'is' to compare pyvals here -- if we use
    # 'in' or '==', then a user __cmp__ method might raise an
    # exception, or lie.
    if isinstance(api_doc, ValueDoc) and api_doc != module:
        if module not in (None, UNKNOWN) and module.pyval is exceptions:
            return
        for builtin_val in __builtin__.__dict__.values():
            if builtin_val is api_doc.pyval:
                return
        
    # Get the start line of the docstring containing the error.
    startline = api_doc.docstring_lineno
    if startline in (None, UNKNOWN):
        startline = introspect_docstring_lineno(api_doc)
        if startline in (None, UNKNOWN):
            startline = None

    # Display a block header.
    header = 'File %s, ' % filename
    if startline is not None:
        header += 'line %d, ' % startline
    header += 'in %s' % name
    log.start_block(header)
    

    # Display all parse errors.  But first, combine any errors
    # with duplicate description messages.
    if startline is None:
        # remove dups, but keep original order:
        dups = {}
        for error in parse_errors:
            message = error.descr()
            if message not in dups:
                log.docstring_warning(message)
                dups[message] = 1
    else:
        # Combine line number fields for dup messages:
        messages = {} # maps message -> list of linenum
        for error in parse_errors:
            error.set_linenum_offset(startline)
            message = error.descr()
            messages.setdefault(message, []).append(error.linenum())
        message_items = messages.items()
        message_items.sort(lambda a,b:cmp(min(a[1]), min(b[1])))
        for message, linenums in message_items:
            linenums = [n for n in linenums if n is not None]
            if len(linenums) == 0:
                log.docstring_warning(message)
            elif len(linenums) == 1:
                log.docstring_warning("Line %s: %s" % (linenums[0], message))
            else:
                linenums = ', '.join(['%s' % l for l in linenums])
                log.docstring_warning("Lines %s: %s" % (linenums, message))

    # Display all field warnings.
    for warning in field_warnings:
        log.docstring_warning(warning)

    # End the message block.
    log.end_block()
Beispiel #4
0
    def __init__(self, module_filename, module_name,
                 docindex=None, url_func=None, name_to_docs=None,
                 tab_width=8):
        """
        Create a new HTML colorizer for the specified module.

        @param module_filename: The name of the file containing the
            module; its text will be loaded from this file.
        @param module_name: The dotted name of the module; this will
            be used to create links back into the API source
            documentation.
        """
        # Get the source version, if possible.
        try: module_filename = py_src_filename(module_filename)
        except: pass
        
        #: The filename of the module we're colorizing.
        self.module_filename = module_filename
        
        #: The dotted name of the module we're colorizing.
        self.module_name = module_name

        #: A docindex, used to create href links from identifiers to
        #: the API documentation for their values.
        self.docindex = docindex

        #: A mapping from short names to lists of ValueDoc, used to
        #: decide which values an identifier might map to when creating
        #: href links from identifiers to the API docs for their values.
        self.name_to_docs = name_to_docs
            
        #: A function that maps APIDoc -> URL, used to create href
        #: links from identifiers to the API documentation for their
        #: values.
        self.url_func = url_func

        #: The index in C{text} of the last character of the last
        #: token we've processed.
        self.pos = 0

        #: A list that maps line numbers to character offsets in
        #: C{text}.  In particular, line C{M{i}} begins at character
        #: C{line_offset[i]} in C{text}.  Since line numbers begin at
        #: 1, the first element of C{line_offsets} is C{None}.
        self.line_offsets = []

        #: A list of C{(toktype, toktext)} for all tokens on the
        #: logical line that we are currently processing.  Once a
        #: complete line of tokens has been collected in C{cur_line},
        #: it is sent to L{handle_line} for processing.
        self.cur_line = []

        #: A list of the names of the class or functions that include
        #: the current block.  C{context} has one element for each
        #: level of indentation; C{context[i]} is the name of the class
        #: or function defined by the C{i}th level of indentation, or
        #: C{None} if that level of indentation doesn't correspond to a
        #: class or function definition.
        self.context = []

        #: A list, corresponding one-to-one with L{self.context},
        #: indicating the type of each entry.  Each element of
        #: C{context_types} is one of: C{'func'}, C{'class'}, C{None}.
        self.context_types = []

        #: A list of indentation strings for each of the current
        #: block's indents.  I.e., the current total indentation can
        #: be found by taking C{''.join(self.indents)}.
        self.indents = []

        #: The line number of the line we're currently processing.
        self.lineno = 0

        #: The name of the class or function whose definition started
        #: on the previous logical line, or C{None} if the previous
        #: logical line was not a class or function definition.
        self.def_name = None

        #: The type of the class or function whose definition started
        #: on the previous logical line, or C{None} if the previous
        #: logical line was not a class or function definition.
        #: Can be C{'func'}, C{'class'}, C{None}.
        self.def_type = None

        #: The number of spaces to replace each tab in source code with
        self.tab_width = tab_width
Beispiel #5
0
    def __init__(self, module_filename, module_name,
                 docindex=None, api_docs=None, url_func=None):
        """
        Create a new HTML colorizer for the specified module.

        @param module_filename: The name of the file containing the
            module; its text will be loaded from this file.
        @param module_name: The dotted name of the module; this will
            be used to create links back into the API source
            documentation.
        """
        # Get the source version, if possible.
        try: module_filename = py_src_filename(module_filename)
        except: pass
        
        #: The filename of the module we're colorizing.
        self.module_filename = module_filename
        
        #: The dotted name of the module we're colorizing.
        self.module_name = module_name

        self.docindex = docindex

        #: A mapping from short names to lists of ValueDoc.
        self.name_to_docs = {}
        for api_doc in api_docs:
            if (api_doc.canonical_name is not None and
                url_func(api_doc) is not None):
                name = api_doc.canonical_name[-1]
                self.name_to_docs.setdefault(name,set()).add(api_doc)
            
        #: A function that maps APIDoc -> URL
        self.url_func = url_func

        #: The index in C{text} of the last character of the last
        #: token we've processed.
        self.pos = 0

        #: A list that maps line numbers to character offsets in
        #: C{text}.  In particular, line C{M{i}} begins at character
        #: C{line_offset[i]} in C{text}.  Since line numbers begin at
        #: 1, the first element of C{line_offsets} is C{None}.
        self.line_offsets = []

        #: A list of C{(toktype, toktext)} for all tokens on the
        #: logical line that we are currently processing.  Once a
        #: complete line of tokens has been collected in C{cur_line},
        #: it is sent to L{handle_line} for processing.
        self.cur_line = []

        #: A list of the names of the class or functions that include
        #: the current block.  C{context} has one element for each
        #: level of indentation; C{context[i]} is the name of the class
        #: or function defined by the C{i}th level of indentation, or
        #: C{None} if that level of indentation doesn't correspond to a
        #: class or function definition.
        self.context = []

        #: A list of indentation strings for each of the current
        #: block's indents.  I.e., the current total indentation can
        #: be found by taking C{''.join(self.indents)}.
        self.indents = []

        #: The line number of the line we're currently processing.
        self.lineno = 0

        #: The name of the class or function whose definition started
        #: on the previous logical line, or C{None} if the previous
        #: logical line was not a class or function definition.
        self.def_name = None