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,103 @@
1
+ /**
2
+ * nodepyx — PythonDetector
3
+ * Locates a usable Python interpreter on the host system.
4
+ *
5
+ * Detection order:
6
+ * 1. nodepyx_PYTHON environment variable
7
+ * 2. Explicit pythonPath from nodepyxConfig
8
+ * 3. Virtualenv / Conda path from config
9
+ * 4. python3 / python3.x on PATH
10
+ * 5. python on PATH
11
+ * 6. Common installation locations (Windows/macOS/Linux)
12
+ *
13
+ * Validates:
14
+ * - Python version ≥ 3.8
15
+ * - Not a stub (pyenv shim without real installation)
16
+ * - Has required modules available (when requested)
17
+ */
18
+ export interface PythonInfo {
19
+ /** Absolute path to Python executable */
20
+ executable: string;
21
+ /** Python version string (e.g. '3.11.4') */
22
+ version: string;
23
+ /** Major.minor as numbers */
24
+ major: number;
25
+ minor: number;
26
+ patch: number;
27
+ /** Absolute path to Python prefix (sys.prefix) */
28
+ prefix: string;
29
+ /** Whether this is inside a virtualenv */
30
+ isVirtualenv: boolean;
31
+ /** Whether this is inside a Conda environment */
32
+ isConda: boolean;
33
+ /** conda environment name (if applicable) */
34
+ condaEnv?: string;
35
+ /** Platform: 'linux' | 'darwin' | 'win32' */
36
+ platform: string;
37
+ /** Architecture: 'x64' | 'arm64' */
38
+ arch: string;
39
+ }
40
+ export interface DetectorOptions {
41
+ /** Minimum Python version required. Default: [3, 8] */
42
+ minVersion?: [number, number];
43
+ /** Explicit path to check first */
44
+ pythonPath?: string;
45
+ /** Timeout for subprocess calls (ms). Default: 10000 */
46
+ timeout?: number;
47
+ /** Skip PATH scanning and only check explicit path. Default: false */
48
+ explicitOnly?: boolean;
49
+ /** Modules that must be importable. Default: [] */
50
+ requiredModules?: string[];
51
+ }
52
+ /**
53
+ * PythonDetector — locates a usable Python interpreter.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const detector = new PythonDetector({ minVersion: [3, 9] });
58
+ * const info = await detector.detect();
59
+ * console.log(info.executable); // /usr/bin/python3
60
+ * console.log(info.version); // 3.11.4
61
+ * ```
62
+ */
63
+ export declare class PythonDetector {
64
+ private readonly _opts;
65
+ constructor(options?: DetectorOptions);
66
+ /**
67
+ * Detect and validate a Python interpreter.
68
+ * Returns the first suitable interpreter found.
69
+ * Throws if no suitable interpreter is found.
70
+ */
71
+ detect(): Promise<PythonInfo>;
72
+ /**
73
+ * Probe a specific Python executable and return its info.
74
+ * Returns null if the executable is invalid or doesn't exist.
75
+ */
76
+ probe(executablePath: string): PythonInfo | null;
77
+ /**
78
+ * Check if a Python executable meets the minimum version requirement.
79
+ */
80
+ isCompatible(info: PythonInfo): boolean;
81
+ /**
82
+ * Check which required modules are missing for a given Python.
83
+ * Returns an empty array if all modules are available.
84
+ */
85
+ checkModules(executable: string, modules: string[]): string[];
86
+ /**
87
+ * List all Python executables found in common locations and PATH.
88
+ */
89
+ listAll(): Promise<PythonInfo[]>;
90
+ private _buildCandidates;
91
+ private _probe;
92
+ private _resolveExecutable;
93
+ private _which;
94
+ private _meetsVersionRequirement;
95
+ private _checkModules;
96
+ }
97
+ export declare class PythonNotFoundError extends Error {
98
+ constructor(message: string);
99
+ }
100
+ export declare class PythonVersionError extends Error {
101
+ constructor(found: string, required: string);
102
+ }
103
+ //# sourceMappingURL=PythonDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PythonDetector.d.ts","sourceRoot":"","sources":["../../src/env/PythonDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAWH,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,YAAY,EAAE,OAAO,CAAC;IACtB,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AA0ED;;;;;;;;;;GAUG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;gBAEtC,OAAO,GAAE,eAAoB;IAYzC;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC;IAkCnC;;;OAGG;IACH,KAAK,CAAC,cAAc,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO;IAIvC;;;OAGG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;IAI7D;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IActC,OAAO,CAAC,gBAAgB;IAuCxB,OAAO,CAAC,MAAM;IAmDd,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,MAAM;IAiBd,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,aAAa;CAwBtB;AAID,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAO5C"}
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+ /**
3
+ * nodepyx — PythonDetector
4
+ * Locates a usable Python interpreter on the host system.
5
+ *
6
+ * Detection order:
7
+ * 1. nodepyx_PYTHON environment variable
8
+ * 2. Explicit pythonPath from nodepyxConfig
9
+ * 3. Virtualenv / Conda path from config
10
+ * 4. python3 / python3.x on PATH
11
+ * 5. python on PATH
12
+ * 6. Common installation locations (Windows/macOS/Linux)
13
+ *
14
+ * Validates:
15
+ * - Python version ≥ 3.8
16
+ * - Not a stub (pyenv shim without real installation)
17
+ * - Has required modules available (when requested)
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.PythonVersionError = exports.PythonNotFoundError = exports.PythonDetector = void 0;
54
+ const child_process_1 = require("child_process");
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ const Logger_1 = require("../utils/Logger");
58
+ const logger = new Logger_1.Logger('PythonDetector');
59
+ // ─── Platform-specific common locations ─────────────────────────────────────
60
+ const COMMON_LOCATIONS = {
61
+ linux: [
62
+ '/usr/bin/python3',
63
+ '/usr/local/bin/python3',
64
+ '/opt/conda/bin/python3',
65
+ '/usr/bin/python3.12',
66
+ '/usr/bin/python3.11',
67
+ '/usr/bin/python3.10',
68
+ '/usr/bin/python3.9',
69
+ '/usr/bin/python3.8',
70
+ '/usr/bin/python',
71
+ ],
72
+ darwin: [
73
+ '/usr/local/bin/python3',
74
+ '/opt/homebrew/bin/python3',
75
+ '/opt/homebrew/bin/python3.12',
76
+ '/opt/homebrew/bin/python3.11',
77
+ '/opt/homebrew/bin/python3.10',
78
+ '/Library/Frameworks/Python.framework/Versions/3.12/bin/python3',
79
+ '/Library/Frameworks/Python.framework/Versions/3.11/bin/python3',
80
+ '/Library/Frameworks/Python.framework/Versions/3.10/bin/python3',
81
+ '/usr/bin/python3',
82
+ '/usr/bin/python',
83
+ ],
84
+ win32: [
85
+ 'C:\\Python312\\python.exe',
86
+ 'C:\\Python311\\python.exe',
87
+ 'C:\\Python310\\python.exe',
88
+ 'C:\\Python39\\python.exe',
89
+ 'C:\\Python38\\python.exe',
90
+ `${process.env.LOCALAPPDATA}\\Programs\\Python\\Python312\\python.exe`,
91
+ `${process.env.LOCALAPPDATA}\\Programs\\Python\\Python311\\python.exe`,
92
+ `${process.env.LOCALAPPDATA}\\Programs\\Python\\Python310\\python.exe`,
93
+ `${process.env.APPDATA}\\Python\\Python312\\python.exe`,
94
+ ],
95
+ aix: [],
96
+ android: [],
97
+ cygwin: [],
98
+ freebsd: [],
99
+ haiku: [],
100
+ netbsd: [],
101
+ openbsd: [],
102
+ sunos: [],
103
+ };
104
+ // Python info extraction script
105
+ const PROBE_SCRIPT = `
106
+ import sys, os, json
107
+ prefix = sys.prefix
108
+ is_venv = (
109
+ hasattr(sys, 'real_prefix') or
110
+ (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix)
111
+ )
112
+ is_conda = 'conda' in sys.version or os.path.exists(os.path.join(prefix, 'conda-meta'))
113
+ conda_env = os.environ.get('CONDA_DEFAULT_ENV')
114
+ info = {
115
+ 'version': '.'.join(map(str, sys.version_info[:3])),
116
+ 'major': sys.version_info.major,
117
+ 'minor': sys.version_info.minor,
118
+ 'patch': sys.version_info.micro,
119
+ 'prefix': prefix,
120
+ 'is_venv': is_venv,
121
+ 'is_conda': is_conda,
122
+ 'conda_env': conda_env,
123
+ 'platform': sys.platform,
124
+ 'arch': __import__('platform').machine(),
125
+ }
126
+ print(json.dumps(info))
127
+ `.trim();
128
+ /**
129
+ * PythonDetector — locates a usable Python interpreter.
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * const detector = new PythonDetector({ minVersion: [3, 9] });
134
+ * const info = await detector.detect();
135
+ * console.log(info.executable); // /usr/bin/python3
136
+ * console.log(info.version); // 3.11.4
137
+ * ```
138
+ */
139
+ class PythonDetector {
140
+ _opts;
141
+ constructor(options = {}) {
142
+ this._opts = {
143
+ minVersion: options.minVersion ?? [3, 8],
144
+ pythonPath: options.pythonPath ?? '',
145
+ timeout: options.timeout ?? 10_000,
146
+ explicitOnly: options.explicitOnly ?? false,
147
+ requiredModules: options.requiredModules ?? [],
148
+ };
149
+ }
150
+ // ─── Public API ──────────────────────────────────────────────────────────
151
+ /**
152
+ * Detect and validate a Python interpreter.
153
+ * Returns the first suitable interpreter found.
154
+ * Throws if no suitable interpreter is found.
155
+ */
156
+ async detect() {
157
+ const candidates = this._buildCandidates();
158
+ for (const candidate of candidates) {
159
+ const info = this._probe(candidate);
160
+ if (!info) {
161
+ continue;
162
+ }
163
+ if (!this._meetsVersionRequirement(info)) {
164
+ logger.debug(`PythonDetector: ${candidate} — version ${info.version} < ${this._opts.minVersion.join('.')}`);
165
+ continue;
166
+ }
167
+ if (this._opts.requiredModules.length > 0) {
168
+ const missing = this._checkModules(info.executable, this._opts.requiredModules);
169
+ if (missing.length > 0) {
170
+ logger.debug(`PythonDetector: ${candidate} — missing modules: ${missing.join(', ')}`);
171
+ continue;
172
+ }
173
+ }
174
+ logger.info(`PythonDetector: using ${info.executable} (${info.version})`);
175
+ return info;
176
+ }
177
+ throw new PythonNotFoundError(`Could not find a suitable Python interpreter (>= ${this._opts.minVersion.join('.')}).` +
178
+ '\nSolutions:' +
179
+ '\n 1. Install Python 3.8+: https://python.org' +
180
+ '\n 2. Set nodepyx_PYTHON env var to the Python executable path' +
181
+ '\n 3. Pass pythonPath in the nodepyx config' +
182
+ '\n 4. Create a virtualenv: nodepyx.init({ virtualenv: { path: ".venv", packages: [] } })');
183
+ }
184
+ /**
185
+ * Probe a specific Python executable and return its info.
186
+ * Returns null if the executable is invalid or doesn't exist.
187
+ */
188
+ probe(executablePath) {
189
+ return this._probe(executablePath);
190
+ }
191
+ /**
192
+ * Check if a Python executable meets the minimum version requirement.
193
+ */
194
+ isCompatible(info) {
195
+ return this._meetsVersionRequirement(info);
196
+ }
197
+ /**
198
+ * Check which required modules are missing for a given Python.
199
+ * Returns an empty array if all modules are available.
200
+ */
201
+ checkModules(executable, modules) {
202
+ return this._checkModules(executable, modules);
203
+ }
204
+ /**
205
+ * List all Python executables found in common locations and PATH.
206
+ */
207
+ async listAll() {
208
+ const results = [];
209
+ const candidates = this._buildCandidates();
210
+ for (const candidate of candidates) {
211
+ const info = this._probe(candidate);
212
+ if (info) {
213
+ results.push(info);
214
+ }
215
+ }
216
+ return results;
217
+ }
218
+ // ─── Private ─────────────────────────────────────────────────────────────
219
+ _buildCandidates() {
220
+ const candidates = [];
221
+ // 1. nodepyx_PYTHON env var (highest priority)
222
+ if (process.env.nodepyx_PYTHON) {
223
+ candidates.push(process.env.nodepyx_PYTHON);
224
+ }
225
+ // 2. Explicit config path
226
+ if (this._opts.pythonPath) {
227
+ candidates.push(this._opts.pythonPath);
228
+ // Also try bin/python inside a venv/conda root
229
+ const binDir = process.platform === 'win32' ? 'Scripts' : 'bin';
230
+ candidates.push(path.join(this._opts.pythonPath, binDir, 'python3'));
231
+ candidates.push(path.join(this._opts.pythonPath, binDir, 'python'));
232
+ }
233
+ if (this._opts.explicitOnly) {
234
+ return candidates;
235
+ }
236
+ // 3. PATH candidates
237
+ const pathCandidates = [
238
+ 'python3.12', 'python3.11', 'python3.10', 'python3.9', 'python3.8',
239
+ 'python3', 'python',
240
+ ];
241
+ for (const name of pathCandidates) {
242
+ const found = this._which(name);
243
+ if (found) {
244
+ candidates.push(found);
245
+ }
246
+ }
247
+ // 4. Common installation locations
248
+ const platformKey = process.platform;
249
+ for (const loc of COMMON_LOCATIONS[platformKey] ?? []) {
250
+ if (loc) {
251
+ candidates.push(loc);
252
+ }
253
+ }
254
+ // Deduplicate while preserving order
255
+ return [...new Set(candidates)];
256
+ }
257
+ _probe(executable) {
258
+ if (!executable) {
259
+ return null;
260
+ }
261
+ try {
262
+ // Resolve Windows executable extension
263
+ const exec = this._resolveExecutable(executable);
264
+ if (!exec) {
265
+ return null;
266
+ }
267
+ const result = (0, child_process_1.spawnSync)(exec, ['-c', PROBE_SCRIPT], {
268
+ encoding: 'utf8',
269
+ timeout: this._opts.timeout,
270
+ maxBuffer: 1024 * 1024,
271
+ env: { ...process.env, PYTHONDONTWRITEBYTECODE: '1' },
272
+ });
273
+ if (result.status !== 0 || result.error || !result.stdout.trim()) {
274
+ return null;
275
+ }
276
+ const raw = JSON.parse(result.stdout.trim());
277
+ return {
278
+ executable: exec,
279
+ version: raw.version,
280
+ major: raw.major,
281
+ minor: raw.minor,
282
+ patch: raw.patch,
283
+ prefix: raw.prefix,
284
+ isVirtualenv: raw.is_venv,
285
+ isConda: raw.is_conda,
286
+ condaEnv: raw.conda_env ?? undefined,
287
+ platform: raw.platform,
288
+ arch: raw.arch,
289
+ };
290
+ }
291
+ catch (err) {
292
+ logger.debug(`PythonDetector._probe(${executable}) failed`, err);
293
+ return null;
294
+ }
295
+ }
296
+ _resolveExecutable(exec) {
297
+ // Absolute path — check existence
298
+ if (path.isAbsolute(exec)) {
299
+ if (fs.existsSync(exec)) {
300
+ return exec;
301
+ }
302
+ // Try with .exe on Windows
303
+ if (process.platform === 'win32' && !exec.endsWith('.exe')) {
304
+ const withExt = exec + '.exe';
305
+ if (fs.existsSync(withExt)) {
306
+ return withExt;
307
+ }
308
+ }
309
+ return null;
310
+ }
311
+ // Relative name — resolve via which
312
+ return this._which(exec);
313
+ }
314
+ _which(name) {
315
+ try {
316
+ const cmd = process.platform === 'win32' ? `where ${name}` : `which ${name}`;
317
+ const result = (0, child_process_1.execSync)(cmd, {
318
+ encoding: 'utf8',
319
+ timeout: 3000,
320
+ stdio: ['pipe', 'pipe', 'pipe'],
321
+ }).trim();
322
+ // `where` returns multiple lines; take the first
323
+ const first = result.split(/\r?\n/)[0]?.trim();
324
+ return first || null;
325
+ }
326
+ catch {
327
+ return null;
328
+ }
329
+ }
330
+ _meetsVersionRequirement(info) {
331
+ const [minMajor, minMinor] = this._opts.minVersion;
332
+ if (info.major !== minMajor) {
333
+ return info.major > minMajor;
334
+ }
335
+ return info.minor >= minMinor;
336
+ }
337
+ _checkModules(executable, modules) {
338
+ if (modules.length === 0) {
339
+ return [];
340
+ }
341
+ const script = modules
342
+ .map(m => `try:\n import ${m}\nexcept ImportError:\n print("MISSING:${m}")`)
343
+ .join('\n');
344
+ try {
345
+ const result = (0, child_process_1.spawnSync)(executable, ['-c', script], {
346
+ encoding: 'utf8',
347
+ timeout: this._opts.timeout,
348
+ maxBuffer: 1024 * 256,
349
+ });
350
+ const missing = [];
351
+ for (const line of (result.stdout ?? '').split('\n')) {
352
+ const match = line.match(/^MISSING:(.+)$/);
353
+ if (match) {
354
+ missing.push(match[1]);
355
+ }
356
+ }
357
+ return missing;
358
+ }
359
+ catch {
360
+ return modules; // assume all missing if we can't check
361
+ }
362
+ }
363
+ }
364
+ exports.PythonDetector = PythonDetector;
365
+ // ─── Error types ─────────────────────────────────────────────────────────────
366
+ class PythonNotFoundError extends Error {
367
+ constructor(message) {
368
+ super(message);
369
+ this.name = 'PythonNotFoundError';
370
+ }
371
+ }
372
+ exports.PythonNotFoundError = PythonNotFoundError;
373
+ class PythonVersionError extends Error {
374
+ constructor(found, required) {
375
+ super(`Python ${found} is below the minimum required version ${required}. ` +
376
+ `Please upgrade Python.`);
377
+ this.name = 'PythonVersionError';
378
+ }
379
+ }
380
+ exports.PythonVersionError = PythonVersionError;
381
+ //# sourceMappingURL=PythonDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PythonDetector.js","sourceRoot":"","sources":["../../src/env/PythonDetector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * nodepyx — VenvManager
3
+ * Creates and manages Python virtualenvs for isolated package installation.
4
+ *
5
+ * Lifecycle:
6
+ * 1. Check if the venv directory exists and is valid.
7
+ * 2. If not, run `python3 -m venv <path>` to create it.
8
+ * 3. Upgrade pip to the latest version.
9
+ * 4. Install configured packages via pip.
10
+ * 5. Return the path to the Python executable inside the venv.
11
+ *
12
+ * State file (.nodepyx/venv-state.json) tracks installed packages
13
+ * to avoid re-running pip on every startup.
14
+ */
15
+ import type { VirtualenvConfig } from '../types/config';
16
+ export interface VenvState {
17
+ /** Venv creation timestamp */
18
+ createdAt: number;
19
+ /** Python version used to create the venv */
20
+ pythonVersion: string;
21
+ /** Packages that have been installed (pip-freeze style name==version) */
22
+ installedPackages: string[];
23
+ /** Last pip install timestamp */
24
+ lastInstallAt: number;
25
+ }
26
+ export interface VenvSetupResult {
27
+ /** Absolute path to Python executable inside the venv */
28
+ pythonExecutable: string;
29
+ /** Absolute path to pip executable */
30
+ pipExecutable: string;
31
+ /** Whether the venv was newly created */
32
+ created: boolean;
33
+ /** Whether packages were (re)installed */
34
+ packagesInstalled: boolean;
35
+ }
36
+ export interface VenvManagerOptions {
37
+ /** Virtualenv config from nodepyxConfig */
38
+ virtualenv: VirtualenvConfig;
39
+ /** Base Python executable to use for creating the venv */
40
+ basePython?: string;
41
+ /** Timeout for pip install in ms. Default: 300000 (5 minutes) */
42
+ installTimeout?: number;
43
+ /** Skip upgrading pip. Default: false */
44
+ skipPipUpgrade?: boolean;
45
+ }
46
+ /**
47
+ * VenvManager — creates and manages Python virtualenvs.
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const manager = new VenvManager({
52
+ * virtualenv: {
53
+ * path: './.venv',
54
+ * packages: ['pandas', 'numpy', 'scikit-learn'],
55
+ * autoInstall: true,
56
+ * }
57
+ * });
58
+ *
59
+ * const result = await manager.setup();
60
+ * console.log(result.pythonExecutable); // ./.venv/bin/python3
61
+ * ```
62
+ */
63
+ export declare class VenvManager {
64
+ private readonly _config;
65
+ private readonly _basePython;
66
+ private readonly _installTimeout;
67
+ private readonly _skipPipUpgrade;
68
+ private readonly _venvPath;
69
+ private readonly _statePath;
70
+ constructor(options: VenvManagerOptions);
71
+ /**
72
+ * Set up the virtualenv and install packages if needed.
73
+ * Returns the path to the Python executable inside the venv.
74
+ */
75
+ setup(): Promise<VenvSetupResult>;
76
+ /**
77
+ * Install additional packages into the venv.
78
+ */
79
+ install(packages: string[]): Promise<void>;
80
+ /**
81
+ * Check which of the configured packages are not installed in the venv.
82
+ */
83
+ getMissingPackages(): string[];
84
+ /**
85
+ * Return the Python executable path inside the venv (without setup).
86
+ */
87
+ get pythonExecutable(): string;
88
+ /**
89
+ * Return true if the venv exists and appears valid.
90
+ */
91
+ isValid(): boolean;
92
+ /**
93
+ * Destroy the venv directory.
94
+ */
95
+ destroy(): void;
96
+ /**
97
+ * Return the list of installed packages (pip freeze format).
98
+ */
99
+ listInstalled(): string[];
100
+ private _venvExists;
101
+ private _createVenv;
102
+ private _upgradePip;
103
+ private _installPackages;
104
+ private _findMissingPackages;
105
+ private _packageToImportName;
106
+ private _updateState;
107
+ private _loadState;
108
+ private _getPythonVersion;
109
+ }
110
+ export declare class VenvCreationError extends Error {
111
+ constructor(message: string);
112
+ }
113
+ export declare class PackageInstallError extends Error {
114
+ readonly packages: string[];
115
+ constructor(packages: string[], detail: string);
116
+ }
117
+ //# sourceMappingURL=VenvManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VenvManager.d.ts","sourceRoot":"","sources":["../../src/env/VenvManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAMxD,MAAM,WAAW,SAAS;IACxB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,UAAU,EAAE,gBAAgB,CAAC;IAC7B,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AA4BD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,OAAO,EAAE,kBAAkB;IAWvC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,eAAe,CAAC;IA2CvC;;OAEG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAK9B;;OAEG;IACH,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,OAAO,IAAI,IAAI;IAOf;;OAEG;IACH,aAAa,IAAI,MAAM,EAAE;IAOzB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,WAAW;IAwBnB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,iBAAiB;CAY1B;AAID,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;gBAChB,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM;CAK/C"}