pypilot-cli 1.2.2__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pypilot_cli-1.3.0/.gitattributes +5 -0
- pypilot_cli-1.3.0/.github/CODEOWNERS +9 -0
- pypilot_cli-1.3.0/.github/ISSUE_TEMPLATE/environment_problem.md +30 -0
- pypilot_cli-1.3.0/.github/workflows/ci.yml +76 -0
- pypilot_cli-1.3.0/.github/workflows/publish.yml +115 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/.gitignore +2 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/CONTRIBUTING.md +33 -21
- pypilot_cli-1.3.0/PKG-INFO +284 -0
- pypilot_cli-1.3.0/README.md +255 -0
- pypilot_cli-1.3.0/hatch_build.py +56 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/pyproject.toml +9 -1
- pypilot_cli-1.3.0/scripts/build_wheels.py +139 -0
- pypilot_cli-1.3.0/scripts/sbom.py +75 -0
- pypilot_cli-1.3.0/src/pypilot/__init__.py +34 -0
- pypilot_cli-1.3.0/src/pypilot/api.py +151 -0
- pypilot_cli-1.3.0/src/pypilot/binary.py +90 -0
- pypilot_cli-1.3.0/src/pypilot/cli.py +117 -0
- pypilot_cli-1.3.0/src/pypilot/engine.py +548 -0
- pypilot_cli-1.3.0/tests/conftest.py +165 -0
- pypilot_cli-1.3.0/tests/test_api.py +110 -0
- pypilot_cli-1.3.0/tests/test_cli.py +212 -0
- pypilot_cli-1.3.0/tests/test_engine.py +288 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/uv.lock +10 -10
- pypilot_cli-1.2.2/.github/workflows/ci.yml +0 -33
- pypilot_cli-1.2.2/.github/workflows/publish.yml +0 -39
- pypilot_cli-1.2.2/PKG-INFO +0 -180
- pypilot_cli-1.2.2/README.md +0 -151
- pypilot_cli-1.2.2/src/pypilot/__init__.py +0 -32
- pypilot_cli-1.2.2/src/pypilot/binary.py +0 -211
- pypilot_cli-1.2.2/src/pypilot/cli.py +0 -27
- pypilot_cli-1.2.2/tests/test_cli.py +0 -112
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/.python-version +0 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/CODE_OF_CONDUCT.md +0 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/LICENSE +0 -0
- {pypilot_cli-1.2.2 → pypilot_cli-1.3.0}/src/pypilot/py.typed +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Every change is reviewed by the maintainer.
|
|
2
|
+
* @Abdullah-Masood-05
|
|
3
|
+
|
|
4
|
+
# The engine pin (DEFAULT_TAG / ENGINE_SHA256) decides which native binary
|
|
5
|
+
# every install downloads or bundles.
|
|
6
|
+
/src/pypilot/binary.py @Abdullah-Masood-05
|
|
7
|
+
/hatch_build.py @Abdullah-Masood-05
|
|
8
|
+
/scripts/ @Abdullah-Masood-05
|
|
9
|
+
/.github/workflows/ @Abdullah-Masood-05
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Environment problem
|
|
3
|
+
about: PyPilot ran, but got your Python environment, packages or GPU setup wrong
|
|
4
|
+
title: ""
|
|
5
|
+
labels: environment
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**What happened**
|
|
10
|
+
What PyPilot reported or did, and what you expected instead.
|
|
11
|
+
|
|
12
|
+
**`pypilot --version`**
|
|
13
|
+
Both lines, please: the engine (`pypilot X.Y.Z`) and the wrapper (`pypilot-cli X.Y.Z (engine: ...)`), plus any `warning:` lines.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
paste here
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**`pypilot doctor --json`**
|
|
20
|
+
Run it in the project folder. It lists your interpreter, virtual environment, manifests and GPU/CUDA facts; remove anything you consider private before posting.
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
paste here
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Install method**
|
|
27
|
+
pip / pipx / `uv tool` / platform wheel or pure wheel (`pip show -f pypilot-cli` lists `pypilot/_engine/` if the engine is bundled).
|
|
28
|
+
|
|
29
|
+
**Anything else**
|
|
30
|
+
Proxy or offline setup (`PYPILOT_OFFLINE`, `HTTPS_PROXY`), `PYPILOT_ENGINE_VERSION`, or a `pypilot` engine on PATH or in `~/.cargo/bin`.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: py${{ matrix.python }} (${{ matrix.os }})
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest]
|
|
19
|
+
python: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
|
|
20
|
+
include:
|
|
21
|
+
# The oldest and newest supported Pythons on the other platforms the
|
|
22
|
+
# engine ships for, since archive handling differs between them.
|
|
23
|
+
- { os: windows-latest, python: "3.8" }
|
|
24
|
+
- { os: windows-latest, python: "3.15" }
|
|
25
|
+
- { os: macos-latest, python: "3.8" }
|
|
26
|
+
- { os: macos-latest, python: "3.15" }
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@v5
|
|
32
|
+
|
|
33
|
+
# Warnings are errors so a deprecation that a new Python release turns
|
|
34
|
+
# into a behaviour change (as 3.14 did for tarfile) fails here first.
|
|
35
|
+
- name: Test
|
|
36
|
+
run: uv run --python ${{ matrix.python }} python -m pytest -W error
|
|
37
|
+
|
|
38
|
+
wheels:
|
|
39
|
+
name: Build all wheels
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v4
|
|
43
|
+
|
|
44
|
+
- name: Install uv
|
|
45
|
+
uses: astral-sh/setup-uv@v5
|
|
46
|
+
|
|
47
|
+
- name: Build the sdist, the pure wheel and the platform wheels
|
|
48
|
+
run: uv run --python 3.12 python scripts/build_wheels.py
|
|
49
|
+
|
|
50
|
+
- name: Check the metadata
|
|
51
|
+
run: uv run --python 3.12 twine check --strict dist/*
|
|
52
|
+
|
|
53
|
+
# The bundled engine must run with no network at all.
|
|
54
|
+
- name: Run the manylinux wheel offline
|
|
55
|
+
run: |
|
|
56
|
+
uv venv --python 3.12 "$RUNNER_TEMP/smoke"
|
|
57
|
+
uv pip install --python "$RUNNER_TEMP/smoke/bin/python" dist/*-manylinux_*.whl
|
|
58
|
+
HOME="$(mktemp -d)" XDG_CACHE_HOME="$(mktemp -d)" PYPILOT_OFFLINE=1 HTTPS_PROXY=http://127.0.0.1:9 \
|
|
59
|
+
"$RUNNER_TEMP/smoke/bin/pypilot" --version 2>&1 | tee version.txt
|
|
60
|
+
grep -q "engine: bundled" version.txt
|
|
61
|
+
|
|
62
|
+
audit:
|
|
63
|
+
name: Audit locked dependencies
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v4
|
|
67
|
+
|
|
68
|
+
- name: Install uv
|
|
69
|
+
uses: astral-sh/setup-uv@v5
|
|
70
|
+
|
|
71
|
+
# The package itself has no runtime dependencies; this covers the build
|
|
72
|
+
# and test tools in uv.lock.
|
|
73
|
+
- name: pip-audit
|
|
74
|
+
run: |
|
|
75
|
+
uv export --frozen --format requirements-txt --no-emit-project -o "$RUNNER_TEMP/requirements.txt"
|
|
76
|
+
uvx pip-audit --strict --disable-pip --require-hashes -r "$RUNNER_TEMP/requirements.txt"
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Test
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v5
|
|
21
|
+
|
|
22
|
+
- name: Test
|
|
23
|
+
run: uv run --python 3.12 python -m pytest -W error
|
|
24
|
+
|
|
25
|
+
build:
|
|
26
|
+
name: Build sdist and wheels
|
|
27
|
+
needs: test
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
|
|
32
|
+
- name: Install uv
|
|
33
|
+
uses: astral-sh/setup-uv@v5
|
|
34
|
+
|
|
35
|
+
- name: Audit locked dependencies
|
|
36
|
+
run: |
|
|
37
|
+
uv export --frozen --format requirements-txt --no-emit-project -o "$RUNNER_TEMP/requirements.txt"
|
|
38
|
+
uvx pip-audit --strict --disable-pip --require-hashes -r "$RUNNER_TEMP/requirements.txt"
|
|
39
|
+
|
|
40
|
+
# One Linux job builds every wheel: it only packs the pinned engine
|
|
41
|
+
# binaries (each checked against ENGINE_SHA256), and Linux keeps the
|
|
42
|
+
# executable bit the Linux and macOS wheels need.
|
|
43
|
+
- name: Build the sdist, the pure wheel and the platform wheels
|
|
44
|
+
run: uv run --python 3.12 python scripts/build_wheels.py
|
|
45
|
+
|
|
46
|
+
- name: Check the metadata
|
|
47
|
+
run: uv run --python 3.12 twine check --strict dist/*
|
|
48
|
+
|
|
49
|
+
- name: Run the manylinux wheel offline
|
|
50
|
+
run: |
|
|
51
|
+
uv venv --python 3.12 "$RUNNER_TEMP/smoke"
|
|
52
|
+
uv pip install --python "$RUNNER_TEMP/smoke/bin/python" dist/*-manylinux_*.whl
|
|
53
|
+
HOME="$(mktemp -d)" XDG_CACHE_HOME="$(mktemp -d)" PYPILOT_OFFLINE=1 HTTPS_PROXY=http://127.0.0.1:9 \
|
|
54
|
+
"$RUNNER_TEMP/smoke/bin/pypilot" --version 2>&1 | tee version.txt
|
|
55
|
+
grep -q "engine: bundled" version.txt
|
|
56
|
+
|
|
57
|
+
- name: Write the CycloneDX SBOM
|
|
58
|
+
run: |
|
|
59
|
+
mkdir sbom
|
|
60
|
+
uv export --frozen --no-dev --format cyclonedx1.5 --preview-features sbom-export -o "$RUNNER_TEMP/uv-sbom.json"
|
|
61
|
+
uv run --python 3.12 python scripts/sbom.py "$RUNNER_TEMP/uv-sbom.json" sbom/pypilot-cli.cdx.json
|
|
62
|
+
|
|
63
|
+
- uses: actions/upload-artifact@v4
|
|
64
|
+
with:
|
|
65
|
+
name: dist
|
|
66
|
+
path: dist/
|
|
67
|
+
if-no-files-found: error
|
|
68
|
+
|
|
69
|
+
- uses: actions/upload-artifact@v4
|
|
70
|
+
with:
|
|
71
|
+
name: sbom
|
|
72
|
+
path: sbom/
|
|
73
|
+
if-no-files-found: error
|
|
74
|
+
|
|
75
|
+
publish:
|
|
76
|
+
name: Publish to PyPI
|
|
77
|
+
needs: build
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
environment:
|
|
80
|
+
name: pypi
|
|
81
|
+
url: https://pypi.org/p/pypilot-cli
|
|
82
|
+
permissions:
|
|
83
|
+
id-token: write
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/download-artifact@v4
|
|
86
|
+
with:
|
|
87
|
+
name: dist
|
|
88
|
+
path: dist/
|
|
89
|
+
|
|
90
|
+
- name: Publish to PyPI
|
|
91
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
92
|
+
|
|
93
|
+
github-release:
|
|
94
|
+
name: Attach wheels and SBOM to the GitHub release
|
|
95
|
+
needs: publish
|
|
96
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
97
|
+
runs-on: ubuntu-latest
|
|
98
|
+
permissions:
|
|
99
|
+
contents: write
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/download-artifact@v4
|
|
102
|
+
with:
|
|
103
|
+
path: artifacts/
|
|
104
|
+
merge-multiple: true
|
|
105
|
+
|
|
106
|
+
- name: Create or update the release
|
|
107
|
+
env:
|
|
108
|
+
GH_TOKEN: ${{ github.token }}
|
|
109
|
+
TAG: ${{ github.ref_name }}
|
|
110
|
+
run: |
|
|
111
|
+
if gh release view "$TAG" -R "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
|
112
|
+
gh release upload "$TAG" -R "$GITHUB_REPOSITORY" --clobber artifacts/*
|
|
113
|
+
else
|
|
114
|
+
gh release create "$TAG" -R "$GITHUB_REPOSITORY" --verify-tag --title "$TAG" --generate-notes artifacts/*
|
|
115
|
+
fi
|
|
@@ -33,11 +33,16 @@ What is in this repo:
|
|
|
33
33
|
|
|
34
34
|
| Path | What it is |
|
|
35
35
|
|---|---|
|
|
36
|
-
| `src/pypilot/binary.py` |
|
|
37
|
-
| `src/pypilot/
|
|
38
|
-
| `src/pypilot/
|
|
39
|
-
| `
|
|
40
|
-
|
|
|
36
|
+
| `src/pypilot/binary.py` | The engine pin: `DEFAULT_TAG` and `ENGINE_SHA256`. The release workflow edits exactly these two. The old function names are re-exported from here |
|
|
37
|
+
| `src/pypilot/engine.py` | Platform detection, the lookup order, the cache, download, SHA-256 verification, offline mode and proxy handling |
|
|
38
|
+
| `src/pypilot/api.py` | `run()`, `arun()` and `RunResult` for use from Python |
|
|
39
|
+
| `src/pypilot/cli.py` | The `pypilot` console script: answers `--version`, passes everything else to the engine along with its exit code |
|
|
40
|
+
| `src/pypilot/__init__.py` | The package version and the public API |
|
|
41
|
+
| `hatch_build.py` | Build hook that turns the wheel into a platform wheel bundling the engine |
|
|
42
|
+
| `scripts/build_wheels.py` | Builds the sdist, the pure wheel and the four platform wheels |
|
|
43
|
+
| `scripts/sbom.py` | Adds the bundled engine to uv's CycloneDX SBOM |
|
|
44
|
+
| `tests/` | The tests |
|
|
45
|
+
| `.github/workflows/` | `ci.yml` (tests, wheel build, `pip-audit`) and `publish.yml` (PyPI and GitHub release) |
|
|
41
46
|
|
|
42
47
|
## License
|
|
43
48
|
|
|
@@ -57,13 +62,15 @@ and include:
|
|
|
57
62
|
prints `PyPilot: downloading native engine from <url> ...`, so include both lines.
|
|
58
63
|
- Whether you are behind a proxy or offline, if the download failed.
|
|
59
64
|
|
|
60
|
-
The engine is looked up in this order:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
The engine is looked up in this order: `PYPILOT_ENGINE_VERSION` if set, then the
|
|
66
|
+
engine bundled in a platform wheel, then the cache, then `~/.cargo/bin`, then `PATH`,
|
|
67
|
+
then a fresh download (never with `PYPILOT_OFFLINE=1`). The cache holds one folder per
|
|
68
|
+
engine release: `%LOCALAPPDATA%\pypilot\bin\<tag>\pypilot.exe` on Windows (falling
|
|
69
|
+
back to `~\.cache\pypilot\bin` if `LOCALAPPDATA` is unset), and
|
|
70
|
+
`$XDG_CACHE_HOME/pypilot/bin/<tag>/pypilot` on Linux and macOS (falling back to
|
|
71
|
+
`~/.cache/pypilot/bin/<tag>/pypilot`). Downloads are checked against the pinned
|
|
72
|
+
SHA-256 before they are extracted. If you suspect a broken download, delete that file
|
|
73
|
+
and run `pypilot --version` again: its stderr line says which engine is in use.
|
|
67
74
|
|
|
68
75
|
If the problem is about an environment (the output of `pypilot doctor`, a wrong
|
|
69
76
|
Python or CUDA choice), report it in the
|
|
@@ -92,7 +99,9 @@ uv sync
|
|
|
92
99
|
|---|---|
|
|
93
100
|
| `uv run python -m pytest -W error` | Run the tests, with warnings as errors (what CI runs) |
|
|
94
101
|
| `uv run --python 3.8 python -m pytest -W error` | The same on a specific Python version |
|
|
95
|
-
| `uv
|
|
102
|
+
| `uv run python -m pytest -W error -m "not network"` | Only the tests that need no network |
|
|
103
|
+
| `uv build` | Build the sdist and the pure wheel into `dist/` |
|
|
104
|
+
| `uv run python scripts/build_wheels.py` | Also build the platform wheels with the verified engine (the Linux and macOS ones only on Linux or macOS, which keep the executable bit) |
|
|
96
105
|
| `uvx twine check dist/*` | Check the built package's metadata |
|
|
97
106
|
|
|
98
107
|
CI runs the tests on Python 3.8 to 3.15 on Linux, and on 3.8 and 3.15 on Windows and
|
|
@@ -100,9 +109,10 @@ macOS, because archive handling differs between platforms. Warnings are errors s
|
|
|
100
109
|
that a deprecation which a new Python release turns into a behaviour change fails
|
|
101
110
|
there first.
|
|
102
111
|
|
|
103
|
-
**
|
|
104
|
-
`pypilot --version`, so they download the real engine from
|
|
105
|
-
(and cache it, see above).
|
|
112
|
+
**Some tests need network access.** The ones marked `network` call the real
|
|
113
|
+
`ensure_binary()` and `pypilot --version`, so they download the real engine from
|
|
114
|
+
GitHub on the first run (and cache it, see above). Everything else (verification,
|
|
115
|
+
offline mode, proxies, the API) runs against a local server or a stand-in engine.
|
|
106
116
|
|
|
107
117
|
## Code notes
|
|
108
118
|
|
|
@@ -126,7 +136,7 @@ there first.
|
|
|
126
136
|
2. Fork the repo and create a branch from `master`.
|
|
127
137
|
3. Keep the change focused. Match the style of the surrounding code, and explain *why*
|
|
128
138
|
in comments rather than restating what the code does. Add or update a test in
|
|
129
|
-
`tests
|
|
139
|
+
`tests/` for a behaviour change.
|
|
130
140
|
4. Make small, logical commits with clear messages (for example `fix(binary): ...`
|
|
131
141
|
or `test: ...`). Use LF line endings.
|
|
132
142
|
5. Run `uv run python -m pytest -W error`.
|
|
@@ -140,7 +150,9 @@ The maintainer reviews pull requests as time allows, so a short wait is normal.
|
|
|
140
150
|
|
|
141
151
|
Releases are cut by the maintainer. Contributors do not need to bump versions or
|
|
142
152
|
create tags. Pushing a tag `vX.Y.Z` runs the publish workflow, which tests, builds
|
|
143
|
-
and publishes to PyPI through
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
the sdist, the pure wheel and the four platform wheels, publishes them to PyPI through
|
|
154
|
+
trusted publishing, and attaches them with a CycloneDX SBOM to the GitHub release.
|
|
155
|
+
`DEFAULT_TAG` and `ENGINE_SHA256` in `src/pypilot/binary.py` name the engine release
|
|
156
|
+
this package ships and the SHA-256 of each of its archives, so a new pip release is
|
|
157
|
+
made only after that engine release exists. PyPI never allows a version number to be
|
|
158
|
+
reused.
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pypilot-cli
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Deterministic Python environment doctor, dependency solver, and hardware compatibility manager.
|
|
5
|
+
Project-URL: Homepage, https://github.com/pypilot-dev/pypilot
|
|
6
|
+
Project-URL: Repository, https://github.com/pypilot-dev/pypilot
|
|
7
|
+
Project-URL: Issues, https://github.com/pypilot-dev/pypilot/issues
|
|
8
|
+
Author-email: Abdullah Masood <Abdullah-Masood-05@users.noreply.github.com>
|
|
9
|
+
License-Expression: AGPL-3.0-or-later
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
25
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
26
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
27
|
+
Requires-Python: >=3.8
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# PyPilot (CLI & Python Package)
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<a href="https://pypi.org/project/pypilot-cli/"><img src="https://img.shields.io/pypi/v/pypilot-cli?color=blue&logo=pypi&logoColor=white" alt="PyPI version" /></a>
|
|
34
|
+
<a href="https://pypi.org/project/pypilot-cli/"><img src="https://img.shields.io/pypi/pyversions/pypilot-cli?logo=python&logoColor=white" alt="Supported Python versions" /></a>
|
|
35
|
+
<a href="https://pypi.org/project/pypilot-cli/"><img src="https://img.shields.io/pypi/dm/pypilot-cli?color=2ea44f" alt="Monthly downloads" /></a>
|
|
36
|
+
<a href="https://github.com/pypilot-dev/pypilot-pip/blob/master/LICENSE"><img src="https://img.shields.io/pypi/l/pypilot-cli?color=blue" alt="License: AGPL-3.0-or-later" /></a>
|
|
37
|
+
<a href="https://github.com/pypilot-dev/pypilot"><img src="https://img.shields.io/badge/engine-Rust-orange?logo=rust&logoColor=white" alt="Rust engine" /></a>
|
|
38
|
+
<a href="https://github.com/pypilot-dev/pypilot"><img src="https://img.shields.io/github/stars/pypilot-dev/pypilot?style=social" alt="GitHub stars" /></a>
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
> ⭐ **Enjoying PyPilot?** If it saved you from a broken environment, please [star it on GitHub](https://github.com/pypilot-dev/pypilot). It's free and it helps other Python developers find it.
|
|
42
|
+
|
|
43
|
+
**PyPilot** is a deterministic Python environment doctor, dependency solver, and toolchain manager. Powered by a high-speed compiled **Rust engine**, PyPilot calculates dependency intersections directly from PyPI wheel metadata, resolves hardware and CUDA build compatibility, and sets up working virtual environments without external AI or API keys.
|
|
44
|
+
|
|
45
|
+
📚 **Documentation:** <https://pypilot-dev.github.io/pypilot/> (the [Python package](https://pypilot-dev.github.io/pypilot/python/), its [API](https://pypilot-dev.github.io/pypilot/python/api), the [engine CLI](https://pypilot-dev.github.io/pypilot/engine/), [pixi](https://pypilot-dev.github.io/pypilot/pixi/) and the [configuration reference](https://pypilot-dev.github.io/pypilot/reference/configuration)).
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## ⚡ High-Speed Native Rust Architecture
|
|
50
|
+
|
|
51
|
+
PyPilot combines the ease of installation via `pip` with the raw execution speed and low memory footprint of compiled Rust:
|
|
52
|
+
- **Instant startup**: Binary execution starts in single-digit milliseconds.
|
|
53
|
+
- **Zero Python overhead**: CLI commands delegate directly to the native `pypilot` binary.
|
|
54
|
+
- **Engine included**: the wheels for Linux `x86_64`, macOS `Apple Silicon` / `Intel` and Windows `x64` bundle the native engine, so `pip install` is all it takes and nothing is downloaded at run time. On other platforms the engine is downloaded once, checked against a pinned SHA-256, and cached; a system-installed Rust binary on your `$PATH` is respected.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 📥 Installation
|
|
59
|
+
|
|
60
|
+
Install via `pip`:
|
|
61
|
+
```bash
|
|
62
|
+
pip install pypilot-cli
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or install as an isolated global tool with `uv`:
|
|
66
|
+
```bash
|
|
67
|
+
uv tool install pypilot-cli
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or via `pipx`:
|
|
71
|
+
```bash
|
|
72
|
+
pipx install pypilot-cli
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
pip picks the right wheel for you:
|
|
76
|
+
|
|
77
|
+
| Platform | Wheel | Engine |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| Linux x86_64, glibc 2.34 or newer (Ubuntu 22.04+, Debian 12+, RHEL/Alma/Rocky 9+, Fedora 35+) | `manylinux_2_34_x86_64` | bundled |
|
|
80
|
+
| macOS 11+ on Apple Silicon | `macosx_11_0_arm64` | bundled |
|
|
81
|
+
| macOS 10.12+ on Intel | `macosx_10_12_x86_64` | bundled |
|
|
82
|
+
| Windows x64 | `win_amd64` | bundled |
|
|
83
|
+
| Anything else (older glibc, other CPUs) | `py3-none-any` | downloaded on first use, if a release exists for the platform |
|
|
84
|
+
|
|
85
|
+
There is no musl (Alpine) build of the engine. On Linux with an older glibc, build the engine from source (`cargo install --path helper` in the [engine repo](https://github.com/pypilot-dev/pypilot)) and the wrapper will find it in `~/.cargo/bin`.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 📖 CLI Reference & Commands
|
|
90
|
+
|
|
91
|
+
PyPilot provides a complete suite of environment doctor and bootstrap tools:
|
|
92
|
+
|
|
93
|
+
### 1. `pypilot doctor`
|
|
94
|
+
Analyzes your current workspace, virtual environment, and dependency manifests (`requirements.txt`, `pyproject.toml`, `environment.yml`). Displays a read-only health check without modifying any files.
|
|
95
|
+
```bash
|
|
96
|
+
pypilot doctor
|
|
97
|
+
# Target a specific workspace folder:
|
|
98
|
+
pypilot doctor --path /path/to/project
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 2. `pypilot setup`
|
|
102
|
+
Bootstraps a deterministic virtual environment. Automatically detects existing system tools:
|
|
103
|
+
- Uses system `uv` if present on `$PATH`.
|
|
104
|
+
- Supports **pip-compatible mode** (`uv venv` + `uv pip`) to accelerate installations without forcing a `pyproject.toml` migration.
|
|
105
|
+
- Falls back cleanly to standard `python -m venv` + `pip` if `uv` is not installed.
|
|
106
|
+
```bash
|
|
107
|
+
pypilot setup
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3. `pypilot check <package>`
|
|
111
|
+
Verifies whether a specific package and its wheels support your project's current Python interpreter version and operating system.
|
|
112
|
+
```bash
|
|
113
|
+
pypilot check mediapipe
|
|
114
|
+
pypilot check torch
|
|
115
|
+
pypilot check tensorflow
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 4. `pypilot install <package>`
|
|
119
|
+
Installs a package into your virtual environment and records it in your manifest (`requirements.txt` or `pyproject.toml`), preserving version constraints.
|
|
120
|
+
```bash
|
|
121
|
+
pypilot install requests
|
|
122
|
+
pypilot install numpy
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 5. `pypilot fix python`
|
|
126
|
+
Recomputes dependency version intersection and rebuilds the virtual environment on a Python version supported by all dependencies.
|
|
127
|
+
```bash
|
|
128
|
+
pypilot fix python
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 6. `pypilot fix cuda`
|
|
132
|
+
Scans system NVIDIA driver version and CUDA runtime, then re-pins PyTorch or TensorFlow wheels to the exact hardware-matched CUDA build.
|
|
133
|
+
```bash
|
|
134
|
+
pypilot fix cuda
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 7. `pypilot update-data`
|
|
138
|
+
Forces an immediate update of bundled hardware driver, CUDA compatibility matrices, and package wheel metadata.
|
|
139
|
+
```bash
|
|
140
|
+
pypilot update-data
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 8. `pypilot migrate-conda`
|
|
144
|
+
Translates legacy Anaconda / Miniconda `environment.yml` configuration files into a standard modern `pyproject.toml`. With `--to pixi`, previews a `pixi.toml` instead (`--write` writes it; see [pixi support](#-pixi-support)).
|
|
145
|
+
```bash
|
|
146
|
+
pypilot migrate-conda
|
|
147
|
+
pypilot migrate-conda --to pixi --write
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 9. `pypilot lsp`
|
|
151
|
+
Runs PyPilot as a Language Server Protocol (LSP) server over `stdio`. Used natively by editor extensions ([Zed](https://zed.dev) and [VS Code](https://marketplace.visualstudio.com/items?itemName=AbdullahMasood-005.pypilot-vscode)) for live import diagnostics and automated environment actions.
|
|
152
|
+
```bash
|
|
153
|
+
pypilot lsp
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 10. `pypilot --version`
|
|
157
|
+
Prints the engine's version (`pypilot X.Y.Z`) on stdout, which is what editor extensions read, and the wrapper's own line on stderr: `pypilot-cli X.Y.Z (engine: <where>, <path>)`. `<where>` is `bundled`, `cache`, `download`, `cargo`, `path` or `override`. It also warns when the engine in use is older than the one this release of `pypilot-cli` pins, or comes from `~/.cargo/bin` / `PATH` with a different version.
|
|
158
|
+
|
|
159
|
+
### 11. `pypilot completions <shell>`
|
|
160
|
+
Prints a shell completion script (generated by the engine), e.g. `pypilot completions bash > ~/.local/share/bash-completion/completions/pypilot`. Every argument except a lone `--version` / `-V` goes to the engine unchanged.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 🐍 Python Programmatic API
|
|
165
|
+
|
|
166
|
+
PyPilot can also be imported and used directly inside Python code:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
import pypilot
|
|
170
|
+
|
|
171
|
+
# Run any PyPilot command programmatically
|
|
172
|
+
result = pypilot.run(["doctor"], capture_output=True)
|
|
173
|
+
print(result.returncode, result.stdout)
|
|
174
|
+
|
|
175
|
+
# Commands with --json print {"pypilot": ..., "command": ..., "ok": ..., ...}
|
|
176
|
+
report = pypilot.run(["doctor", "--json"], capture_output=True).json()
|
|
177
|
+
|
|
178
|
+
# Raise subprocess.CalledProcessError on a non-zero exit
|
|
179
|
+
pypilot.run(["check", "torch"], check=True)
|
|
180
|
+
|
|
181
|
+
# Locate or ensure native engine is available
|
|
182
|
+
bin_path = pypilot.ensure_binary()
|
|
183
|
+
info = pypilot.locate_engine() # EngineInfo(path, source, version)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
From async code, `await pypilot.arun([...])` takes the same arguments and does not block the event loop.
|
|
187
|
+
|
|
188
|
+
- `run(args=None, capture_output=False, check=False, *, cwd=None, env=None, input=None, timeout=None)` returns a `RunResult`, a subclass of `subprocess.CompletedProcess`, so `.returncode`, `.stdout`, `.stderr` and `.check_returncode()` work as before. It adds `.ok` and `.json()`. Output is decoded as UTF-8, which is what the engine writes.
|
|
189
|
+
- Without `check=True` a failing command does not raise. Look at `.returncode`.
|
|
190
|
+
- Engine problems raise `pypilot.EngineError` subclasses: `EngineNotFoundError` (offline and no engine), `EngineDownloadError`, `EngineVerificationError`.
|
|
191
|
+
- The package ships `py.typed`, so type checkers see these signatures.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 📦 pixi support
|
|
196
|
+
|
|
197
|
+
[pixi](https://pixi.sh) installs packages from conda-forge and PyPI into a per-project environment, with a lock file. It helps where pip and uv stop:
|
|
198
|
+
|
|
199
|
+
- **System libraries** (GDAL, PROJ, GEOS, libGL...): pip and uv cannot install them; conda-forge ships them next to the Python bindings.
|
|
200
|
+
- **No wheel for your platform or Python**: conda-forge often has a prebuilt build, so no compiler is needed.
|
|
201
|
+
- **The CUDA toolkit**: pip wheels carry only the CUDA runtime, not `nvcc`; conda-forge provides it per project.
|
|
202
|
+
- **One manifest** for Python together with R, C++ or Rust, **one lock file** (`pixi.lock`) covering native dependencies on every listed OS, and **several environments** (for example `default` and `cuda`) in one project.
|
|
203
|
+
|
|
204
|
+
**pixi projects.** A folder with a `pixi.toml`, or `[tool.pixi.workspace]` in `pyproject.toml`, is managed through pixi whatever `package_manager` says. PyPilot uses the environment in `.pixi/envs/<name>` (`default`, or `pixi_environment` / `--pixi-env <name>`), runs `pixi install` for setup and `pixi add --pypi` for installs, explains pixi's install errors, and never creates a `.venv`, runs uv or writes `pixi.lock`. `pypilot doctor` lists every environment and reports environments on different Pythons, a stale `pixi.lock` (a read-only check) and PyPI dependencies with no wheel for one of the manifest's platforms.
|
|
205
|
+
|
|
206
|
+
**When PyPilot suggests pixi.** In a pip or uv project, PyPilot recognises problems pip and uv cannot solve (a dependency with no wheel whose build needs native libraries, a failed build missing a header such as `gdal.h`, CUDA sources without `nvcc`, a repository mixing Python with R, Rust or C++) and suggests pixi. It never converts anything on its own. With `numpy`, `requests` and `gdal` in `requirements.txt` on Windows:
|
|
207
|
+
|
|
208
|
+
```text
|
|
209
|
+
$ pypilot doctor
|
|
210
|
+
...
|
|
211
|
+
[WARN ] GDAL 3.13.3 needs native libraries pip cannot install
|
|
212
|
+
GDAL 3.13.3 has no wheel for Windows x64, so pip and uv build it from source. [...] pixi installs gdal 3.13.3 from conda-forge with its native libraries (libgdal, proj, geos), built for win-64 and Python 3.15. Run `pypilot migrate-to-pixi` to set the project up with pixi.
|
|
213
|
+
|
|
214
|
+
$ pypilot migrate-to-pixi
|
|
215
|
+
Dry run: nothing was written.
|
|
216
|
+
...
|
|
217
|
+
+[dependencies]
|
|
218
|
+
+python = "3.15.*"
|
|
219
|
+
+numpy = "*"
|
|
220
|
+
+requests = "*"
|
|
221
|
+
+gdal = "*"
|
|
222
|
+
|
|
223
|
+
Would write ...\geo\pixi.toml: python 3.15.*, 3 conda-forge and 0 PyPI dependencies.
|
|
224
|
+
|
|
225
|
+
Next: pypilot migrate-to-pixi --write
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Moving to pixi.** `pypilot migrate-to-pixi` previews a `pixi.toml`; `--write` writes it and `--write --install` also runs `pixi install`. `pypilot migrate-conda --to pixi` does the same from an `environment.yml`. A separate `pixi.toml` is written; `pyproject.toml`, `requirements.txt` and `environment.yml` are never edited, so pip and CI keep working. `pypilot install-pixi` installs pixi with its official installer, and `package_manager = "pixi"` makes `setup` write the `pixi.toml` itself.
|
|
229
|
+
|
|
230
|
+
Guides: [pixi and PyPilot](https://pypilot-dev.github.io/pypilot/pixi/), [the advisory](https://pypilot-dev.github.io/pypilot/pixi/advisory), [migrating to pixi](https://pypilot-dev.github.io/pypilot/pixi/migrate).
|
|
231
|
+
|
|
232
|
+
> Engine 1.2.2, the one `pypilot-cli` 1.2.2 runs, already detects pixi projects and works through `pixi install` and `pixi add --pypi`. The environment choice, doctor's pixi checks, the advisory, `migrate-to-pixi`, `migrate-conda --to pixi`, `install-pixi` and `package_manager = "pixi"` need a newer engine: coming in the next release.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## ⚙️ Configuration
|
|
237
|
+
|
|
238
|
+
PyPilot respects workspace settings in `.pypilot.toml` or your editor configuration:
|
|
239
|
+
- `package_manager`: `"auto"` (default), `"uv"`, `"uv-pip"`, `"pip"`, or `"pixi"` (manage with pixi; a project without a pixi manifest gets a `pixi.toml` from setup). pixi projects are detected whatever this says.
|
|
240
|
+
- `notifications`: `"all"`, `"problems-only"`, or `"off"`.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 🔒 The native engine: lookup, verification, offline and proxies
|
|
245
|
+
|
|
246
|
+
**Where the engine comes from.** The first match wins:
|
|
247
|
+
|
|
248
|
+
1. `PYPILOT_ENGINE_VERSION=vX.Y.Z`, if set: that engine release, from the cache or downloaded (for testing other engines).
|
|
249
|
+
2. The engine bundled in a platform wheel (`site-packages/pypilot/_engine/`).
|
|
250
|
+
3. An earlier verified download of the pinned release, in the cache: `%LOCALAPPDATA%\pypilot\bin\<tag>\` on Windows, `$XDG_CACHE_HOME/pypilot/bin/<tag>/` (default `~/.cache/...`) elsewhere.
|
|
251
|
+
4. `~/.cargo/bin/pypilot`, a source build, if it is at least 1.0.2.
|
|
252
|
+
5. A `pypilot` engine on `PATH`, if it is at least 1.0.2. The wrapper skips its own `pypilot` launcher.
|
|
253
|
+
6. A download of the pinned release, unless offline mode is on.
|
|
254
|
+
|
|
255
|
+
**Verification.** Each `pypilot-cli` release pins one engine release (`DEFAULT_TAG` in `pypilot/binary.py`) and the SHA-256 of each of its archives (`ENGINE_SHA256`). A download is checked before it is extracted or run. On a mismatch the file is deleted and the command fails with `SHA-256 mismatch`. With `PYPILOT_ENGINE_VERSION`, the archive is checked against that release's `SHA256SUMS` file instead. A release without one is refused unless you also set `PYPILOT_ALLOW_UNVERIFIED=1`, which prints a warning. The bundled wheels contain the same verified binaries.
|
|
256
|
+
|
|
257
|
+
**Offline.** `PYPILOT_OFFLINE=1` forbids every download. If no engine is available locally, PyPilot fails at once and tells you so, without waiting on the network. With a platform wheel, offline mode just works.
|
|
258
|
+
|
|
259
|
+
**Proxies.** Downloads use the standard proxy settings: `HTTPS_PROXY` / `HTTP_PROXY` and `NO_PROXY` (either case), or, when none is set, the system settings (Windows Internet Options, macOS network settings). A failed download says which proxy it went through. `PYPILOT_DOWNLOAD_TIMEOUT` sets the network timeout in seconds (default 60).
|
|
260
|
+
|
|
261
|
+
| Variable | Effect |
|
|
262
|
+
|---|---|
|
|
263
|
+
| `PYPILOT_OFFLINE=1` | Never download; fail fast if no engine is available |
|
|
264
|
+
| `PYPILOT_ENGINE_VERSION=vX.Y.Z` | Use this engine release instead of the pinned one |
|
|
265
|
+
| `PYPILOT_ALLOW_UNVERIFIED=1` | Allow a `PYPILOT_ENGINE_VERSION` release that has no `SHA256SUMS` |
|
|
266
|
+
| `PYPILOT_DOWNLOAD_TIMEOUT=<seconds>` | Network timeout for downloads (default 60) |
|
|
267
|
+
| `HTTPS_PROXY`, `NO_PROXY` | Proxy for downloads, and hosts that bypass it |
|
|
268
|
+
|
|
269
|
+
Each GitHub release of `pypilot-cli` also carries a CycloneDX SBOM (`pypilot-cli.cdx.json`) that lists the bundled engine archives with their hashes.
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 💙 Support the project
|
|
274
|
+
|
|
275
|
+
PyPilot is free and open source, built and maintained in spare time. If it helps you:
|
|
276
|
+
|
|
277
|
+
- ⭐ [Star it on GitHub](https://github.com/pypilot-dev/pypilot): it's the easiest way to show support.
|
|
278
|
+
- 🐛 [Report a bug or request a feature](https://github.com/pypilot-dev/pypilot/issues): reproducible environment problems are especially welcome.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 📄 License
|
|
283
|
+
|
|
284
|
+
PyPilot is licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0-or-later)**. See the [LICENSE](https://github.com/pypilot-dev/pypilot-pip/blob/master/LICENSE) file for the full license text.
|