1
"""Run the unmodified PyPI app on a temporary loopback port."""
9
from pathlib import Path
12
from web_edit.app import create_app
15
async def serve(directory: Path, state: Path, timeout: float):
16
# Binding port zero avoids port-selection races with other local servers.
17
with socket.socket() as sock:
18
sock.bind(("127.0.0.1", 0))
19
server = uvicorn.Server(
21
create_app(directory),
27
task = asyncio.create_task(server.serve(sockets=[sock]))
29
while not server.started:
32
raise RuntimeError("Server exited before becoming ready")
33
await asyncio.sleep(0.02)
34
ready = state / "ready.json"
35
temporary = state / "ready.tmp"
37
json.dumps({"pid": os.getpid(), "port": sock.getsockname()[1]})
39
temporary.replace(ready)
40
deadline = time.monotonic() + timeout
41
while not (state / "stop").exists() and time.monotonic() < deadline:
45
await asyncio.sleep(0.1)
47
server.should_exit = True
51
if __name__ == "__main__":
52
parser = argparse.ArgumentParser(description=__doc__)
53
parser.add_argument("directory", type=Path)
54
parser.add_argument("state", type=Path)
55
parser.add_argument("--timeout", type=float, default=120)
56
args = parser.parse_args()
57
750
asyncio.run(serve(args.directory, args.state, args.timeout))