Ejemplo n.º 1
0
    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,
        )
Ejemplo n.º 2
0
    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,
        )
Ejemplo n.º 3
0
    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,
        )
Ejemplo n.º 4
0
    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,
        )
Ejemplo n.º 5
0
    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,
        )
Ejemplo n.º 6
0
    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,
        )
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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