#!/usr/bin/env python """Gradio offline test runner. Runs INSIDE an installed venv. Normally invoked through ../scripts/run-tests.sh, which handles the venv and runs both interpreters. Direct use: venv-py312/bin/python tests/run_tests.py --suites all --report out.md Standard library only: the bundle ships no pytest, so nothing here may import a test framework. """ from __future__ import print_function import argparse import json import os import platform import sys import time sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from harness import Results # noqa: E402 import suites # noqa: E402 ALL = ["environment", "install", "functional", "offline", "performance"] # Which gradio each interpreter is expected to carry. gradio 5.0 raised # requires_python to >=3.10, so 3.9 cannot go past the 4.x branch. EXPECTED = {"3.9": "4.44.1", "3.12": "6.28.0"} def main(): ap = argparse.ArgumentParser(description="Test gradio on offline RHEL 9.6") ap.add_argument("--suites", default="all", help="comma-separated: %s, or 'all'" % ",".join(ALL)) ap.add_argument("--quick", action="store_true", help="fewer repetitions in the performance suite") ap.add_argument("--report", help="write a markdown report here") ap.add_argument("--json", help="write machine-readable results here") ap.add_argument("--bundle", help="bundle root (default: parent of tests/)") args = ap.parse_args() wanted = ALL if args.suites == "all" else \ [s.strip() for s in args.suites.split(",") if s.strip()] unknown = [s for s in wanted if s not in ALL] if unknown: ap.error("unknown suite(s): %s" % ", ".join(unknown)) py = "%d.%d" % sys.version_info[:2] bundle = args.bundle or os.path.dirname(os.path.dirname(os.path.abspath(__file__))) try: import gradio major = int(gradio.__version__.split(".")[0]) gradio_version = gradio.__version__ except Exception as exc: print("FATAL: cannot import gradio in this interpreter: %s" % exc) print("Install it first: scripts/install-gradio.sh %s" % py) return 2 ctx = { "py": py, "tag": "py39" if py == "3.9" else "py312", "major": major, "expect_gradio": EXPECTED.get(py, gradio_version), "bundle": bundle, } print("=" * 74) print(" gradio offline test run") print(" python %s gradio %s %s" % (platform.python_version(), gradio_version, platform.machine())) print(" host %s bundle %s" % (platform.node(), bundle)) print("=" * 74) results = Results() began = time.time() runners = { "environment": lambda: suites.suite_environment(results, ctx), "install": lambda: suites.suite_install(results, ctx), "functional": lambda: suites.suite_functional(results, ctx), "offline": lambda: suites.suite_offline(results, ctx), "performance": lambda: suites.suite_performance(results, ctx, args.quick), } for name in wanted: try: runners[name]() except Exception as exc: # a suite must not kill the run results.add(name, "suite aborted", "FAIL", "%s: %s" % (type(exc).__name__, exc)) elapsed = time.time() - began print("\n" + "=" * 74) print(" %d passed, %d failed, %d warned, %d skipped in %.0fs" % (results.passed, results.failed, results.warned, results.skipped, elapsed)) if results.warned: print(" warnings are known gradio limitations, not bundle defects:") for r in results.rows: if r["status"] == "WARN": print(" - %s: %s" % (r["test"], r["detail"])) print("=" * 74) payload = { "python": platform.python_version(), "gradio": gradio_version, "machine": platform.machine(), "host": platform.node(), "when": time.strftime("%Y-%m-%d %H:%M:%S"), "elapsed_seconds": round(elapsed, 1), "passed": results.passed, "failed": results.failed, "warned": results.warned, "skipped": results.skipped, "rows": results.rows, "metrics": results.metrics, } if args.json: with open(args.json, "w") as fh: json.dump(payload, fh, indent=2) print("results: %s" % args.json) if args.report: write_report(args.report, payload) print("report: %s" % args.report) return 1 if results.failed else 0 def write_report(path, p): out = [] out.append("# Gradio offline test report\n") out.append("| | |") out.append("|---|---|") out.append("| Host | %s |" % p["host"]) out.append("| When | %s |" % p["when"]) out.append("| Python | %s |" % p["python"]) out.append("| gradio | %s |" % p["gradio"]) out.append("| Architecture | %s |" % p["machine"]) out.append("| Duration | %.0f s |" % p["elapsed_seconds"]) out.append("| Result | **%d passed, %d failed, %d warned, %d skipped** |" % (p["passed"], p["failed"], p.get("warned", 0), p["skipped"])) out.append("") if p["failed"]: out.append("## Failures\n") out.append("| Suite | Test | Detail |") out.append("|---|---|---|") for r in p["rows"]: if r["status"] == "FAIL": out.append("| %s | %s | %s |" % (r["suite"], r["test"], r["detail"].replace("|", "\\|"))) out.append("") warns = [r for r in p["rows"] if r["status"] == "WARN"] if warns: out.append("## Warnings\n") out.append("Known limitations of the installed gradio, not defects in " "this bundle.\n") out.append("| Suite | Test | Detail |") out.append("|---|---|---|") for r in warns: out.append("| %s | %s | %s |" % (r["suite"], r["test"], r["detail"].replace("|", "\\|"))) out.append("") out.append("## Tests\n") last = None for r in p["rows"]: if r["suite"] != last: out.append("") out.append("### %s\n" % r["suite"]) out.append("| Result | Test | Detail |") out.append("|---|---|---|") last = r["suite"] out.append("| %s | %s | %s |" % (r["status"], r["test"], r["detail"].replace("|", "\\|"))) out.append("") if p["metrics"]: out.append("## Measurements\n") out.append("These are a baseline for this host, not pass/fail criteria.") out.append("Compare successive runs on the same hardware.\n") out.append("| Metric | Value | Unit | Note |") out.append("|---|---:|---|---|") for m in p["metrics"]: val = ("%.2f" % m["value"]) if isinstance(m["value"], float) else m["value"] out.append("| %s | %s | %s | %s |" % (m["metric"], val, m["unit"], m["note"])) out.append("") with open(path, "w") as fh: fh.write("\n".join(out)) if __name__ == "__main__": sys.exit(main())