nodepyx 1.0.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.
Files changed (184) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +399 -0
  3. package/binding.gyp +73 -0
  4. package/dist/core/PyCallable.d.ts +65 -0
  5. package/dist/core/PyCallable.d.ts.map +1 -0
  6. package/dist/core/PyCallable.js +109 -0
  7. package/dist/core/PyCallable.js.map +1 -0
  8. package/dist/core/PyContext.d.ts +76 -0
  9. package/dist/core/PyContext.d.ts.map +1 -0
  10. package/dist/core/PyContext.js +228 -0
  11. package/dist/core/PyContext.js.map +1 -0
  12. package/dist/core/PyIterator.d.ts +84 -0
  13. package/dist/core/PyIterator.d.ts.map +1 -0
  14. package/dist/core/PyIterator.js +243 -0
  15. package/dist/core/PyIterator.js.map +1 -0
  16. package/dist/core/PyModule.d.ts +55 -0
  17. package/dist/core/PyModule.d.ts.map +1 -0
  18. package/dist/core/PyModule.js +172 -0
  19. package/dist/core/PyModule.js.map +1 -0
  20. package/dist/core/PyProxy.d.ts +65 -0
  21. package/dist/core/PyProxy.d.ts.map +1 -0
  22. package/dist/core/PyProxy.js +483 -0
  23. package/dist/core/PyProxy.js.map +1 -0
  24. package/dist/core/PyRuntime.d.ts +105 -0
  25. package/dist/core/PyRuntime.d.ts.map +1 -0
  26. package/dist/core/PyRuntime.js +438 -0
  27. package/dist/core/PyRuntime.js.map +1 -0
  28. package/dist/env/CondaManager.d.ts +118 -0
  29. package/dist/env/CondaManager.d.ts.map +1 -0
  30. package/dist/env/CondaManager.js +401 -0
  31. package/dist/env/CondaManager.js.map +1 -0
  32. package/dist/env/PackageInstaller.d.ts +233 -0
  33. package/dist/env/PackageInstaller.d.ts.map +1 -0
  34. package/dist/env/PackageInstaller.js +609 -0
  35. package/dist/env/PackageInstaller.js.map +1 -0
  36. package/dist/env/PythonDetector.d.ts +103 -0
  37. package/dist/env/PythonDetector.d.ts.map +1 -0
  38. package/dist/env/PythonDetector.js +381 -0
  39. package/dist/env/PythonDetector.js.map +1 -0
  40. package/dist/env/VenvManager.d.ts +117 -0
  41. package/dist/env/VenvManager.d.ts.map +1 -0
  42. package/dist/env/VenvManager.js +331 -0
  43. package/dist/env/VenvManager.js.map +1 -0
  44. package/dist/index.d.ts +169 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +393 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/plugins/Plugin.interface.d.ts +41 -0
  49. package/dist/plugins/Plugin.interface.d.ts.map +1 -0
  50. package/dist/plugins/Plugin.interface.js +12 -0
  51. package/dist/plugins/Plugin.interface.js.map +1 -0
  52. package/dist/plugins/PluginManager.d.ts +26 -0
  53. package/dist/plugins/PluginManager.d.ts.map +1 -0
  54. package/dist/plugins/PluginManager.js +174 -0
  55. package/dist/plugins/PluginManager.js.map +1 -0
  56. package/dist/plugins/builtin/NumpyPlugin.d.ts +17 -0
  57. package/dist/plugins/builtin/NumpyPlugin.d.ts.map +1 -0
  58. package/dist/plugins/builtin/NumpyPlugin.js +41 -0
  59. package/dist/plugins/builtin/NumpyPlugin.js.map +1 -0
  60. package/dist/plugins/builtin/PandasPlugin.d.ts +19 -0
  61. package/dist/plugins/builtin/PandasPlugin.d.ts.map +1 -0
  62. package/dist/plugins/builtin/PandasPlugin.js +57 -0
  63. package/dist/plugins/builtin/PandasPlugin.js.map +1 -0
  64. package/dist/plugins/builtin/TorchPlugin.d.ts +23 -0
  65. package/dist/plugins/builtin/TorchPlugin.d.ts.map +1 -0
  66. package/dist/plugins/builtin/TorchPlugin.js +50 -0
  67. package/dist/plugins/builtin/TorchPlugin.js.map +1 -0
  68. package/dist/plugins/index.d.ts +7 -0
  69. package/dist/plugins/index.d.ts.map +1 -0
  70. package/dist/plugins/index.js +12 -0
  71. package/dist/plugins/index.js.map +1 -0
  72. package/dist/serialization/DataFrameBridge.d.ts +141 -0
  73. package/dist/serialization/DataFrameBridge.d.ts.map +1 -0
  74. package/dist/serialization/DataFrameBridge.js +355 -0
  75. package/dist/serialization/DataFrameBridge.js.map +1 -0
  76. package/dist/serialization/MsgPackSerializer.d.ts +45 -0
  77. package/dist/serialization/MsgPackSerializer.d.ts.map +1 -0
  78. package/dist/serialization/MsgPackSerializer.js +242 -0
  79. package/dist/serialization/MsgPackSerializer.js.map +1 -0
  80. package/dist/serialization/NumpyBridge.d.ts +96 -0
  81. package/dist/serialization/NumpyBridge.d.ts.map +1 -0
  82. package/dist/serialization/NumpyBridge.js +323 -0
  83. package/dist/serialization/NumpyBridge.js.map +1 -0
  84. package/dist/serialization/Serializer.d.ts +78 -0
  85. package/dist/serialization/Serializer.d.ts.map +1 -0
  86. package/dist/serialization/Serializer.js +281 -0
  87. package/dist/serialization/Serializer.js.map +1 -0
  88. package/dist/types/PythonTypeMapper.d.ts +87 -0
  89. package/dist/types/PythonTypeMapper.d.ts.map +1 -0
  90. package/dist/types/PythonTypeMapper.js +449 -0
  91. package/dist/types/PythonTypeMapper.js.map +1 -0
  92. package/dist/types/StubCache.d.ts +109 -0
  93. package/dist/types/StubCache.d.ts.map +1 -0
  94. package/dist/types/StubCache.js +333 -0
  95. package/dist/types/StubCache.js.map +1 -0
  96. package/dist/types/TypeGenerator.d.ts +139 -0
  97. package/dist/types/TypeGenerator.d.ts.map +1 -0
  98. package/dist/types/TypeGenerator.js +372 -0
  99. package/dist/types/TypeGenerator.js.map +1 -0
  100. package/dist/types/addon.d.ts +114 -0
  101. package/dist/types/addon.d.ts.map +1 -0
  102. package/dist/types/addon.js +32 -0
  103. package/dist/types/addon.js.map +1 -0
  104. package/dist/types/config.d.ts +175 -0
  105. package/dist/types/config.d.ts.map +1 -0
  106. package/dist/types/config.js +35 -0
  107. package/dist/types/config.js.map +1 -0
  108. package/dist/types/index.d.ts +10 -0
  109. package/dist/types/index.d.ts.map +1 -0
  110. package/dist/types/index.js +12 -0
  111. package/dist/types/index.js.map +1 -0
  112. package/dist/types/python.d.ts +235 -0
  113. package/dist/types/python.d.ts.map +1 -0
  114. package/dist/types/python.js +7 -0
  115. package/dist/types/python.js.map +1 -0
  116. package/dist/utils/ErrorTranslator.d.ts +83 -0
  117. package/dist/utils/ErrorTranslator.d.ts.map +1 -0
  118. package/dist/utils/ErrorTranslator.js +210 -0
  119. package/dist/utils/ErrorTranslator.js.map +1 -0
  120. package/dist/utils/Logger.d.ts +27 -0
  121. package/dist/utils/Logger.d.ts.map +1 -0
  122. package/dist/utils/Logger.js +115 -0
  123. package/dist/utils/Logger.js.map +1 -0
  124. package/dist/utils/MemoryMonitor.d.ts +44 -0
  125. package/dist/utils/MemoryMonitor.d.ts.map +1 -0
  126. package/dist/utils/MemoryMonitor.js +143 -0
  127. package/dist/utils/MemoryMonitor.js.map +1 -0
  128. package/package.json +177 -0
  129. package/python/error_handler.py +433 -0
  130. package/python/nodepyx_runtime.py +575 -0
  131. package/python/serializer.py +379 -0
  132. package/python/type_inspector.py +288 -0
  133. package/scripts/build-native.js +68 -0
  134. package/scripts/download-prebuilds.js +99 -0
  135. package/scripts/generate-stubs.js +405 -0
  136. package/scripts/install.js +260 -0
  137. package/src/core/PyCallable.ts +137 -0
  138. package/src/core/PyContext.ts +296 -0
  139. package/src/core/PyIterator.ts +294 -0
  140. package/src/core/PyModule.ts +194 -0
  141. package/src/core/PyProxy.ts +605 -0
  142. package/src/core/PyRuntime.ts +504 -0
  143. package/src/env/CondaManager.ts +451 -0
  144. package/src/env/PackageInstaller.ts +738 -0
  145. package/src/env/PythonDetector.ts +414 -0
  146. package/src/env/VenvManager.ts +396 -0
  147. package/src/index.ts +425 -0
  148. package/src/native/gil_guard.cpp +26 -0
  149. package/src/native/gil_guard.h +175 -0
  150. package/src/native/nodepyx_addon.cpp +886 -0
  151. package/src/native/python_bridge.cpp +790 -0
  152. package/src/native/python_bridge.h +257 -0
  153. package/src/native/thread_pool.cpp +336 -0
  154. package/src/native/thread_pool.h +175 -0
  155. package/src/native/type_converter.cpp +901 -0
  156. package/src/native/type_converter.h +272 -0
  157. package/src/nextjs/PyProvider.tsx +123 -0
  158. package/src/nextjs/index.ts +21 -0
  159. package/src/nextjs/usePython.ts +106 -0
  160. package/src/nextjs/withnodepyx.ts +88 -0
  161. package/src/plugins/Plugin.interface.ts +51 -0
  162. package/src/plugins/PluginManager.ts +155 -0
  163. package/src/plugins/builtin/NumpyPlugin.ts +36 -0
  164. package/src/plugins/builtin/PandasPlugin.ts +49 -0
  165. package/src/plugins/builtin/TorchPlugin.ts +56 -0
  166. package/src/plugins/index.ts +7 -0
  167. package/src/serialization/DataFrameBridge.ts +398 -0
  168. package/src/serialization/MsgPackSerializer.ts +220 -0
  169. package/src/serialization/NumpyBridge.ts +332 -0
  170. package/src/serialization/Serializer.ts +320 -0
  171. package/src/types/PythonTypeMapper.ts +495 -0
  172. package/src/types/StubCache.ts +340 -0
  173. package/src/types/TypeGenerator.ts +491 -0
  174. package/src/types/addon.ts +170 -0
  175. package/src/types/config.ts +226 -0
  176. package/src/types/index.ts +55 -0
  177. package/src/types/python.ts +309 -0
  178. package/src/types/stubs/numpy.d.ts +441 -0
  179. package/src/types/stubs/pandas.d.ts +575 -0
  180. package/src/types/stubs/sklearn.d.ts +728 -0
  181. package/src/types/stubs/torch.d.ts +694 -0
  182. package/src/utils/ErrorTranslator.ts +220 -0
  183. package/src/utils/Logger.ts +119 -0
  184. package/src/utils/MemoryMonitor.ts +175 -0
