From d7fc853091363a353f04cd33218c8ccd14ad6180 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Wed, 6 Oct 2021 16:23:00 +0900 Subject: [PATCH] DOC Add documentation for packages in pyodide [skip ci] (#1874) --- .../sphinx_pyodide/sphinx_pyodide/__init__.py | 2 + .../sphinx_pyodide/sphinx_pyodide/packages.py | 101 ++++++++++++++++++ docs/usage/loading-packages.md | 9 +- docs/usage/packages-in-pyodide.md | 13 +++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 docs/sphinx_pyodide/sphinx_pyodide/packages.py create mode 100644 docs/usage/packages-in-pyodide.md diff --git a/docs/sphinx_pyodide/sphinx_pyodide/__init__.py b/docs/sphinx_pyodide/sphinx_pyodide/__init__.py index a09a5a0a7..17b7bdb04 100644 --- a/docs/sphinx_pyodide/sphinx_pyodide/__init__.py +++ b/docs/sphinx_pyodide/sphinx_pyodide/__init__.py @@ -1,6 +1,7 @@ from .jsdoc import PyodideAnalyzer from .lexers import PyodideLexer, HtmlPyodideLexer from .jsdoc import get_jsdoc_summary_directive, get_jsdoc_content_directive +from .packages import get_packages_summary_directive def wrap_analyzer(app): @@ -75,3 +76,4 @@ def setup(app): app.connect("builder-inited", wrap_analyzer) app.add_directive("js-doc-summary", get_jsdoc_summary_directive(app)) app.add_directive("js-doc-content", get_jsdoc_content_directive(app)) + app.add_directive("pyodide-package-list", get_packages_summary_directive(app)) diff --git a/docs/sphinx_pyodide/sphinx_pyodide/packages.py b/docs/sphinx_pyodide/sphinx_pyodide/packages.py new file mode 100644 index 000000000..31dec7863 --- /dev/null +++ b/docs/sphinx_pyodide/sphinx_pyodide/packages.py @@ -0,0 +1,101 @@ +from docutils import nodes +from docutils.parsers.rst import Directive +import sys +import pathlib +from typing import Dict, Any, Tuple, List + +from sphinx import addnodes + + +base_dir = pathlib.Path(__file__).resolve().parents[3] +sys.path.append(str(base_dir / "pyodide-build")) + +from pyodide_build.io import parse_package_config + + +def get_packages_summary_directive(app): + class PyodidePackagesSummary(Directive): + """A directive that dumps the full list of packages included in Pyodide in place.""" + + required_arguments = 1 + + def run(self): + packages_root = base_dir / self.arguments[0] + packages_list = self.get_package_metadata_list(packages_root) + + packages = {} + for package in packages_list: + name, version, is_library = self.parse_package_info(package) + + # skip libraries (e.g. libxml, libyaml, ...) + if is_library: + continue + + packages[name] = { + "name": name, + "version": version, + } + + result = [] + columns = ("name", "version") + table_markup = self.format_packages_table(packages, columns) + result.extend(table_markup) + + return result + + def parse_package_info(self, config: pathlib.Path) -> Tuple[str, str, bool]: + yaml_data = parse_package_config(config) + + name = yaml_data["package"]["name"] + version = yaml_data["package"]["version"] + is_library = yaml_data.get("build", {}).get("library", False) + + return name, version, is_library + + def get_package_metadata_list( + self, directory: pathlib.Path + ) -> List[pathlib.Path]: + """Return metadata files of packages in alphabetical order (case insensitive)""" + return sorted( + directory.glob("**/meta.yaml"), + key=lambda path: path.parent.name.lower(), + ) + + def format_packages_table( + self, packages: Dict[str, Any], columns: Tuple[str] + ) -> List[Any]: + table_spec = addnodes.tabular_col_spec() + + table = nodes.table("", classes=["longtable"]) + + group = nodes.tgroup("", cols=len(columns)) + group.extend([nodes.colspec("", colwidth=100) for _ in columns]) + table.append(group) + + thead = nodes.thead() + row = nodes.row() + for column in columns: + entry = nodes.entry() + entry += nodes.paragraph(text=column.capitalize()) + row += entry + + thead.append(row) + group += thead + + rows = [] + for name, pkg_info in packages.items(): + row = nodes.row() + rows.append(row) + for column in columns: + value = pkg_info[column] + entry = nodes.entry() + entry += nodes.paragraph(text=value) + row += entry + + tbody = nodes.tbody() + tbody.extend(rows) + group += tbody + + return [table_spec, table] + + return PyodidePackagesSummary diff --git a/docs/usage/loading-packages.md b/docs/usage/loading-packages.md index e343bf22a..dd67bc58d 100644 --- a/docs/usage/loading-packages.md +++ b/docs/usage/loading-packages.md @@ -19,7 +19,7 @@ download all packages that the code snippet imports. This is particularly useful for making a repl since users might import unexpected packages. At present, {any}`loadPackagesFromImports ` will not download packages from PyPi, it will only download packages included in the -Pyodide distribution. +Pyodide distribution. See {ref}`packages-in-pyodide` to check the full list of packages included in Pyodide. ## Loading packages with {any}`pyodide.loadPackage` @@ -150,3 +150,10 @@ installs from PyPi. ``` + +```{eval-rst} +.. toctree:: + :hidden: + + packages-in-pyodide.md +``` \ No newline at end of file diff --git a/docs/usage/packages-in-pyodide.md b/docs/usage/packages-in-pyodide.md new file mode 100644 index 000000000..ad4b18441 --- /dev/null +++ b/docs/usage/packages-in-pyodide.md @@ -0,0 +1,13 @@ + +(packages-in-pyodide)= +# Packages built in Pyodide + +The list of prebuilt Python packages in the current version of Pyodide. +These packages can be loaded through {any}`pyodide.loadPackage` or {any}`micropip.install`. +See {ref}`loading_packages` for information about loading packages. +Note that in addition to this list, pure Python packages with wheels can be loaded +directly from PyPI with {any}`micropip.install`. + +```{eval-rst} +.. pyodide-package-list :: packages +``` \ No newline at end of file