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
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()
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