Skip to content

Commit

Permalink
generate docs when running gradio cc build (#7109)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
pngwn and gradio-pr-bot committed Jan 24, 2024
1 parent 21a16c6 commit 125a832
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 41 deletions.
6 changes: 6 additions & 0 deletions .changeset/lazy-things-accept.md
@@ -0,0 +1,6 @@
---
"@gradio/paramviewer": minor
"gradio": minor
---

feat:generate docs when running `gradio cc build`
36 changes: 35 additions & 1 deletion gradio/cli/commands/components/build.py
Expand Up @@ -9,6 +9,10 @@
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"
Expand All @@ -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():
Expand All @@ -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:
Expand All @@ -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()
Expand Down
125 changes: 85 additions & 40 deletions gradio/cli/commands/components/docs.py
Expand Up @@ -2,7 +2,7 @@

import importlib
from pathlib import Path
from typing import Optional
from typing import Any, Optional

import requests
import tomlkit as toml
Expand Down Expand Up @@ -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

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 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.[/]"
)
5 changes: 5 additions & 0 deletions js/paramviewer/ParamViewer.svelte
Expand Up @@ -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>
Expand All @@ -94,6 +95,10 @@
display: inline-block;
}
.disbaled {
opacity: 0;
}
.wrap :global(pre),
.wrap :global(.highlight) {
margin: 0;
Expand Down

0 comments on commit 125a832

Please sign in to comment.