pyfig 0.6.3 → 0.7.0
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.
- package/README.md +46 -33
- package/SECURITY.md +1 -1
- package/dist/cjs/index.js +396 -256
- package/dist/cjs/index.js.map +10 -9
- package/dist/cjs/sync-resolver.js +356 -231
- package/dist/cjs/sync-resolver.js.map +9 -8
- package/dist/cli.js +12 -3
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +6 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +31 -21
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +9 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +48 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/package-target.d.ts +3 -3
- package/dist/package-target.d.ts.map +1 -1
- package/dist/package-target.js +6 -6
- package/dist/package-target.js.map +1 -1
- package/dist/provision.d.ts +6 -12
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +141 -153
- package/dist/provision.js.map +1 -1
- package/dist/python-venv.d.ts +12 -0
- package/dist/python-venv.d.ts.map +1 -0
- package/dist/{virtual-environment.js → python-venv.js} +12 -9
- package/dist/python-venv.js.map +1 -0
- package/dist/runners.js +12 -12
- package/dist/runners.js.map +1 -1
- package/dist/sync-resolver.js +2 -2
- package/dist/sync-resolver.js.map +1 -1
- package/dist/venv-identity.d.ts +36 -0
- package/dist/venv-identity.d.ts.map +1 -0
- package/dist/venv-identity.js +80 -0
- package/dist/venv-identity.js.map +1 -0
- package/package.json +2 -2
- package/dist/virtual-environment.d.ts +0 -11
- package/dist/virtual-environment.d.ts.map +0 -1
- package/dist/virtual-environment.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# pyfig
|
|
2
2
|
|
|
3
|
-
`pyfig` prepares uv and
|
|
3
|
+
`pyfig` prepares uv and compatible Python venvs from Bun or Node.js. It prefers a valid uv already on the system and searches system Python with downloads disabled before considering a managed Python download.
|
|
4
4
|
|
|
5
|
-
Pyfig never invokes standalone `pip`,
|
|
5
|
+
Pyfig never invokes standalone `pip`, discovers Python project metadata, edits caller-owned requirements files, or creates a project-root `.venv`. Dependency-free callers can reuse a compatible active or project-root venv. A caller that passes dependencies or requirements files gets a content-addressed private venv under `<project-root>/node_modules/.pyfig/venvs/`, so independent libraries cannot replace or downgrade each other's environments.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -13,31 +13,31 @@ bun add pyfig
|
|
|
13
13
|
## Use
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import {
|
|
16
|
+
import { Python } from 'pyfig';
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const pyenv = new Python({
|
|
19
|
+
dependencies: ['requests>=2.32'],
|
|
20
|
+
requirements: ['requirements/runtime.txt'],
|
|
19
21
|
requiresPython: '>=3.11,<4',
|
|
20
22
|
requiresUv: '>=0.10,<1',
|
|
21
23
|
requireEmbedding: true,
|
|
22
24
|
requireGil: true,
|
|
23
25
|
});
|
|
24
26
|
|
|
25
|
-
const environment = await
|
|
26
|
-
['requests>=2.32'],
|
|
27
|
-
{ extras: ['database'] },
|
|
28
|
-
);
|
|
27
|
+
const environment = await pyenv.prepare();
|
|
29
28
|
|
|
30
29
|
console.log(environment.uv);
|
|
31
30
|
console.log(environment.python);
|
|
32
31
|
console.log(environment.managed);
|
|
32
|
+
console.log(environment.venvId);
|
|
33
33
|
|
|
34
|
-
await
|
|
34
|
+
await pyenv.uv(
|
|
35
35
|
['run', '--', 'python', 'script.py'],
|
|
36
36
|
{ stdio: 'inherit' },
|
|
37
37
|
);
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
`
|
|
40
|
+
`dependencies` accepts the requirement syntax uv supports, including PEP 508 specifiers, Git references, URLs, and local file references. `requirements` accepts explicit requirements-file paths, with relative paths resolved from `projectRoot`. Pyfig validates each value as one line and otherwise passes it to uv without interpreting package or source syntax. It does not discover or read `pyproject.toml`, Python lockfiles, or dependency groups. Configuration is bound by the `Python` constructor, so `prepare()`, `uv()`, and `uvSync()` always target the same venv. Temporary resolution inputs are created outside the repository and removed afterward.
|
|
41
41
|
|
|
42
42
|
The same uv-only surface handles direct commands:
|
|
43
43
|
|
|
@@ -62,12 +62,13 @@ Pyfig uses this order:
|
|
|
62
62
|
|
|
63
63
|
1. A compatible configured or `PATH` uv.
|
|
64
64
|
2. Pyfig's cached, checksum-verified uv.
|
|
65
|
-
3.
|
|
66
|
-
4.
|
|
65
|
+
3. For callers without dependencies or requirements files, a compatible explicitly configured venv, active `VIRTUAL_ENV`, or root `.venv`.
|
|
66
|
+
4. A compatible base interpreter from those venvs, then every installed system Python reported by uv with downloads disabled.
|
|
67
67
|
5. An already-cached uv-managed Python that passes the same checks.
|
|
68
68
|
6. A managed Python download, only when installation policy allows it.
|
|
69
|
+
7. An existing hashed venv for the exact interpreter and resolved dependencies, or a new venv below `node_modules/.pyfig/venvs`.
|
|
69
70
|
|
|
70
|
-
An explicit `python` option is strict: an unavailable or incompatible interpreter is an error. Incompatible external venvs are preserved
|
|
71
|
+
An explicit `python` option is strict: an unavailable or incompatible interpreter is an error. Without runtime requirements, an explicitly configured compatible venv can be reused. With dependencies or requirements files, its base interpreter is used for a private venv. Incompatible external venvs are always preserved. Only an incomplete or damaged Pyfig-managed venv may be rebuilt.
|
|
71
72
|
|
|
72
73
|

|
|
73
74
|
|
|
@@ -78,29 +79,38 @@ Native consumers can set `requireEmbedding: true` to require CPython, `Python.h`
|
|
|
78
79
|
## Runtime dependency resolution
|
|
79
80
|
|
|
80
81
|
```ts
|
|
81
|
-
|
|
82
|
-
['orjson>=3.10', 'httpx[http2]'],
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
);
|
|
82
|
+
const pyenv = new Python({
|
|
83
|
+
dependencies: ['orjson>=3.10', 'httpx[http2]'],
|
|
84
|
+
requirements: ['requirements/runtime.txt'],
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await pyenv.prepare();
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
Resolution follows the equivalent of:
|
|
91
91
|
|
|
92
92
|
```sh
|
|
93
|
-
uv pip compile
|
|
94
|
-
|
|
95
|
-
--python /selected/
|
|
93
|
+
uv pip compile /project/requirements/runtime.txt \
|
|
94
|
+
/temporary/runtime-dependencies.txt \
|
|
95
|
+
--python /selected/base/python \
|
|
96
|
+
--no-header --no-annotate --generate-hashes \
|
|
96
97
|
--output-file /temporary/resolved-dependencies.txt
|
|
97
98
|
|
|
99
|
+
uv venv --python /selected/base/python \
|
|
100
|
+
node_modules/.pyfig/venvs/cpython-3.12.7-0123456789abcdef0123
|
|
101
|
+
|
|
98
102
|
uv pip install \
|
|
99
|
-
--python /
|
|
103
|
+
--python /hashed/venv/python \
|
|
100
104
|
-r /temporary/resolved-dependencies.txt
|
|
101
105
|
```
|
|
102
106
|
|
|
103
|
-
|
|
107
|
+
The venv identity includes the exact base interpreter, platform, architecture, GIL/ABI properties, and SHA-256 of uv's complete compiled resolution. This includes every artifact hash emitted by `uv pip compile --generate-hashes`. uv also resolves Git references to commit hashes. Pyfig does not duplicate uv's dependency parser or invent hashes for source types uv cannot hash. Equivalent resolutions can share one venv; a changed artifact hash, Git commit, or other resolved output creates another. The metadata file inside each venv is written last and acts as its publication marker.
|
|
108
|
+
|
|
109
|
+
Only the explicit `dependencies` values and `requirements` files participate in resolution. Known Python project metadata and lockfile paths are rejected as requirements inputs. Pyfig does not use `uv add` or `uv pip sync`, so it neither edits project metadata nor removes packages from an externally owned venv.
|
|
110
|
+
|
|
111
|
+
Raw `pyenv.uv(['pip', ...])` remains an intentional low-level escape hatch. It can mutate the selected venv after publication and bypass the content-addressing guarantee. Use constructor-level `dependencies` or `requirements` when isolation and repeatability matter.
|
|
112
|
+
|
|
113
|
+
Separate venvs work for subprocesses and isolated workers. Native libraries that initialize CPython in the same JavaScript process must use one combined compatible dependency set or move each interpreter into a separate worker process; two venv directories cannot provide two independent process-global CPython runtimes.
|
|
104
114
|
|
|
105
115
|

|
|
106
116
|
|
|
@@ -108,7 +118,7 @@ When no `pyproject.toml` exists, only the temporary dependency input is compiled
|
|
|
108
118
|
|
|
109
119
|
## Project root
|
|
110
120
|
|
|
111
|
-
Pyfig does not interpret `package.json`, workspace metadata, `pyproject.toml`, or lockfiles
|
|
121
|
+
Pyfig does not interpret `package.json`, workspace metadata, `pyproject.toml`, or lockfiles. The root only locates private venv storage and resolves relative requirements-file paths. Root precedence is:
|
|
112
122
|
|
|
113
123
|
1. `projectRoot`
|
|
114
124
|
2. `PYFIG_PROJECT_ROOT`
|
|
@@ -121,12 +131,12 @@ Set `projectRoot` explicitly in reusable libraries and unusual workspace layouts
|
|
|
121
131
|
|
|
122
132
|
| Export | Responsibility |
|
|
123
133
|
| --- | --- |
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
134
|
+
| `new Python(options)` | Bind one immutable venv configuration and memoize its preparation. |
|
|
135
|
+
| `pyenv.prepare()` | Resolve and prepare that configuration's exact venv. |
|
|
136
|
+
| `pyenv.pythonInfo()` | Return the selected interpreter and embedding metadata. |
|
|
137
|
+
| `pyenv.uvInfo()` | Return the selected uv executable and version. |
|
|
138
|
+
| `pyenv.uv()` / `pyenv.uvSync()` | Spawn uv and pin pip/run commands to the same venv. |
|
|
139
|
+
| `ensurePython(options?)` | Standalone Python preparation API using the same options. |
|
|
130
140
|
| `ensureUv(options?)` | Prefer existing uv, otherwise bootstrap verified uv when allowed. |
|
|
131
141
|
| `uvSpawn()` / `uvSpawnSync()` | Standalone uv spawn API. |
|
|
132
142
|
| `resolveProjectRoot(start?)` | Resolve the nearest Git root without reading manifests. |
|
|
@@ -143,6 +153,8 @@ When embedding files are available, `PythonInfo.embedding.stableAbiLibraryPath`
|
|
|
143
153
|
|
|
144
154
|
| API option | Environment variable | Default |
|
|
145
155
|
| --- | --- | --- |
|
|
156
|
+
| `dependencies` | — | `[]` |
|
|
157
|
+
| `requirements` | — | `[]` |
|
|
146
158
|
| `python` | `PYFIG_PYTHON` | uv discovery |
|
|
147
159
|
| `requiresPython` | `PYFIG_REQUIRES_PYTHON` | `>=3.10,<4` |
|
|
148
160
|
| `managedPython` | `PYFIG_MANAGED_PYTHON` | `3.12` |
|
|
@@ -169,6 +181,7 @@ bunx --bun pyfig
|
|
|
169
181
|
bunx --bun pyfig --check
|
|
170
182
|
bunx --bun pyfig --requires-python '>=3.12,<3.14'
|
|
171
183
|
bunx --bun pyfig --requires-uv '>=0.12,<1'
|
|
184
|
+
bunx --bun pyfig --dependency 'requests>=2.32' --requirement requirements/runtime.txt
|
|
172
185
|
bunx --bun pyfig --require-embedding --require-gil
|
|
173
186
|
bunx --bun pyfig --project-root /path/to/repository
|
|
174
187
|
bunx --bun pyfig --json
|
|
@@ -180,7 +193,7 @@ bunx --bun pyfig --json
|
|
|
180
193
|
|
|
181
194
|
Pyfig resolves a compatible uv release from Astral's GitHub releases, downloads that exact archive over HTTPS, verifies its adjacent SHA-256 checksum, validates the staged executable version, and atomically publishes it in Pyfig's cache. A compatible cached executable is probed locally without a network request. Release metadata is cached on disk for 24 hours; stale metadata is refreshed under a Loqkit lock and remains available as a fallback when GitHub's API is temporarily unavailable. Set `GITHUB_TOKEN` or `GH_TOKEN` to authenticate release discovery on CI and other rate-limited hosts. Pyfig does not execute installer scripts or modify shell profiles.
|
|
182
195
|
|
|
183
|
-
Provisioning mutations use Loqkit's layered in-memory, worker, native-file-lock-when-available, and portable-file coordination with capability checks before and after acquisition. Compatible managed uv executables are cached by resolved version; Loqkit coordinates both the `requiresUv` policy lookup and exact release publication.
|
|
196
|
+
Provisioning mutations use Loqkit's layered in-memory, worker, native-file-lock-when-available, and portable-file coordination with capability checks before and after acquisition. Compatible managed uv executables are cached by resolved version; Loqkit coordinates both the `requiresUv` policy lookup and exact release publication. Each hashed venv has its own provisioning key. Creation, installation, and validation finish before the venv metadata marker is published. Preparation is memoized within one `pyenv`; separate processes converge through the same resolved identity and Loqkit lock.
|
|
184
197
|
|
|
185
198
|
## Platform support
|
|
186
199
|
|
package/SECURITY.md
CHANGED
|
@@ -4,6 +4,6 @@ Pyfig can download Astral uv release archives and can ask uv to download Python
|
|
|
4
4
|
|
|
5
5
|
Pyfig resolves a uv release allowed by `requiresUv`, then fetches that exact release URL over HTTPS with bounded redirects and timeouts. GitHub release metadata is cached for 24 hours under Loqkit coordination, with validated stale metadata available if refresh fails. Pyfig verifies the adjacent SHA-256 checksum, validates the staged executable's reported version, and atomically publishes it into its cache. It never executes an installer script or modifies shell profiles or the host `PATH`. Proxy variables are honored through a per-request dispatcher without logging proxy credentials.
|
|
6
6
|
|
|
7
|
-
Provisioning uses in-process, worker, optional native advisory, and portable filesystem coordination followed by a post-lock capability check. Runtime dependency mutation uses uv's target-environment lock. Pyfig pins uv commands to the selected venv and removes configuration values that could redirect them. It
|
|
7
|
+
Provisioning uses in-process, worker, optional native advisory, and portable filesystem coordination followed by a post-lock capability check. Runtime dependency mutation uses uv's target-environment lock. Pyfig pins uv commands to the selected venv and removes configuration values that could redirect them. It resolves only caller-provided dependency specifiers and requirements files; it does not discover or read Python project metadata. Caller-owned requirements files are read-only.
|
|
8
8
|
|
|
9
9
|
Executable paths, project roots, version specifiers, package specifications, indexes, and proxy settings remain trusted configuration. Do not let an untrusted user choose `python`, `PYFIG_UV`, `cacheDir`, package arguments, or related environment variables in a privileged process. A checksum fetched from the same release protects transfer integrity, not a compromised upstream publisher.
|