def reportErrors(obj: model.Documentable, errs: Sequence[ParseError]) -> None: if errs and obj.fullName() not in obj.system.docstring_syntax_errors: obj.system.docstring_syntax_errors.add(obj.fullName()) for err in errs: obj.report('bad docstring: ' + err.descr(), lineno_offset=(err.linenum() or 1) - 1, section='docstring')
def extract_fields(obj: model.Documentable) -> None: """Populate Attributes for module/class variables using fields from that module/class's docstring. Must only be called for objects that have a docstring. """ doc = obj.docstring assert doc is not None, obj pdoc = parse_docstring(obj, doc, obj) obj.parsed_docstring = pdoc for field in pdoc.fields: tag = field.tag() if tag in ['ivar', 'cvar', 'var', 'type']: arg = field.arg() if arg is None: obj.report("Missing field name in @%s" % (tag, ), 'docstring', field.lineno) continue attrobj: Optional[model.Documentable] = obj.contents.get(arg) if attrobj is None: attrobj = obj.system.Attribute(obj.system, arg, obj) attrobj.kind = None attrobj.parentMod = obj.parentMod obj.system.addObject(attrobj) attrobj.setLineNumber(obj.docstring_lineno + field.lineno) if tag == 'type': attrobj.parsed_type = field.body() else: attrobj.parsed_docstring = field.body() attrobj.kind = field_name_to_human_name[tag]
def taglink(o: model.Documentable, label: Optional[str] = None) -> Tag: if not o.isVisible: o.system.msg("html", "don't link to %s" % o.fullName()) if label is None: label = o.fullName() # Create a link to the object, with a "data-type" attribute which says what # kind of object it is (class, etc). This helps doc2dash figure out what it # is. ret: Tag = tags.a(href=o.url, class_="code", **{"data-type": o.kind})(label) return ret
def push(self, obj: model.Documentable, lineno: int) -> None: self._stack.append(self.current) self.current = obj if isinstance(obj, model.Module): assert self.currentMod is None obj.parentMod = self.currentMod = obj elif self.currentMod is not None: if obj.parentMod is not None: assert obj.parentMod is self.currentMod else: obj.parentMod = self.currentMod else: assert obj.parentMod is None if lineno: obj.setLineNumber(lineno)
def privacyClass(self, documentable: Documentable) -> PrivacyClass: """Report the privacy level for an object. Hide the module 'docstring_parser.tests'. """ if documentable.fullName().startswith("docstring_parser.tests"): return PrivacyClass.HIDDEN return super().privacyClass(documentable)
def taglink(o: model.Documentable, page_url: str, label: Optional[str] = None) -> Tag: if not o.isVisible: o.system.msg("html", "don't link to %s" % o.fullName()) if label is None: label = o.fullName() url = o.url if url.startswith(page_url + '#'): # When linking to an item on the same page, omit the path. # Besides shortening the HTML, this also avoids the page being reloaded # if the query string is non-empty. url = url[len(page_url):] ret: Tag = tags.a(label, href=url) return ret
def node2fullname(expr: Optional[ast.expr], ctx: model.Documentable) -> Optional[str]: dottedname = node2dottedname(expr) if dottedname is None: return None base = ctx.expandName(dottedname[0]) if base: return '.'.join([base] + dottedname[1:]) else: return None
def get_docstring( obj: model.Documentable ) -> Tuple[Optional[str], Optional[model.Documentable]]: for source in obj.docsources(): doc = source.docstring if doc: return doc, source if doc is not None: # Treat empty docstring as undocumented. return None, source return None, None
def objects_order(o: model.Documentable) -> Tuple[int, int, str]: """ Function to use as the value of standard library's L{sorted} function C{key} argument such that the objects are sorted by: Privacy, Kind and Name. Example:: children = sorted((o for o in ob.contents.values() if o.isVisible), key=objects_order) """ return (-o.privacyClass.value, -o.kind.value if o.kind else 0, o.fullName().lower())
def _generateLine(self, obj: Documentable) -> str: """ Return inventory line for object. name domain_name:type priority URL display_name Domain name is always: py Priority is always: -1 Display name is always: - """ # Avoid circular import. from pydoctor import model full_name = obj.fullName() if obj.documentation_location is model.DocLocation.OWN_PAGE: url = obj.fullName() + '.html' else: url = obj.parent.fullName() + '.html#' + obj.name display = '-' if isinstance(obj, (model.Package, model.Module)): domainname = 'module' elif isinstance(obj, model.Class): domainname = 'class' elif isinstance(obj, model.Function): if obj.kind == 'Function': domainname = 'function' else: domainname = 'method' elif isinstance(obj, model.Attribute): domainname = 'attribute' else: domainname = 'obj' self.error('sphinx', "Unknown type %r for %s." % ( type(obj), full_name, )) return f'{full_name} py:{domainname} -1 {url} {display}\n'
def format_docstring(obj: model.Documentable) -> Tag: """Generate an HTML representation of a docstring""" doc, source = get_docstring(obj) # Use cached or split version if possible. pdoc = obj.parsed_docstring if source is None: if pdoc is None: # We don't use 'source' if pdoc is None, but mypy is not that # sophisticated, so we fool it by assigning a dummy object. source = obj else: # A split field is documented by its parent. source = obj.parent assert source is not None if pdoc is None and doc is not None: pdoc = parse_docstring(obj, doc, source) obj.parsed_docstring = pdoc ret: Tag = tags.div if pdoc is None: ret(tags.p(class_='undocumented')("Undocumented")) else: try: stan = pdoc.to_stan(_EpydocLinker(source)) except Exception as e: errs = [ParseError(f'{e.__class__.__name__}: {e}', 1)] if doc is None: stan = tags.p(class_="undocumented")('Broken description') else: pdoc_plain = pydoctor.epydoc.markup.plaintext.parse_docstring( doc, errs) stan = pdoc_plain.to_stan(_EpydocLinker(source)) reportErrors(source, errs) if stan.tagName: ret(stan) else: ret(*stan.children) fh = FieldHandler(obj) if isinstance(obj, model.Function): fh.set_param_types_from_annotations(obj.annotations) if pdoc is not None: for field in pdoc.fields: fh.handle(Field.from_epydoc(field, source)) if isinstance(obj, model.Function): fh.resolve_types() ret(fh.format()) return ret
def _lckey(x: model.Documentable) -> Tuple[str, str]: return (x.fullName().lower(), x.fullName())
def fullName(obj: model.Documentable) -> str: return obj.fullName()
def hasdocstring(ob: model.Documentable) -> bool: for source in ob.docsources(): if source.docstring is not None: return True return False
def node2fullname(expr: Optional[ast.expr], ctx: model.Documentable) -> Optional[str]: dottedname = node2dottedname(expr) if dottedname is None: return None return ctx.expandName('.'.join(dottedname))