Example #1
0
def get_class_attributes(cls) -> Dict[str, Tuple[Any, str]]:
    """Returns a dictionary that maps attribute name to a tuple of
    (type, description).

    Args:
        cls: Class object.

    Examples:
        >>> from examples.google_style import ExampleClass
        >>> attrs = get_class_attributes(ExampleClass)
        >>> attrs['a'][0] is str
        True
        >>> attrs['a'][1]
        'The first attribute. Comment *inline* with attribute.'
        >>> attrs['b'][0] == Dict[str, int]
        True
        >>> attrs['c'][0] is None
        True
    """
    source = get_source(cls)
    if not source:
        return {}
    source = utils.join(source.split("\n"))
    node = ast.parse(source)
    nodes = ast.walk(node)
    module = importlib.import_module(cls.__module__)
    attr_lineno = get_attributes_with_lineno(nodes, module)
    return get_attributes_dict(attr_lineno, source, prefix="self.")
Example #2
0
def split_section(doc: str) -> Iterator[Tuple[str, str, str]]:
    """Yields a tuple of (section name, contents, style).

    Args:
        doc: Docstring

    Examples:
        >>> doc = "abc\\n\\nArgs:\\n    x: X\\n"
        >>> it = split_section(doc)
        >>> next(it)
        ('', 'abc', '')
        >>> next(it)
        ('Parameters', 'x: X', 'google')
    """
    lines = [x.rstrip() for x in doc.split("\n")]
    name = ""
    style = ""
    start = indent = 0
    for stop, line in enumerate(lines, 1):
        if stop == len(lines):
            next_indent = -1
        else:
            next_indent = get_indent(lines[stop])
        if not line and next_indent < indent and name:
            if start < stop - 1:
                yield name, join(lines[start:stop - 1]), style
            start = stop
            name = ""
        else:
            section, style_ = section_heading(line)
            if section:
                if start < stop - 1:
                    yield name, join(lines[start:stop - 1]), style
                style = style_
                name = rename_section(section)
                start = stop
                if style == "numpy":  # skip underline without counting the length.
                    start += 1
                indent = next_indent
    if start < len(lines):
        yield name, join(lines[start:]), style
Example #3
0
def parse_returns(doc: str, style: str) -> Tuple[str, str]:
    """Returns a tuple of (type, markdown)."""
    lines = doc.split("\n")
    if style == "google":
        if ":" in lines[0]:
            type, _, lines[0] = lines[0].partition(":")
            type = type.strip()
            lines[0] = lines[0].strip()
        else:
            type = ""
    else:
        type = lines[0].strip()
        lines = lines[1:]
    return type, join(lines)
Example #4
0
def get_dataclass_attributes(cls) -> Dict[str, Tuple[Any, str]]:
    """Returns a dictionary that maps attribute name to a tuple of
    (type, description).

    Args:
        cls: Dataclass object.

    Examples:
        >>> from mkapi.core.base import Item, Type, Inline
        >>> attrs = get_dataclass_attributes(Item)
        >>> attrs['type'][0] is Type
        True
        >>> attrs['description'][0] is Inline
        True
    """
    fields = cls.__dataclass_fields__.values()
    attrs = {}
    for field in fields:
        if field.type != InitVar:
            attrs[field.name] = field.type, ""

    source = get_source(cls)
    source = utils.join(source.split("\n"))
    if not source:
        return {}
    node = ast.parse(source).body[0]

    def nodes():
        for x in ast.iter_child_nodes(node):
            if isinstance(x, _ast.FunctionDef):
                break
            yield x

    module = importlib.import_module(cls.__module__)
    attr_lineno = get_attributes_with_lineno(nodes(), module)
    for name, (type, description) in get_attributes_dict(attr_lineno,
                                                         source).items():
        if name in attrs:
            attrs[name] = attrs[name][0], description
        else:
            attrs[name] = type, description

    return attrs
Example #5
0
def get_class_attributes(cls) -> Dict[str, Tuple[Any, str]]:
    """Returns a dictionary that maps attribute name to a tuple of
    (type, description)."""
    try:
        source = inspect.getsource(cls.__init__) or ""
        if not source:
            return {}
    except TypeError:
        return {}
    source = utils.join(source.split("\n"))
    node = ast.parse(source)

    attr_list: List[Tuple] = []
    module = importlib.import_module(cls.__module__)
    globals = dict(inspect.getmembers(module))
    for x in ast.walk(node):
        if isinstance(x, _ast.AnnAssign):
            attr, lineno, type_str = parse_annotation_assign(x)
            type = eval(type_str, globals)
            attr_list.append((attr, lineno, type))
        if isinstance(x, _ast.Attribute) and isinstance(x.ctx, _ast.Store):
            attr_list.append(parse_attribute_with_lineno(x))
    attr_list = sorted(attr_list, key=lambda x: x[1])

    attrs: Dict[str, Tuple[Any, str]] = {}
    lines = source.split("\n")
    for name, lineno, *type in attr_list:
        if name.startswith("self."):
            name = name[5:]
            desc = get_description(lines, lineno)
            if type:
                attrs[name] = type[
                    0], desc  # Assignment with type annotation wins.
            elif name not in attrs:
                attrs[name] = None, desc
    return attrs