def parse_source(doc: Docstring, obj: Any): """Parses parameters' docstring to inspect type and description from source. Examples: >>> from mkapi.core.base import Base >>> doc = Docstring() >>> parse_source(doc, Base) >>> section = doc['Parameters'] >>> section['name'].to_tuple() ('name', 'str, optional', 'Name of self.') >>> section = doc['Attributes'] >>> section['html'].to_tuple() ('html', 'str', 'HTML output after conversion.') """ signature = get_signature(obj) name = "Parameters" section = signature[name] if name in doc: section = section.merge(doc[name], force=True) if section: doc.set_section(section, replace=True) name = "Attributes" section = signature[name] if name not in doc and not section: return doc[name].update(section) if is_dataclass(obj) and "Parameters" in doc: for item in doc["Parameters"].items: if item.name in section: doc[name].set_item(item)
def test_var(): def func(x, *args, **kwargs): pass s = get_signature(func) assert s.parameters.items[1].name == "*args" assert s.parameters.items[2].name == "**kwargs"
def parse_attribute(doc: Docstring, obj: Any): """Parses attributes' docstring to inspect type and description from source.""" signature = get_signature(obj) attrs = signature.attributes attrs_desc = signature.attributes_desc if inspect.ismethod(obj): print(obj) print(attrs) if not attrs: return section = doc["Attributes"] if section is None: if any(x for x in attrs_desc.values()): section = Section("Attributes") doc["Attributes"] = section else: return items = [] for name in attrs: item = section[name] if item: if not item.type.markdown: item.type = Type(attrs[name]) if not item.markdown: item.markdown = attrs_desc[name] del section[name] elif attrs_desc[name]: item = Item(name, attrs_desc[name], type=Type(attrs[name])) else: continue items.append(item) items.extend(section.items) section.items = items
def postprocess(doc: Docstring, obj: Any): parse_bases(doc, obj) if inspect.ismodule(obj) or inspect.isclass(obj): parse_attribute(doc, obj) if isinstance(obj, property): parse_property(doc, obj) if not callable(obj): return signature = get_signature(obj) if signature.signature is None: return def get_type(type: str) -> Type: if type.startswith("("): # tuple type = type[1:-1] return Type(type) if doc["Parameters"] is not None: for item in doc["Parameters"].items: if not item.type and item.name in signature.parameters: item.type = get_type(signature.parameters[item.name]) if "{default}" in item.desc.markdown and item.name in signature: default = signature.defaults[item.name] item.desc.markdown = item.desc.markdown.replace( "{default}", default) if doc["Attributes"] is not None and signature.attributes: for item in doc["Attributes"].items: if not item.type and item.name in signature.attributes: item.type = get_type(signature.attributes[item.name]) for name in ["Returns", "Yields"]: section = doc[name] if section is not None and not section.type: section.type = Type(getattr(signature, name.lower())) if doc["Returns"] is None and doc["Yields"] is None: from mkapi.core.node import get_kind kind = get_kind(obj) if kind == "generator": doc.type = Type(signature.yields) else: doc.type = Type(signature.returns) for section in doc.sections: if section.name in ["Example", "Examples"]: break if section.markdown: section.markdown = replace_link(obj, section.markdown) else: for item in section.items: if item.markdown: item.markdown = replace_link(obj, item.markdown)
def parse_property(doc: Docstring, obj: Any): """Parses property's docstring to inspect type.""" doc.type = Type(get_signature(obj.fget).returns) if not doc.type: section = doc.sections[0] markdown = section.markdown type, markdown = preprocess.split_type(markdown) if type: doc.type = Type(type) section.markdown = markdown
def __post_init__(self): obj = get_origin(self.obj) self.sourcefile, self.lineno = get_sourcefile_and_lineno(obj) prefix, name = split_prefix_and_name(obj) qualname = get_qualname(obj) kind = self.get_kind() signature = get_signature(obj) self.object = Object( prefix=prefix, name=name, qualname=qualname, kind=kind, signature=signature, ) self.docstring = get_docstring(obj) self.obj = obj self.members = self.get_members() for member in self.members: member.parent = self
def postprocess(doc: Docstring, obj: Any): parse_bases(doc, obj) parse_source(doc, obj) if not callable(obj): return signature = get_signature(obj) if signature.signature is None: return if "Parameters" in doc: for item in doc["Parameters"].items: description = item.description if "{default}" in description.name and item.name in signature: default = signature.defaults[item.name] description.markdown = description.name.replace( "{default}", default) for name in ["Returns", "Yields"]: if name in doc: section = doc[name] if not section.type: section.type = Type(getattr(signature, name.lower())) if "Returns" not in doc and "Yields" not in doc: from mkapi.core.node import get_kind kind = get_kind(obj) if kind == "generator": doc.type = Type(signature.yields) else: doc.type = Type(signature.returns) sections: List[Section] = [] for section in doc.sections: if section.name not in ["Example", "Examples"]: for base in section: base.markdown = replace_link(obj, base.markdown) if section.name in ["Note", "Notes", "Warning", "Warnings"]: markdown = preprocess.admonition(section.name, section.markdown) if sections and sections[-1].name == "": sections[-1].markdown += "\n\n" + markdown continue else: section.name = "" section.markdown = markdown sections.append(section) doc.sections = sections