Пример #1
0
    def submodules(self) -> list["Module"]:
        """A list of all (direct) submodules."""
        if not self.is_package:
            return []

        if _safe_getattr(self.obj, "__all__", False):
            # If __all__ is set, only show submodules specified there.
            return [
                mod for mod in self.members.values()
                if isinstance(mod, Module)
                and mod.modulename.startswith(self.modulename)
            ]

        else:
            submodules = []
            for mod in pkgutil.iter_modules(
                    self.obj.__path__, f"{self.fullname}."):  # type: ignore
                if mod.name.split(".")[-1].startswith("_"):
                    continue
                try:
                    module = extract.load_module(mod.name)
                except RuntimeError:
                    warnings.warn(
                        f"Couldn't import {mod.name}:\n{traceback.format_exc()}",
                        RuntimeWarning,
                    )
                    continue
                submodules.append(Module(module))
            return submodules
Пример #2
0
def test_all_with_import_err():
    mod = extract.load_module(extract.parse_spec(here / "import_err"))
    m = Module(mod)
    with pytest.warns(
            RuntimeWarning,
            match=
            "Found 'err' in test.import_err.__all__, but it does not resolve: Error importing test.import_err",
    ):
        assert m.members
Пример #3
0
def test_attrs():
    mod = extract.load_module(
        extract.parse_spec(here / "testdata" / "demo_long.py"))

    m = Module(mod)
    assert m.variables
    assert m.classes
    assert m.functions

    c = m.members["Foo"]
    assert isinstance(c, Class)
    assert c.class_variables
    assert c.instance_variables
    assert c.classmethods
    assert c.staticmethods
    assert c.methods
Пример #4
0
    def handle_request(self) -> Optional[str]:
        """Actually handle a request. Called by `do_HEAD` and `do_GET`."""
        path = self.path.split("?", 1)[0]

        if path == "/":
            out = render.html_index(self.server.all_modules)
        else:
            module = removesuffix(path.lstrip("/"), ".html").replace("/", ".")
            if module not in self.server.all_modules:
                self.send_response(404)
                self.send_header("content-type", "text/html")
                self.end_headers()
                return render.html_error(error=f"Module {module!r} not found")

            mtime = ""
            t = extract.module_mtime(module)
            if t:
                mtime = f"{t:.1f}"
            if "mtime=1" in self.path:
                self.send_response(200)
                self.send_header("content-type", "text/plain")
                self.end_headers()
                return mtime

            try:
                extract.invalidate_caches(module)
                mod = doc.Module(extract.load_module(module))
            except Exception:
                self.send_response(500)
                self.send_header("content-type", "text/html")
                self.end_headers()
                return render.html_error(
                    error=f"Error importing {module!r}",
                    details=traceback.format_exc(),
                )
            out = render.html_module(
                module=mod,
                all_modules=self.server.all_modules,
                mtime=mtime,
            )

        self.send_response(200)
        self.send_header("content-type", "text/html")
        self.end_headers()
        return out
Пример #5
0
    def _member_objects(self) -> dict[str, Any]:
        members = {}

        all = _safe_getattr(self.obj, "__all__", False)
        if all:
            for name in all:
                if name in self.obj.__dict__:
                    val = self.obj.__dict__[name]
                elif name in self._var_annotations:
                    val = empty
                else:
                    # this may be an unimported submodule, try importing.
                    # (https://docs.python.org/3/tutorial/modules.html#importing-from-a-package)
                    try:
                        val = extract.load_module(f"{self.modulename}.{name}")
                    except RuntimeError as e:
                        warnings.warn(
                            f"Found {name!r} in {self.modulename}.__all__, but it does not resolve: {e}",
                            RuntimeWarning,
                        )
                        val = empty
                members[name] = val

        else:
            for name, obj in self.obj.__dict__.items():
                # We already exclude everything here that is imported, only a TypeVar,
                # or a variable without annotation and docstring.
                # If one needs to document one of these things, __all__ is the correct way.
                if isinstance(obj, TypeVar):
                    continue
                obj_module = inspect.getmodule(obj)
                declared_in_this_module = self.obj.__name__ == _safe_getattr(
                    obj_module, "__name__", None)
                if declared_in_this_module or name in self._documented_members:
                    members[name] = obj
            for name in self._var_annotations:
                members.setdefault(name, empty)

            members, notfound = doc_ast.sort_by_source(self.obj, {}, members)
            members.update(notfound)

        return members
Пример #6
0
    def _member_objects(self) -> dict[str, Any]:
        members = {}

        if all := _safe_getattr(self.obj, "__all__", False):
            for name in all:
                if name in self.obj.__dict__:
                    val = self.obj.__dict__[name]
                elif name in self._var_annotations:
                    val = empty
                else:
                    # this may be an unimported submodule, try importing.
                    # (https://docs.python.org/3/tutorial/modules.html#importing-from-a-package)
                    try:
                        val = extract.load_module(f"{self.modulename}.{name}")
                    except RuntimeError as e:
                        warnings.warn(
                            f"Found {name!r} in {self.modulename}.__all__, but it does not resolve: {e}",
                            RuntimeWarning,
                        )
                        val = empty
                members[name] = val
Пример #7
0
def pdoc(
    *modules: Union[Path, str],
    output_directory: Optional[Path] = None,
    format: Literal["html"] = "html",
) -> str:
    """
    Render the documentation for a list of modules.

     - If `output_directory` is `None`, returns the rendered documentation
       for the first module in the list.
     - If `output_directory` is set, recursively writes the rendered output
       for all specified modules and their submodules to the target destination.

    Rendering options can be configured by calling `pdoc.render.configure` in advance.
    """
    retval = io.StringIO()
    if output_directory:

        def write(mod: doc.Module):
            assert output_directory
            outfile = output_directory / f"{mod.fullname.replace('.', '/')}.html"
            outfile.parent.mkdir(parents=True, exist_ok=True)
            outfile.write_bytes(r(mod).encode())

    else:

        def write(mod: doc.Module):
            retval.write(r(mod))

    all_modules = extract.parse_specs(modules)

    if format == "html":

        def r(mod: doc.Module) -> str:
            return render.html_module(module=mod, all_modules=all_modules)

    elif format == "markdown":  # pragma: no cover
        raise NotImplementedError(
            "Markdown support is currently unimplemented, but PRs are welcome!"
        )
    elif format == "repr":
        r = render.repr_module
    else:
        raise ValueError(f"Invalid rendering format {format!r}.")

    for mod in all_modules:
        try:
            m = extract.load_module(mod)
        except RuntimeError:
            warnings.warn(f"Error importing {mod}:\n{traceback.format_exc()}",
                          RuntimeWarning)
        else:
            write(doc.Module(m))

        if not output_directory:
            return retval.getvalue()

    assert output_directory

    if format == "html":
        index = render.html_index(all_modules)
        if index:
            (output_directory / "index.html").write_bytes(index.encode())

    return retval.getvalue()