@@ -0,0 +1,401 @@
1
+ "use strict";
2
+ /**
3
+ * nodepyx — CondaManager
4
+ * Manages Conda environments for Python package isolation.
5
+ *
6
+ * Supports:
7
+ * - Detecting an existing conda environment by name
8
+ * - Creating new conda environments
9
+ * - Installing packages into a conda environment (conda + pip fallback)
10
+ * - Returning the Python executable path inside a conda env
11
+ *
12
+ * Detection order for conda executable:
13
+ * 1. CONDA_EXE environment variable
14
+ * 2. MAMBA_EXE (uses mamba as a drop-in replacement)
15
+ * 3. condaPath from config
16
+ * 4. 'conda' on PATH
17
+ * 5. Common installation locations
18
+ */
19
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ var desc = Object.getOwnPropertyDescriptor(m, k);
22
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
23
+ desc = { enumerable: true, get: function() { return m[k]; } };
24
+ }
25
+ Object.defineProperty(o, k2, desc);
26
+ }) : (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ o[k2] = m[k];
29
+ }));
30
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
32
+ }) : function(o, v) {
33
+ o["default"] = v;
34
+ });
35
+ var __importStar = (this && this.__importStar) || (function () {
36
+ var ownKeys = function(o) {
37
+ ownKeys = Object.getOwnPropertyNames || function (o) {
38
+ var ar = [];
39
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
40
+ return ar;
41
+ };
42
+ return ownKeys(o);
43
+ };
44
+ return function (mod) {
45
+ if (mod && mod.__esModule) return mod;
46
+ var result = {};
47
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
48
+ __setModuleDefault(result, mod);
49
+ return result;
50
+ };
51
+ })();
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.CondaPackageInstallError = exports.CondaEnvError = exports.CondaNotFoundError = exports.CondaManager = void 0;
54
+ const child_process_1 = require("child_process");
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ const os = __importStar(require("os"));
58
+ const Logger_1 = require("../utils/Logger");
59
+ const logger = new Logger_1.Logger('CondaManager');
60
+ // ─── Common conda installation paths ─────────────────────────────────────────
61
+ const CONDA_LOCATIONS_LINUX = [
62
+ '/opt/conda/bin/conda',
63
+ `${os.homedir()}/anaconda3/bin/conda`,
64
+ `${os.homedir()}/miniconda3/bin/conda`,
65
+ `${os.homedir()}/miniconda/bin/conda`,
66
+ '/usr/local/bin/conda',
67
+ ];
68
+ const CONDA_LOCATIONS_DARWIN = [
69
+ `${os.homedir()}/opt/anaconda3/bin/conda`,
70
+ `${os.homedir()}/opt/miniconda3/bin/conda`,
71
+ '/opt/homebrew/bin/conda',
72
+ `/opt/conda/bin/conda`,
73
+ ];
74
+ const CONDA_LOCATIONS_WIN = [
75
+ `${process.env.USERPROFILE}\\Anaconda3\\Scripts\\conda.exe`,
76
+ `${process.env.USERPROFILE}\\Miniconda3\\Scripts\\conda.exe`,
77
+ `C:\\Anaconda3\\Scripts\\conda.exe`,
78
+ `C:\\Miniconda3\\Scripts\\conda.exe`,
79
+ `${process.env.PROGRAMDATA}\\Anaconda3\\Scripts\\conda.exe`,
80
+ ];
81
+ /**
82
+ * CondaManager — manages Conda environments.
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const manager = new CondaManager({
87
+ * conda: {
88
+ * envName: 'my-ml-env',
89
+ * packages: ['numpy', 'pandas', 'scikit-learn'],
90
+ * channels: ['conda-forge', 'defaults'],
91
+ * }
92
+ * });
93
+ *
94
+ * const result = await manager.setup();
95
+ * console.log(result.pythonExecutable); // /opt/conda/envs/my-ml-env/bin/python3
96
+ * ```
97
+ */
98
+ class CondaManager {
99
+ _config;
100
+ _timeout;
101
+ _preferMamba;
102
+ _condaExec = null;
103
+ constructor(options) {
104
+ this._config = options.conda;
105
+ this._timeout = options.timeout ?? 300_000;
106
+ this._preferMamba = options.preferMamba ?? true;
107
+ }
108
+ // ─── Public API ──────────────────────────────────────────────────────────
109
+ /**
110
+ * Set up the Conda environment.
111
+ * Creates the environment if it doesn't exist, then installs packages.
112
+ */
113
+ async setup() {
114
+ const condaExec = this._findCondaExecutable();
115
+ if (!condaExec) {
116
+ throw new CondaNotFoundError('Could not find conda executable. ' +
117
+ 'Install Anaconda/Miniconda or set CONDA_EXE environment variable.');
118
+ }
119
+ this._condaExec = condaExec;
120
+ logger.info(`CondaManager: using conda at ${condaExec}`);
121
+ let created = false;
122
+ let packagesInstalled = false;
123
+ // ── Check if environment exists ──────────────────────────────────────
124
+ const existingEnv = await this._findEnv(this._config.envName);
125
+ if (!existingEnv) {
126
+ logger.info(`CondaManager: creating environment '${this._config.envName}'`);
127
+ await this._createEnv();
128
+ created = true;
129
+ }
130
+ const envInfo = await this._getEnvInfo(this._config.envName);
131
+ if (!envInfo) {
132
+ throw new CondaEnvError(`Environment '${this._config.envName}' not found after creation`);
133
+ }
134
+ // ── Install packages ─────────────────────────────────────────────────
135
+ const packagesToInstall = this._config.packages ?? [];
136
+ if (packagesToInstall.length > 0) {
137
+ logger.info(`CondaManager: installing packages into '${this._config.envName}'`);
138
+ await this._installPackages(envInfo.prefix, packagesToInstall);
139
+ packagesInstalled = true;
140
+ }
141
+ return {
142
+ pythonExecutable: envInfo.pythonExecutable,
143
+ created,
144
+ packagesInstalled,
145
+ envInfo,
146
+ };
147
+ }
148
+ /**
149
+ * List all conda environments.
150
+ */
151
+ async listEnvironments() {
152
+ const conda = this._findCondaExecutable();
153
+ if (!conda) {
154
+ return [];
155
+ }
156
+ try {
157
+ const result = (0, child_process_1.spawnSync)(conda, ['env', 'list', '--json'], { encoding: 'utf8', timeout: 30_000, stdio: 'pipe' });
158
+ if (result.status !== 0) {
159
+ return [];
160
+ }
161
+ const parsed = JSON.parse(result.stdout);
162
+ const envs = [];
163
+ for (const prefix of parsed.envs ?? []) {
164
+ const name = path.basename(prefix);
165
+ const pyExec = this._pythonInPrefix(prefix);
166
+ if (fs.existsSync(pyExec)) {
167
+ envs.push({
168
+ name,
169
+ prefix,
170
+ pythonExecutable: pyExec,
171
+ isActive: process.env.CONDA_PREFIX === prefix,
172
+ });
173
+ }
174
+ }
175
+ return envs;
176
+ }
177
+ catch {
178
+ return [];
179
+ }
180
+ }
181
+ /**
182
+ * Check if a conda environment exists.
183
+ */
184
+ async environmentExists(envName) {
185
+ return (await this._findEnv(envName)) !== null;
186
+ }
187
+ /**
188
+ * Get the Python executable for a conda environment.
189
+ */
190
+ async getPythonExecutable(envName) {
191
+ const info = await this._getEnvInfo(envName);
192
+ return info?.pythonExecutable ?? null;
193
+ }
194
+ /**
195
+ * Install packages into an existing environment.
196
+ */
197
+ async installPackages(envName, packages) {
198
+ const info = await this._getEnvInfo(envName);
199
+ if (!info) {
200
+ throw new CondaEnvError(`Environment '${envName}' not found`);
201
+ }
202
+ await this._installPackages(info.prefix, packages);
203
+ }
204
+ /**
205
+ * Remove a conda environment.
206
+ */
207
+ async removeEnvironment(envName) {
208
+ const conda = this._ensureCondaExec();
209
+ const result = (0, child_process_1.spawnSync)(conda, ['env', 'remove', '--name', envName, '--yes'], { encoding: 'utf8', timeout: 120_000, stdio: 'pipe' });
210
+ if (result.status !== 0) {
211
+ logger.warn(`CondaManager: failed to remove env '${envName}'`);
212
+ }
213
+ else {
214
+ logger.info(`CondaManager: removed environment '${envName}'`);
215
+ }
216
+ }
217
+ /**
218
+ * Return the conda executable path (or null if not found).
219
+ */
220
+ get condaExecutable() {
221
+ return this._findCondaExecutable();
222
+ }
223
+ // ─── Private ─────────────────────────────────────────────────────────────
224
+ _findCondaExecutable() {
225
+ // mamba is a faster drop-in
226
+ if (this._preferMamba) {
227
+ const mamba = process.env.MAMBA_EXE || this._which('mamba');
228
+ if (mamba) {
229
+ return mamba;
230
+ }
231
+ }
232
+ // CONDA_EXE env var
233
+ if (process.env.CONDA_EXE) {
234
+ return process.env.CONDA_EXE;
235
+ }
236
+ // Explicit config path
237
+ if (this._config.condaPath) {
238
+ return this._config.condaPath;
239
+ }
240
+ // PATH
241
+ const fromPath = this._which('conda');
242
+ if (fromPath) {
243
+ return fromPath;
244
+ }
245
+ // Common locations
246
+ const locations = process.platform === 'win32' ? CONDA_LOCATIONS_WIN :
247
+ process.platform === 'darwin' ? CONDA_LOCATIONS_DARWIN :
248
+ CONDA_LOCATIONS_LINUX;
249
+ for (const loc of locations) {
250
+ if (loc && fs.existsSync(loc)) {
251
+ return loc;
252
+ }
253
+ }
254
+ return null;
255
+ }
256
+ _ensureCondaExec() {
257
+ const exec = this._condaExec ?? this._findCondaExecutable();
258
+ if (!exec) {
259
+ throw new CondaNotFoundError('conda executable not found');
260
+ }
261
+ return exec;
262
+ }
263
+ async _findEnv(envName) {
264
+ try {
265
+ const envs = await this.listEnvironments();
266
+ const match = envs.find(e => e.name === envName);
267
+ return match?.prefix ?? null;
268
+ }
269
+ catch {
270
+ return null;
271
+ }
272
+ }
273
+ async _getEnvInfo(envName) {
274
+ try {
275
+ const envs = await this.listEnvironments();
276
+ return envs.find(e => e.name === envName) ?? null;
277
+ }
278
+ catch {
279
+ return null;
280
+ }
281
+ }
282
+ async _createEnv() {
283
+ const conda = this._ensureCondaExec();
284
+ const args = [
285
+ 'create',
286
+ '--name', this._config.envName,
287
+ '--yes',
288
+ 'python>=3.8',
289
+ '--quiet',
290
+ ];
291
+ if (this._config.channels?.length) {
292
+ for (const ch of this._config.channels) {
293
+ args.push('--channel', ch);
294
+ }
295
+ }
296
+ const result = (0, child_process_1.spawnSync)(conda, args, {
297
+ encoding: 'utf8',
298
+ timeout: this._timeout,
299
+ stdio: ['ignore', 'pipe', 'pipe'],
300
+ });
301
+ if (result.status !== 0) {
302
+ const err = result.stderr?.trim() || 'conda create failed';
303
+ throw new CondaEnvError(`Failed to create conda env '${this._config.envName}': ${err}`);
304
+ }
305
+ logger.info(`CondaManager: created env '${this._config.envName}'`);
306
+ }
307
+ async _installPackages(prefix, packages) {
308
+ if (packages.length === 0) {
309
+ return;
310
+ }
311
+ const conda = this._ensureCondaExec();
312
+ // Split into conda-installable and pip-only packages
313
+ const pipOnlyMarker = 'pip::';
314
+ const condaPackages = packages.filter(p => !p.startsWith(pipOnlyMarker));
315
+ const pipPackages = packages.filter(p => p.startsWith(pipOnlyMarker)).map(p => p.slice(pipOnlyMarker.length));
316
+ // conda install
317
+ if (condaPackages.length > 0) {
318
+ const condaArgs = [
319
+ 'install',
320
+ '--prefix', prefix,
321
+ '--yes',
322
+ '--quiet',
323
+ ...condaPackages,
324
+ ];
325
+ if (this._config.channels?.length) {
326
+ for (const ch of this._config.channels) {
327
+ condaArgs.push('--channel', ch);
328
+ }
329
+ }
330
+ const result = (0, child_process_1.spawnSync)(conda, condaArgs, {
331
+ encoding: 'utf8',
332
+ timeout: this._timeout,
333
+ stdio: ['ignore', 'pipe', 'pipe'],
334
+ });
335
+ if (result.status !== 0) {
336
+ // Fall back to pip for failed packages
337
+ logger.warn(`CondaManager: conda install failed, falling back to pip`);
338
+ pipPackages.push(...condaPackages);
339
+ }
340
+ else {
341
+ logger.info(`CondaManager: conda-installed ${condaPackages.join(', ')}`);
342
+ }
343
+ }
344
+ // pip install (fallback)
345
+ if (pipPackages.length > 0) {
346
+ const pip = path.join(prefix, process.platform === 'win32' ? 'Scripts\\pip.exe' : 'bin/pip3');
347
+ if (!fs.existsSync(pip)) {
348
+ logger.warn(`CondaManager: pip not found in env, skipping: ${pipPackages.join(', ')}`);
349
+ return;
350
+ }
351
+ const result = (0, child_process_1.spawnSync)(pip, ['install', '--quiet', ...pipPackages], {
352
+ encoding: 'utf8',
353
+ timeout: this._timeout,
354
+ stdio: ['ignore', 'pipe', 'pipe'],
355
+ });
356
+ if (result.status !== 0) {
357
+ throw new CondaPackageInstallError(pipPackages, result.stderr?.trim() ?? 'unknown error');
358
+ }
359
+ logger.info(`CondaManager: pip-installed ${pipPackages.join(', ')}`);
360
+ }
361
+ }
362
+ _pythonInPrefix(prefix) {
363
+ return path.join(prefix, process.platform === 'win32' ? 'python.exe' : 'bin/python3');
364
+ }
365
+ _which(name) {
366
+ try {
367
+ const cmd = process.platform === 'win32' ? `where ${name}` : `which ${name}`;
368
+ const result = (0, child_process_1.execSync)(cmd, { encoding: 'utf8', timeout: 3000, stdio: 'pipe' }).trim();
369
+ return result.split(/\r?\n/)[0]?.trim() || null;
370
+ }
371
+ catch {
372
+ return null;
373
+ }
374
+ }
375
+ }
376
+ exports.CondaManager = CondaManager;
377
+ // ─── Error types ─────────────────────────────────────────────────────────────
378
+ class CondaNotFoundError extends Error {
379
+ constructor(message) {
380
+ super(message);
381
+ this.name = 'CondaNotFoundError';
382
+ }
383
+ }
384
+ exports.CondaNotFoundError = CondaNotFoundError;
385
+ class CondaEnvError extends Error {
386
+ constructor(message) {
387
+ super(message);
388
+ this.name = 'CondaEnvError';
389
+ }
390
+ }
391
+ exports.CondaEnvError = CondaEnvError;
392
+ class CondaPackageInstallError extends Error {
393
+ packages;
394
+ constructor(packages, detail) {
395
+ super(`Failed to install conda packages [${packages.join(', ')}]: ${detail}`);
396
+ this.name = 'CondaPackageInstallError';
397
+ this.packages = packages;
398
+ }
399
+ }
400
+ exports.CondaPackageInstallError = CondaPackageInstallError;
401
+ //# sourceMappingURL=CondaManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CondaManager.js","sourceRoot":"","sources":["../../src/env/CondaManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,233 @@
1
+ /**
2
+ * nodepyx — PackageInstaller
3
+ *
4
+ * Standalone pip-based package installer that works both inside and outside
5
+ * virtualenv/conda contexts. It is the single place where all pip interaction
6
+ * is concentrated so that VenvManager, CondaManager, and the public nodepyx API
7
+ * all delegate here instead of shelling out to pip themselves.
8
+ *
9
+ * Responsibilities
10
+ * ──────────────────────────────────────────────────────────────────────────────
11
+ * • Resolve the "import name" from the "install name" (e.g. scikit-learn → sklearn)
12
+ * • Check whether a package is already importable before trying to install it
13
+ * • Run pip with the correct flags (--quiet, --no-warn-script-location, etc.)
14
+ * • Support per-package version constraints ("numpy>=1.24,<2")
15
+ * • Support extras ("uvicorn[standard]")
16
+ * • Support index overrides (corporate PyPI mirrors, --extra-index-url)
17
+ * • Upgrade existing installations when requested
18
+ * • Emit structured progress events via EventEmitter
19
+ * • Retry transient network failures up to N times with back-off
20
+ * • Parse pip's JSON output (--report) for installed metadata when available
21
+ * • Return full InstallResult objects describing what happened
22
+ *
23
+ * Usage
24
+ * ──────────────────────────────────────────────────────────────────────────────
25
+ * const installer = new PackageInstaller({ pythonExecutable: '/usr/bin/python3' });
26
+ *
27
+ * const result = await installer.install(['pandas', 'numpy>=1.24', 'torch']);
28
+ * console.log(result.installed); // ['pandas==2.2.2', 'numpy==1.26.4', ...]
29
+ *
30
+ * installer.on('progress', (ev) => console.log(ev.package, ev.status));
31
+ */
32
+ import { EventEmitter } from 'events';
33
+ /** A single package specification that can be installed. */
34
+ export interface PackageSpec {
35
+ /** Raw pip spec: "pandas", "numpy>=1.24,<2", "torch==2.3.0+cu121" */
36
+ spec: string;
37
+ /**
38
+ * Override the import (module) name used to test whether the package is
39
+ * already importable. Defaults to the auto-detected mapping.
40
+ * e.g. spec="scikit-learn" → importName="sklearn"
41
+ */
42
+ importName?: string;
43
+ /** Force reinstall even if already importable. */
44
+ forceReinstall?: boolean;
45
+ /** Install pre-release versions */
46
+ preRelease?: boolean;
47
+ }
48
+ /** Options passed to the PackageInstaller constructor. */
49
+ export interface PackageInstallerOptions {
50
+ /** Python executable to use for pip invocations. Required. */
51
+ pythonExecutable: string;
52
+ /**
53
+ * Extra --index-url override (corporate mirror etc.)
54
+ * If omitted, pip uses its default index.
55
+ */
56
+ indexUrl?: string;
57
+ /**
58
+ * Additional --extra-index-url entries (e.g. CUDA wheels).
59
+ * Supports multiple URLs.
60
+ */
61
+ extraIndexUrls?: string[];
62
+ /**
63
+ * Trusted hosts (--trusted-host) required when using HTTP mirrors.
64
+ */
65
+ trustedHosts?: string[];
66
+ /**
67
+ * Maximum retry attempts for transient network errors. Default: 3.
68
+ */
69
+ maxRetries?: number;
70
+ /**
71
+ * Base delay (ms) between retry attempts. Each retry doubles. Default: 1000.
72
+ */
73
+ retryDelayMs?: number;
74
+ /**
75
+ * Working directory for pip. Defaults to process.cwd().
76
+ */
77
+ cwd?: string;
78
+ /**
79
+ * Additional environment variables to inject into pip subprocess.
80
+ */
81
+ env?: Record<string, string>;
82
+ /**
83
+ * Timeout (ms) per pip invocation. Default: 300 000 (5 min).
84
+ */
85
+ timeoutMs?: number;
86
+ /**
87
+ * If true, pass --quiet to suppress pip chatter. Default: true.
88
+ */
89
+ quiet?: boolean;
90
+ /**
91
+ * If true, pass --upgrade to pip for already-installed packages. Default: false.
92
+ */
93
+ upgrade?: boolean;
94
+ }
95
+ /** Status of a single package during/after installation. */
96
+ export type PackageStatus = 'already_installed' | 'installing' | 'installed' | 'upgraded' | 'failed' | 'skipped';
97
+ /** Progress event emitted during installation. */
98
+ export interface InstallProgressEvent {
99
+ package: string;
100
+ status: PackageStatus;
101
+ version?: string;
102
+ error?: string;
103
+ }
104
+ /** Aggregated result of an install() call. */
105
+ export interface InstallResult {
106
+ /** Packages that were successfully installed or upgraded (with versions). */
107
+ installed: string[];
108
+ /** Packages that were already present and did not need installation. */
109
+ alreadyInstalled: string[];
110
+ /** Packages that failed to install. */
111
+ failed: Array<{
112
+ spec: string;
113
+ error: string;
114
+ }>;
115
+ /** Whether every requested package ended up available. */
116
+ success: boolean;
117
+ /** Combined stdout/stderr from pip (useful for debugging). */
118
+ output: string;
119
+ }
120
+ /** Metadata returned by `pip show`. */
121
+ export interface PackageMetadata {
122
+ name: string;
123
+ version: string;
124
+ location: string;
125
+ requires: string[];
126
+ requiredBy: string[];
127
+ summary: string;
128
+ }
129
+ declare const INSTALL_TO_IMPORT: Record<string, string>;
130
+ /**
131
+ * Extract the bare package name from a spec string.
132
+ * "numpy>=1.24,<2" → "numpy"
133
+ * "torch==2.3.0+cu121" → "torch"
134
+ * "uvicorn[standard]" → "uvicorn"
135
+ */
136
+ declare function extractPackageName(spec: string): string;
137
+ /**
138
+ * Determine the Python import name for a given install spec.
139
+ */
140
+ declare function resolveImportName(spec: string, override?: string): string;
141
+ export declare class PackageInstaller extends EventEmitter {
142
+ private readonly _python;
143
+ private readonly _opts;
144
+ constructor(options: PackageInstallerOptions);
145
+ /**
146
+ * Install one or more packages.
147
+ *
148
+ * @param packages - Array of pip spec strings or PackageSpec objects.
149
+ * @returns InstallResult describing what happened to each package.
150
+ */
151
+ install(packages: Array<string | PackageSpec>): Promise<InstallResult>;
152
+ /**
153
+ * Install a single package and return the installed version string.
154
+ * Throws on failure.
155
+ */
156
+ installOne(spec: string, options?: Partial<PackageSpec>): Promise<string>;
157
+ /**
158
+ * Upgrade a package to the latest version.
159
+ */
160
+ upgrade(spec: string): Promise<string>;
161
+ /**
162
+ * Uninstall one or more packages.
163
+ */
164
+ uninstall(packages: string[]): Promise<void>;
165
+ /**
166
+ * Check whether a package is currently importable by Python.
167
+ */
168
+ isImportable(importName: string): boolean;
169
+ /**
170
+ * Check whether a package (by install name) is installed and return
171
+ * its version string, or null if not installed.
172
+ */
173
+ getVersion(packageName: string): string | null;
174
+ /**
175
+ * Return full metadata for an installed package.
176
+ */
177
+ getMetadata(packageName: string): PackageMetadata | null;
178
+ /**
179
+ * List all packages installed in the current Python environment.
180
+ */
181
+ listInstalled(): Array<{
182
+ name: string;
183
+ version: string;
184
+ }>;
185
+ /**
186
+ * Check which packages from the given list are missing.
187
+ *
188
+ * @param packages - Array of pip spec strings.
189
+ * @returns Array of spec strings that are NOT currently importable.
190
+ */
191
+ getMissing(packages: string[]): string[];
192
+ /**
193
+ * Ensure pip itself is up-to-date.
194
+ */
195
+ upgradePip(): Promise<void>;
196
+ /**
197
+ * Run `python -c "import X"` to test importability.
198
+ * This is faster than `pip show` for the common case.
199
+ */
200
+ private _isImportable;
201
+ /**
202
+ * Build pip install argument list.
203
+ */
204
+ private _buildPipArgs;
205
+ /**
206
+ * Execute pip install with retry logic.
207
+ */
208
+ private _pipInstall;
209
+ /**
210
+ * Spawn pip and collect output.
211
+ */
212
+ private _runPip;
213
+ /** Merge per-package results into the aggregate InstallResult. */
214
+ private _mergeResults;
215
+ /** Emit a typed progress event. */
216
+ private _emit;
217
+ /** Parse `pip show` output into PackageMetadata. */
218
+ private _parsePipShow;
219
+ }
220
+ /**
221
+ * Create a PackageInstaller for the system Python (or the python3 in PATH).
222
+ */
223
+ export declare function createSystemInstaller(options?: Partial<Omit<PackageInstallerOptions, 'pythonExecutable'>>): PackageInstaller;
224
+ /**
225
+ * Create a PackageInstaller tied to a specific virtualenv directory.
226
+ */
227
+ export declare function createVenvInstaller(venvDir: string, options?: Partial<Omit<PackageInstallerOptions, 'pythonExecutable'>>): PackageInstaller;
228
+ /**
229
+ * Resolve the import name from a pip install spec using the built-in table.
230
+ * Exposed for testing and introspection.
231
+ */
232
+ export { resolveImportName, extractPackageName, INSTALL_TO_IMPORT };
233
+ //# sourceMappingURL=PackageInstaller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PackageInstaller.d.ts","sourceRoot":"","sources":["../../src/env/PackageInstaller.ts"],"names":[],"mappings":"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"}