[CI/Build] Strengthen pre-commit with markdownlint, SPDX, and policy hooks (#6273)

Signed-off-by: wangyu <410167048@qq.com>
Signed-off-by: [Your Name] <your.email@example.com>
Signed-off-by: wangyu <53896905+yenuo26@users.noreply.github.com>
This commit is contained in:
wangyu authored and GitHub committed 2026-08-20 21:07:04 +08:00
1 parent 10906e3a6d
commit 273ffce130
30 files changed
+1497 -332

No files matched your search

+118
View File
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Validate .buildkite YAML against the official Buildkite schema.
Test pipelines (test-ready.yml, etc.) use Omni-only keys such as
``mirror_hardwares`` and ``source_file_dependencies``. Those are expanded or
stripped the same way ``upload_pipeline.py`` does before upload, then the
rendered YAML is checked with check-jsonschema.
"""
from __future__ import annotations
import subprocess
import sys
import tempfile
from pathlib import Path
from typing import Any
import yaml
ROOT = Path(__file__).resolve().parents[2]
SCRIPTS = ROOT / ".buildkite" / "common" / "scripts"
sys.path.insert(0, str(SCRIPTS))
from upload_pipeline import _render_test_pipeline # noqa: E402
SKIP_FILES = {
".buildkite/common/ci_mirror_hardwares.yml",
".buildkite/npu/pipeline-npu-a3.yml",
}
# AMD pipelines are uploaded by a different path and use list-valued
# mirror_hardwares plus agent_pool/grade, which CUDA's expander rejects.
AMD_STRIP_KEYS = frozenset({"mirror_hardwares", "agent_pool", "grade", "source_file_dependencies"})
def _normalize(path: str) -> str:
return path.replace("\\", "/")
def _strip_keys(obj: Any, keys: frozenset[str]) -> Any:
if isinstance(obj, dict):
return {k: _strip_keys(v, keys) for k, v in obj.items() if k not in keys}
if isinstance(obj, list):
return [_strip_keys(item, keys) for item in obj]
return obj
def _prepare_pipeline(path: Path) -> dict[str, Any]:
rel = _normalize(str(path.relative_to(ROOT) if path.is_absolute() else path))
doc = yaml.safe_load(path.read_text(encoding="utf-8"))
if not isinstance(doc, dict):
raise ValueError(f"{rel}: expected a mapping (pipeline YAML), got {type(doc).__name__}")
if "/amd/" in f"/{rel}":
return _strip_keys(doc, AMD_STRIP_KEYS)
return _render_test_pipeline(doc, changed_files=None)
def _validate(path: Path, doc: dict[str, Any]) -> int:
with tempfile.NamedTemporaryFile(
mode="w",
suffix=".yml",
encoding="utf-8",
delete=False,
) as handle:
yaml.safe_dump(doc, handle, sort_keys=False)
tmp = Path(handle.name)
try:
result = subprocess.run(
[
sys.executable,
"-m",
"check_jsonschema",
"--builtin-schema",
"vendor.buildkite",
str(tmp),
],
capture_output=True,
text=True,
)
finally:
tmp.unlink(missing_ok=True)
if result.returncode == 0:
return 0
rel = _normalize(str(path))
sys.stderr.write(f"{rel}: Buildkite schema validation failed\n")
sys.stderr.write(result.stdout or "")
sys.stderr.write(result.stderr or "")
return 1
def main(argv: list[str]) -> int:
rc = 0
for raw in argv:
path = Path(raw)
rel = _normalize(str(path))
if rel in SKIP_FILES:
continue
if not path.is_file():
path = ROOT / path
try:
doc = _prepare_pipeline(path)
except Exception as exc: # noqa: BLE001 - surface expander errors as hook failures
sys.stderr.write(f"{rel}: {exc}\n")
rc = 1
continue
rc |= _validate(path, doc)
return rc
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))
+368
View File
@@ -0,0 +1,368 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Ban dangerous / policy-violating imports unless a file is allowlisted.
Ported from vllm/tools/pre_commit/check_forbidden_imports.py. Existing
vllm_omni/ usages are grandfathered; add a path to the matching
allowed_files set only after a security/policy review.
"""
import sys
from dataclasses import dataclass, field
import regex as re
# Hub entry points that must go through the vLLM-tagged repo_utils helpers.
_HF_NAMES = (
r"HfApi|HfFileSystem|hf_hub_download|snapshot_download"
r"|list_repo_files|file_exists|try_to_load_from_cache"
r"|list_repo_refs|repo_exists"
)
# Non-library trees: examples, tests, and tooling may keep stdlib imports.
_NON_LIBRARY_DIRS = {
"examples/",
"tests/",
"benchmarks/",
"apps/",
"docs/",
"tools/",
"scripts/",
".buildkite/",
".github/",
}
@dataclass
class ForbiddenImport:
pattern: str
tip: str
allowed_pattern: re.Pattern = re.compile(r"^$") # matches nothing by default
allowed_files: set[str] = field(default_factory=set)
allowed_dirs: set[str] = field(default_factory=set)
CHECK_IMPORTS = {
"pickle/cloudpickle": ForbiddenImport(
pattern=(
r"^\s*(import\s+(?:[\w.]+\s*(?:as\s+\w+)?\s*,\s*)*(pickle|cloudpickle)\b"
r"|from\s+(pickle|cloudpickle)\s+import\b)"
),
tip=("Avoid using pickle or cloudpickle or add this file to tools/pre_commit/check_forbidden_imports.py."),
allowed_files={
# STOP AND READ BEFORE YOU ADD ANYTHING ELSE TO THIS LIST:
# pickle/cloudpickle are unsafe when deserializing untrusted data.
"tests/diffusion/attention/test_attention_sp.py",
"tests/helpers/process.py",
"vllm_omni/diffusion/distributed/group_coordinator.py",
},
),
"base64": ForbiddenImport(
pattern=r"^\s*(?:import\s+base64(?:$|\s|,)|from\s+base64\s+import)",
tip=("Replace 'import base64' with 'import pybase64' or 'import pybase64 as base64'."),
allowed_pattern=re.compile(r"^\s*import\s+pybase64(\s*|\s+as\s+base64\s*)$"),
allowed_dirs=_NON_LIBRARY_DIRS,
allowed_files={
"vllm_omni/benchmarks/data_modules/daily_omni_dataset.py",
"vllm_omni/benchmarks/data_modules/random_multi_modal_dataset.py",
"vllm_omni/benchmarks/data_modules/seed_tts_dataset.py",
"vllm_omni/entrypoints/openai/api_server.py",
"vllm_omni/entrypoints/openai/audio_utils_mixin.py",
"vllm_omni/entrypoints/openai/image_api_utils.py",
"vllm_omni/entrypoints/openai/protocol/images.py",
"vllm_omni/entrypoints/openai/realtime_connection.py",
"vllm_omni/entrypoints/openai/serving_chat.py",
"vllm_omni/entrypoints/openai/serving_speech.py",
"vllm_omni/entrypoints/openai/serving_speech_stream.py",
"vllm_omni/entrypoints/openai/video_api_utils.py",
"vllm_omni/entrypoints/openai/video_stream_base.py",
"vllm_omni/entrypoints/openai/video_stream_session.py",
"vllm_omni/experimental/fullduplex/client.py",
"vllm_omni/experimental/fullduplex/engine/contracts.py",
"vllm_omni/experimental/fullduplex/joyvl/memory/memory.py",
"vllm_omni/experimental/fullduplex/minicpmo45/adapter.py",
"vllm_omni/experimental/fullduplex/minicpmo45/input.py",
"vllm_omni/experimental/fullduplex/minicpmo45/runtime.py",
"vllm_omni/experimental/fullduplex/minicpmo45/stage0.py",
"vllm_omni/experimental/fullduplex/openai/audio.py",
"vllm_omni/experimental/fullduplex/openai/realtime_input.py",
"vllm_omni/experimental/fullduplex/openai/runtime_bridge.py",
"vllm_omni/experimental/fullduplex/openai/serving.py",
"vllm_omni/experimental/fullduplex/personaplex/input.py",
"vllm_omni/experimental/fullduplex/personaplex/runtime_extension.py",
"vllm_omni/experimental/fullduplex/personaplex/stage0.py",
"vllm_omni/model_executor/models/indextts2/tokenizer_v2_5.py",
"vllm_omni/model_executor/models/qwen3_tts/prompt_embeds_builder.py",
"vllm_omni/model_executor/models/qwen3_tts/qwen3_tts_tokenizer.py",
"vllm_omni/tokenizers/mammoth_moda2_tokenizer.py",
"vllm_omni/transformers_utils/processors/audiox.py",
},
),
"re": ForbiddenImport(
pattern=r"^\s*(?:import\s+re(?:$|\s|,)|from\s+re\s+import)",
tip="Replace 'import re' with 'import regex as re' or 'import regex'.",
allowed_pattern=re.compile(r"^\s*import\s+regex(\s*|\s+as\s+re\s*)$"),
allowed_dirs=_NON_LIBRARY_DIRS,
allowed_files={
"setup.py",
"vllm_omni/benchmarks/data_modules/daily_omni_eval.py",
"vllm_omni/config/stage_config.py",
"vllm_omni/diffusion/layers/mot/ops/mot_gemm.py",
"vllm_omni/diffusion/model_loader/diffusers_loader.py",
"vllm_omni/diffusion/models/diffusers_adapter/pipeline_diffusers_adapter.py",
"vllm_omni/diffusion/models/dreamid_omni/fusion.py",
"vllm_omni/diffusion/models/dreamzero/pipeline_dreamzero.py",
"vllm_omni/diffusion/models/glm_image/pipeline_glm_image.py",
"vllm_omni/diffusion/models/gr00t/modeling/processing_gr00t_n1d7.py",
"vllm_omni/diffusion/models/hunyuan_video/pipeline_hunyuan_video_1_5.py",
"vllm_omni/diffusion/models/longcat_image/pipeline_longcat_image.py",
"vllm_omni/diffusion/models/longcat_image/pipeline_longcat_image_edit.py",
"vllm_omni/diffusion/models/longcat_video/pipeline_longcat_video_avatar.py",
"vllm_omni/diffusion/models/minimax_h3/encoder.py",
"vllm_omni/diffusion/models/nextstep_1_1/pipeline_nextstep_1_1.py",
"vllm_omni/diffusion/models/omnivoice/pipeline_omnivoice.py",
"vllm_omni/diffusion/models/soulx_singer/modules/preprocess/asr.py",
"vllm_omni/diffusion/models/soulx_singer/preprocess/g2p.py",
"vllm_omni/diffusion/profiler/diffusion_pipeline_profiler.py",
"vllm_omni/distributed/omni_connectors/utils/env.py",
"vllm_omni/entrypoints/cli/logo.py",
"vllm_omni/entrypoints/openai/serving_speech.py",
"vllm_omni/experimental/fullduplex/joyvl/memory/memory.py",
"vllm_omni/model_executor/models/common/whisper_vq.py",
"vllm_omni/model_executor/models/fish_speech/prompt_utils.py",
"vllm_omni/model_executor/models/glm_tts/text_frontend.py",
"vllm_omni/model_executor/models/higgs_audio_v2/higgs_audio_v2_tokenizer.py",
"vllm_omni/model_executor/models/indextts2/indextts2_talker.py",
"vllm_omni/model_executor/models/indextts2/text_processing_v2_5.py",
"vllm_omni/model_executor/models/indextts2/utils/common.py",
"vllm_omni/model_executor/models/ming_flash_omni/text_processing.py",
"vllm_omni/model_executor/models/ming_flash_omni/vision_encoder.py",
"vllm_omni/model_executor/models/ming_tts/prompt_assembly.py",
"vllm_omni/model_executor/models/nemotron_voicechat/nemo_vendored/ear_tts_commons.py",
"vllm_omni/model_executor/stage_input_processors/ming_flash_omni.py",
"vllm_omni/outputs/output_modality.py",
"vllm_omni/quantization/mxfp4_config.py",
"vllm_omni/quantization/tools/merge_mxfp4_dualscale_checkpoint.py",
"vllm_omni/utils/custom_voice_io.py",
},
),
"triton": ForbiddenImport(
pattern=r"^(from|import)\s+triton(\s|\.|$)",
tip="Use 'from vllm.triton_utils import triton' instead.",
allowed_pattern=re.compile(r"from vllm.triton_utils import (triton|tl|tl, triton)"),
),
"tilelang": ForbiddenImport(
pattern=r"^(from|import)\s+tilelang(\s|\.|$)",
tip="Use 'from vllm.tilelang_utils import tilelang, T' instead.",
allowed_pattern=re.compile(
r"from\s+vllm\.tilelang_utils\s+import\s+"
r"(tilelang|T|T, tilelang|tilelang, T)\b"
),
),
"huggingface_hub repo API": ForbiddenImport(
# Catch `from huggingface_hub import `, including parenthesized,
# multi-line imports.
pattern=(
r"^\s*from\s+huggingface_hub\s+import\s*\([^)]*\b(?:" + _HF_NAMES + r")\b"
r"|"
r"^\s*from\s+huggingface_hub\s+import\b[^\n]*\b(?:" + _HF_NAMES + r")\b"
),
tip=(
"Use the shared, vLLM-tagged helpers from "
"vllm.transformers_utils.repo_utils (e.g. hf_api(), hf_fs(), "
"list_repo_files, file_exists) instead of calling "
"huggingface_hub directly."
),
allowed_dirs=_NON_LIBRARY_DIRS,
allowed_files={
"vllm_omni/benchmarks/data_modules/daily_omni_dataset.py",
"vllm_omni/benchmarks/data_modules/seed_tts_dataset.py",
"vllm_omni/benchmarks/data_modules/seed_tts_eval.py",
"vllm_omni/diffusion/lora/loader.py",
"vllm_omni/diffusion/model_loader/hub_prefetch.py",
"vllm_omni/diffusion/models/cosmos3/sound_tokenizer.py",
"vllm_omni/diffusion/models/dreamzero/pipeline_dreamzero.py",
"vllm_omni/diffusion/models/helios/pipeline_helios.py",
"vllm_omni/diffusion/models/longcat_video/pipeline_longcat_video_avatar.py",
"vllm_omni/diffusion/models/ltx2/ltx2_components.py",
"vllm_omni/diffusion/models/magi_human/pipeline_magi_human.py",
"vllm_omni/diffusion/models/omnivoice/pipeline_omnivoice.py",
"vllm_omni/diffusion/models/pi0/pipeline_pi0.py",
"vllm_omni/diffusion/models/sensenova_u1/pipeline_sensenova_u1.py",
"vllm_omni/diffusion/models/soulx_singer/utils.py",
"vllm_omni/diffusion/models/utils.py",
"vllm_omni/diffusion/models/wan2_2/pipeline_wan2_2.py",
"vllm_omni/engine/arg_utils.py",
"vllm_omni/engine/stage_init_utils.py",
"vllm_omni/entrypoints/openai/api_server.py",
"vllm_omni/entrypoints/openai/serving_speech.py",
"vllm_omni/entrypoints/openai/tts_adapters/cosyvoice3.py",
"vllm_omni/experimental/fullduplex/personaplex/runtime.py",
"vllm_omni/experimental/fullduplex/personaplex/serving/server.py",
"vllm_omni/model_executor/model_loader/weight_utils.py",
"vllm_omni/model_executor/models/audex/checkpoint.py",
"vllm_omni/model_executor/models/bagel/bagel.py",
"vllm_omni/model_executor/models/cosyvoice3/cosyvoice3.py",
"vllm_omni/model_executor/models/covo_audio/covo_audio_code2wav.py",
"vllm_omni/model_executor/models/dots_tts/dots_tts_talker.py",
"vllm_omni/model_executor/models/dynin_omni/dynin_omni_common.py",
"vllm_omni/model_executor/models/dynin_omni/dynin_omni_token2audio.py",
"vllm_omni/model_executor/models/glm_tts/glm_tts.py",
"vllm_omni/model_executor/models/higgs_audio_v2/higgs_audio_v2_code2wav.py",
"vllm_omni/model_executor/models/higgs_audio_v2/higgs_audio_v2_tokenizer.py",
"vllm_omni/model_executor/models/higgs_audio_v3/higgs_audio_v3_code2wav.py",
"vllm_omni/model_executor/models/indextts2/preprocess_utils.py",
"vllm_omni/model_executor/models/indextts2/s2mel/modules/bigvgan.py",
"vllm_omni/model_executor/models/indextts2/tokenizer_v2_5.py",
"vllm_omni/model_executor/models/ming_tts/speaker_extractor.py",
"vllm_omni/model_executor/models/minicpmo_4_5/minicpmo_4_5_code2wav.py",
"vllm_omni/model_executor/models/omnivoice/omnivoice.py",
"vllm_omni/model_executor/models/personaplex/personaplex_mimi.py",
"vllm_omni/model_executor/models/step_audio2/step_audio2_token2wav.py",
"vllm_omni/model_executor/models/voxtral_tts/voxtral_tts.py",
"vllm_omni/transformers_utils/configs/higgs_audio_v3.py",
},
),
}
def _normalize_path(path: str) -> str:
return path.replace("\\", "/")
def check_file(path: str) -> int:
path = _normalize_path(path)
with open(path, encoding="utf-8") as f:
content = f.read()
return_code = 0
# Check all patterns in the whole file
for import_name, forbidden_import in CHECK_IMPORTS.items():
# Skip files that are allowed for this import
if path in forbidden_import.allowed_files:
continue
# Skip directories that are allowed for this import
if any(path.startswith(prefix) for prefix in forbidden_import.allowed_dirs):
continue
# Search for forbidden imports
for match in re.finditer(forbidden_import.pattern, content, re.MULTILINE):
# Check if it's allowed
if forbidden_import.allowed_pattern.match(match.group()):
continue
# Skip matches inside a comment
line_start = content.rfind("\n", 0, match.start()) + 1
if "#" in content[line_start : match.start()]:
continue
# Calculate line number from match position
line_num = content[: match.start() + 1].count("\n") + 1
print(
f"{path}:{line_num}: "
"\033[91merror:\033[0m " # red color
f"Found forbidden import: {import_name}. {forbidden_import.tip}"
)
return_code = 1
return return_code
def main():
returncode = 0
for path in sys.argv[1:]:
returncode |= check_file(path)
return returncode
def test_regex():
def matches(rule: str, content: str) -> bool:
return bool(re.search(CHECK_IMPORTS[rule].pattern, content, re.MULTILINE))
pickle_cases = [
# Should match
("import pickle", True),
("import cloudpickle", True),
("import pickle as pkl", True),
("import cloudpickle as cpkl", True),
("from pickle import *", True),
("from cloudpickle import dumps", True),
("from pickle import dumps, loads", True),
("from cloudpickle import (dumps, loads)", True),
(" import pickle", True),
("\timport cloudpickle", True),
("from pickle import loads", True),
("import pickle, os", True),
("import os, pickle", True),
("import os, pickle as pkl", True),
("import pickle as pkl, os", True),
("import os.path, cloudpickle", True),
("import cloudpickle, json", True),
# Should not match
("import somethingelse", False),
("from somethingelse import pickle", False),
("# import pickle", False),
("print('import pickle')", False),
("import pickleas as asdf", False),
]
for i, (content, should_match) in enumerate(pickle_cases):
result = matches("pickle/cloudpickle", content)
assert result == should_match, f"pickle case {i} failed: {content!r} (expected {should_match}, got {result})"
tilelang_cases = [
# Should match
("import tilelang", True),
("import tilelang.language as T", True),
("from tilelang.jit import JITImpl", True),
("from tilelang.jit.kernel import JITKernel", True),
# Should not match: indented (local) imports are allowed, mirroring
# the "triton" rule, so mocked-module test imports are not flagged.
(" import tilelang", False),
(" from tilelang.jit import JITImpl", False),
("from vllm.tilelang_utils import tilelang", False),
("from vllm.tilelang_utils import T", False),
("from vllm.tilelang_utils import T, tilelang", False),
("from vllm.tilelang_utils import tilelang, T", False),
("import tilelang_kernels", False),
]
for i, (content, should_match) in enumerate(tilelang_cases):
result = matches("tilelang", content)
assert result == should_match, f"tilelang case {i} failed: {content!r} (expected {should_match}, got {result})"
hf_cases = [
# Should match
("from huggingface_hub import snapshot_download", True),
("from huggingface_hub import hf_hub_download", True),
("from huggingface_hub import HfApi", True),
("from huggingface_hub import HfFileSystem", True),
("from huggingface_hub import list_repo_files", True),
("from huggingface_hub import try_to_load_from_cache", True),
(" from huggingface_hub import snapshot_download", True),
("from huggingface_hub import PyTorchModelHubMixin, hf_hub_download", True),
("from huggingface_hub import (snapshot_download)", True),
# Parenthesized multi-line import must not bypass the hook
("from huggingface_hub import (\n snapshot_download,\n)", True),
(
"from huggingface_hub import (\n PyTorchModelHubMixin,\n HfApi,\n)",
True,
),
# Should not match
("import huggingface_hub", False),
("import huggingface_hub as hf", False),
("from huggingface_hub import PyTorchModelHubMixin", False),
("from huggingface_hub.constants import HF_HUB_CACHE", False),
("from huggingface_hub.utils import EntryNotFoundError", False),
("from vllm.transformers_utils.repo_utils import hf_api", False),
("from huggingface_hub import (\n PyTorchModelHubMixin,\n)", False),
("# from huggingface_hub import snapshot_download", False),
]
for i, (content, should_match) in enumerate(hf_cases):
result = matches("huggingface_hub repo API", content)
assert result == should_match, (
f"huggingface_hub case {i} failed: {content!r} (expected {should_match}, got {result})"
)
print("All regex tests passed.")
if __name__ == "__main__":
if "--test-regex" in sys.argv:
test_regex()
else:
sys.exit(main())
-87
View File
@@ -1,87 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import sys
import regex as re
# List of files (relative to repo root) that are allowed to import pickle or
# cloudpickle
#
# STOP AND READ BEFORE YOU ADD ANYTHING ELSE TO THIS LIST:
# The pickle and cloudpickle modules are known to be unsafe when deserializing
# data from potentially untrusted parties. They have resulted in multiple CVEs
# for vLLM and numerous vulnerabilities in the Python ecosystem more broadly.
# Before adding new uses of pickle/cloudpickle, please consider safer
# alternatives like msgpack or pydantic that are already in use in vLLM. Only
# add to this list if absolutely necessary and after careful security review.
ALLOWED_FILES = {
"tests/helpers/process.py",
"vllm_omni/diffusion/distributed/group_coordinator.py",
"tests/diffusion/attention/test_attention_sp.py",
# Measures the wire size of diffusion outputs. The transport pickles them,
# and only pickle reproduces the per-view storage duplication under test
# (torch.save deduplicates shared storages). No untrusted data is loaded.
"tests/diffusion/test_diffusion_ipc.py",
}
PICKLE_RE = re.compile(
r"^\s*(import\s+(pickle|cloudpickle)(\s|$|\sas)"
r"|from\s+(pickle|cloudpickle)\s+import\b)"
)
def scan_file(path: str) -> int:
with open(path, encoding="utf-8") as f:
for i, line in enumerate(f, 1):
if PICKLE_RE.match(line):
print(
f"{path}:{i}: "
"\033[91merror:\033[0m " # red color
"Found pickle/cloudpickle import"
)
return 1
return 0
def main():
returncode = 0
for filename in sys.argv[1:]:
if filename in ALLOWED_FILES:
continue
returncode |= scan_file(filename)
return returncode
def test_regex():
test_cases = [
# Should match
("import pickle", True),
("import cloudpickle", True),
("import pickle as pkl", True),
("import cloudpickle as cpkl", True),
("from pickle import *", True),
("from cloudpickle import dumps", True),
("from pickle import dumps, loads", True),
("from cloudpickle import (dumps, loads)", True),
(" import pickle", True),
("\timport cloudpickle", True),
("from pickle import loads", True),
# Should not match
("import somethingelse", False),
("from somethingelse import pickle", False),
("# import pickle", False),
("print('import pickle')", False),
("import pickleas as asdf", False),
]
for i, (line, should_match) in enumerate(test_cases):
result = bool(PICKLE_RE.match(line))
assert result == should_match, f"Test case {i} failed: '{line}' (expected {should_match}, got {result})"
print("All regex tests passed.")
if __name__ == "__main__":
if "--test-regex" in sys.argv:
test_regex()
else:
sys.exit(main())
+206
View File
@@ -0,0 +1,206 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Require SPDX license headers on source files.
Ported from vllm/tools/pre_commit/check_spdx_header.py. The copyright line
uses the vLLM-Omni project name rather than upstream vLLM. Shell scripts
(``.sh``) are included so wrappers such as ``shellcheck.sh`` cannot keep a
stale upstream copyright that Python/Rust/proto files would have rewritten.
``.pyi`` stubs use the same ``#`` header style as ``.py``.
"""
import sys
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
# Older files still carry the upstream vLLM copyright line. Treat it as stale
# and rewrite it to the Omni line instead of inserting a duplicate header.
LEGACY_COPYRIGHT_TEXT = "SPDX-FileCopyrightText: Copyright contributors to the vLLM project"
@dataclass(frozen=True)
class HeaderStyle:
"""Comment syntax and preamble handling for an SPDX header."""
comment_prefix: str
preserve_shebang: bool = False
class SPDXStatus(Enum):
"""SPDX header status enumeration"""
EMPTY = "empty" # empty __init__.py
COMPLETE = "complete"
MISSING_LICENSE = "missing_license" # Only has copyright line
MISSING_COPYRIGHT = "missing_copyright" # Only has license line
MISSING_BOTH = "missing_both" # Completely missing
LICENSE_TEXT = "SPDX-License-Identifier: Apache-2.0"
COPYRIGHT_TEXT = "SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project"
FILE_STYLES = {
".py": HeaderStyle("#", preserve_shebang=True),
".pyi": HeaderStyle("#"),
".sh": HeaderStyle("#", preserve_shebang=True),
".rs": HeaderStyle("//"),
".proto": HeaderStyle("//"),
}
def file_style(file_path):
"""Return the declared header style for a file."""
suffix = Path(file_path).suffix
try:
return FILE_STYLES[suffix]
except KeyError:
raise ValueError(f"Unsupported file type: {file_path}") from None
def spdx_header(style):
"""Return the SPDX header for a file style."""
license_line = f"{style.comment_prefix} {LICENSE_TEXT}"
copyright_line = f"{style.comment_prefix} {COPYRIGHT_TEXT}"
return license_line, copyright_line
def legacy_copyright_line(style):
"""Return the stale upstream vLLM copyright line for a file style."""
return f"{style.comment_prefix} {LEGACY_COPYRIGHT_TEXT}"
def header_insertion_index(style, lines):
"""Return the line index where a missing header should be inserted."""
if style.preserve_shebang and lines and lines[0].startswith("#!"):
return 1
return 0
def check_spdx_header_status(file_path):
"""Check SPDX header status of the file"""
style = file_style(file_path)
license_line, copyright_line = spdx_header(style)
with open(file_path, encoding="UTF-8") as file:
lines = file.readlines()
if not lines:
# Empty file
return SPDXStatus.EMPTY
has_license = False
has_copyright = False
# Check all lines for SPDX headers (not just the first two)
for raw_line in lines:
line = raw_line.strip()
if line == license_line:
has_license = True
elif line == copyright_line:
has_copyright = True
# Determine status based on what we found
if has_license and has_copyright:
return SPDXStatus.COMPLETE
elif has_license and not has_copyright:
# Only has license line (or a stale vLLM copyright line)
return SPDXStatus.MISSING_COPYRIGHT
elif not has_license and has_copyright:
# Only has copyright line
return SPDXStatus.MISSING_LICENSE
else:
# Completely missing both lines
return SPDXStatus.MISSING_BOTH
def add_header(file_path, status):
"""Add or supplement SPDX header based on status"""
style = file_style(file_path)
license_line, copyright_line = spdx_header(style)
stale_copyright_line = legacy_copyright_line(style)
full_spdx_header = f"{license_line}\n{copyright_line}"
with open(file_path, "r+", encoding="UTF-8") as file:
lines = file.readlines()
file.seek(0, 0)
file.truncate()
if status == SPDXStatus.MISSING_BOTH:
# Completely missing, add complete header
insertion_index = header_insertion_index(style, lines)
file.writelines(lines[:insertion_index])
file.write(full_spdx_header + "\n")
remaining_lines = lines[insertion_index:]
if remaining_lines and remaining_lines[0].strip():
file.write("\n")
file.writelines(remaining_lines)
elif status == SPDXStatus.MISSING_COPYRIGHT:
# Only has license line, need to add copyright line.
# Rewrite a stale upstream vLLM copyright line in place.
replaced = False
for i, line in enumerate(lines):
if line.strip() == stale_copyright_line:
lines[i] = f"{copyright_line}\n"
replaced = True
break
if not replaced:
for i, line in enumerate(lines):
if line.strip() == license_line:
lines.insert(i + 1, f"{copyright_line}\n")
break
file.writelines(lines)
elif status == SPDXStatus.MISSING_LICENSE:
# Only has copyright line, need to add license line
# Find the copyright line and add license line before it
for i, line in enumerate(lines):
if line.strip() == copyright_line:
# Insert license line before copyright line
lines.insert(i, f"{license_line}\n")
break
file.writelines(lines)
def main():
"""Main function"""
files_missing_both = []
files_missing_copyright = []
files_missing_license = []
for file_path in sys.argv[1:]:
if Path(file_path).suffix not in FILE_STYLES:
continue
status = check_spdx_header_status(file_path)
if status == SPDXStatus.MISSING_BOTH:
files_missing_both.append(file_path)
elif status == SPDXStatus.MISSING_COPYRIGHT:
files_missing_copyright.append(file_path)
elif status == SPDXStatus.MISSING_LICENSE:
files_missing_license.append(file_path)
else:
continue
# Collect all files that need fixing
all_files_to_fix = files_missing_both + files_missing_copyright + files_missing_license
if all_files_to_fix:
print("The following files are missing the SPDX header:")
if files_missing_both:
for file_path in files_missing_both:
print(f" {file_path}")
add_header(file_path, SPDXStatus.MISSING_BOTH)
if files_missing_copyright:
for file_path in files_missing_copyright:
print(f" {file_path}")
add_header(file_path, SPDXStatus.MISSING_COPYRIGHT)
if files_missing_license:
for file_path in files_missing_license:
print(f" {file_path}")
add_header(file_path, SPDXStatus.MISSING_LICENSE)
sys.exit(1 if all_files_to_fix else 0)
if __name__ == "__main__":
main()
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Ban direct torch.cuda.* usage outside an allowlist.
Modeled on vllm/tools/pre_commit/check_torch_cuda.py. Call sites should use
current_omni_platform / OmniPlatform instead of CUDA-only torch.cuda APIs.
"""
import sys
import regex as re
# Match `torch.cuda.xxx` device/memory/seed helpers that have portable Omni
# platform equivalents. CUDAGraph / is_available / stream capture are not in
# this list (same split as upstream vLLM).
_TORCH_CUDA_PATTERNS = [
r"\btorch\.cuda\.(empty_cache|synchronize|device_count|current_device|memory_reserved|memory_allocated|max_memory_allocated|max_memory_reserved|reset_peak_memory_stats|memory_stats|mem_get_info|set_device)\b",
# Match torch.cuda.device(...) including args. `device\()\b` misses
# `device()` (no word char after `)`) and `device(0)`.
r"\btorch\.cuda\.device\s*\(",
r"\btorch\.cuda\.(manual_seed|manual_seed_all)\b",
r"\bwith\storch\.cuda\.device\b",
# Calls torch.cuda.{_is_compiled/_device_count_amdsmi/_device_count_nvml} internally
r"\bcuda_device_count_stateless\(\)\b",
]
# Platform adapters must call native torch.cuda / torch.npu / torch.xpu APIs.
ALLOWED_PREFIXES = {
"vllm_omni/platforms/",
}
# Grandfathered call sites. Remove a path after migrating it to
# current_omni_platform / OmniPlatform. Do not add new files without review.
ALLOWED_FILES = {
"benchmarks/kernels/mot_linear_benchmarks.py",
"examples/online_serving/qwen2_5_omni/gradio_demo.py",
"examples/online_serving/qwen3_omni/gradio_demo.py",
"tests/dfx/reliability/helpers.py",
"tests/diffusion/distributed/test_cfg_parallel.py",
"tests/diffusion/distributed/test_pipeline_parallel.py",
"tests/e2e/accuracy/wan22_i2v/run_wan22_i2v_diffusers_cp.py",
"tests/e2e/features/custom_pipeline/test_async_omni_collective_rpc.py",
"tests/e2e/features/fullduplex/test_personaplex_elastic.py",
"tests/entrypoints/test_omni_sleep_mode.py",
"tools/configure_stage_memory.py",
"vllm_omni/diffusion/models/bagel/pipeline_bagel.py",
"vllm_omni/diffusion/models/lance/pipeline_lance.py",
"vllm_omni/diffusion/models/magi_human/pipeline_magi_human.py",
"vllm_omni/diffusion/models/nextstep_1_1/pipeline_nextstep_1_1.py",
"vllm_omni/distributed/omni_connectors/connectors/mooncake_transfer_engine_connector.py",
"vllm_omni/distributed/omni_connectors/connectors/mori_transfer_engine_connector.py",
"vllm_omni/experimental/ar_diffusion/runner.py",
"vllm_omni/model_executor/models/moss_tts/cuda_graph_streaming_decoder_wrapper.py",
"vllm_omni/model_executor/models/moss_tts_nano/modeling_moss_tts_nano.py",
"vllm_omni/model_executor/models/qwen3_tts/cuda_graph_decoder_wrapper.py",
"vllm_omni/worker/gpu_ar_model_runner.py",
}
_GENERIC_TIP = (
"Found torch.cuda API call. Use current_omni_platform / OmniPlatform "
"(empty_cache, synchronize, get_device_count, current_device, "
"get_device_memory, set_device) instead."
)
_SEED_TIP = (
"Found CUDA manual-seed API call. Use "
"torch.Generator(device=current_omni_platform.device_type).manual_seed(...) "
"instead."
)
def _normalize_path(path: str) -> str:
return path.replace("\\", "/")
def _is_allowed(path: str) -> bool:
if any(path.startswith(prefix) for prefix in ALLOWED_PREFIXES):
return True
return path in ALLOWED_FILES
def scan_file(path: str) -> int:
with open(path, encoding="utf-8") as f:
content = f.read()
for pattern in _TORCH_CUDA_PATTERNS:
for match in re.finditer(pattern, content, re.MULTILINE):
line_start = content.rfind("\n", 0, match.start()) + 1
if "#" in content[line_start : match.start()]:
continue
line_num = content[: match.start() + 1].count("\n") + 1
matched_text = match.group(0)
tip = _SEED_TIP if "manual_seed" in matched_text else _GENERIC_TIP
print(f"{path}:{line_num}: \033[91merror:\033[0m {tip}")
return 1
return 0
def main():
returncode = 0
for filename in sys.argv[1:]:
path = _normalize_path(filename)
if _is_allowed(path):
continue
returncode |= scan_file(path)
return returncode
if __name__ == "__main__":
sys.exit(main())
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Run mypy on changed files.
Ported from vllm/tools/pre_commit/mypy.py. Group files so tests can use
``follow_imports=skip`` without pulling that setting into library code.
Usage:
python tools/pre_commit/mypy.py <python_version> <changed_files...>
Args:
python_version: Python version to use (e.g. "3.10") or "local" to use
the interpreter running this script.
changed_files: List of changed files to check.
"""
from __future__ import annotations
import subprocess
import sys
import regex as re
# tests/ uses follow_imports=skip so third-party and library errors do not
# leak into test type-checking. After a directory is clean under skip, it
# can join the default group (follow_imports from pyproject.toml).
SEPARATE_GROUPS = [
"tests",
]
# Model trees are large third-party ports. Drop a prefix from this list when
# that directory is ready to be type-checked (same ratchet as upstream vLLM).
EXCLUDE = [
r"vllm_omni/model_executor/models/",
r"vllm_omni/diffusion/models/",
]
def _normalize_path(path: str) -> str:
return path.replace("\\", "/")
def group_files(changed_files: list[str]) -> dict[str, list[str]]:
"""Group changed files into different mypy calls."""
exclude_pattern = re.compile(f"^{'|'.join(EXCLUDE)}.*")
file_groups: dict[str, list[str]] = {"": []}
file_groups.update({k: [] for k in SEPARATE_GROUPS})
# Longest path first so a sub-directory is not shadowed by its parent.
separate_groups = sorted(SEPARATE_GROUPS, key=len, reverse=True)
for changed_file in changed_files:
changed_file = _normalize_path(changed_file)
if exclude_pattern.match(changed_file):
continue
for directory in separate_groups:
if re.match(f"^{directory}.*", changed_file):
file_groups[directory].append(changed_file)
break
else:
if changed_file.startswith(("vllm_omni/", "tests/")):
file_groups[""].append(changed_file)
return file_groups
def mypy(
targets: list[str],
python_version: str | None,
follow_imports: str | None,
file_group: str,
) -> int:
"""Run mypy on the given targets."""
args = ["mypy"]
if python_version is not None:
args += ["--python-version", python_version]
if follow_imports is not None:
args += ["--follow-imports", follow_imports]
print(f"$ {' '.join(args)} {file_group}")
return subprocess.run(args + targets, check=False).returncode
def main() -> int:
python_version = sys.argv[1]
file_groups = group_files(sys.argv[2:])
if python_version == "local":
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
returncode = 0
for file_group, changed_files in file_groups.items():
follow_imports = None if file_group == "" else "skip"
if changed_files:
returncode |= mypy(changed_files, python_version, follow_imports, file_group)
return returncode
if __name__ == "__main__":
sys.exit(main())
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
#
# Lint bash scripts for undefined vars, quoting, and similar bugs.
# Do not download a binary: use a distro/package-manager install so the
# artifact is signed (apt/dnf/brew) or at least an explicit local install.
set -euo pipefail
is_windows_exe() {
[[ "$1" == *.exe ]]
}
is_git_bash() {
case "$(uname -s)" in
MINGW*|MSYS*|CYGWIN*) return 0 ;;
*) return 1 ;;
esac
}
find_native_shellcheck() {
local cand
cand="$(command -v shellcheck 2>/dev/null || true)"
if [ -n "$cand" ] && ! is_windows_exe "$cand"; then
echo "$cand"
return 0
fi
return 1
}
install_hint() {
echo "Please install shellcheck with your package manager, then re-run:"
echo " Debian/Ubuntu/WSL: sudo apt-get install shellcheck"
echo " Fedora: sudo dnf install ShellCheck"
echo " macOS: brew install shellcheck"
echo " Git Bash: scoop install shellcheck"
echo " https://github.com/koalaman/shellcheck?tab=readme-ov-file#installing"
}
SHELLCHECK_BIN=""
if SHELLCHECK_BIN="$(find_native_shellcheck)"; then
:
elif is_git_bash && SHELLCHECK_BIN="$(command -v shellcheck.exe 2>/dev/null || true)" && [ -n "$SHELLCHECK_BIN" ]; then
:
else
install_hint
exit 1
fi
should_lint() {
local f="${1//\\//}"
f="${f#./}"
case "$f" in
*.sh) ;;
*) return 1 ;;
esac
git check-ignore -q "$f" && return 1
return 0
}
run_shellcheck() {
local f
for f in "$@"; do
if should_lint "$f"; then
"$SHELLCHECK_BIN" -s bash "$f"
fi
done
}
if [ "$#" -gt 0 ]; then
run_shellcheck "$@"
exit 0
fi
# Direct invocation with no args: lint every tracked *.sh.
while IFS= read -r -d '' f || [ -n "$f" ]; do
git check-ignore -q "$f" && continue
"$SHELLCHECK_BIN" -s bash "$f"
done < <(find . -path ./.git -prune -o -name "*.sh" -print0)