Python API
pypilot-cli also exposes a small API for running the engine from Python. It is typed (py.typed). Items marked 1.3 are new in 1.3.0.
import pypilot
result = pypilot.run(["doctor"], capture_output=True)
print(result.returncode)
print(result.stdout)
# since 1.3.0: parse --json output, raise on failure, find the engine
report = pypilot.run(["doctor", "--json"], capture_output=True).json()
pypilot.run(["check", "torch"], check=True)
info = pypilot.locate_engine() # EngineInfo(path, source, version)pypilot.run(...)
pypilot.run(args=None, capture_output=False, check=False, *,
cwd=None, env=None, input=None, timeout=None) -> RunResultRun the engine with args, a list of strings such as ["check", "torch"] (a plain string raises TypeError). Finds or downloads the engine first, like the CLI. Output is decoded as UTF-8, which is what the engine writes, whatever the locale.
| Parameter | Meaning |
|---|---|
capture_output | Capture stdout and stderr instead of leaving them on the terminal |
check 1.3 | Raise subprocess.CalledProcessError on a non-zero exit. Default False: inspect returncode yourself |
cwd, env, input, timeout 1.3 | As for subprocess.run. cwd is an easy way to point the engine at a project without --path |
Version 1.2.2 and older have run(args=None, capture_output=False) only, returning a plain subprocess.CompletedProcess[str].
import pypilot
res = pypilot.run(["explain", "--json"], capture_output=True, cwd="path/to/project")
explanation = res.json()["explanation"]
print(explanation["supported_range"], explanation["recommendation"])--json and explain need engine 1.3.0 or newer (the one pypilot-cli 1.3.0 runs); see Machine-readable output.
RunResult 1.3
A subclass of subprocess.CompletedProcess[str], so .args, .returncode, .stdout, .stderr and .check_returncode() work as before. It adds:
.ok:returncode == 0..json(): parse stdout as the command's--jsondocument ({"pypilot", "command", "ok", …}). RaisesValueErrorif stdout was not captured.
Note that doctor and check exit 0 even when they report problems; read res.json()["ok"] for their verdict.
await pypilot.arun(...) 1.3
The same parameters and result as run, without blocking the event loop. Locating (and possibly downloading) the engine happens in a worker thread. On timeout, or when the task is cancelled, the engine process is killed; a timeout raises subprocess.TimeoutExpired.
import asyncio, pypilot
async def main():
res = await pypilot.arun(["doctor", "--json"], capture_output=True, timeout=120)
print(res.json()["ok"])
asyncio.run(main())Finding the engine
pypilot.ensure_binary() -> pathlib.Path
Return the path of a usable engine, downloading the pinned release if needed and allowed. The search order is described in Which engine it runs.
pypilot.locate_engine() -> EngineInfo 1.3
The same search, with where the engine came from: EngineInfo(path, source, version), a frozen dataclass. source is override, bundled, cache, cargo, path or download; version is a (major, minor, patch) tuple, or None when it could not be read.
pypilot.get_cache_dir() -> pathlib.Path
The directory where downloaded engines are cached (created if missing): %LOCALAPPDATA%\pypilot\bin on Windows, $XDG_CACHE_HOME/pypilot/bin or ~/.cache/pypilot/bin elsewhere. Since 1.3.0 it keeps one subfolder per engine tag in it.
Errors 1.3
Engine problems raise subclasses of pypilot.EngineError (itself a RuntimeError):
| Exception | When |
|---|---|
EngineNotFoundError | No engine is available and none may be downloaded (PYPILOT_OFFLINE=1) |
EngineDownloadError | A release file could not be fetched; .status holds the HTTP status when there was one |
EngineVerificationError | A download did not match its expected SHA-256, or could not be checked |
An unsupported OS or architecture raises RuntimeError. In 1.2.2 and older, network errors from the download propagate as they are.
pypilot.__version__
The package version, for example "1.3.0".
pypilot.binary
Lower-level names live in pypilot.binary and may change. DEFAULT_TAG (the pinned engine tag, "v1.3.0") and, 1.3, ENGINE_SHA256 (the hash of each archive of that release) are the two assignments the engine's release automation bumps. The helpers get_platform_slug(), download_binary(tag=DEFAULT_TAG), probe_binary(path) (runs --version) and parse_version(text) stay importable from here; since 1.3.0 they live in pypilot.engine.
