chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:38 +08:00
commit 309eedff77
1201 changed files with 210635 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""Run mypy type checking on all livekit packages.
Auto-discovers all plugin packages in livekit-plugins/ and runs mypy on them.
Uses mypy's incremental mode (.mypy_cache) for fast re-checks after the first run.
Passes given arguments to mypy. Arguments after `--` passed to `uv run`.
Third-party type stubs are declared in the `typing` dependency group in
pyproject.toml and locked in uv.lock. We intentionally do NOT use
`mypy --install-types`: it requires pip, installs unpinned stubs,
and requires a forward pass in most cases.
When a dependency introduces a stub not declared yet, mypy records
the complete set of stub packages it wants in `.mypy_cache/missing_stubs`,
the same list `--install-types` consumes.
See https://github.com/python/mypy/issues/10600#issuecomment-2481074163.
We read that file for the full set, then fail with the
exact `uv add` command to declare and lock them. The script never installs stubs
itself, so every run is a single deterministic pass..
"""
import subprocess
import sys
from pathlib import Path
# Plugins to exclude from type checking
EXCLUDED_PLUGINS = [
"browser",
"nvidia",
"rtzr",
]
# mypy records the full set of stub packages it wants here, one per line.
_MISSING_STUBS = ".mypy_cache/missing_stubs"
INSTALL_STUBS_MESSAGE = """
check_types: mypy needs type stubs that aren't currently installed.
Make sure to add them to the `typing` group and lock them with:
uv add --group typing {}
"""
def get_packages(repo_root: Path) -> list[str]:
"""Return all packages to type-check."""
packages = ["livekit.agents"]
plugins_dir = repo_root / "livekit-plugins"
for plugin_dir in sorted(plugins_dir.glob("livekit-plugins-*")):
if plugin_dir.is_dir():
# livekit-plugins-openai -> openai
# livekit-plugins-turn-detector -> turn_detector
plugin_name = plugin_dir.name.replace("livekit-plugins-", "").replace("-", "_")
if plugin_name in EXCLUDED_PLUGINS:
continue
packages.append(f"livekit.plugins.{plugin_name}")
return packages
def read_missing_stubs(repo_root: Path) -> list[str]:
"""The full stub-package list mypy recorded in .mypy_cache/missing_stubs."""
marker = repo_root / _MISSING_STUBS
if not marker.exists():
return []
return sorted(set(map(str.strip, marker.read_text().splitlines())))
def main() -> None:
"""
Command:
`python scripts/check_types.py --verbose -- --no-sync`
Translates to:
`uv run --no-sync mypy ... --verbose`
"""
repo_root = Path(__file__).parent.parent
packages = get_packages(repo_root)
try:
mypy_args_end = sys.argv.index("--")
except ValueError:
mypy_args, uv_run_args = sys.argv[1:], []
else:
mypy_args, uv_run_args = sys.argv[1:mypy_args_end], sys.argv[mypy_args_end + 1 :]
pkg_args: list[str] = []
for pkg in packages:
pkg_args.extend(["-p", pkg])
command = [
"uv",
"run",
"--group",
"typing",
*uv_run_args,
"mypy",
"--untyped-calls-exclude=smithy_aws_core",
*pkg_args,
*mypy_args,
]
print(*command, "\n")
returncode = subprocess.run(command, cwd=repo_root).returncode
if returncode and (missing := read_missing_stubs(repo_root)):
print(INSTALL_STUBS_MESSAGE.format(" ".join(missing)), file=sys.stderr)
sys.exit(returncode)
if __name__ == "__main__":
main()
+121
View File
@@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""Generate a markdown summary from JUnit XML test results."""
from __future__ import annotations
import argparse
import sys
import textwrap
import xml.etree.ElementTree as ET
def generate_summary(xml_path: str) -> str:
"""Parse JUnit XML and generate markdown summary."""
lines: list[str] = []
try:
tree = ET.parse(xml_path)
root = tree.getroot()
testsuite = root.find("testsuite") if root.tag != "testsuite" else root
if testsuite is None:
testsuite = root
tests = int(testsuite.get("tests", 0))
failures = int(testsuite.get("failures", 0))
errors = int(testsuite.get("errors", 0))
skipped = int(testsuite.get("skipped", 0))
time_taken = float(testsuite.get("time", 0))
passed = tests - failures - errors - skipped
if failures == 0 and errors == 0:
status = "✓ All tests passed"
else:
status = "✗ Some tests failed"
lines.append("## STT Test Results\n")
lines.append(f"**Status:** {status}\n")
lines.append("| Metric | Count |")
lines.append("|--------|-------|")
lines.append(f"| ✓ Passed | {passed} |")
lines.append(f"| ✗ Failed | {failures} |")
lines.append(f"| × Errors | {errors} |")
lines.append(f"| → Skipped | {skipped} |")
lines.append(f"| ▣ Total | {tests} |")
lines.append(f"| ⏱ Duration | {time_taken:.1f}s |")
lines.append("")
if failures > 0 or errors > 0:
lines.append("<details>")
lines.append("<summary>Failed Tests</summary>\n")
for testcase in testsuite.iter("testcase"):
failure = testcase.find("failure")
error = testcase.find("error")
if failure is not None or error is not None:
name = testcase.get("name", "unknown")
classname = testcase.get("classname", "")
elem = failure if failure is not None else error
msg = elem.text if elem.text else elem.get("message", "")
msg = msg[:2000]
indented_msg = textwrap.indent(msg.strip(), " ")
lines.append(f"- **{classname}::{name}**")
lines.append(" ```")
lines.append(indented_msg)
lines.append(" ```")
lines.append("</details>")
skipped_tests = [tc for tc in testsuite.iter("testcase") if tc.find("skipped") is not None]
if skipped_tests:
lines.append("<details>")
lines.append("<summary>Skipped Tests</summary>\n")
lines.append("| Test | Reason |")
lines.append("|------|--------|")
for testcase in skipped_tests[:20]:
name = testcase.get("name", "unknown")
classname = testcase.get("classname", "")
skip = testcase.find("skipped")
reason = skip.get("message", "") if skip is not None else ""
test_name = f"{classname}::{name}".replace("|", "\\|")
reason_escaped = reason.strip().replace("|", "\\|").replace("\n", " ")
lines.append(f"| `{test_name}` | {reason_escaped} |")
if len(skipped_tests) > 20:
lines.append(f"| ... | ... and {len(skipped_tests) - 20} more |")
lines.append("</details>")
except Exception as e:
lines.append("## STT Test Results\n")
lines.append(f"⚠ Could not parse test results: {e}")
return "\n".join(lines)
def main() -> int:
parser = argparse.ArgumentParser(description="Generate test summary from JUnit XML")
parser.add_argument(
"xml_path",
nargs="?",
default="test-results.xml",
help="Path to JUnit XML file (default: test-results.xml)",
)
parser.add_argument(
"-o",
"--output",
default=None,
help="Output file path (default: stdout)",
)
args = parser.parse_args()
summary = generate_summary(args.xml_path)
if args.output:
with open(args.output, "w") as f:
f.write(summary)
else:
print(summary)
return 0
if __name__ == "__main__":
sys.exit(main())