Files
wehub-resource-sync eec33d25b2
pre-commit / pre-commit (push) Failing after 1s
Build Wheel / build (3.11) (push) Failing after 1s
Build Wheel / build (3.12) (push) Failing after 0s
chore: import upstream snapshot with attribution
2026-07-13 12:29:08 +08:00

262 lines
10 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
import ast
import logging
import re
import sys
from argparse import SUPPRESS, Action, ArgumentParser, HelpFormatter, _ArgumentGroup
from collections.abc import Iterable
from importlib.machinery import ModuleSpec
from pathlib import Path
from typing import Literal
from unittest.mock import MagicMock
from pydantic_core import core_schema
class _FlexibleArgumentParser(ArgumentParser):
"""Fallback parser for docs when vllm is unavailable.
Accepts the 'deprecated' kwarg used by vllm CLI and emits warnings
if a deprecated argument is actually provided.
"""
_deprecated: set[Action] = set()
_deprecated_warned: set[str] = set()
if sys.version_info < (3, 13):
def parse_known_args(self, args=None, namespace=None):
namespace, args = super().parse_known_args(args, namespace)
for action in _FlexibleArgumentParser._deprecated:
if (
hasattr(namespace, dest := action.dest)
and getattr(namespace, dest) != action.default
and dest not in _FlexibleArgumentParser._deprecated_warned
):
_FlexibleArgumentParser._deprecated_warned.add(dest)
logger.warning("argument '%s' is deprecated", dest)
return namespace, args
def add_argument(self, *args, **kwargs):
deprecated = kwargs.pop("deprecated", False)
action = super().add_argument(*args, **kwargs)
if deprecated:
_FlexibleArgumentParser._deprecated.add(action)
return action
class _FlexibleArgumentGroup(_ArgumentGroup):
def add_argument(self, *args, **kwargs):
deprecated = kwargs.pop("deprecated", False)
action = super().add_argument(*args, **kwargs)
if deprecated:
_FlexibleArgumentParser._deprecated.add(action)
return action
def add_argument_group(self, *args, **kwargs):
group = self._FlexibleArgumentGroup(self, *args, **kwargs)
self._action_groups.append(group)
return group
logger = logging.getLogger("mkdocs")
# Define root and doc output directories
ROOT_DIR = Path(__file__).parent.parent.parent.parent
ARGPARSE_DOC_DIR = ROOT_DIR / "docs/generated/argparse_omni"
# Ensure the repo root is in sys.path for dynamic imports
sys.path.insert(0, str(ROOT_DIR))
class PydanticMagicMock(MagicMock):
"""`MagicMock` that's able to generate pydantic-core schemas and avoids _mock_name=None errors."""
def __init__(self, *args, **kwargs):
name = kwargs.pop("name", None)
super().__init__(*args, **kwargs)
self.__spec__ = ModuleSpec(name, None)
self._mock_name = name or "mock"
def __get_pydantic_core_schema__(self, source_type, handler):
return core_schema.any_schema()
# --- Static extraction for CLI argument docs ---
def extract_omni_serve_subparser_init():
"""
Statically parse vllm_omni/entrypoints/cli/serve.py to extract the subparser_init method
and return a callable that adds arguments to a parser. This avoids import and mock issues.
"""
serve_path = ROOT_DIR / "vllm_omni" / "entrypoints" / "cli" / "serve.py"
with open(serve_path, encoding="utf-8") as f:
source = f.read()
tree = ast.parse(source, filename=str(serve_path))
# Find class OmniServeCommand
for node in tree.body:
if isinstance(node, ast.ClassDef) and node.name == "OmniServeCommand":
for item in node.body:
if isinstance(item, ast.FunctionDef) and item.name == "subparser_init":
# We'll exec this function body in a dummy context
func_code = ast.Module(body=[item], type_ignores=[])
code = compile(func_code, filename=str(serve_path), mode="exec")
# Prepare dummy context
local_vars = {}
# Provide a dummy subparsers with add_parser returning our parser
class DummySubparsers:
def add_parser(self, name, **kwargs):
return _FlexibleArgumentParser(prog=name)
dummy_subparsers = DummySubparsers()
# Provide globals for exec
# Extract DESCRIPTION from the source file (assume it's a triple-quoted string at the top)
m = re.search(r'DESCRIPTION\s*=\s*([ru]?""".*?""")', source, re.DOTALL)
DESCRIPTION = m.group(1)[3:-3] if m else ""
exec_globals = {
"_FlexibleArgumentParser": _FlexibleArgumentParser,
"FlexibleArgumentParser": _FlexibleArgumentParser,
"TrackingArgumentParser": _FlexibleArgumentParser, # only needs add_argument, not tracking
"TrackingNamespace": None, # type annotation only
"make_arg_parser": lambda parser: parser, # no-op for doc
"_ensure_vllm_platform": lambda: None, # no-op for doc
"VLLM_SUBCMD_PARSER_EPILOG": "",
"logger": logger,
"DummySubparsers": DummySubparsers,
"argparse": __import__("argparse"),
"json": __import__("json"),
"DESCRIPTION": DESCRIPTION,
}
exec(code, exec_globals, local_vars)
# Get the function
subparser_init = local_vars["subparser_init"]
# Return a callable that mimics OmniServeCommand().subparser_init
def parser_factory():
class DummySelf:
name = "serve"
return subparser_init(DummySelf(), dummy_subparsers)
return parser_factory
raise RuntimeError("Could not statically extract OmniServeCommand.subparser_init")
OmniServeCommand = type("OmniServeCommand", (), {"subparser_init": staticmethod(extract_omni_serve_subparser_init())})
class MarkdownFormatter(HelpFormatter):
"""Custom formatter that generates markdown for argument groups."""
def __init__(self, prog: str, starting_heading_level: int = 3):
super().__init__(prog, max_help_position=sys.maxsize, width=sys.maxsize)
self._section_heading_prefix = "#" * starting_heading_level
self._argument_heading_prefix = "#" * (starting_heading_level + 1)
self._markdown_output = []
def start_section(self, heading: str):
if heading not in {"positional arguments", "options"}:
heading_md = f"\n{self._section_heading_prefix} {heading}\n\n"
self._markdown_output.append(heading_md)
def end_section(self):
pass
def add_text(self, text: str):
if text:
self._markdown_output.append(f"{text.strip()}\n\n")
def add_usage(self, usage, actions, groups, prefix=None):
pass
def add_arguments(self, actions: Iterable[Action]):
for action in actions:
if len(action.option_strings) == 0 or "--help" in action.option_strings:
continue
option_strings = f"`{'`, `'.join(action.option_strings)}`"
heading_md = f"{self._argument_heading_prefix} {option_strings}\n\n"
self._markdown_output.append(heading_md)
if choices := action.choices:
choices = f"`{'`, `'.join(str(c) for c in choices)}`"
self._markdown_output.append(f"Possible choices: {choices}\n\n")
elif (metavar := action.metavar) and isinstance(metavar, (list, tuple)):
metavar = f"`{'`, `'.join(str(m) for m in metavar)}`"
self._markdown_output.append(f"Possible choices: {metavar}\n\n")
if action.help:
self._markdown_output.append(f"{action.help}\n\n")
if (default := action.default) != SUPPRESS:
# Make empty string defaults visible
if default == "":
default = '""'
self._markdown_output.append(f"Default: `{default}`\n\n")
def format_help(self):
"""Return the formatted help as markdown."""
return "".join(self._markdown_output)
# Function to create parser using subparser_init style CLI class
def create_parser_subparser_init(subcmd_class):
"""
Create an argparse parser using subparser_init style CLI class, with MarkdownFormatter.
Compatible with both AST-extracted static parser_factory and real class instance method.
"""
class DummySubparsers:
def add_parser(self, name, **kwargs):
return _FlexibleArgumentParser(prog=name)
dummy_subparsers = DummySubparsers()
# If subparser_init is a zero-arg static function (AST-extracted), call it directly
subparser_init = getattr(subcmd_class, "subparser_init", None)
if subparser_init is not None:
import inspect
sig = inspect.signature(subparser_init)
if len(sig.parameters) == 0:
parser = subparser_init()
else:
parser = subcmd_class().subparser_init(dummy_subparsers)
else:
parser = subcmd_class().subparser_init(dummy_subparsers)
parser.formatter_class = MarkdownFormatter
return parser
def on_startup(command: Literal["build", "gh-deploy", "serve"], dirty: bool):
"""
Entry point for doc generation. Builds doc directory and outputs markdown for each CLI command.
"""
logger.info("Generating vllm-omni argparse documentation")
logger.debug("Root directory: %s", ROOT_DIR.resolve())
logger.debug("Output directory: %s", ARGPARSE_DOC_DIR.resolve())
if not ARGPARSE_DOC_DIR.exists():
ARGPARSE_DOC_DIR.mkdir(parents=True)
# Register all CLI parsers; you can easily add more commands here
parsers = {
"omni_serve": create_parser_subparser_init(OmniServeCommand),
# "another_cmd": create_parser_subparser_init(AnotherCommandClass),
}
for stem, parser in parsers.items():
doc_path = ARGPARSE_DOC_DIR / f"{stem}.inc.md"
with open(doc_path, "w", encoding="utf-8") as f:
f.write(super(type(parser), parser).format_help())
logger.info("Argparse generated: %s", doc_path.relative_to(ROOT_DIR))
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
on_startup("build", False)