def test_section_delete_item(): a = Item("a", "int", "aaa") b = Item("b", "str", "bbb") c = Item("c", "float", "ccc") s = Section("Parameters", items=[a, b, c]) del s["b"] assert "b" not in s with pytest.raises(KeyError): del s["x"]
def parse_parameter(lines: List[str], style: str) -> Item: """Returns a Item instance that represents a parameter. Args: lines: Splitted parameter docstring lines. style: Docstring style. `google` or `numpy`. """ if style == "google": name, _, line = lines[0].partition(":") name = name.strip() parsed = [line.strip()] pattern = r"(.*?)\s*?\((.*?)\)" else: name = lines[0].strip() parsed = [] pattern = r"([^ ]*?)\s*:\s*(.*)" if len(lines) > 1: indent = get_indent(lines[1]) for line in lines[1:]: parsed.append(line[indent:]) m = re.match(pattern, name) if m: name, type = m.group(1), m.group(2) else: type = "" return Item(name, Type(type), Inline("\n".join(parsed)))
def set_attributes(self): """ Examples: >>> from mkapi.core.base import Base >>> s = Signature(Base) >>> s.parameters['name'].to_tuple() ('name', 'str, optional', 'Name of self.') >>> s.attributes['html'].to_tuple() ('html', 'str', 'HTML output after conversion.') """ items = [] for name, (type, description) in get_attributes(self.obj).items(): if isinstance(type, str) and type: type = resolve_forward_ref(self.obj, type) else: type = to_string(type, obj=self.obj) if type else "" if not type: type, description = preprocess.split_type(description) item = Item(name, Type(type), Inline(description)) if is_dataclass(self.obj): if name in self.parameters: self.parameters[name].set_description(item.description) if self.obj.__dataclass_fields__[name].type != InitVar: items.append(item) else: items.append(item) self.attributes = Section("Attributes", items=items)
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 inherit_signature(node: Node, name: str = ""): """Inherits Parameters or Attributes section from signature. Args: node: Node instance. name: Section name: 'Parameters' or 'Attributes', or ''. If name is '', both sections are inherited. Examples: >>> from mkapi.core.object import get_object >>> base = Node(get_object('mkapi.core.base.Base')) >>> [item.name for item in base.docstring['Attributes'].items] ['html'] >>> inherit_signature(base) >>> [item.name for item in base.docstring['Attributes'].items] ['name', 'markdown', 'html'] """ if not name: for name in ["Parameters", "Attributes"]: inherit_signature(node, name) return _, params = get_params(node, name) if not params: return node_section = node.docstring[name] items = [] for item_name, type in params.items(): if node_section is None or item_name not in node_section: item = Item(item_name, markdown="", type=Type(type)) else: item = node_section[item_name] # type:ignore items.append(item) node.docstring[name] = Section(name, items=items)
def transform_members(node: Node, mode: str, filters: Optional[List[str]] = None): def is_member(kind): if mode in ["method", "function"]: return mode in kind or kind == "generator" else: return mode in kind and "method" not in kind members = [ member for member in node.members if is_member(member.object.kind) ] if not members: return name = mode[0].upper() + mode[1:] + ("es" if mode == "class" else "s") section = Section(name) for member in members: object = member.object kind = object.kind type = get_type(member) if member.docstring and "" in member.docstring: description = member.docstring[""].markdown if "\n\n" in description: description = description.split("\n\n")[0] else: description = "" item = Item(object.name, type, Inline(description), kind) item.markdown, url = "", "" if filters and ("link" in filters or "all" in filters): url = "#" + object.id elif filters and "apilink" in filters: url = "../" + node.object.id + "#" + object.id signature: Dict[str, Any] = {} if object.kind not in ["class", "dataclass"]: args = [item.name for item in object.signature.parameters.items] signature["arguments"] = args else: signature["arguments"] = None item.html = renderer.render_object_member(object.name, url, signature) if filters and "sourcelink" in filters: source_link_from_section_item(item, object) section.items.append(item) node.docstring.set_section(section)
def parse_bases(doc: Docstring, obj: Any): """Parses base classes to create a Base(s) line.""" if not inspect.isclass(obj) or not hasattr(obj, "mro"): return objs = get_mro(obj)[1:] if not objs: return types = [get_link(obj, include_module=True) for obj in objs] items = [Item(type=Type(type)) for type in types if type] doc.set_section(Section("Bases", items=items))
def get_section(name: str, doc: str, style: str) -> Section: """Returns a [Section]() instance.""" type = "" markdown = "" items = [] if name in ["Parameters", "Attributes", "Raises"]: items = [ Item(n, m, Type(t)) for n, m, t in parse_parameters(doc, style) ] elif name in ["Returns", "Yields"]: markdown, type = parse_returns(doc, style) else: markdown = doc return Section(name, markdown, items, Type(type))
def transform_members(node: Node, mode: str, filters: Optional[List[str]] = None): def is_member(kind): if mode in ["method", "function"]: return mode in kind or kind == "generator" else: return mode in kind and 'method' not in kind members = [ member for member in node.members if is_member(member.object.kind) ] if not members: return name = mode[0].upper() + mode[1:] + ("es" if mode == "class" else "s") section = Section(name) for member in members: object = member.object kind = object.kind type = get_type(member) section_ = member.docstring[""] if section_: markdown = section_.markdown if "\n\n" in markdown: markdown = markdown.split("\n\n")[0] item = Item(name, markdown, type=type, kind=kind) item.markdown, url, signature = "", "", "" if filters and "link" in filters: url = "#" + object.id if object.kind not in ["class", "dataclass"]: signature = "(" + ",".join( object.signature.parameters.keys()) + ")" item.html = renderer.render_object_member(object.name, url, signature) section.items.append(item) node.docstring[name] = section
def transform_property(node: Node): section = node.docstring["Attributes"] members = [] for member in node.members: if "property" in member.object.kind: if section is None: section = Section("Attributes") node.docstring['Attributes'] = section name = member.object.name kind = member.object.kind type = member.object.type markdown = member.docstring.sections[0].markdown item = Item(name, markdown, type=type, kind=kind) section.items.append(item) else: members.append(member) node.members = members
def transform_property(node: Node, filters: List[str] = None): section = None members = [] for member in node.members: object = member.object if "property" in object.kind: if section is None: section = node.docstring["Attributes"] name = object.name kind = object.kind type = object.type description = member.docstring.sections[0].markdown item = Item(name, type, Inline(description), kind=kind) if filters and "sourcelink" in filters: source_link_from_section_item(item, object) section.items.append(item) else: members.append(member) node.members = members
def __post_init__(self): if self.obj is None: return try: self.signature = inspect.signature(self.obj) except (TypeError, ValueError): self.set_attributes() return items = [] for name, parameter in self.signature.parameters.items(): if name == "self": continue elif parameter.kind is inspect.Parameter.VAR_POSITIONAL: name = "*" + name elif parameter.kind is inspect.Parameter.VAR_KEYWORD: name = "**" + name if isinstance(parameter.annotation, str): type = resolve_forward_ref(self.obj, parameter.annotation) else: type = to_string(parameter.annotation, obj=self.obj) default = parameter.default if default == inspect.Parameter.empty: self.defaults[name] = default else: self.defaults[name] = f"{default!r}" if not type: type = "optional" elif not type.endswith(", optional"): type += ", optional" items.append(Item(name, Type(type))) self.parameters = Section("Parameters", items=items) self.set_attributes() return_annotation = self.signature.return_annotation if isinstance(return_annotation, str): self.returns = resolve_forward_ref(self.obj, return_annotation) else: self.returns = to_string(return_annotation, "returns", obj=self.obj) self.yields = to_string(return_annotation, "yields", obj=self.obj)
def test_update_item(): a = Item("a", "int", "aaa") b = Item("b", "str", "bbb") with pytest.raises(ValueError): a.update(b)