generate docs when running gradio cc build (#7109)

* add docs command to build

* add changeset

* add changeset

* add arg to disable

* add changeset

* tweaks

* tweaks

* tweaks

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
pngwn 2024-01-24 18:12:18 +00:00 committed by GitHub
parent 21a16c60e8
commit 125a832ab7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 131 additions and 41 deletions

View File

@ -0,0 +1,6 @@
---
"@gradio/paramviewer": minor
"gradio": minor
---
feat:generate docs when running `gradio cc build`

View File

@ -9,6 +9,10 @@ from tomlkit import dump, parse
from typing_extensions import Annotated
import gradio
from gradio.cli.commands.components._docs_utils import (
get_deep,
)
from gradio.cli.commands.components.docs import run_command
from gradio.cli.commands.display import LivePanelDisplay
gradio_template_path = Path(gradio.__file__).parent / "templates" / "frontend"
@ -25,6 +29,9 @@ def _build(
bump_version: Annotated[
bool, typer.Option(help="Whether to bump the version number automatically.")
] = False,
generate_docs: Annotated[
bool, typer.Option(help="Whether to generate the documentation as well.")
] = True,
):
name = Path(path).resolve()
if not (name / "pyproject.toml").exists():
@ -35,7 +42,12 @@ def _build(
f":package: Building package in [orange3]{str(name.name)}[/]", add_sleep=0.2
)
pyproject_toml = parse((path / "pyproject.toml").read_text())
package_name = pyproject_toml["project"]["name"] # type: ignore
package_name = get_deep(pyproject_toml, ["project", "name"])
if not isinstance(package_name, str):
raise ValueError(
"Your pyproject.toml file does not have a [project] name field!"
)
try:
importlib.import_module(package_name) # type: ignore
except ModuleNotFoundError as e:
@ -62,6 +74,28 @@ def _build(
"Set [bold][magenta]--bump-version[/][/] to automatically bump the version number."
)
if generate_docs:
_demo_dir = Path("demo").resolve()
_demo_name = "app.py"
_demo_path = _demo_dir / _demo_name
_readme_path = name / "README.md"
run_command(
live=live,
name=package_name,
suppress_demo_check=False,
pyproject_toml=pyproject_toml,
generate_space=True,
generate_readme=True,
type_mode="simple",
_demo_path=_demo_path,
_demo_dir=_demo_dir,
_readme_path=_readme_path,
space_url=None,
_component_dir=name,
simple=True,
)
if build_frontend:
live.update(":art: Building frontend")
component_directory = path.resolve()

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import importlib
from pathlib import Path
from typing import Optional
from typing import Any, Optional
import requests
import tomlkit as toml
@ -77,69 +77,114 @@ def _docs(
with open(_component_dir / "pyproject.toml") as f:
data = toml.loads(f.read())
with open(_demo_path) as f:
demo = f.read()
name = get_deep(data, ["project", "name"])
if not isinstance(name, str):
raise ValueError("Name not found in pyproject.toml")
pypi_exists = requests.get(f"https://pypi.org/pypi/{name}/json").status_code
run_command(
live=live,
name=name,
suppress_demo_check=suppress_demo_check,
pyproject_toml=data,
generate_space=generate_space,
generate_readme=generate_readme,
type_mode="simple",
_demo_path=_demo_path,
_demo_dir=_demo_dir,
_readme_path=_readme_path,
space_url=space_url,
_component_dir=_component_dir,
)
pypi_exists = pypi_exists == 200 or False
local_version = get_deep(data, ["project", "version"])
description = str(get_deep(data, ["project", "description"]) or "")
repo = get_deep(data, ["project", "urls", "repository"])
space = space_url if space_url else get_deep(data, ["project", "urls", "space"])
def run_command(
live: LivePanelDisplay,
name: str,
pyproject_toml: dict[str, Any],
suppress_demo_check: bool,
generate_space: bool,
generate_readme: bool,
type_mode: str,
_demo_path: Path,
_demo_dir: Path,
_readme_path: Path,
space_url: str | None,
_component_dir: Path,
simple: bool = False,
):
with open(_demo_path) as f:
demo = f.read()
if not local_version and not pypi_exists:
raise ValueError(
f"Cannot find version in pyproject.toml or on PyPI for [orange3]{name}[/].\nIf you have just published to PyPI, please wait a few minutes and try again."
)
pypi_exists = requests.get(f"https://pypi.org/pypi/{name}/json").status_code
module = importlib.import_module(name)
(docs, type_mode) = extract_docstrings(module)
pypi_exists = pypi_exists == 200 or False
if generate_space:
local_version = get_deep(pyproject_toml, ["project", "version"])
description = str(get_deep(pyproject_toml, ["project", "description"]) or "")
repo = get_deep(pyproject_toml, ["project", "urls", "repository"])
space = (
space_url
if space_url
else get_deep(pyproject_toml, ["project", "urls", "space"])
)
if not local_version and not pypi_exists:
raise ValueError(
f"Cannot find version in pyproject.toml or on PyPI for [orange3]{name}[/].\nIf you have just published to PyPI, please wait a few minutes and try again."
)
module = importlib.import_module(name)
(docs, type_mode) = extract_docstrings(module)
if generate_space:
if not simple:
live.update(":computer: [blue]Generating space.[/]")
source = make_space(
docs=docs,
name=name,
description=description,
local_version=local_version
if local_version is None
else str(local_version),
demo=demo,
space=space if space is None else str(space),
repo=repo if repo is None else str(repo),
pypi_exists=pypi_exists,
suppress_demo_check=suppress_demo_check,
)
source = make_space(
docs=docs,
name=name,
description=description,
local_version=local_version
if local_version is None
else str(local_version),
demo=demo,
space=space if space is None else str(space),
repo=repo if repo is None else str(repo),
pypi_exists=pypi_exists,
suppress_demo_check=suppress_demo_check,
)
with open(_demo_dir / "space.py", "w") as f:
f.write(source)
with open(_demo_dir / "space.py", "w") as f:
f.write(source)
if not simple:
live.update(
f":white_check_mark: Space created in [orange3]{_demo_dir}/space.py[/]\n"
)
with open(_demo_dir / "css.css", "w") as f:
f.write(css)
with open(_demo_dir / "css.css", "w") as f:
f.write(css)
if generate_readme:
if generate_readme:
if not simple:
live.update(":pencil: [blue]Generating README.[/]")
readme = make_markdown(
docs, name, description, local_version, demo, space, repo, pypi_exists
)
readme = make_markdown(
docs, name, description, local_version, demo, space, repo, pypi_exists
)
with open(_readme_path, "w") as f:
f.write(readme)
with open(_readme_path, "w") as f:
f.write(readme)
if not simple:
live.update(
f":white_check_mark: README generated in [orange3]{_readme_path}[/]"
)
if simple:
short_readme_path = Path(_readme_path).relative_to(_component_dir)
short_demo_path = Path(_demo_dir / "space.py").relative_to(_component_dir)
live.update(
f":white_check_mark: Documention generated in [orange3]{short_demo_path}[/] and [orange3]{short_readme_path}[/]. Pass --no-generate-docs to disable auto documentation."
)
if type_mode == "simple":
print(
live.update(
"\n:orange_circle: [red]The docs were generated in simple mode. Updating python to a version greater than 3.9 will result in richer documentation.[/]"
)

View File

@ -69,6 +69,7 @@
<button
on:click={() => (show_desc[i] = !show_desc[i])}
class="arrow"
class:disabled={!description && !_default}
class:hidden={!show_desc[i]}>▲</button
>
</div>
@ -94,6 +95,10 @@
display: inline-block;
}
.disbaled {
opacity: 0;
}
.wrap :global(pre),
.wrap :global(.highlight) {
margin: 0;