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.")
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
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)
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
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