def get_method_documentation( self, node: ObjectNode, properties: Optional[List[str]] = None) -> Method: """ Get the documentation for a method. Arguments: node: The node representing the method and its parents. properties: A list of properties to apply to the method. Return: The documented method object. """ method = node.obj path = node.dotted_path source: Optional[Source] try: source = Source(*inspect.getsourcelines(method)) except OSError as error: self.errors.append(f"Couldn't read source for '{path}': {error}") source = None except TypeError: source = None return Method( name=node.name, path=path, file_path=node.file_path, docstring=inspect.getdoc(method) or "", signature=inspect.signature(method), properties=properties or [], source=source, )
def get_function_documentation(self, node: ObjectNode) -> Function: """ Get the documentation for a function. Arguments: node: The node representing the function and its parents. Return: The documented function object. """ function = node.obj path = node.dotted_path source: Optional[Source] signature: Optional[inspect.Signature] try: signature = inspect.signature(function) except TypeError as error: self.errors.append(f"Couldn't get signature for '{path}': {error}") signature = None try: source = Source(*inspect.getsourcelines(function)) except OSError as error: self.errors.append(f"Couldn't read source for '{path}': {error}") source = None return Function( name=node.name, path=node.dotted_path, file_path=node.file_path, docstring=inspect.getdoc(function) or "", signature=signature, source=source, )
def get_method_documentation( self, node: ObjectNode, properties: Optional[List[str]] = None) -> Method: """ Get the documentation for a method or method descriptor. Arguments: node: The node representing the method and its parents. properties: A list of properties to apply to the method. Returns: The documented method object. """ method = node.obj path = node.dotted_path signature: Optional[inspect.Signature] source: Optional[Source] try: source = Source(*inspect.getsourcelines(method)) except OSError as error: self.errors.append(f"Couldn't read source for '{path}': {error}") source = None except TypeError: source = None if node.is_coroutine_function(): if properties is None: properties = ["async"] else: properties.append("async") try: # for "built-in" functions, e.g. those implemented in C, # inspect.signature() uses the __text_signature__ attribute, which # provides a limited but still useful amount of signature information. # "built-in" functions with no __text_signature__ will # raise a ValueError(). signature = inspect.signature(method) except ValueError as error: self.errors.append( f"Couldn't read signature for '{path}': {error}") signature = None return Method( name=node.name, path=path, file_path=node.file_path, docstring=inspect.getdoc(method), signature=signature, properties=properties or [], source=source, )
def get_property_documentation(self, node: ObjectNode) -> Attribute: """ Get the documentation for a property. Arguments: node: The node representing the property and its parents. Returns: The documented attribute object (properties are considered attributes for now). """ prop = node.obj path = node.dotted_path properties = ["property"] if node.is_cached_property(): # cached_property is always writable, see the docs properties.extend(["writable", "cached"]) sig_source_func = prop.func else: properties.append("readonly" if prop.fset is None else "writable") sig_source_func = prop.fget source: Optional[Source] try: signature = inspect.signature(sig_source_func) except (TypeError, ValueError) as error: self.errors.append(f"Couldn't get signature for '{path}': {error}") attr_type = None else: attr_type = signature.return_annotation try: source = Source(*inspect.getsourcelines(sig_source_func)) except (OSError, TypeError) as error: self.errors.append(f"Couldn't get source for '{path}': {error}") source = None return Attribute( name=node.name, path=path, file_path=node.file_path, docstring=inspect.getdoc(prop), attr_type=attr_type, properties=properties, source=source, )
def get_property_documentation(self, node: ObjectNode) -> Attribute: """ Get the documentation for an attribute. Arguments: node: The node representing the attribute and its parents. Returns: The documented attribute object. """ prop = node.obj path = node.dotted_path properties = [ "property", "readonly" if prop.fset is None else "writable" ] source: Optional[Source] try: signature = inspect.signature(prop.fget) except (TypeError, ValueError) as error: self.errors.append(f"Couldn't get signature for '{path}': {error}") attr_type = None else: attr_type = signature.return_annotation try: source = Source(*inspect.getsourcelines(prop.fget)) except (OSError, TypeError) as error: self.errors.append(f"Couldn't get source for '{path}': {error}") source = None return Attribute( name=node.name, path=path, file_path=node.file_path, docstring=inspect.getdoc(prop.fget), attr_type=attr_type, properties=properties, source=source, )
def get_cython_function_documentation(self, node: ObjectNode) -> Function: """ Get the documentation for a cython function. Arguments: node: The node representing the cython function and its parents. Returns: The documented cython function object. """ function = node.obj path = node.dotted_path source: Optional[Source] signature: Optional[inspect.Signature] try: signature = inspect.signature(function) except TypeError as error: self.errors.append(f"Couldn't get signature for '{path}': {error}") signature = None try: source = Source(*inspect.getsourcelines(function)) except (OSError, TypeError) as error: self.errors.append(f"Couldn't read source for '{path}': {error}") source = None properties: List[str] = [] if node.is_coroutine_function(): properties.append("async") return Function( name=node.name, path=node.dotted_path, file_path=node.file_path, docstring=inspect.getdoc(function), signature=signature, source=source, properties=properties, )
def get_module_documentation(self, node: ObjectNode, select_members=None) -> Module: """ Get the documentation for a module and its children. Arguments: node: The node representing the module and its parents. select_members: Explicit members to select. Returns: The documented module object. """ module = node.obj path = node.dotted_path name = path.split(".")[-1] source: Optional[Source] try: source = Source(inspect.getsource(module), 1) except OSError as error: try: code = Path(node.file_path).read_text() except (OSError, UnicodeDecodeError): self.errors.append( f"Couldn't read source for '{path}': {error}") source = None else: source = Source(code, 1) if code else None root_object = Module( name=name, path=path, file_path=node.file_path, docstring=inspect.getdoc(module), source=source, ) if select_members is False: return root_object select_members = select_members or set() attributes_data = get_module_attributes(module) root_object.parse_docstring(self.docstring_parser, attributes=attributes_data) for member_name, member in inspect.getmembers(module): if self.select(member_name, select_members): # type: ignore child_node = ObjectNode(member, member_name, parent=node) if child_node.is_class( ) and node.root.obj is inspect.getmodule(member): root_object.add_child( self.get_class_documentation(child_node)) elif child_node.is_function( ) and node.root.obj is inspect.getmodule(member): root_object.add_child( self.get_function_documentation(child_node)) elif member_name in attributes_data: root_object.add_child( self.get_attribute_documentation( child_node, attributes_data[member_name])) if hasattr(module, "__path__"): # noqa: WPS421 (hasattr) for _, modname, _ in pkgutil.iter_modules(module.__path__): if self.select(modname, select_members): leaf = get_object_tree(f"{path}.{modname}") root_object.add_child(self.get_module_documentation(leaf)) return root_object
def get_module_documentation(self, node: ObjectNode, members=None) -> Module: """ Get the documentation for a module and its children. Arguments: node: The node representing the module and its parents. members: Explicit members to select. Return: The documented module object. """ module = node.obj path = node.dotted_path name = path.split(".")[-1] source: Optional[Source] try: source = Source(inspect.getsource(module), 1) except OSError as error: try: with Path(node.file_path).open() as fd: code = fd.readlines() if code: source = Source(code, 1) else: source = None except OSError: self.errors.append( f"Couldn't read source for '{path}': {error}") source = None root_object = Module(name=name, path=path, file_path=node.file_path, docstring=inspect.getdoc(module) or "", source=source) if members is False: return root_object # type_hints = get_type_hints(module) members = members or set() for member_name, member in inspect.getmembers( module, lambda m: node.root.obj is inspect.getmodule(m)): if self.select(member_name, members): # type: ignore child_node = ObjectNode(member, member_name, parent=node) if child_node.is_class(): root_object.add_child( self.get_class_documentation(child_node)) elif child_node.is_function(): root_object.add_child( self.get_function_documentation(child_node)) try: package_path = module.__path__ except AttributeError: pass else: for _, modname, _ in pkgutil.iter_modules(package_path): if self.select(modname, members): leaf = get_object_tree(f"{path}.{modname}") root_object.add_child(self.get_module_documentation(leaf)) return root_object