Files
agent-radar 1a3a4ccde1
Creator App Tests / PR Spam Gate (push) Skipped
Frontend Tests / PR Spam Gate (push) Skipped
NPM Format (website & console) / PR Spam Gate (push) Skipped
Pre-commit Checks / PR Spam Gate (push) Skipped
QwenPaw Creator Plugin Release / check-version (push) Canceled after 0s
QwenPaw Creator Plugin Release / upload-oss (push) Canceled after 0s
Tests / PR Spam Gate (push) Skipped
CodeQL / CodeQL (python) (push) Canceled after 0s
CodeQL / CodeQL (typescript) (push) Canceled after 0s
Creator App Tests / Creator Backend Tests (push) Canceled after 0s
Creator App Tests / Creator UI Build & Tests (push) Canceled after 0s
E2E Smoke Tests / Playwright UI Smoke (push) Canceled after 0s
Frontend Tests / Detect console changes (push) Canceled after 0s
NPM Format (website & console) / website format check (push) Canceled after 0s
NPM Format (website & console) / console format check (push) Canceled after 0s
Pre-commit Checks / Pre-commit (push) Canceled after 0s
QwenPaw Data Plugin Release / check-version (push) Canceled after 0s
Tests / Detect code changes (push) Canceled after 0s
Frontend Tests / Vitest Unit Tests (push) Canceled after 0s
Frontend Tests / Frontend Summary (push) Canceled after 0s
QwenPaw Data Plugin Release / upload-oss (push) Canceled after 0s
Tests / Maintainer Approval (push) Canceled after 0s
Tests / Unit Tests - py3.11 - macos-latest (push) Canceled after 0s
Tests / Unit Tests - py3.11 - ubuntu-latest (push) Canceled after 0s
Tests / Unit Tests - py3.13 - ubuntu-latest (push) Canceled after 0s
Tests / Unit Tests - py3.11 - windows-latest (push) Canceled after 0s
Tests / Contract Tests - py3.11 - macos-latest (push) Canceled after 0s
Tests / Contract Tests - py3.11 - ubuntu-latest (push) Canceled after 0s
Tests / Contract Tests - py3.13 - ubuntu-latest (push) Canceled after 0s
Tests / Contract Tests - py3.11 - windows-latest (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - macos-latest - p0 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - macos-latest - p1 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - macos-latest - p2 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - ubuntu-latest - fallback (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - ubuntu-latest - p0 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - ubuntu-latest - p1 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - ubuntu-latest - p2 (push) Canceled after 0s
Tests / Integrated Tests - py3.13 - ubuntu-latest - p0 (push) Canceled after 0s
Tests / Integrated Tests - py3.13 - ubuntu-latest - p1 (push) Canceled after 0s
Tests / Integrated Tests - py3.13 - ubuntu-latest - p2 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - windows-latest - p0 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - windows-latest - p1 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - windows-latest - p2 (push) Canceled after 0s
Tests / Coverage Report (push) Canceled after 0s
Tests / Test Summary (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:01:50 +08:00

48 lines
2.0 KiB
Python

# -*- coding: utf-8 -*-
"""Coverage-mode app launcher for Windows integration tests.
Launches the same server as ``python -m qwenpaw app`` (same CLI entry,
same argv layout), but first maps SIGBREAK to KeyboardInterrupt.
Why this wrapper exists (Windows-only, coverage mode only):
The integration fixture stops the app subprocess with CTRL_BREAK_EVENT
so the child can run its atexit handlers and flush subprocess coverage
data. But CPython only installs a Python-level handler for SIGINT
(see ``Modules/signalmodule.c`` init: ``set_handler(SIGINT, ...)``);
SIGBREAK keeps the CRT default action, and neither uvicorn (handles
SIGINT/SIGTERM only) nor QwenPaw registers a SIGBREAK handler. The
default action terminates the process immediately -- atexit never runs,
so coverage's save never happens and all recorded data is dropped.
Forensics proof (fork run 31671241854): every app's tracer was active
(per-app debug logs with ``Tracing '...qwenpaw...'`` dispositions), yet
main-process saves never materialized and the combined data held 752
files with 0 executed lines, while the identical mechanism on
ubuntu/macos recorded ~53k lines.
Raising KeyboardInterrupt instead puts the shutdown on the exact same
graceful path POSIX enjoys with SIGINT: uvicorn unwinds, the interpreter
exits normally, atexit runs, coverage flushes.
This file is only used when ``QWENPAW_INTEGRATION_COVERAGE`` is enabled
on ``win32``; the normal (non-coverage) launch command is unchanged.
"""
import runpy
import signal
import sys
def _sigbreak_to_keyboard_interrupt(signum, frame):
raise KeyboardInterrupt
if hasattr(signal, "SIGBREAK"):
signal.signal(signal.SIGBREAK, _sigbreak_to_keyboard_interrupt)
# Emulate ``python -m qwenpaw app <args...>``. The fixture invokes this
# wrapper as ``python _coverage_app_main.py app --host ...``, so the
# subcommand and its flags are already in sys.argv[1:]; only argv[0]
# (the wrapper path) needs replacing with the program name.
sys.argv = ["qwenpaw", *sys.argv[1:]]
runpy.run_module("qwenpaw", run_name="__main__")