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.
- package/LICENSE +22 -0
- package/README.md +399 -0
- package/binding.gyp +73 -0
- package/dist/core/PyCallable.d.ts +65 -0
- package/dist/core/PyCallable.d.ts.map +1 -0
- package/dist/core/PyCallable.js +109 -0
- package/dist/core/PyCallable.js.map +1 -0
- package/dist/core/PyContext.d.ts +76 -0
- package/dist/core/PyContext.d.ts.map +1 -0
- package/dist/core/PyContext.js +228 -0
- package/dist/core/PyContext.js.map +1 -0
- package/dist/core/PyIterator.d.ts +84 -0
- package/dist/core/PyIterator.d.ts.map +1 -0
- package/dist/core/PyIterator.js +243 -0
- package/dist/core/PyIterator.js.map +1 -0
- package/dist/core/PyModule.d.ts +55 -0
- package/dist/core/PyModule.d.ts.map +1 -0
- package/dist/core/PyModule.js +172 -0
- package/dist/core/PyModule.js.map +1 -0
- package/dist/core/PyProxy.d.ts +65 -0
- package/dist/core/PyProxy.d.ts.map +1 -0
- package/dist/core/PyProxy.js +483 -0
- package/dist/core/PyProxy.js.map +1 -0
- package/dist/core/PyRuntime.d.ts +105 -0
- package/dist/core/PyRuntime.d.ts.map +1 -0
- package/dist/core/PyRuntime.js +438 -0
- package/dist/core/PyRuntime.js.map +1 -0
- package/dist/env/CondaManager.d.ts +118 -0
- package/dist/env/CondaManager.d.ts.map +1 -0
- package/dist/env/CondaManager.js +401 -0
- package/dist/env/CondaManager.js.map +1 -0
- package/dist/env/PackageInstaller.d.ts +233 -0
- package/dist/env/PackageInstaller.d.ts.map +1 -0
- package/dist/env/PackageInstaller.js +609 -0
- package/dist/env/PackageInstaller.js.map +1 -0
- package/dist/env/PythonDetector.d.ts +103 -0
- package/dist/env/PythonDetector.d.ts.map +1 -0
- package/dist/env/PythonDetector.js +381 -0
- package/dist/env/PythonDetector.js.map +1 -0
- package/dist/env/VenvManager.d.ts +117 -0
- package/dist/env/VenvManager.d.ts.map +1 -0
- package/dist/env/VenvManager.js +331 -0
- package/dist/env/VenvManager.js.map +1 -0
- package/dist/index.d.ts +169 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +393 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/Plugin.interface.d.ts +41 -0
- package/dist/plugins/Plugin.interface.d.ts.map +1 -0
- package/dist/plugins/Plugin.interface.js +12 -0
- package/dist/plugins/Plugin.interface.js.map +1 -0
- package/dist/plugins/PluginManager.d.ts +26 -0
- package/dist/plugins/PluginManager.d.ts.map +1 -0
- package/dist/plugins/PluginManager.js +174 -0
- package/dist/plugins/PluginManager.js.map +1 -0
- package/dist/plugins/builtin/NumpyPlugin.d.ts +17 -0
- package/dist/plugins/builtin/NumpyPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/NumpyPlugin.js +41 -0
- package/dist/plugins/builtin/NumpyPlugin.js.map +1 -0
- package/dist/plugins/builtin/PandasPlugin.d.ts +19 -0
- package/dist/plugins/builtin/PandasPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/PandasPlugin.js +57 -0
- package/dist/plugins/builtin/PandasPlugin.js.map +1 -0
- package/dist/plugins/builtin/TorchPlugin.d.ts +23 -0
- package/dist/plugins/builtin/TorchPlugin.d.ts.map +1 -0
- package/dist/plugins/builtin/TorchPlugin.js +50 -0
- package/dist/plugins/builtin/TorchPlugin.js.map +1 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +12 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/serialization/DataFrameBridge.d.ts +141 -0
- package/dist/serialization/DataFrameBridge.d.ts.map +1 -0
- package/dist/serialization/DataFrameBridge.js +355 -0
- package/dist/serialization/DataFrameBridge.js.map +1 -0
- package/dist/serialization/MsgPackSerializer.d.ts +45 -0
- package/dist/serialization/MsgPackSerializer.d.ts.map +1 -0
- package/dist/serialization/MsgPackSerializer.js +242 -0
- package/dist/serialization/MsgPackSerializer.js.map +1 -0
- package/dist/serialization/NumpyBridge.d.ts +96 -0
- package/dist/serialization/NumpyBridge.d.ts.map +1 -0
- package/dist/serialization/NumpyBridge.js +323 -0
- package/dist/serialization/NumpyBridge.js.map +1 -0
- package/dist/serialization/Serializer.d.ts +78 -0
- package/dist/serialization/Serializer.d.ts.map +1 -0
- package/dist/serialization/Serializer.js +281 -0
- package/dist/serialization/Serializer.js.map +1 -0
- package/dist/types/PythonTypeMapper.d.ts +87 -0
- package/dist/types/PythonTypeMapper.d.ts.map +1 -0
- package/dist/types/PythonTypeMapper.js +449 -0
- package/dist/types/PythonTypeMapper.js.map +1 -0
- package/dist/types/StubCache.d.ts +109 -0
- package/dist/types/StubCache.d.ts.map +1 -0
- package/dist/types/StubCache.js +333 -0
- package/dist/types/StubCache.js.map +1 -0
- package/dist/types/TypeGenerator.d.ts +139 -0
- package/dist/types/TypeGenerator.d.ts.map +1 -0
- package/dist/types/TypeGenerator.js +372 -0
- package/dist/types/TypeGenerator.js.map +1 -0
- package/dist/types/addon.d.ts +114 -0
- package/dist/types/addon.d.ts.map +1 -0
- package/dist/types/addon.js +32 -0
- package/dist/types/addon.js.map +1 -0
- package/dist/types/config.d.ts +175 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +35 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +12 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/python.d.ts +235 -0
- package/dist/types/python.d.ts.map +1 -0
- package/dist/types/python.js +7 -0
- package/dist/types/python.js.map +1 -0
- package/dist/utils/ErrorTranslator.d.ts +83 -0
- package/dist/utils/ErrorTranslator.d.ts.map +1 -0
- package/dist/utils/ErrorTranslator.js +210 -0
- package/dist/utils/ErrorTranslator.js.map +1 -0
- package/dist/utils/Logger.d.ts +27 -0
- package/dist/utils/Logger.d.ts.map +1 -0
- package/dist/utils/Logger.js +115 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/MemoryMonitor.d.ts +44 -0
- package/dist/utils/MemoryMonitor.d.ts.map +1 -0
- package/dist/utils/MemoryMonitor.js +143 -0
- package/dist/utils/MemoryMonitor.js.map +1 -0
- package/package.json +177 -0
- package/python/error_handler.py +433 -0
- package/python/nodepyx_runtime.py +575 -0
- package/python/serializer.py +379 -0
- package/python/type_inspector.py +288 -0
- package/scripts/build-native.js +68 -0
- package/scripts/download-prebuilds.js +99 -0
- package/scripts/generate-stubs.js +405 -0
- package/scripts/install.js +260 -0
- package/src/core/PyCallable.ts +137 -0
- package/src/core/PyContext.ts +296 -0
- package/src/core/PyIterator.ts +294 -0
- package/src/core/PyModule.ts +194 -0
- package/src/core/PyProxy.ts +605 -0
- package/src/core/PyRuntime.ts +504 -0
- package/src/env/CondaManager.ts +451 -0
- package/src/env/PackageInstaller.ts +738 -0
- package/src/env/PythonDetector.ts +414 -0
- package/src/env/VenvManager.ts +396 -0
- package/src/index.ts +425 -0
- package/src/native/gil_guard.cpp +26 -0
- package/src/native/gil_guard.h +175 -0
- package/src/native/nodepyx_addon.cpp +886 -0
- package/src/native/python_bridge.cpp +790 -0
- package/src/native/python_bridge.h +257 -0
- package/src/native/thread_pool.cpp +336 -0
- package/src/native/thread_pool.h +175 -0
- package/src/native/type_converter.cpp +901 -0
- package/src/native/type_converter.h +272 -0
- package/src/nextjs/PyProvider.tsx +123 -0
- package/src/nextjs/index.ts +21 -0
- package/src/nextjs/usePython.ts +106 -0
- package/src/nextjs/withnodepyx.ts +88 -0
- package/src/plugins/Plugin.interface.ts +51 -0
- package/src/plugins/PluginManager.ts +155 -0
- package/src/plugins/builtin/NumpyPlugin.ts +36 -0
- package/src/plugins/builtin/PandasPlugin.ts +49 -0
- package/src/plugins/builtin/TorchPlugin.ts +56 -0
- package/src/plugins/index.ts +7 -0
- package/src/serialization/DataFrameBridge.ts +398 -0
- package/src/serialization/MsgPackSerializer.ts +220 -0
- package/src/serialization/NumpyBridge.ts +332 -0
- package/src/serialization/Serializer.ts +320 -0
- package/src/types/PythonTypeMapper.ts +495 -0
- package/src/types/StubCache.ts +340 -0
- package/src/types/TypeGenerator.ts +491 -0
- package/src/types/addon.ts +170 -0
- package/src/types/config.ts +226 -0
- package/src/types/index.ts +55 -0
- package/src/types/python.ts +309 -0
- package/src/types/stubs/numpy.d.ts +441 -0
- package/src/types/stubs/pandas.d.ts +575 -0
- package/src/types/stubs/sklearn.d.ts +728 -0
- package/src/types/stubs/torch.d.ts +694 -0
- package/src/utils/ErrorTranslator.ts +220 -0
- package/src/utils/Logger.ts +119 -0
- package/src/utils/MemoryMonitor.ts +175 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nodepyx — Thread Pool Header
|
|
3
|
+
* Manages a pool of worker threads for executing Python code
|
|
4
|
+
* without blocking the Node.js event loop.
|
|
5
|
+
*
|
|
6
|
+
* Design:
|
|
7
|
+
* - Worker threads acquire the GIL before running Python
|
|
8
|
+
* - Tasks are queued using a lock-free MPMC queue
|
|
9
|
+
* - Results are delivered back to Node.js via libuv async handles
|
|
10
|
+
* - Backpressure is applied when queue exceeds maxQueueSize
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
#pragma once
|
|
14
|
+
|
|
15
|
+
#include <napi.h>
|
|
16
|
+
#include <functional>
|
|
17
|
+
#include <memory>
|
|
18
|
+
#include <thread>
|
|
19
|
+
#include <mutex>
|
|
20
|
+
#include <condition_variable>
|
|
21
|
+
#include <deque>
|
|
22
|
+
#include <atomic>
|
|
23
|
+
#include <string>
|
|
24
|
+
#include <vector>
|
|
25
|
+
#include <chrono>
|
|
26
|
+
|
|
27
|
+
namespace nodepyx {
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Task result — carries either a success value or an error.
|
|
31
|
+
*/
|
|
32
|
+
struct TaskResult {
|
|
33
|
+
bool success = false;
|
|
34
|
+
std::string resultJson; // JSON-encoded result for JS
|
|
35
|
+
std::string errorType; // Python exception type
|
|
36
|
+
std::string errorMessage; // Python exception message
|
|
37
|
+
std::string errorTraceback; // Full Python traceback
|
|
38
|
+
uint32_t objectId = 0; // For Python object references
|
|
39
|
+
bool isObject = false; // Whether result is a Python object ref
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A task to be executed in the Python thread pool.
|
|
44
|
+
*/
|
|
45
|
+
struct PythonTask {
|
|
46
|
+
/** Unique task ID for tracking */
|
|
47
|
+
uint64_t id;
|
|
48
|
+
/** The actual Python work to do (runs with GIL held) */
|
|
49
|
+
std::function<TaskResult()> work;
|
|
50
|
+
/** Callback invoked in the event loop thread with the result */
|
|
51
|
+
std::function<void(TaskResult)> callback;
|
|
52
|
+
/** Timestamp when task was submitted (for timeout tracking) */
|
|
53
|
+
std::chrono::steady_clock::time_point submittedAt;
|
|
54
|
+
/** Timeout in milliseconds (0 = no timeout) */
|
|
55
|
+
uint32_t timeoutMs;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Pool statistics for monitoring.
|
|
60
|
+
*/
|
|
61
|
+
struct PoolStats {
|
|
62
|
+
std::atomic<uint64_t> totalTasksSubmitted{0};
|
|
63
|
+
std::atomic<uint64_t> totalTasksCompleted{0};
|
|
64
|
+
std::atomic<uint64_t> totalTasksFailed{0};
|
|
65
|
+
std::atomic<uint64_t> totalTasksTimedOut{0};
|
|
66
|
+
std::atomic<uint64_t> currentQueueSize{0};
|
|
67
|
+
std::atomic<uint32_t> activeThreads{0};
|
|
68
|
+
std::atomic<uint64_t> totalExecutionTimeUs{0};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* PythonThreadPool — manages N worker threads that execute Python tasks.
|
|
73
|
+
*
|
|
74
|
+
* Thread lifecycle:
|
|
75
|
+
* 1. Worker thread starts and calls PyEval_RestoreThread to get GIL state
|
|
76
|
+
* 2. Worker enters wait loop (releases GIL while waiting for work)
|
|
77
|
+
* 3. When task arrives, worker acquires GIL, executes task, releases GIL
|
|
78
|
+
* 4. Result is posted back to JS via libuv
|
|
79
|
+
*/
|
|
80
|
+
class PythonThreadPool {
|
|
81
|
+
public:
|
|
82
|
+
explicit PythonThreadPool(uint32_t numThreads = 4, uint32_t maxQueueSize = 1000);
|
|
83
|
+
~PythonThreadPool();
|
|
84
|
+
|
|
85
|
+
// Non-copyable, non-movable
|
|
86
|
+
PythonThreadPool(const PythonThreadPool&) = delete;
|
|
87
|
+
PythonThreadPool& operator=(const PythonThreadPool&) = delete;
|
|
88
|
+
PythonThreadPool(PythonThreadPool&&) = delete;
|
|
89
|
+
PythonThreadPool& operator=(PythonThreadPool&&) = delete;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Initialize the thread pool. Must be called from the main thread
|
|
93
|
+
* after Python is initialized (Py_Initialize() called).
|
|
94
|
+
*/
|
|
95
|
+
void initialize(Napi::Env env);
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Submit a task to the pool. Thread-safe.
|
|
99
|
+
*
|
|
100
|
+
* @param work - Function to run with GIL held in a worker thread
|
|
101
|
+
* @param callback - Function to call in event loop with result
|
|
102
|
+
* @param timeoutMs - Task timeout in milliseconds (0 = no timeout)
|
|
103
|
+
* @returns task ID, or 0 if queue is full
|
|
104
|
+
*/
|
|
105
|
+
uint64_t submit(
|
|
106
|
+
std::function<TaskResult()> work,
|
|
107
|
+
std::function<void(TaskResult)> callback,
|
|
108
|
+
uint32_t timeoutMs = 0
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Resize the thread pool. Blocks until all queued tasks complete.
|
|
113
|
+
*/
|
|
114
|
+
void resize(uint32_t newNumThreads);
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Graceful shutdown — waits for all queued tasks to complete.
|
|
118
|
+
*/
|
|
119
|
+
void shutdown();
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Force shutdown — cancels queued tasks, waits for active tasks.
|
|
123
|
+
*/
|
|
124
|
+
void forceShutdown();
|
|
125
|
+
|
|
126
|
+
/** Get current pool statistics */
|
|
127
|
+
const PoolStats& getStats() const noexcept { return _stats; }
|
|
128
|
+
|
|
129
|
+
/** Get number of pending tasks in queue */
|
|
130
|
+
size_t getQueueSize() const;
|
|
131
|
+
|
|
132
|
+
/** Get number of active worker threads */
|
|
133
|
+
uint32_t getActiveThreadCount() const noexcept { return _stats.activeThreads.load(); }
|
|
134
|
+
|
|
135
|
+
/** Get total thread count */
|
|
136
|
+
uint32_t getThreadCount() const noexcept { return static_cast<uint32_t>(_threads.size()); }
|
|
137
|
+
|
|
138
|
+
/** Check if pool is running */
|
|
139
|
+
bool isRunning() const noexcept { return _running.load(); }
|
|
140
|
+
|
|
141
|
+
private:
|
|
142
|
+
/** Worker thread entry point */
|
|
143
|
+
void _workerThread(uint32_t threadId);
|
|
144
|
+
|
|
145
|
+
/** Post result back to event loop via libuv */
|
|
146
|
+
void _postResult(uint64_t taskId, TaskResult result, std::function<void(TaskResult)> callback);
|
|
147
|
+
|
|
148
|
+
/** Check and handle task timeout */
|
|
149
|
+
bool _isTimedOut(const PythonTask& task) const;
|
|
150
|
+
|
|
151
|
+
uint32_t _numThreads;
|
|
152
|
+
uint32_t _maxQueueSize;
|
|
153
|
+
std::atomic<bool> _running{false};
|
|
154
|
+
std::atomic<bool> _draining{false};
|
|
155
|
+
std::atomic<uint64_t> _nextTaskId{1};
|
|
156
|
+
|
|
157
|
+
// Task queue
|
|
158
|
+
std::deque<PythonTask> _queue;
|
|
159
|
+
mutable std::mutex _queueMutex;
|
|
160
|
+
std::condition_variable _queueCv;
|
|
161
|
+
std::condition_variable _drainCv;
|
|
162
|
+
|
|
163
|
+
// Worker threads
|
|
164
|
+
std::vector<std::thread> _threads;
|
|
165
|
+
|
|
166
|
+
// libuv async handle for posting results back to JS
|
|
167
|
+
// (Using Napi::ThreadSafeFunction for safe cross-thread callback)
|
|
168
|
+
Napi::ThreadSafeFunction _tsfn;
|
|
169
|
+
|
|
170
|
+
// Statistics
|
|
171
|
+
PoolStats _stats;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
} // namespace nodepyx
|
|
175
|
+
|