diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index d1f0609f..3106a23e 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -9,6 +9,10 @@ on: jobs: docs-build: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + root: [sdk, cli] if: github.event.pull_request.draft == false timeout-minutes: 15 @@ -30,21 +34,25 @@ jobs: uv pip list - name: Build docs - working-directory: python/docs + working-directory: python/docs/${{ matrix.root }} run: | - export PATH="$PWD/../.venv/bin:$PATH" + export PATH="$PWD/../../.venv/bin:$PATH" make html SPHINXOPTS="-W --keep-going" - name: Upload docs artifact if: github.event_name == 'pull_request' uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: - name: docs-build - path: python/docs/build/html/ + name: docs-${{ matrix.root }} + path: python/docs/${{ matrix.root }}/build/html/ retention-days: 7 docs-linkcheck: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + root: [sdk, cli] if: github.event.pull_request.draft == false timeout-minutes: 15 @@ -65,9 +73,9 @@ jobs: uv pip install -e . - name: Check links - working-directory: python/docs + working-directory: python/docs/${{ matrix.root }} run: | - export PATH="$PWD/../.venv/bin:$PATH" + export PATH="$PWD/../../.venv/bin:$PATH" make linkcheck guardian-docs: diff --git a/.gitignore b/.gitignore index 90a93631..b0639ec9 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,7 @@ instance/ .scrapy # Sphinx documentation +/docs/ docs/_build/ python/docs/_build/ @@ -161,3 +162,4 @@ cython_debug/ .idea/ /uv.lock .vscode* +.worktrees/ diff --git a/python/README.md b/python/README.md index 1eea5542..6184ba44 100644 --- a/python/README.md +++ b/python/README.md @@ -197,7 +197,8 @@ pip install -e . Build docs from the repository root: ```bash -uv run --group docs sphinx-build -M html python/docs/source python/docs/build -W --keep-going +uv run --group docs sphinx-build -M html python/docs/sdk python/docs/sdk/build -W --keep-going +uv run --group docs sphinx-build -M html python/docs/cli python/docs/cli/build -W --keep-going ``` # License diff --git a/python/docs/Makefile b/python/docs/Makefile index 713e2915..c7222ae8 100644 --- a/python/docs/Makefile +++ b/python/docs/Makefile @@ -1,14 +1,18 @@ -# Minimal makefile for Sphinx documentation +# Build both independent Sphinx documentation roots. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SOURCEDIR = source -BUILDDIR = build +SPHINXOPTS ?= +ROOTS = sdk cli + +.PHONY: help html linkcheck clean help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @echo "Build targets: html, linkcheck, clean" + +html: + @for root in $(ROOTS); do $(MAKE) -C $$root html SPHINXOPTS="$(SPHINXOPTS)" || exit $$?; done -.PHONY: help Makefile +linkcheck: + @for root in $(ROOTS); do $(MAKE) -C $$root linkcheck SPHINXOPTS="$(SPHINXOPTS)" || exit $$?; done -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +clean: + @for root in $(ROOTS); do $(MAKE) -C $$root clean || exit $$?; done diff --git a/python/docs/cli/Makefile b/python/docs/cli/Makefile new file mode 100644 index 00000000..91116bf4 --- /dev/null +++ b/python/docs/cli/Makefile @@ -0,0 +1,14 @@ +# Minimal makefile for Sphinx documentation + +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = build + +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/python/docs/cli/_reference.py b/python/docs/cli/_reference.py new file mode 100644 index 00000000..2f0ff1a7 --- /dev/null +++ b/python/docs/cli/_reference.py @@ -0,0 +1,278 @@ +"""Structured Click command reference rendering for the CLI documentation.""" + +from __future__ import annotations + +import inspect + +import click +from click_extra.sphinx.click import TreeDirective +from docutils import nodes +from docutils.statemachine import StringList + + +def _clean_text(value: str | None) -> str: + """Return a compact description for a command or parameter.""" + if not value: + return "No description provided." + return " ".join(inspect.cleandoc(value).split()) + + +def _display_default(value: object) -> str: + if value is None: + return "—" + if isinstance(value, bool): + return str(value).lower() + return repr(value) + + +def _literal(value: object, rst: bool) -> str: + marker = "``" if rst else "`" + return f"{marker}{value}{marker}" + + +def _display_type(param: click.Parameter, context: click.Context) -> str: + """Get the Click metavar without depending on a Click minor version.""" + for getter in ( + lambda: param.make_metavar(context), + lambda: param.make_metavar(), + lambda: param.type.get_metavar(param, context), + lambda: param.type.name, + ): + try: + value = getter() + except (AttributeError, TypeError): + continue + if value: + return str(value) + return "—" + + +def _split_help(value: str | None) -> tuple[list[str], list[str]]: + """Separate command prose from its documented examples.""" + text = inspect.cleandoc(value or "").strip() + if not text: + return [], [] + + lines = text.splitlines() + example_index = next( + (index for index, line in enumerate(lines) if line.strip().lower() in {"example:", "examples:"}), + None, + ) + if example_index is None: + return lines, [] + + description = lines[:example_index] + while description and not description[-1].strip(): + description.pop() + + examples = [line[2:] if line.startswith(" ") else line for line in lines[example_index + 1 :]] + while examples and not examples[-1].strip(): + examples.pop() + return description, examples + + +def _parameter_rows( + command: click.Command, + context: click.Context, + rst: bool, +) -> tuple[list[list[str]], list[list[str]]]: + arguments: list[list[str]] = [] + options: list[list[str]] = [] + + for param in command.params: + # Every command answers --help identically, so a row for it on each + # Options table is repeated noise — omit it throughout. + if isinstance(param, click.Option) and "--help" in param.opts: + continue + description = _clean_text(getattr(param, "help", None)) + if isinstance(param, click.Argument): + # An argument's metavar just repeats its name, so show the Click + # type (text, path, integer, ...) instead. + arguments.append( + [ + _literal(param.name.upper(), rst), + _literal(param.type.name or "text", rst), + "yes" if param.required else "no", + description, + ], + ) + continue + + if isinstance(param, click.Option): + names = [*param.opts, *param.secondary_opts] + options.append( + [ + ", ".join(_literal(name, rst) for name in names), + _literal(_display_type(param, context), rst) if not param.is_flag else "—", + "yes" if param.required else "no", + # A flag's implicit false default carries no information. + "—" + if param.default is None or (param.is_flag and param.default is False) + else _literal(_display_default(param.default), rst), + description, + ], + ) + + return arguments, options + + +def _command_link(name: str, anchor: str) -> nodes.paragraph: + """A table cell linking a command's name to its section on this page.""" + paragraph = nodes.paragraph() + link = nodes.reference(refuri=f"#{anchor}") + link += nodes.literal(text=name) + paragraph += link + return paragraph + + +def _append_table( + directive: ReferenceDirective, + parent: nodes.Element, + headers: list[str], + rows: list[list[str]], + source_file: str, +) -> None: + table = nodes.table(classes=["colwidths-auto"]) + tgroup = nodes.tgroup(cols=len(headers)) + table += tgroup + for _ in headers: + tgroup += nodes.colspec(colwidth=1) + + def add_row(container: nodes.Element, values: list[str | nodes.Node]) -> None: + row = nodes.row() + for value in values: + entry = nodes.entry() + if isinstance(value, nodes.Node): + entry += value + else: + directive.state.nested_parse(StringList([value], source_file), 0, entry) + row += entry + container += row + + thead = nodes.thead() + add_row(thead, headers) + tgroup += thead + tbody = nodes.tbody() + for row in rows: + add_row(tbody, row) + tgroup += tbody + parent += table + + +class ReferenceDirective(TreeDirective): + """Render Click metadata as a structured API-style reference.""" + + def run(self) -> list[nodes.Node]: + if self.content: + self.runner.execute_source(self) + + cli_expr = self.arguments[0].strip() + try: + cli = eval(cli_expr, self.runner.namespace) + except Exception as exc: + raise RuntimeError( + f"lightning-reference: failed to evaluate {cli_expr!r}: {exc}", + ) from exc + if not isinstance(cli, click.Command): + raise TypeError( + f"lightning-reference: {cli_expr!r} did not yield a click.Command (got {type(cli).__name__}).", + ) + + max_depth = self.options.get("max-depth", 10) + root_label = self.options.get("root-label") or cli.name or cli_expr + anchor_prefix = self.options.get("anchor-prefix") or self._slug(root_label) + root_parts = root_label.split() + entries = self._walk(cli, max_depth) + source_file, _ = self.get_source_info() + # A container (not a section): the page's own title already names the + # root command, so the root gets no heading of its own — and a title-less + # section would leak its first paragraph into the page toc. The class lets + # downstream stylesheets target CLI reference pages without content-sniffing. + # Child sections are hoisted out on return (see below). + root_section = nodes.container(ids=[anchor_prefix], classes=["cli-reference"]) + command_sections: dict[tuple[str, ...], nodes.Element] = {(): root_section} + + for path, command in [([], cli), *entries]: + anchor = "-".join([anchor_prefix, *(self._slug(part) for part in path)]) + label = " ".join([root_label, *path]) + full_path = [*root_parts, *path] + context = click.Context(command, info_name=" ".join(full_path)) + if path: + command_section = nodes.section(ids=[anchor]) + command_sections[tuple(path[:-1])] += command_section + command_sections[tuple(path)] = command_section + command_section += nodes.title(text=label) + else: + command_section = root_section + + description, examples = _split_help(command.help) + if description: + self.state.nested_parse(StringList(description, source_file), 0, command_section) + + usage = " ".join(command.collect_usage_pieces(context)) + usage = " ".join([*full_path, usage]).strip() + if usage: + # A literal block (rather than an inline literal) so themes give + # the synopsis code-block treatment: highlighting + a copy button. + label = nodes.paragraph() + label += nodes.strong(text="Usage:") + command_section += label + command_section += nodes.literal_block(usage, usage, language="console") + + if isinstance(command, click.Group) and command.commands: + # "Commands" matches Click's own vocabulary: the usage line says + # `COMMAND [ARGS]...` and Click's help prints a "Commands" section. + commands_section = nodes.section(ids=[f"{anchor}-commands"]) + commands_section += nodes.title(text="Commands") + rows = [ + [ + _command_link(name, f"{anchor}-{self._slug(name)}"), + _clean_text(subcommand.get_short_help_str(limit=200)), + ] + for name, subcommand in sorted(command.commands.items()) + ] + _append_table(self, commands_section, ["Command", "Description"], rows, source_file) + command_section += commands_section + + arguments, options = _parameter_rows(command, context, True) + if arguments: + arguments_section = nodes.section(ids=[f"{anchor}-arguments"]) + arguments_section += nodes.title(text="Arguments") + _append_table( + self, + arguments_section, + ["Name", "Type", "Required", "Description"], + arguments, + source_file, + ) + command_section += arguments_section + if options: + options_section = nodes.section(ids=[f"{anchor}-options"]) + options_section += nodes.title(text="Options") + _append_table( + self, + options_section, + ["Option", "Type", "Required", "Default", "Description"], + options, + source_file, + ) + command_section += options_section + if examples: + examples_section = nodes.section(ids=[f"{anchor}-examples"]) + examples_section += nodes.title(text="Examples") + examples_section += nodes.literal_block( + "\n".join(examples), + "\n".join(examples), + language="console", + ) + command_section += examples_section + + # Hoist the root's child sections (Commands, each subcommand, ...) to + # document level: Sphinx's page toc only descends through sections, so + # anything left inside the container would vanish from "On this page". + result: list[nodes.Node] = [root_section] + for child in list(root_section.children): + if isinstance(child, nodes.section): + root_section.remove(child) + result.append(child) + return result diff --git a/python/docs/source/_static/copybutton.js b/python/docs/cli/_static/copybutton.js similarity index 100% rename from python/docs/source/_static/copybutton.js rename to python/docs/cli/_static/copybutton.js diff --git a/python/docs/source/_static/images/icon.svg b/python/docs/cli/_static/images/icon.svg similarity index 100% rename from python/docs/source/_static/images/icon.svg rename to python/docs/cli/_static/images/icon.svg diff --git a/python/docs/source/_static/images/logo-large.svg b/python/docs/cli/_static/images/logo-large.svg similarity index 100% rename from python/docs/source/_static/images/logo-large.svg rename to python/docs/cli/_static/images/logo-large.svg diff --git a/python/docs/source/_static/images/logo-small.svg b/python/docs/cli/_static/images/logo-small.svg similarity index 100% rename from python/docs/source/_static/images/logo-small.svg rename to python/docs/cli/_static/images/logo-small.svg diff --git a/python/docs/source/_static/images/logo.png b/python/docs/cli/_static/images/logo.png similarity index 100% rename from python/docs/source/_static/images/logo.png rename to python/docs/cli/_static/images/logo.png diff --git a/python/docs/source/_static/images/logo.svg b/python/docs/cli/_static/images/logo.svg similarity index 100% rename from python/docs/source/_static/images/logo.svg rename to python/docs/cli/_static/images/logo.svg diff --git a/python/docs/source/_static/main.css b/python/docs/cli/_static/main.css similarity index 100% rename from python/docs/source/_static/main.css rename to python/docs/cli/_static/main.css diff --git a/python/docs/source/_templates/theme_variables.jinja b/python/docs/cli/_templates/theme_variables.jinja similarity index 100% rename from python/docs/source/_templates/theme_variables.jinja rename to python/docs/cli/_templates/theme_variables.jinja diff --git a/python/docs/cli/api-key.rst b/python/docs/cli/api-key.rst new file mode 100644 index 00000000..ce5874b4 --- /dev/null +++ b/python/docs/cli/api-key.rst @@ -0,0 +1,8 @@ +API Key ++++++++ + +.. lightning-reference:: api_key + :root-label: lightning api-key + :anchor-prefix: api-key + + from lightning_sdk.cli.groups import api_key diff --git a/python/docs/cli/base-studio.rst b/python/docs/cli/base-studio.rst new file mode 100644 index 00000000..b1846b0a --- /dev/null +++ b/python/docs/cli/base-studio.rst @@ -0,0 +1,8 @@ +Base Studio ++++++++++++ + +.. lightning-reference:: base_studio + :root-label: lightning base-studio + :anchor-prefix: base-studio + + from lightning_sdk.cli.groups import base_studio diff --git a/python/docs/source/conf.py b/python/docs/cli/conf.py similarity index 84% rename from python/docs/source/conf.py rename to python/docs/cli/conf.py index 49ba2151..ff834e1d 100644 --- a/python/docs/source/conf.py +++ b/python/docs/cli/conf.py @@ -3,16 +3,17 @@ import sys import click -from click.formatting import HelpFormatter _PATH_HERE = os.path.abspath(os.path.dirname(__file__)) _PATH_ROOT = os.path.realpath(os.path.join(_PATH_HERE, "..", "..")) +sys.path.insert(0, _PATH_HERE) sys.path.insert(0, _PATH_ROOT) +os.environ["LIGHTNING_EXPERIMENTAL_CLI_ONLY"] = "1" + import lightning_sdk # noqa: E402 from lightning_sdk.cli.entrypoint import main_cli as _main_cli # noqa: E402 - -_main_cli.context_class.formatter_class = HelpFormatter +from _reference import ReferenceDirective # noqa: E402 _CLI_ARGUMENT_HELP = { ("lightning config set user", "user_name"): "User name to make active in the local Lightning CLI config.", @@ -96,47 +97,6 @@ def _apply_cli_argument_help(command: click.Command, command_path: str) -> None: _apply_cli_argument_help(_main_cli, "lightning") -def _strip_click_bar(line: str) -> str: - return line[2:] if line.startswith("| ") else line - - -def _is_cli_example_heading(line: str) -> bool: - return _strip_click_bar(line).strip() in {"Example:", "Examples:"} - - -def _is_cli_example_line(line: str) -> bool: - line = _strip_click_bar(line) - return line == "" or line.startswith(" ") - - -def _format_cli_examples_as_code_blocks(app, ctx, lines: list[str]) -> None: # noqa: ANN001, ARG001 - formatted: list[str] = [] - index = 0 - - while index < len(lines): - line = lines[index] - if not _is_cli_example_heading(line): - formatted.append(line) - index += 1 - continue - - formatted.extend([_strip_click_bar(line).strip(), "", ".. code-block:: console", ""]) - index += 1 - - example_lines: list[str] = [] - while index < len(lines) and _is_cli_example_line(lines[index]): - example_lines.append(_strip_click_bar(lines[index])) - index += 1 - - while example_lines and example_lines[-1] == "": - example_lines.pop() - - formatted.extend(f" {example_line.lstrip()}" if example_line else "" for example_line in example_lines) - formatted.append("") - - lines[:] = formatted - - project = "Lightning SDK" copyright = "Lightning AI" # noqa: A001 author = "Lightning AI" @@ -155,20 +115,18 @@ def _format_cli_examples_as_code_blocks(app, ctx, lines: list[str]) -> None: # "sphinx.ext.autosectionlabel", "sphinx.ext.todo", "sphinx_autodoc_typehints", - "sphinx_click", + "click_extra.sphinx", "sphinx_copybutton", "sphinx_paramlinks", "sphinx_togglebutton", - "myst_parser", ] -templates_path = ["_templates"] +click_extra_enable_exec_directives = True -myst_heading_anchors = 3 +templates_path = ["_templates"] source_suffix = { ".rst": "restructuredtext", - ".md": "markdown", } master_doc = "index" @@ -254,8 +212,6 @@ def _can_resolve_host(hostname: str) -> bool: "tqdm", "backoff", ] -sphinx_click_mock_imports = autodoc_mock_imports - copybutton_prompt_text = ">>> " copybutton_prompt_text1 = "... " copybutton_only_copy_prompt_lines = True @@ -270,4 +226,4 @@ def _can_resolve_host(hostname: str) -> bool: def setup(app) -> None: # noqa: ANN001 app.add_css_file("main.css") - app.connect("sphinx-click-process-description", _format_cli_examples_as_code_blocks) + app.add_directive("lightning-reference", ReferenceDirective) diff --git a/python/docs/cli/config.rst b/python/docs/cli/config.rst new file mode 100644 index 00000000..c801b8af --- /dev/null +++ b/python/docs/cli/config.rst @@ -0,0 +1,8 @@ +Config +++++++ + +.. lightning-reference:: config + :root-label: lightning config + :anchor-prefix: config + + from lightning_sdk.cli.groups import config diff --git a/python/docs/cli/container.rst b/python/docs/cli/container.rst new file mode 100644 index 00000000..c93c1c61 --- /dev/null +++ b/python/docs/cli/container.rst @@ -0,0 +1,8 @@ +Container ++++++++++ + +.. lightning-reference:: container + :root-label: lightning container + :anchor-prefix: container + + from lightning_sdk.cli.groups import container diff --git a/python/docs/cli/cp.rst b/python/docs/cli/cp.rst new file mode 100644 index 00000000..4c47fd57 --- /dev/null +++ b/python/docs/cli/cp.rst @@ -0,0 +1,8 @@ +Copy +++++ + +.. lightning-reference:: cp + :root-label: lightning cp + :anchor-prefix: cp + + from lightning_sdk.cli.groups import cp diff --git a/python/docs/cli/deployment.rst b/python/docs/cli/deployment.rst new file mode 100644 index 00000000..cc29bf15 --- /dev/null +++ b/python/docs/cli/deployment.rst @@ -0,0 +1,8 @@ +Deployment +++++++++++ + +.. lightning-reference:: deployment + :root-label: lightning deployment + :anchor-prefix: deployment + + from lightning_sdk.cli.groups import deployment diff --git a/python/docs/cli/file.rst b/python/docs/cli/file.rst new file mode 100644 index 00000000..b9cb5e78 --- /dev/null +++ b/python/docs/cli/file.rst @@ -0,0 +1,8 @@ +File +++++ + +.. lightning-reference:: file + :root-label: lightning file + :anchor-prefix: file + + from lightning_sdk.cli.groups import file diff --git a/python/docs/cli/folder.rst b/python/docs/cli/folder.rst new file mode 100644 index 00000000..4c317f2a --- /dev/null +++ b/python/docs/cli/folder.rst @@ -0,0 +1,8 @@ +Folder +++++++ + +.. lightning-reference:: folder + :root-label: lightning folder + :anchor-prefix: folder + + from lightning_sdk.cli.groups import folder diff --git a/python/docs/cli/index.rst b/python/docs/cli/index.rst new file mode 100644 index 00000000..6b864f4d --- /dev/null +++ b/python/docs/cli/index.rst @@ -0,0 +1,92 @@ +Command Line Interface +++++++++++++++++++++++ + +The Python package installs the ``lightning`` command. The ``lightning-sdk`` +console script is an alias for the same command group. + +Use the CLI when you want to manage Lightning AI resources from a terminal, +CI job, shell script, or other automation. + +.. lightning-reference:: main_cli + :root-label: lightning + :anchor-prefix: lightning + + from lightning_sdk.cli.entrypoint import main_cli + +Install +------- + +Install or upgrade the Python package: + +.. code-block:: bash + + pip install lightning-sdk -U + +Authenticate +------------ + +For interactive use, sign in with: + +.. code-block:: bash + + lightning login + +For non-interactive environments, configure credentials through environment +variables instead: + +.. code-block:: bash + + export LIGHTNING_USER_ID=your-user-id + export LIGHTNING_API_KEY=your-api-key + +Usage +----- + +Run a command group directly: + +.. code-block:: bash + + lightning [command] + +Every command and subcommand exposes help directly: + +.. code-block:: bash + + lightning COMMAND --help + +Common Workflows +---------------- + +* Develop interactively with :doc:`studio`. +* Submit and inspect training or batch work with :doc:`job` and :doc:`mmt`. +* Build and operate inference services with :doc:`deployment` and :doc:`model`. +* Move data and artifacts with :doc:`file`, :doc:`folder`, :doc:`container`, and :doc:`cp`. +* Configure accounts, organizations, teamspaces, cloud accounts, and SSH with + :doc:`config`, :doc:`api-key`, and :doc:`ssh`. +* Manage lower-level sandbox sessions with :doc:`sandbox`. + +Command details +--------------- + +The pages below keep focused URLs for each command group and its full option +reference. + +.. toctree:: + :maxdepth: 1 + + config + job + mmt + machine + deployment + container + model + api-key + file + folder + ssh + studio + sandbox + base-studio + license + cp diff --git a/python/docs/cli/job.rst b/python/docs/cli/job.rst new file mode 100644 index 00000000..292fc270 --- /dev/null +++ b/python/docs/cli/job.rst @@ -0,0 +1,8 @@ +Job ++++ + +.. lightning-reference:: job + :root-label: lightning job + :anchor-prefix: job + + from lightning_sdk.cli.groups import job diff --git a/python/docs/cli/license.rst b/python/docs/cli/license.rst new file mode 100644 index 00000000..9ff67763 --- /dev/null +++ b/python/docs/cli/license.rst @@ -0,0 +1,8 @@ +License ++++++++ + +.. lightning-reference:: license + :root-label: lightning license + :anchor-prefix: license + + from lightning_sdk.cli.groups import license diff --git a/python/docs/cli/machine.rst b/python/docs/cli/machine.rst new file mode 100644 index 00000000..d02e6d0c --- /dev/null +++ b/python/docs/cli/machine.rst @@ -0,0 +1,8 @@ +Machine ++++++++ + +.. lightning-reference:: machine + :root-label: lightning machine + :anchor-prefix: machine + + from lightning_sdk.cli.groups import machine diff --git a/python/docs/cli/make.bat b/python/docs/cli/make.bat new file mode 100644 index 00000000..c1becfd1 --- /dev/null +++ b/python/docs/cli/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/python/docs/cli/mmt.rst b/python/docs/cli/mmt.rst new file mode 100644 index 00000000..b994fb61 --- /dev/null +++ b/python/docs/cli/mmt.rst @@ -0,0 +1,8 @@ +Multi-Machine Training +++++++++++++++++++++++ + +.. lightning-reference:: mmt + :root-label: lightning mmt + :anchor-prefix: mmt + + from lightning_sdk.cli.groups import mmt diff --git a/python/docs/cli/model.rst b/python/docs/cli/model.rst new file mode 100644 index 00000000..5dafe706 --- /dev/null +++ b/python/docs/cli/model.rst @@ -0,0 +1,8 @@ +Model ++++++ + +.. lightning-reference:: model + :root-label: lightning model + :anchor-prefix: model + + from lightning_sdk.cli.groups import model diff --git a/python/docs/cli/sandbox.rst b/python/docs/cli/sandbox.rst new file mode 100644 index 00000000..f8e711d2 --- /dev/null +++ b/python/docs/cli/sandbox.rst @@ -0,0 +1,8 @@ +Sandbox ++++++++ + +.. lightning-reference:: sandbox + :root-label: lightning sandbox + :anchor-prefix: sandbox + + from lightning_sdk.cli.groups import sandbox diff --git a/python/docs/cli/ssh.rst b/python/docs/cli/ssh.rst new file mode 100644 index 00000000..fdd0ab7e --- /dev/null +++ b/python/docs/cli/ssh.rst @@ -0,0 +1,8 @@ +SSH ++++ + +.. lightning-reference:: ssh + :root-label: lightning ssh + :anchor-prefix: ssh + + from lightning_sdk.cli.groups import ssh diff --git a/python/docs/cli/studio.rst b/python/docs/cli/studio.rst new file mode 100644 index 00000000..43ae54cc --- /dev/null +++ b/python/docs/cli/studio.rst @@ -0,0 +1,8 @@ +Studio +++++++ + +.. lightning-reference:: studio + :root-label: lightning studio + :anchor-prefix: studio + + from lightning_sdk.cli.groups import studio diff --git a/python/docs/make.bat b/python/docs/make.bat index 4d9eb83d..b6f1cd11 100644 --- a/python/docs/make.bat +++ b/python/docs/make.bat @@ -2,34 +2,20 @@ pushd %~dp0 -REM Command file for Sphinx documentation +if "%1" == "" goto help if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) -set SOURCEDIR=source -set BUILDDIR=build - -if "%1" == "" goto help -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 +for %%R in (sdk cli) do ( + call %%R\make.bat %1 + if errorlevel 1 exit /b 1 ) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% goto end :help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +echo Build targets: html, linkcheck, clean :end popd diff --git a/python/docs/sdk/Makefile b/python/docs/sdk/Makefile new file mode 100644 index 00000000..91116bf4 --- /dev/null +++ b/python/docs/sdk/Makefile @@ -0,0 +1,14 @@ +# Minimal makefile for Sphinx documentation + +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = build + +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/python/docs/sdk/_static/copybutton.js b/python/docs/sdk/_static/copybutton.js new file mode 100644 index 00000000..aef241ab --- /dev/null +++ b/python/docs/sdk/_static/copybutton.js @@ -0,0 +1,78 @@ +/* Copied from the official Python docs: https://docs.python.org/3/_static/copybutton.js */ +$(document).ready(function () { + /* Add a [>>>] button on the top-right corner of code samples to hide + * the >>> and ... prompts and the output and thus make the code + * copyable. */ + var div = $( + ".highlight-python .highlight," + + ".highlight-python3 .highlight," + + ".highlight-pycon .highlight," + + ".highlight-default .highlight", + ); + var pre = div.find("pre"); + + // get the styles from the current theme + pre.parent().parent().css("position", "relative"); + var hide_text = "Hide the prompts and output"; + var show_text = "Show the prompts and output"; + var border_width = pre.css("border-top-width"); + var border_style = pre.css("border-top-style"); + var border_color = pre.css("border-top-color"); + var button_styles = { + cursor: "pointer", + position: "absolute", + top: "0", + right: "0", + "border-color": border_color, + "border-style": border_style, + "border-width": border_width, + color: border_color, + "text-size": "75%", + "font-family": "monospace", + "padding-left": "0.2em", + "padding-right": "0.2em", + "border-radius": "0 3px 0 0", + }; + + // create and add the button to all the code blocks that contain >>> + div.each(function (index) { + var jthis = $(this); + if (jthis.find(".gp").length > 0) { + var button = $('>>>'); + button.css(button_styles); + button.attr("title", hide_text); + button.data("hidden", "false"); + jthis.prepend(button); + } + // tracebacks (.gt) contain bare text elements that need to be + // wrapped in a span to work with .nextUntil() (see later) + jthis + .find("pre:has(.gt)") + .contents() + .filter(function () { + return this.nodeType == 3 && this.data.trim().length > 0; + }) + .wrap(""); + }); + + // define the behavior of the button when it's clicked + $(".copybutton").click(function (e) { + e.preventDefault(); + var button = $(this); + if (button.data("hidden") === "false") { + // hide the code output + button.parent().find(".go, .gp, .gt").hide(); + button.next("pre").find(".gt").nextUntil(".gp, .go").css("visibility", "hidden"); + button.css("text-decoration", "line-through"); + button.attr("title", show_text); + button.data("hidden", "true"); + } else { + // show the code output + button.parent().find(".go, .gp, .gt").show(); + button.next("pre").find(".gt").nextUntil(".gp, .go").css("visibility", "visible"); + button.css("text-decoration", "none"); + button.attr("title", hide_text); + button.data("hidden", "false"); + } + }); +}); diff --git a/python/docs/sdk/_static/images/icon.svg b/python/docs/sdk/_static/images/icon.svg new file mode 100644 index 00000000..e88fc190 --- /dev/null +++ b/python/docs/sdk/_static/images/icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/python/docs/sdk/_static/images/logo-large.svg b/python/docs/sdk/_static/images/logo-large.svg new file mode 100644 index 00000000..39531f95 --- /dev/null +++ b/python/docs/sdk/_static/images/logo-large.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/python/docs/sdk/_static/images/logo-small.svg b/python/docs/sdk/_static/images/logo-small.svg new file mode 100644 index 00000000..1f523a57 --- /dev/null +++ b/python/docs/sdk/_static/images/logo-small.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/python/docs/sdk/_static/images/logo.png b/python/docs/sdk/_static/images/logo.png new file mode 100644 index 00000000..392c965b Binary files /dev/null and b/python/docs/sdk/_static/images/logo.png differ diff --git a/python/docs/sdk/_static/images/logo.svg b/python/docs/sdk/_static/images/logo.svg new file mode 100644 index 00000000..60efaa29 --- /dev/null +++ b/python/docs/sdk/_static/images/logo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/python/docs/sdk/_static/main.css b/python/docs/sdk/_static/main.css new file mode 100644 index 00000000..8739cdf7 --- /dev/null +++ b/python/docs/sdk/_static/main.css @@ -0,0 +1 @@ +/* Custom styles for lightning-sdk docs */ diff --git a/python/docs/sdk/_templates/theme_variables.jinja b/python/docs/sdk/_templates/theme_variables.jinja new file mode 100644 index 00000000..5d092539 --- /dev/null +++ b/python/docs/sdk/_templates/theme_variables.jinja @@ -0,0 +1,18 @@ +{%- set external_urls = { + 'github': 'https://github.com/Lightning-AI/lightning-Sandbox', + 'github_issues': 'https://github.com/Lightning-AI/lightning-Sandbox/issues', + 'contributing': 'https://github.com/Lightning-AI/lightning/blob/master/CONTRIBUTING.md', + 'governance': 'https://github.com/Lightning-AI/lightning/blob/master/governance.md', + 'docs': 'https://lightning-ai.github.io/lightning-Sandbox/', + 'twitter': 'https://twitter.com/LightningAI', + 'discuss': 'https://discord.com/invite/tfXFetEZxv', + 'tutorials': 'https://lightning.ai', + 'previous_pytorch_versions': 'https://lightning-ai.github.io/lightning-Sandbox/', + 'home': 'https://lightning-ai.github.io/lightning-Sandbox/', + 'get_started': 'https://lightning.ai', + 'features': 'https://lightning-ai.github.io/lightning-Sandbox/', + 'blog': 'https://www.Lightning.ai/blog', + 'resources': 'https://lightning.ai', + 'support': 'https://lightning-ai.github.io/lightning-Sandbox/', +} +-%} diff --git a/python/docs/source/api.rst b/python/docs/sdk/api.rst similarity index 100% rename from python/docs/source/api.rst rename to python/docs/sdk/api.rst diff --git a/python/docs/source/api/agent.rst b/python/docs/sdk/api/agent.rst similarity index 100% rename from python/docs/source/api/agent.rst rename to python/docs/sdk/api/agent.rst diff --git a/python/docs/source/api/deployment.rst b/python/docs/sdk/api/deployment.rst similarity index 100% rename from python/docs/source/api/deployment.rst rename to python/docs/sdk/api/deployment.rst diff --git a/python/docs/source/api/experiment.rst b/python/docs/sdk/api/experiment.rst similarity index 100% rename from python/docs/source/api/experiment.rst rename to python/docs/sdk/api/experiment.rst diff --git a/python/docs/source/api/job.rst b/python/docs/sdk/api/job.rst similarity index 100% rename from python/docs/source/api/job.rst rename to python/docs/sdk/api/job.rst diff --git a/python/docs/source/api/k8s-cluster.rst b/python/docs/sdk/api/k8s-cluster.rst similarity index 100% rename from python/docs/source/api/k8s-cluster.rst rename to python/docs/sdk/api/k8s-cluster.rst diff --git a/python/docs/source/api/machine.rst b/python/docs/sdk/api/machine.rst similarity index 100% rename from python/docs/source/api/machine.rst rename to python/docs/sdk/api/machine.rst diff --git a/python/docs/source/api/mmt.rst b/python/docs/sdk/api/mmt.rst similarity index 100% rename from python/docs/source/api/mmt.rst rename to python/docs/sdk/api/mmt.rst diff --git a/python/docs/source/api/models.rst b/python/docs/sdk/api/models.rst similarity index 100% rename from python/docs/source/api/models.rst rename to python/docs/sdk/api/models.rst diff --git a/python/docs/source/api/organization.rst b/python/docs/sdk/api/organization.rst similarity index 100% rename from python/docs/source/api/organization.rst rename to python/docs/sdk/api/organization.rst diff --git a/python/docs/source/api/owner.rst b/python/docs/sdk/api/owner.rst similarity index 100% rename from python/docs/source/api/owner.rst rename to python/docs/sdk/api/owner.rst diff --git a/python/docs/source/api/status.rst b/python/docs/sdk/api/status.rst similarity index 100% rename from python/docs/source/api/status.rst rename to python/docs/sdk/api/status.rst diff --git a/python/docs/source/api/studio.rst b/python/docs/sdk/api/studio.rst similarity index 100% rename from python/docs/source/api/studio.rst rename to python/docs/sdk/api/studio.rst diff --git a/python/docs/source/api/teamspace.rst b/python/docs/sdk/api/teamspace.rst similarity index 100% rename from python/docs/source/api/teamspace.rst rename to python/docs/sdk/api/teamspace.rst diff --git a/python/docs/source/api/user.rst b/python/docs/sdk/api/user.rst similarity index 100% rename from python/docs/source/api/user.rst rename to python/docs/sdk/api/user.rst diff --git a/python/docs/sdk/conf.py b/python/docs/sdk/conf.py new file mode 100644 index 00000000..b7dcd0a3 --- /dev/null +++ b/python/docs/sdk/conf.py @@ -0,0 +1,139 @@ +import os +import socket +import sys + +_PATH_HERE = os.path.abspath(os.path.dirname(__file__)) +_PATH_ROOT = os.path.realpath(os.path.join(_PATH_HERE, "..", "..")) +sys.path.insert(0, _PATH_ROOT) + +import lightning_sdk # noqa: E402 +project = "Lightning SDK" +copyright = "Lightning AI" # noqa: A001 +author = "Lightning AI" +version = lightning_sdk.__version__ +release = lightning_sdk.__version__ + +needs_sphinx = "8.0" + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinx.ext.autosectionlabel", + "sphinx.ext.todo", + "sphinx_autodoc_typehints", + "sphinx_copybutton", + "sphinx_paramlinks", + "sphinx_togglebutton", + "myst_parser", +] + +templates_path = ["_templates"] + +myst_heading_anchors = 3 + +source_suffix = { + ".rst": "restructuredtext", + ".md": "markdown", +} + +master_doc = "index" +language = "en" +exclude_patterns = ["_build", "_templates"] +pygments_style = None + +html_theme = "pydata_sphinx_theme" +html_theme_options = { + "github_url": "https://github.com/Lightning-AI/lightning-sdk", + "show_toc_level": 2, +} + +html_static_path = ["_static"] +htmlhelp_basename = "lightning-sdk-doc" + + +def _can_resolve_host(hostname: str) -> bool: + try: + socket.getaddrinfo(hostname, 443) + except OSError: + return False + return True + + +if all(_can_resolve_host(host) for host in ("docs.python.org", "pytorch.org")): + intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "torch": ("https://pytorch.org/docs/stable/", None), + } +else: + intersphinx_mapping = {} + +nitpicky = True +nitpick_ignore = [ + ("py:class", "typing.Any"), + ("py:data", "typing.Any"), + ("py:data", "typing.Optional"), + ("py:data", "typing.Union"), + ("py:class", "pathlib.Path"), + ("py:class", "pathlib._local.Path"), + ("py:class", "enum.Enum"), + # base / internal types not worth documenting separately + ("py:class", "Auth"), + ("py:class", "lightning_sdk.api.deployment_api.Auth"), + ("py:class", "MachineDict"), +] +nitpick_ignore_regex = [ + # private / internal base classes + ("py:class", r".*\._\w+"), + # generated openapi types (full path) + ("py:class", r"lightning_sdk\.lightning_cloud\..*"), + # V1* and Externalv1* openapi short names + ("py:class", r"V1\w+"), + ("py:class", r"Externalv1\w+"), +] + +autosummary_generate = True +autodoc_member_order = "groupwise" +autoclass_content = "both" +autodoc_typehints = "description" +typehints_description_target = "documented_params" + +autodoc_default_options = { + "members": True, + "methods": True, + "special-members": "__call__", + "exclude-members": "_abc_impl", + "show-inheritance": True, +} + +autosectionlabel_prefix_document = True +autosectionlabel_maxdepth = 1 + +autodoc_mock_imports = [ + "lightning_cloud", + "requests", + "docker", + "fastapi", + "uvicorn", + "simple_term_menu", + "rich", + "tqdm", + "backoff", +] +copybutton_prompt_text = ">>> " +copybutton_prompt_text1 = "... " +copybutton_only_copy_prompt_lines = True + +linkcheck_anchors = False +linkcheck_timeout = 60 +linkcheck_retries = 3 +linkcheck_ignore = [ + r"https://lightning\.ai/.*", +] + + +def setup(app) -> None: # noqa: ANN001 + app.add_css_file("main.css") diff --git a/python/docs/source/examples.rst b/python/docs/sdk/examples.rst similarity index 100% rename from python/docs/source/examples.rst rename to python/docs/sdk/examples.rst diff --git a/python/docs/source/examples/api-cli.rst b/python/docs/sdk/examples/api-cli.rst similarity index 100% rename from python/docs/source/examples/api-cli.rst rename to python/docs/sdk/examples/api-cli.rst diff --git a/python/docs/source/examples/jobs-cli.rst b/python/docs/sdk/examples/jobs-cli.rst similarity index 100% rename from python/docs/source/examples/jobs-cli.rst rename to python/docs/sdk/examples/jobs-cli.rst diff --git a/python/docs/source/examples/jobs.rst b/python/docs/sdk/examples/jobs.rst similarity index 100% rename from python/docs/source/examples/jobs.rst rename to python/docs/sdk/examples/jobs.rst diff --git a/python/docs/source/examples/mmts-cli.rst b/python/docs/sdk/examples/mmts-cli.rst similarity index 100% rename from python/docs/source/examples/mmts-cli.rst rename to python/docs/sdk/examples/mmts-cli.rst diff --git a/python/docs/source/examples/mmts.rst b/python/docs/sdk/examples/mmts.rst similarity index 100% rename from python/docs/source/examples/mmts.rst rename to python/docs/sdk/examples/mmts.rst diff --git a/python/docs/source/examples/sandboxes-cli.rst b/python/docs/sdk/examples/sandboxes-cli.rst similarity index 100% rename from python/docs/source/examples/sandboxes-cli.rst rename to python/docs/sdk/examples/sandboxes-cli.rst diff --git a/python/docs/source/examples/sandboxes.rst b/python/docs/sdk/examples/sandboxes.rst similarity index 100% rename from python/docs/source/examples/sandboxes.rst rename to python/docs/sdk/examples/sandboxes.rst diff --git a/python/docs/source/examples/studios-cli.rst b/python/docs/sdk/examples/studios-cli.rst similarity index 100% rename from python/docs/source/examples/studios-cli.rst rename to python/docs/sdk/examples/studios-cli.rst diff --git a/python/docs/source/examples/studios.rst b/python/docs/sdk/examples/studios.rst similarity index 100% rename from python/docs/source/examples/studios.rst rename to python/docs/sdk/examples/studios.rst diff --git a/python/docs/source/examples/teamspaces-cli.rst b/python/docs/sdk/examples/teamspaces-cli.rst similarity index 100% rename from python/docs/source/examples/teamspaces-cli.rst rename to python/docs/sdk/examples/teamspaces-cli.rst diff --git a/python/docs/source/examples/teamspaces.rst b/python/docs/sdk/examples/teamspaces.rst similarity index 100% rename from python/docs/source/examples/teamspaces.rst rename to python/docs/sdk/examples/teamspaces.rst diff --git a/python/docs/source/index.rst b/python/docs/sdk/index.rst similarity index 88% rename from python/docs/source/index.rst rename to python/docs/sdk/index.rst index 5e78f425..234127f4 100644 --- a/python/docs/source/index.rst +++ b/python/docs/sdk/index.rst @@ -47,8 +47,6 @@ Documentation Map The :ref:`Examples ` provide tutorial walkthroughs for common CLI and SDK workflows. -The :ref:`CLI reference ` documents the command-line interface. - The :ref:`API reference ` documents every public class and function. .. _start-section: @@ -62,14 +60,4 @@ Start install quickstart examples - cli - -.. _api-reference-section: - -API Reference -============= - -.. toctree:: - :maxdepth: 1 - api diff --git a/python/docs/source/install.rst b/python/docs/sdk/install.rst similarity index 100% rename from python/docs/source/install.rst rename to python/docs/sdk/install.rst diff --git a/python/docs/sdk/make.bat b/python/docs/sdk/make.bat new file mode 100644 index 00000000..c1becfd1 --- /dev/null +++ b/python/docs/sdk/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/python/docs/source/quickstart.rst b/python/docs/sdk/quickstart.rst similarity index 100% rename from python/docs/source/quickstart.rst rename to python/docs/sdk/quickstart.rst diff --git a/python/docs/source/cli.rst b/python/docs/source/cli.rst deleted file mode 100644 index 55c2ae44..00000000 --- a/python/docs/source/cli.rst +++ /dev/null @@ -1,93 +0,0 @@ -Command Line Interface -====================== - -The Python package installs the ``lightning`` command. The ``lightning-sdk`` -console script is an alias for the same command group. - -Use the CLI when you want to manage Lightning AI resources from a terminal, -CI job, shell script, or other automation. The command reference below is -generated from the Click command tree, so command groups, options, arguments, -and examples stay aligned with the installed package. - -Install -------- - -Install or upgrade the Python package: - -.. code-block:: bash - - pip install lightning-sdk -U - -Authenticate ------------- - -For interactive use, sign in with: - -.. code-block:: bash - - lightning login - -For non-interactive environments, configure credentials through environment -variables instead: - -.. code-block:: bash - - export LIGHTNING_USER_ID=your-user-id - export LIGHTNING_API_KEY=your-api-key - -Usage ------ - -Run a command group directly: - -.. code-block:: bash - - lightning [command] - -Every command and subcommand exposes help from the same Click definitions used -by this reference: - -.. code-block:: bash - - lightning COMMAND --help - -Common Workflows ----------------- - -- Develop interactively with :doc:`cli/studio`. -- Submit and inspect training or batch work with :doc:`cli/job` and - :doc:`cli/mmt`. -- Build and operate inference services with :doc:`cli/deployment` and - :doc:`cli/model`. -- Move data and artifacts with :doc:`cli/file`, :doc:`cli/folder`, - :doc:`cli/container`, and :doc:`cli/cp`. -- Configure accounts, organizations, teamspaces, cloud accounts, and SSH with - :doc:`cli/config`, :doc:`cli/api-key`, and :doc:`cli/ssh`. -- Manage lower-level sandbox sessions with :doc:`cli/sandbox`. - -Command Groups --------------- - -.. toctree:: - :maxdepth: 1 - - cli/config - cli/job - cli/mmt - cli/machine - cli/deployment - cli/container - cli/model - cli/api-key - cli/file - cli/folder - cli/ssh - cli/studio - cli/sandbox - cli/base-studio - cli/license - cli/cp - -.. click:: lightning_sdk.cli.entrypoint:main_cli - :prog: lightning - :nested: short diff --git a/python/docs/source/cli/api-key.rst b/python/docs/source/cli/api-key.rst deleted file mode 100644 index 0ffcbc03..00000000 --- a/python/docs/source/cli/api-key.rst +++ /dev/null @@ -1,6 +0,0 @@ -API Key -======= - -.. click:: lightning_sdk.cli.groups:api_key - :prog: lightning api-key - :nested: full diff --git a/python/docs/source/cli/base-studio.rst b/python/docs/source/cli/base-studio.rst deleted file mode 100644 index f9cc7415..00000000 --- a/python/docs/source/cli/base-studio.rst +++ /dev/null @@ -1,6 +0,0 @@ -Base Studio -=========== - -.. click:: lightning_sdk.cli.groups:base_studio - :prog: lightning base-studio - :nested: full diff --git a/python/docs/source/cli/config.rst b/python/docs/source/cli/config.rst deleted file mode 100644 index e33ec115..00000000 --- a/python/docs/source/cli/config.rst +++ /dev/null @@ -1,6 +0,0 @@ -Config -====== - -.. click:: lightning_sdk.cli.groups:config - :prog: lightning config - :nested: full diff --git a/python/docs/source/cli/container.rst b/python/docs/source/cli/container.rst deleted file mode 100644 index 4c4a8143..00000000 --- a/python/docs/source/cli/container.rst +++ /dev/null @@ -1,6 +0,0 @@ -Container -========= - -.. click:: lightning_sdk.cli.groups:container - :prog: lightning container - :nested: full diff --git a/python/docs/source/cli/cp.rst b/python/docs/source/cli/cp.rst deleted file mode 100644 index 57598bb5..00000000 --- a/python/docs/source/cli/cp.rst +++ /dev/null @@ -1,6 +0,0 @@ -Copy -==== - -.. click:: lightning_sdk.cli.groups:cp - :prog: lightning cp - :nested: full diff --git a/python/docs/source/cli/deployment.rst b/python/docs/source/cli/deployment.rst deleted file mode 100644 index 1c6a1c65..00000000 --- a/python/docs/source/cli/deployment.rst +++ /dev/null @@ -1,6 +0,0 @@ -Deployment -========== - -.. click:: lightning_sdk.cli.groups:deployment - :prog: lightning deployment - :nested: full diff --git a/python/docs/source/cli/file.rst b/python/docs/source/cli/file.rst deleted file mode 100644 index 5cf5cfe8..00000000 --- a/python/docs/source/cli/file.rst +++ /dev/null @@ -1,6 +0,0 @@ -File -==== - -.. click:: lightning_sdk.cli.groups:file - :prog: lightning file - :nested: full diff --git a/python/docs/source/cli/folder.rst b/python/docs/source/cli/folder.rst deleted file mode 100644 index 35394def..00000000 --- a/python/docs/source/cli/folder.rst +++ /dev/null @@ -1,6 +0,0 @@ -Folder -====== - -.. click:: lightning_sdk.cli.groups:folder - :prog: lightning folder - :nested: full diff --git a/python/docs/source/cli/job.rst b/python/docs/source/cli/job.rst deleted file mode 100644 index 1741d463..00000000 --- a/python/docs/source/cli/job.rst +++ /dev/null @@ -1,6 +0,0 @@ -Job -=== - -.. click:: lightning_sdk.cli.groups:job - :prog: lightning job - :nested: full diff --git a/python/docs/source/cli/license.rst b/python/docs/source/cli/license.rst deleted file mode 100644 index 22ed5662..00000000 --- a/python/docs/source/cli/license.rst +++ /dev/null @@ -1,6 +0,0 @@ -License -======= - -.. click:: lightning_sdk.cli.groups:license - :prog: lightning license - :nested: full diff --git a/python/docs/source/cli/machine.rst b/python/docs/source/cli/machine.rst deleted file mode 100644 index c940cc95..00000000 --- a/python/docs/source/cli/machine.rst +++ /dev/null @@ -1,6 +0,0 @@ -Machine -======= - -.. click:: lightning_sdk.cli.groups:machine - :prog: lightning machine - :nested: full diff --git a/python/docs/source/cli/mmt.rst b/python/docs/source/cli/mmt.rst deleted file mode 100644 index 80819f7b..00000000 --- a/python/docs/source/cli/mmt.rst +++ /dev/null @@ -1,6 +0,0 @@ -Multi-Machine Training -====================== - -.. click:: lightning_sdk.cli.groups:mmt - :prog: lightning mmt - :nested: full diff --git a/python/docs/source/cli/model.rst b/python/docs/source/cli/model.rst deleted file mode 100644 index c5297b4d..00000000 --- a/python/docs/source/cli/model.rst +++ /dev/null @@ -1,6 +0,0 @@ -Model -===== - -.. click:: lightning_sdk.cli.groups:model - :prog: lightning model - :nested: full diff --git a/python/docs/source/cli/sandbox.rst b/python/docs/source/cli/sandbox.rst deleted file mode 100644 index 7069759d..00000000 --- a/python/docs/source/cli/sandbox.rst +++ /dev/null @@ -1,6 +0,0 @@ -Sandbox -======= - -.. click:: lightning_sdk.cli.groups:sandbox - :prog: lightning sandbox - :nested: full diff --git a/python/docs/source/cli/ssh.rst b/python/docs/source/cli/ssh.rst deleted file mode 100644 index 78b058c2..00000000 --- a/python/docs/source/cli/ssh.rst +++ /dev/null @@ -1,6 +0,0 @@ -SSH -=== - -.. click:: lightning_sdk.cli.groups:ssh - :prog: lightning ssh - :nested: full diff --git a/python/docs/source/cli/studio.rst b/python/docs/source/cli/studio.rst deleted file mode 100644 index d8b9d936..00000000 --- a/python/docs/source/cli/studio.rst +++ /dev/null @@ -1,6 +0,0 @@ -Studio -====== - -.. click:: lightning_sdk.cli.groups:studio - :prog: lightning studio - :nested: full diff --git a/python/pyproject.toml b/python/pyproject.toml index a51b62e3..36fea1cf 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -50,7 +50,7 @@ serve = ["litserve>=0.2.5"] [dependency-groups] docs = [ "sphinx>=8.0,<9.0", - "sphinx-click>=6.2,<7.0", + "click-extra[sphinx]>=8.3,<9.0", "myst-parser>=5.0.0", "docutils>=0.20", "sphinx-autodoc-typehints>=1.16",