@adhd/apigen-python-env 0.2.5 → 0.2.7

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.
Files changed (4) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/index.js +1 -10
  3. package/index.mjs +205 -186
  4. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## 0.2.6 (2026-09-26)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **vite-plugins:** absorb perf/test-resolve-fix — test-time @adhd/* source resolution ([3e344506](https://github.com/PseudoSky/adhd/commit/3e344506))
6
+
7
+ ### 🩹 Fixes
8
+
9
+ - **nx:** reconcile main's e2e lane with the flat ESLint config + fix missing-deps ([cf72a2ab](https://github.com/PseudoSky/adhd/commit/cf72a2ab))
10
+ - **vite:** restore import.meta.url in CJS output under vite 8 ([7916e639](https://github.com/PseudoSky/adhd/commit/7916e639))
11
+ - **nx:** finish the ESLint v9 flat-config migration and unblock the gate ([53f4ff3e](https://github.com/PseudoSky/adhd/commit/53f4ff3e))
12
+
13
+ ### ❤️ Thank You
14
+
15
+ - pseudosky
16
+
1
17
  ## 0.2.5 (2026-09-24)
2
18
 
3
19
  This was a version bump only for apigen-python-env to align it with other projects, there were no code changes.
package/index.js CHANGED
@@ -1,10 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const D=require("node:fs"),I=require("node:os"),q=require("node:path"),F=require("node:crypto"),h=require("node:child_process");function P(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const n in t)if(n!=="default"){const i=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,i.get?i:{enumerable:!0,get:()=>t[n]})}}return e.default=t,Object.freeze(e)}const r=P(D),b=P(I),o=P(q);function k(t){const e=t??__dirname,n=o.resolve(e,"..","..","..","python");if(r.existsSync(o.join(n,"apigen_python")))return n;const i=o.join(e,"python");if(r.existsSync(o.join(i,"apigen_python")))return i;let a=e;for(let c=0;c<20;c++){const p=o.join(a,"packages","apigen","python");if(r.existsSync(o.join(p,"apigen_python")))return p;const u=o.dirname(a);if(u===a)break;a=u}return n}const H=["python3.13","python3.12","python3.11","python3"],m=[3,11];function J(t){const e=h.spawnSync(t,["-c",'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")'],{encoding:"utf8",timeout:15e3});if(e.status!==0||!e.stdout)return;const[n,i]=e.stdout.trim().split(".").map(Number);if(!(!Number.isFinite(n)||!Number.isFinite(i)))return[n,i]}function M(){for(const t of H){const e=J(t);if(e&&(e[0]>m[0]||e[0]===m[0]&&e[1]>=m[1]))return t}throw new Error(`apigen-python-env: no Python >= ${m.join(".")} found on PATH (tried: ${H.join(", ")}). Install Python ${m.join(".")}+ or set APIGEN_PYTHON to a provisioned interpreter.`)}function Y(t){return process.platform==="win32"?o.join(t,"Scripts","python.exe"):o.join(t,"bin","python3")}function G(t){const e=r.readFileSync(o.join(t,"pyproject.toml"));return F.createHash("sha256").update(e).digest("hex")}function O(t){try{const e=JSON.parse(r.readFileSync(t,"utf8"));if(typeof e.pyprojectHash=="string"&&Array.isArray(e.extras))return e}catch{}}function B(t,e,n){const i=Date.now()+e;for(;;)try{r.mkdirSync(t,{recursive:!1});break}catch{if(Date.now()>i){try{r.rmdirSync(t)}catch{}continue}h.spawnSync(process.execPath,["-e","setTimeout(()=>{}, 250)"],{timeout:5e3})}try{return n()}finally{try{r.rmdirSync(t)}catch{}}}function V(t={}){const e=k(),n=process.env.APIGEN_PYTHON;if(n){if(!r.existsSync(n))throw new Error(`apigen-python-env: APIGEN_PYTHON points to a missing file: ${n}`);return{python:n,venvDir:"",pythonPkgDir:e}}const i=[...new Set(t.extras??[])].sort(),a=t.envHome??process.env.APIGEN_PYENV_HOME??o.join(b.homedir(),".adhd","apigen"),c=o.join(a,"pyvenv"),p=o.join(c,".apigen-stamp"),u=G(e),y=Y(c),l=()=>{if(!r.existsSync(y))return!1;const s=O(p);return!s||s.pyprojectHash!==u?!1:i.every(d=>s.extras.includes(d))};if(l())return{python:y,venvDir:c,pythonPkgDir:e};r.mkdirSync(a,{recursive:!0});const v=o.join(a,"pyvenv.lock"),w=t.lockTimeoutMs??3e5;return B(v,w,()=>{if(l())return{python:y,venvDir:c,pythonPkgDir:e};const s=O(p),d=[...new Set([...(s==null?void 0:s.extras)??[],...i])].sort();r.rmSync(c,{recursive:!0,force:!0});const _=M(),j=h.spawnSync(_,["-m","venv",c],{encoding:"utf8",timeout:12e4});if(j.status!==0)throw new Error(`apigen-python-env: "${_} -m venv" failed (exit ${j.status}):
2
- ${j.stderr}`);const x=o.join(e,"build");r.existsSync(x)&&r.rmSync(x,{recursive:!0,force:!0});for(const f of r.readdirSync(e))f.endsWith(".egg-info")&&r.rmSync(o.join(e,f),{recursive:!0,force:!0});const S=r.mkdtempSync(o.join(b.tmpdir(),"apigen-python-wheel-"));try{const f=h.spawnSync(y,["-m","pip","wheel","--no-deps","--wheel-dir",S,e],{encoding:"utf8",timeout:6e5});if(f.status!==0)throw new Error(`apigen-python-env: pip wheel failed (exit ${f.status}):
3
- ${f.stderr}
4
- stdout:
5
- ${f.stdout}`);const E=r.readdirSync(S).filter(A=>A.endsWith(".whl"));if(E.length===0)throw new Error("apigen-python-env: pip wheel produced no .whl file");const $=o.join(S,E[0]),N=d.length?`${$}[${d.join(",")}]`:$,g=h.spawnSync(y,["-m","pip","install","--quiet","--disable-pip-version-check",N],{encoding:"utf8",timeout:6e5});if(g.status!==0)throw new Error(`apigen-python-env: pip install "${N}" failed (exit ${g.status}):
6
- ${g.stderr}
7
- stdout:
8
- ${g.stdout}`)}finally{r.rmSync(S,{recursive:!0,force:!0})}const T={pyprojectHash:u,extras:d};return r.writeFileSync(p,JSON.stringify(T)),{python:y,venvDir:c,pythonPkgDir:e}})}function L(t,e,n,i,a){return new Promise((c,p)=>{var v,w;const u=h.spawn(t,["-m","apigen_python.extractor",n,"--namespace",i,"--emit-json"],{cwd:e,env:{...process.env,PYTHONPATH:e},stdio:["ignore","pipe","pipe"]});let y="",l="";(v=u.stdout)==null||v.on("data",s=>{y+=s.toString("utf8")}),(w=u.stderr)==null||w.on("data",s=>{l+=s.toString("utf8")}),u.on("error",p),u.on("exit",s=>{if(s!==0){p(new Error(`${a}: extractor --emit-json exited with code ${s}:
9
- ${l}`));return}try{c(JSON.parse(y))}catch(d){p(new Error(`${a}: extractor --emit-json produced invalid JSON (${d.message}):
10
- ${y}`))}})})}exports.ensurePythonEnv=V;exports.resolvePythonPkgDir=k;exports.runExtractorEmitJson=L;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));let c=require("node:fs");c=s(c);let l=require("node:os");l=s(l);let u=require("node:path");u=s(u);let d=require("node:crypto"),f=require("node:child_process");function p(e){let t=e??__dirname,n=u.resolve(t,`..`,`..`,`..`,`python`);if(c.existsSync(u.join(n,`apigen_python`)))return n;let r=u.join(t,`python`);if(c.existsSync(u.join(r,`apigen_python`)))return r;let i=t;for(let e=0;e<20;e++){let e=u.join(i,`packages`,`apigen`,`python`);if(c.existsSync(u.join(e,`apigen_python`)))return e;let t=u.dirname(i);if(t===i)break;i=t}return n}var m=[`python3.13`,`python3.12`,`python3.11`,`python3`],h=[3,11];function g(e){let t=(0,f.spawnSync)(e,[`-c`,`import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")`],{encoding:`utf8`,timeout:15e3});if(t.status!==0||!t.stdout)return;let[n,r]=t.stdout.trim().split(`.`).map(Number);if(Number.isFinite(n)&&Number.isFinite(r))return[n,r]}function _(){for(let e of m){let t=g(e);if(t&&(t[0]>h[0]||t[0]===h[0]&&t[1]>=h[1]))return e}throw Error(`apigen-python-env: no Python >= ${h.join(`.`)} found on PATH (tried: ${m.join(`, `)}). Install Python ${h.join(`.`)}+ or set APIGEN_PYTHON to a provisioned interpreter.`)}function v(e){return process.platform===`win32`?u.join(e,`Scripts`,`python.exe`):u.join(e,`bin`,`python3`)}function y(e){let t=c.readFileSync(u.join(e,`pyproject.toml`));return(0,d.createHash)(`sha256`).update(t).digest(`hex`)}function b(e){try{let t=JSON.parse(c.readFileSync(e,`utf8`));if(typeof t.pyprojectHash==`string`&&Array.isArray(t.extras))return t}catch{}}function x(e,t,n){let r=Date.now()+t;for(;;)try{c.mkdirSync(e,{recursive:!1});break}catch{if(Date.now()>r){try{c.rmdirSync(e)}catch{}continue}(0,f.spawnSync)(process.execPath,[`-e`,`setTimeout(()=>{}, 250)`],{timeout:5e3})}try{return n()}finally{try{c.rmdirSync(e)}catch{}}}function S(e={}){let t=p(),n=process.env.APIGEN_PYTHON;if(n){if(!c.existsSync(n))throw Error(`apigen-python-env: APIGEN_PYTHON points to a missing file: ${n}`);return{python:n,venvDir:``,pythonPkgDir:t}}let r=[...new Set(e.extras??[])].sort(),i=e.envHome??process.env.APIGEN_PYENV_HOME??u.join(l.homedir(),`.adhd`,`apigen`),a=u.join(i,`pyvenv`),o=u.join(a,`.apigen-stamp`),s=y(t),d=v(a),m=()=>{if(!c.existsSync(d))return!1;let e=b(o);return e?.pyprojectHash===s&&r.every(t=>e.extras.includes(t))};return m()?{python:d,venvDir:a,pythonPkgDir:t}:(c.mkdirSync(i,{recursive:!0}),x(u.join(i,`pyvenv.lock`),e.lockTimeoutMs??3e5,()=>{if(m())return{python:d,venvDir:a,pythonPkgDir:t};let e=b(o),n=[...new Set([...e?.extras??[],...r])].sort();c.rmSync(a,{recursive:!0,force:!0});let i=_(),p=(0,f.spawnSync)(i,[`-m`,`venv`,a],{encoding:`utf8`,timeout:12e4});if(p.status!==0)throw Error(`apigen-python-env: "${i} -m venv" failed (exit ${p.status}):\n${p.stderr}`);let h=u.join(t,`build`);c.existsSync(h)&&c.rmSync(h,{recursive:!0,force:!0});for(let e of c.readdirSync(t))e.endsWith(`.egg-info`)&&c.rmSync(u.join(t,e),{recursive:!0,force:!0});let g=c.mkdtempSync(u.join(l.tmpdir(),`apigen-python-wheel-`));try{let e=(0,f.spawnSync)(d,[`-m`,`pip`,`wheel`,`--no-deps`,`--wheel-dir`,g,t],{encoding:`utf8`,timeout:6e5});if(e.status!==0)throw Error(`apigen-python-env: pip wheel failed (exit ${e.status}):\n${e.stderr}\nstdout:\n${e.stdout}`);let r=c.readdirSync(g).filter(e=>e.endsWith(`.whl`));if(r.length===0)throw Error(`apigen-python-env: pip wheel produced no .whl file`);let i=u.join(g,r[0]),a=n.length?`${i}[${n.join(`,`)}]`:i,o=(0,f.spawnSync)(d,[`-m`,`pip`,`install`,`--quiet`,`--disable-pip-version-check`,a],{encoding:`utf8`,timeout:6e5});if(o.status!==0)throw Error(`apigen-python-env: pip install "${a}" failed (exit ${o.status}):\n${o.stderr}\nstdout:\n${o.stdout}`)}finally{c.rmSync(g,{recursive:!0,force:!0})}let v={pyprojectHash:s,extras:n};return c.writeFileSync(o,JSON.stringify(v)),{python:d,venvDir:a,pythonPkgDir:t}}))}function C(e,t,n,r,i){return new Promise((a,o)=>{let s=(0,f.spawn)(e,[`-m`,`apigen_python.extractor`,n,`--namespace`,r,`--emit-json`],{cwd:t,env:{...process.env,PYTHONPATH:t},stdio:[`ignore`,`pipe`,`pipe`]}),c=``,l=``;s.stdout?.on(`data`,e=>{c+=e.toString(`utf8`)}),s.stderr?.on(`data`,e=>{l+=e.toString(`utf8`)}),s.on(`error`,o),s.on(`exit`,e=>{if(e!==0){o(Error(`${i}: extractor --emit-json exited with code ${e}:\n${l}`));return}try{a(JSON.parse(c))}catch(e){o(Error(`${i}: extractor --emit-json produced invalid JSON (${e.message}):\n${c}`))}})})}exports.ensurePythonEnv=S,exports.resolvePythonPkgDir=p,exports.runExtractorEmitJson=C;
package/index.mjs CHANGED
@@ -1,195 +1,214 @@
1
- import * as n from "node:fs";
2
- import * as H from "node:os";
3
- import * as r from "node:path";
4
- import { createHash as T } from "node:crypto";
5
- import { spawnSync as l, spawn as I } from "node:child_process";
6
- function O(e) {
7
- const t = e ?? __dirname, o = r.resolve(t, "..", "..", "..", "python");
8
- if (n.existsSync(r.join(o, "apigen_python")))
9
- return o;
10
- const s = r.join(t, "python");
11
- if (n.existsSync(r.join(s, "apigen_python")))
12
- return s;
13
- let a = t;
14
- for (let c = 0; c < 20; c++) {
15
- const p = r.join(a, "packages", "apigen", "python");
16
- if (n.existsSync(r.join(p, "apigen_python")))
17
- return p;
18
- const u = r.dirname(a);
19
- if (u === a)
20
- break;
21
- a = u;
22
- }
23
- return o;
1
+ import * as e from "node:fs";
2
+ import * as t from "node:os";
3
+ import * as n from "node:path";
4
+ import { createHash as r } from "node:crypto";
5
+ import { spawn as i, spawnSync as a } from "node:child_process";
6
+ //#region src/lib/python-env.ts
7
+ function o(t) {
8
+ let r = t ?? __dirname, i = n.resolve(r, "..", "..", "..", "python");
9
+ if (e.existsSync(n.join(i, "apigen_python"))) return i;
10
+ let a = n.join(r, "python");
11
+ if (e.existsSync(n.join(a, "apigen_python"))) return a;
12
+ let o = r;
13
+ for (let t = 0; t < 20; t++) {
14
+ let t = n.join(o, "packages", "apigen", "python");
15
+ if (e.existsSync(n.join(t, "apigen_python"))) return t;
16
+ let r = n.dirname(o);
17
+ if (r === o) break;
18
+ o = r;
19
+ }
20
+ return i;
24
21
  }
25
- const _ = ["python3.13", "python3.12", "python3.11", "python3"], m = [3, 11];
26
- function D(e) {
27
- const t = l(e, ["-c", 'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")'], {
28
- encoding: "utf8",
29
- timeout: 15e3
30
- });
31
- if (t.status !== 0 || !t.stdout)
32
- return;
33
- const [o, s] = t.stdout.trim().split(".").map(Number);
34
- if (!(!Number.isFinite(o) || !Number.isFinite(s)))
35
- return [o, s];
22
+ var s = [
23
+ "python3.13",
24
+ "python3.12",
25
+ "python3.11",
26
+ "python3"
27
+ ], c = [3, 11];
28
+ function l(e) {
29
+ let t = a(e, ["-c", "import sys; print(f\"{sys.version_info[0]}.{sys.version_info[1]}\")"], {
30
+ encoding: "utf8",
31
+ timeout: 15e3
32
+ });
33
+ if (t.status !== 0 || !t.stdout) return;
34
+ let [n, r] = t.stdout.trim().split(".").map(Number);
35
+ if (Number.isFinite(n) && Number.isFinite(r)) return [n, r];
36
36
  }
37
- function F() {
38
- for (const e of _) {
39
- const t = D(e);
40
- if (t && (t[0] > m[0] || t[0] === m[0] && t[1] >= m[1]))
41
- return e;
42
- }
43
- throw new Error(
44
- `apigen-python-env: no Python >= ${m.join(".")} found on PATH (tried: ${_.join(", ")}). Install Python ${m.join(".")}+ or set APIGEN_PYTHON to a provisioned interpreter.`
45
- );
37
+ function u() {
38
+ for (let e of s) {
39
+ let t = l(e);
40
+ if (t && (t[0] > c[0] || t[0] === c[0] && t[1] >= c[1])) return e;
41
+ }
42
+ throw Error(`apigen-python-env: no Python >= ${c.join(".")} found on PATH (tried: ${s.join(", ")}). Install Python ${c.join(".")}+ or set APIGEN_PYTHON to a provisioned interpreter.`);
46
43
  }
47
- function Y(e) {
48
- return process.platform === "win32" ? r.join(e, "Scripts", "python.exe") : r.join(e, "bin", "python3");
44
+ function d(e) {
45
+ return process.platform === "win32" ? n.join(e, "Scripts", "python.exe") : n.join(e, "bin", "python3");
49
46
  }
50
- function J(e) {
51
- const t = n.readFileSync(r.join(e, "pyproject.toml"));
52
- return T("sha256").update(t).digest("hex");
47
+ function f(t) {
48
+ let i = e.readFileSync(n.join(t, "pyproject.toml"));
49
+ return r("sha256").update(i).digest("hex");
53
50
  }
54
- function k(e) {
55
- try {
56
- const t = JSON.parse(n.readFileSync(e, "utf8"));
57
- if (typeof t.pyprojectHash == "string" && Array.isArray(t.extras))
58
- return t;
59
- } catch {
60
- }
51
+ function p(t) {
52
+ try {
53
+ let n = JSON.parse(e.readFileSync(t, "utf8"));
54
+ if (typeof n.pyprojectHash == "string" && Array.isArray(n.extras)) return n;
55
+ } catch {}
61
56
  }
62
- function G(e, t, o) {
63
- const s = Date.now() + t;
64
- for (; ; )
65
- try {
66
- n.mkdirSync(e, { recursive: !1 });
67
- break;
68
- } catch {
69
- if (Date.now() > s) {
70
- try {
71
- n.rmdirSync(e);
72
- } catch {
73
- }
74
- continue;
75
- }
76
- l(process.execPath, ["-e", "setTimeout(()=>{}, 250)"], { timeout: 5e3 });
77
- }
78
- try {
79
- return o();
80
- } finally {
81
- try {
82
- n.rmdirSync(e);
83
- } catch {
84
- }
85
- }
57
+ function m(t, n, r) {
58
+ let i = Date.now() + n;
59
+ for (;;) try {
60
+ e.mkdirSync(t, { recursive: !1 });
61
+ break;
62
+ } catch {
63
+ if (Date.now() > i) {
64
+ try {
65
+ e.rmdirSync(t);
66
+ } catch {}
67
+ continue;
68
+ }
69
+ a(process.execPath, ["-e", "setTimeout(()=>{}, 250)"], { timeout: 5e3 });
70
+ }
71
+ try {
72
+ return r();
73
+ } finally {
74
+ try {
75
+ e.rmdirSync(t);
76
+ } catch {}
77
+ }
86
78
  }
87
- function V(e = {}) {
88
- const t = O(), o = process.env.APIGEN_PYTHON;
89
- if (o) {
90
- if (!n.existsSync(o))
91
- throw new Error(`apigen-python-env: APIGEN_PYTHON points to a missing file: ${o}`);
92
- return { python: o, venvDir: "", pythonPkgDir: t };
93
- }
94
- const s = [...new Set(e.extras ?? [])].sort(), a = e.envHome ?? process.env.APIGEN_PYENV_HOME ?? r.join(H.homedir(), ".adhd", "apigen"), c = r.join(a, "pyvenv"), p = r.join(c, ".apigen-stamp"), u = J(t), d = Y(c), h = () => {
95
- if (!n.existsSync(d))
96
- return !1;
97
- const i = k(p);
98
- return !i || i.pyprojectHash !== u ? !1 : s.every((y) => i.extras.includes(y));
99
- };
100
- if (h())
101
- return { python: d, venvDir: c, pythonPkgDir: t };
102
- n.mkdirSync(a, { recursive: !0 });
103
- const v = r.join(a, "pyvenv.lock"), w = e.lockTimeoutMs ?? 3e5;
104
- return G(v, w, () => {
105
- if (h())
106
- return { python: d, venvDir: c, pythonPkgDir: t };
107
- const i = k(p), y = [.../* @__PURE__ */ new Set([...(i == null ? void 0 : i.extras) ?? [], ...s])].sort();
108
- n.rmSync(c, { recursive: !0, force: !0 });
109
- const x = F(), j = l(x, ["-m", "venv", c], { encoding: "utf8", timeout: 12e4 });
110
- if (j.status !== 0)
111
- throw new Error(
112
- `apigen-python-env: "${x} -m venv" failed (exit ${j.status}):
113
- ${j.stderr}`
114
- );
115
- const $ = r.join(t, "build");
116
- n.existsSync($) && n.rmSync($, { recursive: !0, force: !0 });
117
- for (const f of n.readdirSync(t))
118
- f.endsWith(".egg-info") && n.rmSync(r.join(t, f), { recursive: !0, force: !0 });
119
- const S = n.mkdtempSync(r.join(H.tmpdir(), "apigen-python-wheel-"));
120
- try {
121
- const f = l(
122
- d,
123
- ["-m", "pip", "wheel", "--no-deps", "--wheel-dir", S, t],
124
- { encoding: "utf8", timeout: 6e5 }
125
- );
126
- if (f.status !== 0)
127
- throw new Error(
128
- `apigen-python-env: pip wheel failed (exit ${f.status}):
129
- ${f.stderr}
130
- stdout:
131
- ${f.stdout}`
132
- );
133
- const P = n.readdirSync(S).filter((b) => b.endsWith(".whl"));
134
- if (P.length === 0)
135
- throw new Error("apigen-python-env: pip wheel produced no .whl file");
136
- const E = r.join(S, P[0]), N = y.length ? `${E}[${y.join(",")}]` : E, g = l(
137
- d,
138
- ["-m", "pip", "install", "--quiet", "--disable-pip-version-check", N],
139
- { encoding: "utf8", timeout: 6e5 }
140
- );
141
- if (g.status !== 0)
142
- throw new Error(
143
- `apigen-python-env: pip install "${N}" failed (exit ${g.status}):
144
- ${g.stderr}
145
- stdout:
146
- ${g.stdout}`
147
- );
148
- } finally {
149
- n.rmSync(S, { recursive: !0, force: !0 });
150
- }
151
- const A = { pyprojectHash: u, extras: y };
152
- return n.writeFileSync(p, JSON.stringify(A)), { python: d, venvDir: c, pythonPkgDir: t };
153
- });
79
+ function h(r = {}) {
80
+ let i = o(), s = process.env.APIGEN_PYTHON;
81
+ if (s) {
82
+ if (!e.existsSync(s)) throw Error(`apigen-python-env: APIGEN_PYTHON points to a missing file: ${s}`);
83
+ return {
84
+ python: s,
85
+ venvDir: "",
86
+ pythonPkgDir: i
87
+ };
88
+ }
89
+ let c = [...new Set(r.extras ?? [])].sort(), l = r.envHome ?? process.env.APIGEN_PYENV_HOME ?? n.join(t.homedir(), ".adhd", "apigen"), h = n.join(l, "pyvenv"), g = n.join(h, ".apigen-stamp"), _ = f(i), v = d(h), y = () => {
90
+ if (!e.existsSync(v)) return !1;
91
+ let t = p(g);
92
+ return t?.pyprojectHash === _ && c.every((e) => t.extras.includes(e));
93
+ };
94
+ return y() ? {
95
+ python: v,
96
+ venvDir: h,
97
+ pythonPkgDir: i
98
+ } : (e.mkdirSync(l, { recursive: !0 }), m(n.join(l, "pyvenv.lock"), r.lockTimeoutMs ?? 3e5, () => {
99
+ if (y()) return {
100
+ python: v,
101
+ venvDir: h,
102
+ pythonPkgDir: i
103
+ };
104
+ let r = p(g), o = [.../* @__PURE__ */ new Set([...r?.extras ?? [], ...c])].sort();
105
+ e.rmSync(h, {
106
+ recursive: !0,
107
+ force: !0
108
+ });
109
+ let s = u(), l = a(s, [
110
+ "-m",
111
+ "venv",
112
+ h
113
+ ], {
114
+ encoding: "utf8",
115
+ timeout: 12e4
116
+ });
117
+ if (l.status !== 0) throw Error(`apigen-python-env: "${s} -m venv" failed (exit ${l.status}):\n${l.stderr}`);
118
+ let d = n.join(i, "build");
119
+ e.existsSync(d) && e.rmSync(d, {
120
+ recursive: !0,
121
+ force: !0
122
+ });
123
+ for (let t of e.readdirSync(i)) t.endsWith(".egg-info") && e.rmSync(n.join(i, t), {
124
+ recursive: !0,
125
+ force: !0
126
+ });
127
+ let f = e.mkdtempSync(n.join(t.tmpdir(), "apigen-python-wheel-"));
128
+ try {
129
+ let t = a(v, [
130
+ "-m",
131
+ "pip",
132
+ "wheel",
133
+ "--no-deps",
134
+ "--wheel-dir",
135
+ f,
136
+ i
137
+ ], {
138
+ encoding: "utf8",
139
+ timeout: 6e5
140
+ });
141
+ if (t.status !== 0) throw Error(`apigen-python-env: pip wheel failed (exit ${t.status}):\n${t.stderr}\nstdout:\n${t.stdout}`);
142
+ let r = e.readdirSync(f).filter((e) => e.endsWith(".whl"));
143
+ if (r.length === 0) throw Error("apigen-python-env: pip wheel produced no .whl file");
144
+ let s = n.join(f, r[0]), c = o.length ? `${s}[${o.join(",")}]` : s, l = a(v, [
145
+ "-m",
146
+ "pip",
147
+ "install",
148
+ "--quiet",
149
+ "--disable-pip-version-check",
150
+ c
151
+ ], {
152
+ encoding: "utf8",
153
+ timeout: 6e5
154
+ });
155
+ if (l.status !== 0) throw Error(`apigen-python-env: pip install "${c}" failed (exit ${l.status}):\n${l.stderr}\nstdout:\n${l.stdout}`);
156
+ } finally {
157
+ e.rmSync(f, {
158
+ recursive: !0,
159
+ force: !0
160
+ });
161
+ }
162
+ let m = {
163
+ pyprojectHash: _,
164
+ extras: o
165
+ };
166
+ return e.writeFileSync(g, JSON.stringify(m)), {
167
+ python: v,
168
+ venvDir: h,
169
+ pythonPkgDir: i
170
+ };
171
+ }));
154
172
  }
155
- function q(e, t, o, s, a) {
156
- return new Promise((c, p) => {
157
- var v, w;
158
- const u = I(
159
- e,
160
- ["-m", "apigen_python.extractor", o, "--namespace", s, "--emit-json"],
161
- {
162
- cwd: t,
163
- env: { ...process.env, PYTHONPATH: t },
164
- stdio: ["ignore", "pipe", "pipe"]
165
- }
166
- );
167
- let d = "", h = "";
168
- (v = u.stdout) == null || v.on("data", (i) => {
169
- d += i.toString("utf8");
170
- }), (w = u.stderr) == null || w.on("data", (i) => {
171
- h += i.toString("utf8");
172
- }), u.on("error", p), u.on("exit", (i) => {
173
- if (i !== 0) {
174
- p(new Error(`${a}: extractor --emit-json exited with code ${i}:
175
- ${h}`));
176
- return;
177
- }
178
- try {
179
- c(JSON.parse(d));
180
- } catch (y) {
181
- p(
182
- new Error(
183
- `${a}: extractor --emit-json produced invalid JSON (${y.message}):
184
- ${d}`
185
- )
186
- );
187
- }
188
- });
189
- });
173
+ //#endregion
174
+ //#region src/lib/run-extractor.ts
175
+ function g(e, t, n, r, a) {
176
+ return new Promise((o, s) => {
177
+ let c = i(e, [
178
+ "-m",
179
+ "apigen_python.extractor",
180
+ n,
181
+ "--namespace",
182
+ r,
183
+ "--emit-json"
184
+ ], {
185
+ cwd: t,
186
+ env: {
187
+ ...process.env,
188
+ PYTHONPATH: t
189
+ },
190
+ stdio: [
191
+ "ignore",
192
+ "pipe",
193
+ "pipe"
194
+ ]
195
+ }), l = "", u = "";
196
+ c.stdout?.on("data", (e) => {
197
+ l += e.toString("utf8");
198
+ }), c.stderr?.on("data", (e) => {
199
+ u += e.toString("utf8");
200
+ }), c.on("error", s), c.on("exit", (e) => {
201
+ if (e !== 0) {
202
+ s(/* @__PURE__ */ Error(`${a}: extractor --emit-json exited with code ${e}:\n${u}`));
203
+ return;
204
+ }
205
+ try {
206
+ o(JSON.parse(l));
207
+ } catch (e) {
208
+ s(/* @__PURE__ */ Error(`${a}: extractor --emit-json produced invalid JSON (${e.message}):\n${l}`));
209
+ }
210
+ });
211
+ });
190
212
  }
191
- export {
192
- V as ensurePythonEnv,
193
- O as resolvePythonPkgDir,
194
- q as runExtractorEmitJson
195
- };
213
+ //#endregion
214
+ export { h as ensurePythonEnv, o as resolvePythonPkgDir, g as runExtractorEmitJson };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhd/apigen-python-env",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "main": "./index.js",
5
5
  "module": "./index.mjs",
6
6
  "types": "./index.d.ts",
@@ -12,7 +12,7 @@
12
12
  "provisioning"
13
13
  ],
14
14
  "dependencies": {
15
- "@adhd/apigen-core-client": "^0.3.1"
15
+ "@adhd/apigen-core-client": "^0.3.3"
16
16
  },
17
17
  "publishConfig": {
18
18
  "access": "public"