more-compute 0.1.4__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- frontend/app/globals.css +322 -77
- frontend/app/layout.tsx +98 -82
- frontend/components/Cell.tsx +234 -95
- frontend/components/Notebook.tsx +430 -199
- frontend/components/{AddCellButton.tsx → cell/AddCellButton.tsx} +0 -2
- frontend/components/cell/MonacoCell.tsx +726 -0
- frontend/components/layout/ConnectionBanner.tsx +41 -0
- frontend/components/{Sidebar.tsx → layout/Sidebar.tsx} +16 -11
- frontend/components/modals/ConfirmModal.tsx +154 -0
- frontend/components/modals/SuccessModal.tsx +140 -0
- frontend/components/output/MarkdownRenderer.tsx +116 -0
- frontend/components/popups/ComputePopup.tsx +674 -365
- frontend/components/popups/MetricsPopup.tsx +11 -7
- frontend/components/popups/SettingsPopup.tsx +11 -13
- frontend/contexts/PodWebSocketContext.tsx +247 -0
- frontend/eslint.config.mjs +11 -0
- frontend/lib/monaco-themes.ts +160 -0
- frontend/lib/settings.ts +128 -26
- frontend/lib/themes.json +9973 -0
- frontend/lib/websocket-native.ts +19 -8
- frontend/lib/websocket.ts +59 -11
- frontend/next.config.ts +8 -0
- frontend/package-lock.json +1705 -3
- frontend/package.json +8 -1
- frontend/styling_README.md +18 -0
- kernel_run.py +159 -42
- more_compute-0.2.1.dist-info/METADATA +126 -0
- more_compute-0.2.1.dist-info/RECORD +100 -0
- morecompute/__version__.py +1 -1
- morecompute/execution/executor.py +31 -20
- morecompute/execution/worker.py +68 -7
- morecompute/models/__init__.py +31 -0
- morecompute/models/api_models.py +197 -0
- morecompute/notebook.py +50 -7
- morecompute/server.py +574 -94
- morecompute/services/data_manager.py +379 -0
- morecompute/services/lsp_service.py +335 -0
- morecompute/services/pod_manager.py +122 -20
- morecompute/services/pod_monitor.py +138 -0
- morecompute/services/prime_intellect.py +87 -63
- morecompute/utils/config_util.py +59 -0
- morecompute/utils/special_commands.py +11 -5
- morecompute/utils/zmq_util.py +51 -0
- frontend/components/MarkdownRenderer.tsx +0 -84
- frontend/components/popups/PythonPopup.tsx +0 -292
- more_compute-0.1.4.dist-info/METADATA +0 -173
- more_compute-0.1.4.dist-info/RECORD +0 -86
- /frontend/components/{CellButton.tsx → cell/CellButton.tsx} +0 -0
- /frontend/components/{ErrorModal.tsx → modals/ErrorModal.tsx} +0 -0
- /frontend/components/{CellOutput.tsx → output/CellOutput.tsx} +0 -0
- /frontend/components/{ErrorDisplay.tsx → output/ErrorDisplay.tsx} +0 -0
- {more_compute-0.1.4.dist-info → more_compute-0.2.1.dist-info}/WHEEL +0 -0
- {more_compute-0.1.4.dist-info → more_compute-0.2.1.dist-info}/entry_points.txt +0 -0
- {more_compute-0.1.4.dist-info → more_compute-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {more_compute-0.1.4.dist-info → more_compute-0.2.1.dist-info}/top_level.txt +0 -0
frontend/package.json
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"@codemirror/theme-one-dark": "^6.1.3",
|
|
15
15
|
"@hugeicons/core-free-icons": "^1.1.0",
|
|
16
16
|
"@hugeicons/react": "^1.1.1",
|
|
17
|
+
"@monaco-editor/react": "^4.7.0",
|
|
17
18
|
"@radix-ui/react-icons": "^1.3.2",
|
|
18
19
|
"@types/socket.io-client": "^1.4.36",
|
|
19
20
|
"@uiw/react-codemirror": "^4.25.2",
|
|
@@ -21,11 +22,17 @@
|
|
|
21
22
|
"codemirror": "^5.65.2",
|
|
22
23
|
"framer-motion": "^12.23.22",
|
|
23
24
|
"lucide-react": "^0.544.0",
|
|
25
|
+
"monaco-editor": "^0.54.0",
|
|
26
|
+
"monaco-languageclient": "^10.2.0",
|
|
24
27
|
"next": "15.5.4",
|
|
25
28
|
"react": "19.1.0",
|
|
26
29
|
"react-dom": "19.1.0",
|
|
30
|
+
"react-window": "^2.2.1",
|
|
31
|
+
"react-window-infinite-loader": "^2.0.0",
|
|
27
32
|
"socket.io-client": "^4.8.1",
|
|
28
|
-
"sortablejs": "^1.15.3"
|
|
33
|
+
"sortablejs": "^1.15.3",
|
|
34
|
+
"vscode-languageclient": "^9.0.1",
|
|
35
|
+
"vscode-languageserver-protocol": "^3.17.5"
|
|
29
36
|
},
|
|
30
37
|
"devDependencies": {
|
|
31
38
|
"@eslint/eslintrc": "^3",
|
kernel_run.py
CHANGED
|
@@ -8,6 +8,7 @@ import time
|
|
|
8
8
|
import signal
|
|
9
9
|
import threading
|
|
10
10
|
import webbrowser
|
|
11
|
+
import platform
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
|
|
13
14
|
from morecompute.notebook import Notebook
|
|
@@ -22,6 +23,7 @@ class NotebookLauncher:
|
|
|
22
23
|
self.root_dir = Path(__file__).parent
|
|
23
24
|
self.debug = debug
|
|
24
25
|
self.notebook_path = notebook_path
|
|
26
|
+
self.is_windows = platform.system() == "Windows"
|
|
25
27
|
root_dir = notebook_path.parent if notebook_path.parent != Path('') else Path.cwd()
|
|
26
28
|
os.environ["MORECOMPUTE_ROOT"] = str(root_dir.resolve())
|
|
27
29
|
os.environ["MORECOMPUTE_NOTEBOOK_PATH"] = str(self.notebook_path)
|
|
@@ -78,48 +80,107 @@ class NotebookLauncher:
|
|
|
78
80
|
sys.exit(1)
|
|
79
81
|
|
|
80
82
|
def _ensure_port_available(self, port: int) -> None:
|
|
83
|
+
"""Cross-platform port availability check and cleanup"""
|
|
81
84
|
import socket
|
|
85
|
+
|
|
82
86
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
83
87
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
84
88
|
try:
|
|
85
89
|
s.bind(("127.0.0.1", port))
|
|
86
|
-
return # free
|
|
90
|
+
return # Port is free
|
|
87
91
|
except OSError:
|
|
88
|
-
pass # in use
|
|
89
|
-
|
|
90
|
-
print(f"\nPort {port}
|
|
92
|
+
pass # Port is in use
|
|
93
|
+
|
|
94
|
+
print(f"\nPort {port} is currently in use.")
|
|
91
95
|
pids = []
|
|
96
|
+
|
|
92
97
|
try:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
if self.is_windows:
|
|
99
|
+
# Windows: Use netstat
|
|
100
|
+
out = subprocess.check_output(
|
|
101
|
+
["netstat", "-ano"],
|
|
102
|
+
text=True,
|
|
103
|
+
encoding='utf-8',
|
|
104
|
+
errors='replace'
|
|
105
|
+
)
|
|
106
|
+
for line in out.splitlines():
|
|
107
|
+
if f":{port}" in line and "LISTENING" in line:
|
|
108
|
+
parts = line.split()
|
|
109
|
+
if parts and parts[-1].isdigit():
|
|
110
|
+
pid = int(parts[-1])
|
|
111
|
+
if pid not in pids:
|
|
112
|
+
pids.append(pid)
|
|
113
|
+
# Get process name
|
|
114
|
+
try:
|
|
115
|
+
proc_out = subprocess.check_output(
|
|
116
|
+
["tasklist", "/FI", f"PID eq {pid}", "/FO", "CSV", "/NH"],
|
|
117
|
+
text=True,
|
|
118
|
+
encoding='utf-8',
|
|
119
|
+
errors='replace'
|
|
120
|
+
)
|
|
121
|
+
proc_name = proc_out.split(',')[0].strip('"')
|
|
122
|
+
print(f" PID {pid}: {proc_name}")
|
|
123
|
+
except Exception:
|
|
124
|
+
print(f" PID {pid}")
|
|
125
|
+
else:
|
|
126
|
+
# Unix: Use lsof
|
|
127
|
+
out = subprocess.check_output(
|
|
128
|
+
["lsof", "-nP", f"-iTCP:{port}", "-sTCP:LISTEN"],
|
|
129
|
+
text=True,
|
|
130
|
+
encoding='utf-8',
|
|
131
|
+
errors='replace'
|
|
132
|
+
)
|
|
133
|
+
print(out)
|
|
134
|
+
for line in out.splitlines()[1:]:
|
|
135
|
+
parts = line.split()
|
|
136
|
+
if len(parts) > 1 and parts[1].isdigit():
|
|
137
|
+
pids.append(int(parts[1]))
|
|
138
|
+
except Exception as e:
|
|
139
|
+
print(f"Could not list processes: {e}")
|
|
140
|
+
|
|
141
|
+
if not pids:
|
|
142
|
+
print(f"Could not find process using port {port}.")
|
|
143
|
+
print("Please free the port manually or set MORECOMPUTE_PORT to a different port.")
|
|
144
|
+
sys.exit(1)
|
|
145
|
+
|
|
146
|
+
resp = input(f"Kill process(es) on port {port} and continue? [y/N]: ").strip().lower()
|
|
102
147
|
if resp != "y":
|
|
103
148
|
print("Aborting. Set MORECOMPUTE_PORT to a different port to override.")
|
|
104
149
|
sys.exit(1)
|
|
105
|
-
|
|
150
|
+
|
|
151
|
+
# Kill processes
|
|
106
152
|
for pid in pids:
|
|
107
153
|
try:
|
|
108
|
-
|
|
154
|
+
if self.is_windows:
|
|
155
|
+
subprocess.run(
|
|
156
|
+
["taskkill", "/F", "/PID", str(pid)],
|
|
157
|
+
stdout=subprocess.DEVNULL,
|
|
158
|
+
stderr=subprocess.DEVNULL,
|
|
159
|
+
encoding='utf-8',
|
|
160
|
+
errors='replace'
|
|
161
|
+
)
|
|
162
|
+
else:
|
|
163
|
+
os.kill(pid, signal.SIGKILL)
|
|
164
|
+
except Exception as e:
|
|
165
|
+
print(f"Failed to kill PID {pid}: {e}")
|
|
166
|
+
|
|
167
|
+
# Fallback: kill known patterns (Unix only)
|
|
168
|
+
if not self.is_windows:
|
|
169
|
+
try:
|
|
170
|
+
subprocess.run(["pkill", "-f", "uvicorn .*morecompute.server:app"],
|
|
171
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
109
172
|
except Exception:
|
|
110
173
|
pass
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
#
|
|
121
|
-
time.sleep(0.5)
|
|
122
|
-
# Poll until it binds
|
|
174
|
+
try:
|
|
175
|
+
subprocess.run(["pkill", "-f", "morecompute.execution.worker"],
|
|
176
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
177
|
+
except Exception:
|
|
178
|
+
pass
|
|
179
|
+
|
|
180
|
+
# Windows needs more time to release ports
|
|
181
|
+
time.sleep(1.0 if self.is_windows else 0.5)
|
|
182
|
+
|
|
183
|
+
# Poll until port is available
|
|
123
184
|
start = time.time()
|
|
124
185
|
while time.time() - start < 5.0:
|
|
125
186
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s2:
|
|
@@ -129,6 +190,7 @@ class NotebookLauncher:
|
|
|
129
190
|
return
|
|
130
191
|
except OSError:
|
|
131
192
|
time.sleep(0.25)
|
|
193
|
+
|
|
132
194
|
print(f"Port {port} still busy. Please free it or set MORECOMPUTE_PORT to another port.")
|
|
133
195
|
sys.exit(1)
|
|
134
196
|
|
|
@@ -137,25 +199,51 @@ class NotebookLauncher:
|
|
|
137
199
|
try:
|
|
138
200
|
frontend_dir = self.root_dir / "frontend"
|
|
139
201
|
|
|
202
|
+
# Use Windows-specific npm command
|
|
203
|
+
npm_cmd = "npm.cmd" if self.is_windows else "npm"
|
|
204
|
+
|
|
205
|
+
# Verify npm exists
|
|
206
|
+
try:
|
|
207
|
+
subprocess.run(
|
|
208
|
+
[npm_cmd, "--version"],
|
|
209
|
+
check=True,
|
|
210
|
+
stdout=subprocess.DEVNULL,
|
|
211
|
+
stderr=subprocess.DEVNULL,
|
|
212
|
+
shell=self.is_windows,
|
|
213
|
+
encoding='utf-8',
|
|
214
|
+
errors='replace'
|
|
215
|
+
)
|
|
216
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
217
|
+
print("\nError: npm not found. Please install Node.js from https://nodejs.org/")
|
|
218
|
+
print("After installation, restart your terminal and try again.")
|
|
219
|
+
self.cleanup()
|
|
220
|
+
sys.exit(1)
|
|
221
|
+
|
|
140
222
|
# Check if node_modules exists
|
|
141
223
|
if not (frontend_dir / "node_modules").exists():
|
|
142
224
|
print("Installing dependencies...")
|
|
143
225
|
subprocess.run(
|
|
144
|
-
[
|
|
226
|
+
[npm_cmd, "install"],
|
|
145
227
|
cwd=frontend_dir,
|
|
146
228
|
check=True,
|
|
147
229
|
stdout=subprocess.DEVNULL,
|
|
148
|
-
stderr=subprocess.DEVNULL
|
|
230
|
+
stderr=subprocess.DEVNULL,
|
|
231
|
+
shell=self.is_windows,
|
|
232
|
+
encoding='utf-8',
|
|
233
|
+
errors='replace'
|
|
149
234
|
)
|
|
150
235
|
|
|
151
236
|
fe_stdout = None if self.debug else subprocess.DEVNULL
|
|
152
237
|
fe_stderr = None if self.debug else subprocess.DEVNULL
|
|
153
238
|
|
|
154
239
|
self.frontend_process = subprocess.Popen(
|
|
155
|
-
[
|
|
240
|
+
[npm_cmd, "run", "dev"],
|
|
156
241
|
cwd=frontend_dir,
|
|
157
242
|
stdout=fe_stdout,
|
|
158
|
-
stderr=fe_stderr
|
|
243
|
+
stderr=fe_stderr,
|
|
244
|
+
shell=self.is_windows, # CRITICAL for Windows
|
|
245
|
+
encoding='utf-8',
|
|
246
|
+
errors='replace'
|
|
159
247
|
)
|
|
160
248
|
|
|
161
249
|
# Wait a bit then open browser
|
|
@@ -170,18 +258,40 @@ class NotebookLauncher:
|
|
|
170
258
|
def cleanup(self):
|
|
171
259
|
"""Clean up processes on exit"""
|
|
172
260
|
if self.frontend_process:
|
|
173
|
-
self.frontend_process.terminate()
|
|
174
261
|
try:
|
|
175
|
-
self.
|
|
176
|
-
|
|
177
|
-
|
|
262
|
+
if self.is_windows:
|
|
263
|
+
# Windows: Use taskkill for more reliable cleanup
|
|
264
|
+
subprocess.run(
|
|
265
|
+
["taskkill", "/F", "/T", "/PID", str(self.frontend_process.pid)],
|
|
266
|
+
stdout=subprocess.DEVNULL,
|
|
267
|
+
stderr=subprocess.DEVNULL
|
|
268
|
+
)
|
|
269
|
+
else:
|
|
270
|
+
self.frontend_process.terminate()
|
|
271
|
+
try:
|
|
272
|
+
self.frontend_process.wait(timeout=5)
|
|
273
|
+
except subprocess.TimeoutExpired:
|
|
274
|
+
self.frontend_process.kill()
|
|
275
|
+
except Exception:
|
|
276
|
+
pass
|
|
178
277
|
|
|
179
278
|
if self.backend_process:
|
|
180
|
-
self.backend_process.terminate()
|
|
181
279
|
try:
|
|
182
|
-
self.
|
|
183
|
-
|
|
184
|
-
|
|
280
|
+
if self.is_windows:
|
|
281
|
+
# Windows: Use taskkill for more reliable cleanup
|
|
282
|
+
subprocess.run(
|
|
283
|
+
["taskkill", "/F", "/T", "/PID", str(self.backend_process.pid)],
|
|
284
|
+
stdout=subprocess.DEVNULL,
|
|
285
|
+
stderr=subprocess.DEVNULL
|
|
286
|
+
)
|
|
287
|
+
else:
|
|
288
|
+
self.backend_process.terminate()
|
|
289
|
+
try:
|
|
290
|
+
self.backend_process.wait(timeout=5)
|
|
291
|
+
except subprocess.TimeoutExpired:
|
|
292
|
+
self.backend_process.kill()
|
|
293
|
+
except Exception:
|
|
294
|
+
pass
|
|
185
295
|
|
|
186
296
|
def run(self):
|
|
187
297
|
"""Main run method"""
|
|
@@ -190,12 +300,19 @@ class NotebookLauncher:
|
|
|
190
300
|
|
|
191
301
|
# Set up signal handlers
|
|
192
302
|
def signal_handler(signum, frame):
|
|
193
|
-
|
|
303
|
+
# Shutdown immediately on Ctrl+C
|
|
304
|
+
print("\nREMINDER: Any running GPU pods will continue to incur costs until you terminate them in the Compute popup.")
|
|
305
|
+
print("\n Thanks for using MoreCompute!\n")
|
|
194
306
|
self.cleanup()
|
|
195
307
|
sys.exit(0)
|
|
196
308
|
|
|
197
|
-
signal
|
|
198
|
-
|
|
309
|
+
# Windows signal handling is different
|
|
310
|
+
if not self.is_windows:
|
|
311
|
+
signal.signal(signal.SIGINT, signal_handler)
|
|
312
|
+
signal.signal(signal.SIGTERM, signal_handler)
|
|
313
|
+
else:
|
|
314
|
+
# Windows only supports SIGINT and SIGBREAK
|
|
315
|
+
signal.signal(signal.SIGINT, signal_handler)
|
|
199
316
|
|
|
200
317
|
# Start services
|
|
201
318
|
self.start_backend()
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: more-compute
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: An interactive notebook environment for local and GPU computing
|
|
5
|
+
Home-page: https://github.com/DannyMang/MORECOMPUTE
|
|
6
|
+
Author: MoreCompute Team
|
|
7
|
+
Author-email: MoreCompute Team <hello@morecompute.dev>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/DannyMang/MORECOMPUTE
|
|
10
|
+
Project-URL: Repository, https://github.com/DannyMang/MORECOMPUTE
|
|
11
|
+
Project-URL: Issues, https://github.com/DannyMang/MORECOMPUTE/issues
|
|
12
|
+
Keywords: jupyter,notebook,gpu,computing,interactive
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: fastapi>=0.104.0
|
|
27
|
+
Requires-Dist: uvicorn[standard]>=0.24.0
|
|
28
|
+
Requires-Dist: python-multipart>=0.0.5
|
|
29
|
+
Requires-Dist: nbformat>=5.0.0
|
|
30
|
+
Requires-Dist: click>=8.0.0
|
|
31
|
+
Requires-Dist: pyzmq>=25.0.0
|
|
32
|
+
Requires-Dist: psutil>=5.9.0
|
|
33
|
+
Requires-Dist: httpx>=0.24.0
|
|
34
|
+
Requires-Dist: cachetools>=5.3.0
|
|
35
|
+
Requires-Dist: matplotlib>=3.5.0
|
|
36
|
+
Dynamic: author
|
|
37
|
+
Dynamic: home-page
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
Dynamic: requires-python
|
|
40
|
+
|
|
41
|
+
# more-compute
|
|
42
|
+
|
|
43
|
+
[](https://pypi.org/project/more-compute/)
|
|
44
|
+
[](https://www.python.org/downloads/)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
|
|
47
|
+
Interactive notebook environment for local Python development. Works with standard `.ipynb` files,
|
|
48
|
+
similar to Jupyter Lab but more awesome.
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
**Prerequisites:** [Node.js](https://nodejs.org/) 16+ required for web interface.
|
|
53
|
+
|
|
54
|
+
### Using uv (Recommended)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# macOS/Linux
|
|
58
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
59
|
+
uv tool install more-compute
|
|
60
|
+
|
|
61
|
+
# Windows
|
|
62
|
+
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
63
|
+
uv tool install more-compute
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Using pip
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install more-compute
|
|
70
|
+
|
|
71
|
+
# Add to PATH if needed:
|
|
72
|
+
# macOS/Linux: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
|
73
|
+
# Windows: See troubleshooting below
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
more-compute notebook.ipynb # Open existing notebook
|
|
80
|
+
more-compute # Create and open new notebook
|
|
81
|
+
more-compute --debug # Show logs
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Opens automatically at http://localhost:8000
|
|
85
|
+
|
|
86
|
+
## Troubleshooting
|
|
87
|
+
|
|
88
|
+
**Command not found:**
|
|
89
|
+
```bash
|
|
90
|
+
uv tool update-shell # Fixes PATH automatically
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Manual PATH fix (macOS/Linux):**
|
|
94
|
+
```bash
|
|
95
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
|
96
|
+
source ~/.bashrc
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Manual PATH fix (Windows):**
|
|
100
|
+
```powershell
|
|
101
|
+
$pythonScripts = python -c "import site; print(site.USER_BASE)"
|
|
102
|
+
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
103
|
+
[Environment]::SetEnvironmentVariable("Path", "$userPath;$pythonScripts\Scripts", "User")
|
|
104
|
+
# Restart PowerShell
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Port in use:**
|
|
108
|
+
```bash
|
|
109
|
+
export MORECOMPUTE_PORT=8080 # macOS/Linux
|
|
110
|
+
$env:MORECOMPUTE_PORT = "8080" # Windows
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Development
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
git clone https://github.com/DannyMang/MORECOMPUTE.git
|
|
117
|
+
cd MORECOMPUTE
|
|
118
|
+
uv venv && source .venv/bin/activate
|
|
119
|
+
uv pip install -e .
|
|
120
|
+
cd frontend && npm install && cd ..
|
|
121
|
+
python kernel_run.py notebook.ipynb
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT - see [LICENSE](LICENSE)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
kernel_run.py,sha256=otblv5fH9VyucgBsh_LwcgAWLNun0E9ioGIZvzWuP84,14656
|
|
2
|
+
frontend/.DS_Store,sha256=uQeHnkKyuTF1AVax3NPqtN0uCH6XNXAxL9Nkb6Q9cGw,8196
|
|
3
|
+
frontend/.gitignore,sha256=IH4mX_SQH5rZ-W2M4IUw4E-fxgCBVHKmbQpEYJbWVM0,480
|
|
4
|
+
frontend/README.md,sha256=YLVf9995r3JZD5UkII5GZCvDK9wXXNrUE0loHA4vlY8,1450
|
|
5
|
+
frontend/__init__.py,sha256=L5SAOdfDfKqlgEVCvYQQRDZBTlCxutZKSpJp4018IG4,100
|
|
6
|
+
frontend/eslint.config.mjs,sha256=LBCCw4SomtiVMmlTSpYRXfkRs6Xs04R1YFfoyorYyT8,879
|
|
7
|
+
frontend/next-env.d.ts,sha256=ha5a7nXwEZZ88tJcvDQvYtaTFOnZJff0qjRW_Cz_zKY,262
|
|
8
|
+
frontend/next.config.mjs,sha256=n0o6cIIVIoOtI6JlvAK-HUFd2lg1pQPfUwlFS4O6TK0,346
|
|
9
|
+
frontend/next.config.ts,sha256=OL_rEfTIZxsB_B5R9JX2AxYXgC0Fc_XiDoRlOGEDEpk,368
|
|
10
|
+
frontend/package-lock.json,sha256=uv1cRVRHKZCzk5ceHJN8bOhJzv4a3XjeIbyTF2oYCho,306688
|
|
11
|
+
frontend/package.json,sha256=P7Hrwl1vUCUjhi44Eg3oqc4-4l-V0Ea6__S2Mx_Qp7A,1367
|
|
12
|
+
frontend/postcss.config.mjs,sha256=FB7yTKJ6mdCJYiEP3yAhLTQ1_c-iG0bNiLRNIvdR364,81
|
|
13
|
+
frontend/styling_README.md,sha256=RAQ4q-axGqugym8L22KpxB2ReBbEtg67YCEHLvTVvAw,196
|
|
14
|
+
frontend/tailwind.config.ts,sha256=eP9nVaAuyYo46vGQfCyWbo25_pr2hW830fs1Itcix9Q,620
|
|
15
|
+
frontend/tsconfig.json,sha256=7SvBlRBYmuXAlAteRQTGwEE7ooWuNaPUrZ219dOo61E,598
|
|
16
|
+
frontend/app/favicon.ico,sha256=K4rS0zRVqPc2_DqOv48L3qiEitTA20iigzvQ-c13WTI,25931
|
|
17
|
+
frontend/app/globals.css,sha256=imFZBoEmnHEOpo7Jegj8F71iPwSwNQivtH0ylpCKyWE,35682
|
|
18
|
+
frontend/app/layout.tsx,sha256=R1vUDTImQzUJIW51rdvBUIsvejSbjfLrwgbLSjrmcMM,6035
|
|
19
|
+
frontend/app/page.tsx,sha256=p-DgDv8xDnwcRfDJY4rtfSQ2VdYwbnP3G-otWqDR1l0,256
|
|
20
|
+
frontend/components/Cell.tsx,sha256=JeXn5Z_jzezYOtrgl291b6HBKJdfhQ88dTTDZjFoWmk,12237
|
|
21
|
+
frontend/components/Notebook.tsx,sha256=tJt45gyNch3ifWjnKUDoyvik7snrgRqt55gQgiYEnlc,21528
|
|
22
|
+
frontend/components/cell/AddCellButton.tsx,sha256=ZC2Vck0JIRDxGYhYv3LPYAdKDo13U6008WG_-XoPlIM,1012
|
|
23
|
+
frontend/components/cell/CellButton.tsx,sha256=BjfazBKzlybA5Syx6tXGTJa1U_jwL8C_IeQKbcHlkyk,1364
|
|
24
|
+
frontend/components/cell/MonacoCell.tsx,sha256=11jSlfGcUpxvbRDJr1GGocNtzZIarioDdgg7WLuZs9U,24334
|
|
25
|
+
frontend/components/layout/ConnectionBanner.tsx,sha256=-m77wKCFpeRJ_AQwnM38jLwCY5vfpqE846xeXmT3p8A,870
|
|
26
|
+
frontend/components/layout/Sidebar.tsx,sha256=kxgO2mXX11xI6rX478cUqqQ3xB40jlby21y27GTJSLU,1551
|
|
27
|
+
frontend/components/modals/ConfirmModal.tsx,sha256=3WgXy_wmR8FHZPwzMevfZHFXa0blR4v_SbKG3d5McT4,3652
|
|
28
|
+
frontend/components/modals/ErrorModal.tsx,sha256=kkGHQvgyMYlScKwni04-V_Dq6a0-lg0WodglLARR-uA,3536
|
|
29
|
+
frontend/components/modals/SuccessModal.tsx,sha256=7NVg0MFPVvsBGDOHPVyZTNx4kmZLHgxdhZKKtTD9FTU,3385
|
|
30
|
+
frontend/components/output/CellOutput.tsx,sha256=D1ZIvOmQvFn_4Y1ahGM5rp0Yr5_Zp_loNJaEUA-GCrA,2073
|
|
31
|
+
frontend/components/output/ErrorDisplay.tsx,sha256=d6I2WVyDLPsonyDuqsrrN8sc_KHg0VTAW86DfcqfqL0,5978
|
|
32
|
+
frontend/components/output/MarkdownRenderer.tsx,sha256=RtZ5yNRxDXIh_NkNsNiy30wMGIW7V1gfhsjecgMdc80,3341
|
|
33
|
+
frontend/components/popups/ComputePopup.tsx,sha256=B7AwwjpJ9_nNI5qSN53jdR2tAulB5yl7spjMXjH4yDM,44021
|
|
34
|
+
frontend/components/popups/FilterPopup.tsx,sha256=4kx9txg8cWeC6XHlh0pu0-BAfZkLTDYEU93fMdzn86M,13818
|
|
35
|
+
frontend/components/popups/FolderPopup.tsx,sha256=V2tDAbztvNIUyPWtFiwjeIoCmFGQyDosQgST_JsAzLo,5215
|
|
36
|
+
frontend/components/popups/MetricsPopup.tsx,sha256=V4Srat-RRr7B046Ezg5w99_E_t9j0P3Ch5DO9rF7Nx0,5028
|
|
37
|
+
frontend/components/popups/PackagesPopup.tsx,sha256=K_9kGlQ-y-njugOLrahbv0KHRh_mXIlzuMg0giRsTb8,3606
|
|
38
|
+
frontend/components/popups/SettingsPopup.tsx,sha256=etwDuB4HHfadzN7CZf9omZ0uNl_4vhwJ92C5p3rleuY,2395
|
|
39
|
+
frontend/contexts/PodWebSocketContext.tsx,sha256=QyEg1Msyum7h3T6F3j6pn4Ds5sXFT_9WYu5_0YZ2IUI,8256
|
|
40
|
+
frontend/lib/api.ts,sha256=0N4PCSC5pfbq7GvR_6aOdPZ3JGujzi1Rz4V51g8sHP8,10852
|
|
41
|
+
frontend/lib/monaco-themes.ts,sha256=jh_pZAmSMKjY_belbMbZX2WpFBN7baRxvJp9shUDYgk,5396
|
|
42
|
+
frontend/lib/settings.ts,sha256=ZAdwLErjPITkIc87D3DTcHYhhUP3fBI-LpDYsH9eVE4,5842
|
|
43
|
+
frontend/lib/themes.json,sha256=mk6IGy6o_DCOerBH3QmfXozTHEiy-alsTLTTIaba7No,292018
|
|
44
|
+
frontend/lib/websocket-native.ts,sha256=6QUSLSONnCImPp9hpFo_XdXME5X7DOptW1mrtG7E99A,5962
|
|
45
|
+
frontend/lib/websocket.ts,sha256=V2Y7sktt2dm1G-ZILggcqIWccsh-xoAG9dLHpNVqIqs,4500
|
|
46
|
+
frontend/public/file.svg,sha256=K2eBLDJcGZoCU2zb7qDFk6cvcH0yO3LuPgjbqwZ1O9Q,391
|
|
47
|
+
frontend/public/globe.svg,sha256=thS5vxg5JZV2YayFFJj-HYAp_UOmL7_thvniYkpX588,1035
|
|
48
|
+
frontend/public/next.svg,sha256=VZld-tbstJRaHoVt3KA8XhaqW_E_0htN9qdK55NXvPw,1375
|
|
49
|
+
frontend/public/vercel.svg,sha256=8IEzey_uY1tFW2MnVAaj5_OdagFOJa2Q2rWmfmKhKsQ,128
|
|
50
|
+
frontend/public/window.svg,sha256=ZEdoxKrrR2e84pM0TusMEl-4BKlNgBRAQkByIC2F46E,385
|
|
51
|
+
frontend/public/assets/icons/add.svg,sha256=_R2g6_rQSd9uQ52d_yxLY8kFGvAgJBAOvWUN00aoSkY,511
|
|
52
|
+
frontend/public/assets/icons/check.svg,sha256=MdLhklRIgz5dZqWuUQe0CdBzfA5W63X6RbvOT3C9YTE,261
|
|
53
|
+
frontend/public/assets/icons/copy.svg,sha256=Bd_NXZR-inj4X0WGhkpojErq6F6UXwpdp3DL6rm57r0,355
|
|
54
|
+
frontend/public/assets/icons/folder.svg,sha256=uzpAVxIsuGivdrte56WJOfqCWc1TNN9ldPhrHKEA674,400
|
|
55
|
+
frontend/public/assets/icons/metric.svg,sha256=biafr0qAHRV_8CnMEWrh3Wk3ZMAgbfaL0I1N7Uqfp_U,440
|
|
56
|
+
frontend/public/assets/icons/packages.svg,sha256=70XqerYscy3b-YkLpuNSBalECfmlfRVjgN5Pq4Uvd-I,460
|
|
57
|
+
frontend/public/assets/icons/play.svg,sha256=ca5409xQtDl8rOHp0Dv6t6WWra7QvTupbcGj-OubjL8,326
|
|
58
|
+
frontend/public/assets/icons/python.svg,sha256=uuyGYqFGHCyswya1TScnyy8c4HugLQD1uCbQNRBPZJ8,9605
|
|
59
|
+
frontend/public/assets/icons/setting.svg,sha256=oUwRxiQjyK33aAv4AK1r8FYwIM8RnuwKTTaMU9v_l-U,610
|
|
60
|
+
frontend/public/assets/icons/stop.svg,sha256=98xoeoVwCEFq142v5IYE1GxcD4o3_UGa0pCOu3wzbqw,285
|
|
61
|
+
frontend/public/assets/icons/trash.svg,sha256=ikf6zdvwlLWmmGISVPzrtDlQNMPJ3VskgoCfQCEbCck,398
|
|
62
|
+
frontend/public/assets/icons/up-down.svg,sha256=ocaOoU8RZDKuyrlcPJjESz24GGvas16rytFbC7DXzGg,339
|
|
63
|
+
frontend/public/assets/icons/x.svg,sha256=TPiVYZTK-vRlaG-nLrARcnPIWCJ1xA9sqhr-9Y4Kquk,270
|
|
64
|
+
frontend/public/fonts/Fira.ttf,sha256=dbSM4W7Drd9n_EkfXq8P31KuxbjZ1wtuFiZ8aFebvTw,242896
|
|
65
|
+
frontend/public/fonts/Tiempos.woff2,sha256=h83bJKvAK301wXCMIvK7ZG5j0H2K3tzAfgo0yk4z8OE,13604
|
|
66
|
+
frontend/public/fonts/VeraMono.ttf,sha256=2kKB3H2xej385kpiztkodcWJU0AFXsi6JKORTrl7NJ0,49224
|
|
67
|
+
frontend/types/notebook.ts,sha256=v23RaZe6H3lU5tq6sqnJDPxC2mu0NZFDCJfiN0mgvSs,1359
|
|
68
|
+
more_compute-0.2.1.dist-info/licenses/LICENSE,sha256=0Ot-XIetYt06iay6IhtpJkruD-cLZtjyv7_aIEE-oSc,1073
|
|
69
|
+
morecompute/__init__.py,sha256=pcMVq8Q7qb42AOn7tqgoZJOi3epDDBnEriiv2WVKnXY,87
|
|
70
|
+
morecompute/__version__.py,sha256=HfjVOrpTnmZ-xVFCYSVmX50EXaBQeJteUHG-PD6iQs8,22
|
|
71
|
+
morecompute/cli.py,sha256=kVvzvPBqF8xO6UuhU_-TBn99nKwJ405R2mAS6zU0KBc,734
|
|
72
|
+
morecompute/notebook.py,sha256=KEcv0eOEh9N7bPVGoRuKJb47G9MmpQ5zz1B6Dm58w18,4651
|
|
73
|
+
morecompute/process_worker.py,sha256=KsE3r-XpkYGuyO4w3t54VKkD51LfNHAZc3TYattMtrg,7185
|
|
74
|
+
morecompute/server.py,sha256=W_EfX4NiSYZgK3ZZFP-LPO78_Sjzuyo3eiKprnAxsfI,40144
|
|
75
|
+
morecompute/execution/__init__.py,sha256=jPmBmq8BZWbUEY9XFSpqt5FkgX04uNS10WnUlr7Rnms,134
|
|
76
|
+
morecompute/execution/__main__.py,sha256=pAWB_1bn99u8Gb-tVMSMI-NYvbYbDiwbn40L0a0djeA,202
|
|
77
|
+
morecompute/execution/executor.py,sha256=v8OKWuHykuLvhnvsRydFECcgqRqfCFM__FAHb22ARcg,20128
|
|
78
|
+
morecompute/execution/worker.py,sha256=9z1-3ruT5DbsqRJWw54J8VFVOnm_X1Vwcp6GCV5JP4o,12465
|
|
79
|
+
morecompute/models/__init__.py,sha256=VLJ5GWi2uTNiZBdvl-ipSbmA6EL8FZHZ5oq-rJmm9z0,640
|
|
80
|
+
morecompute/models/api_models.py,sha256=-ydvi9SeTfdoY9oVPNQS4by-kQGSknx6BHhGD8E2tpo,4553
|
|
81
|
+
morecompute/services/data_manager.py,sha256=c4GKucetMM-VPNbHyzce6bZRvFfmz8kTd5RppLjoLVc,14329
|
|
82
|
+
morecompute/services/lsp_service.py,sha256=Le8ARImcg2P6oueF_14L8rStHOOseHruRTd_wfDVw7s,12237
|
|
83
|
+
morecompute/services/pod_manager.py,sha256=rg6mQJOieElDaO-KGBmg7wO6APkBThLpWmDi472Mvbw,21068
|
|
84
|
+
morecompute/services/pod_monitor.py,sha256=Y5aiNoVsvkGiHddNbfR1laAKn8G0eY0_nJyTM4VVkyg,4711
|
|
85
|
+
morecompute/services/prime_intellect.py,sha256=b705rHv3RPRsgWedRlHwoP_S-TxxZtMSyZhnaiZpMgk,10273
|
|
86
|
+
morecompute/static/styles.css,sha256=el_NtrUMbAUNSiMVBn1xlG70m3iPv7dyaIbWQMexhsY,19277
|
|
87
|
+
morecompute/utils/__init__.py,sha256=VIxCL3S1pnjEs4cjKGZqZB68_P8FegdeMIqBjJhI5jQ,419
|
|
88
|
+
morecompute/utils/cache_util.py,sha256=lVlXudHvtyvSo_kCSxORJrI85Jod8FrQLbI2f_JOIbA,661
|
|
89
|
+
morecompute/utils/config_util.py,sha256=fGTQll7Zh05ZHrW8LuQNTJGziGnIfvKIU3azbrY-I-s,1793
|
|
90
|
+
morecompute/utils/error_utils.py,sha256=e50WLFdD6ngIC30xAgrzdTYtD8tPOIFkKAAh_sPbK0I,11667
|
|
91
|
+
morecompute/utils/notebook_util.py,sha256=3hH94dtXvhizRVTU9a2b38m_51Y4igoXpkjAXUqpVBQ,1353
|
|
92
|
+
morecompute/utils/python_environment_util.py,sha256=l8WWWPwKbypknw8GwL22NXCji5i1FOy1vWG47J6og4g,7441
|
|
93
|
+
morecompute/utils/special_commands.py,sha256=JTc9II2EitmivwTTdnydEefShasiTa-7w8tNyYVIenw,19104
|
|
94
|
+
morecompute/utils/system_environment_util.py,sha256=32mQRubo0i4X61o-825T7m-eUSidcEp07qkInP1sWZA,4774
|
|
95
|
+
morecompute/utils/zmq_util.py,sha256=tx7-iS04UN69OFtBzkxcEnRhT7xtI9EzRnrZ_nsH_O0,1889
|
|
96
|
+
more_compute-0.2.1.dist-info/METADATA,sha256=zbjJ25jtbsr9fTTe33coPyMpTKTlLPa9gqpfIQJ6nXw,3593
|
|
97
|
+
more_compute-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
98
|
+
more_compute-0.2.1.dist-info/entry_points.txt,sha256=xp7z9eRPNRM4oxkZZVlyXkhkSjN1AjoYI_B7qpDJ1bI,49
|
|
99
|
+
more_compute-0.2.1.dist-info/top_level.txt,sha256=Tamm6ADzjwaQa1z27O7Izcyhyt9f0gVjMv1_tC810aI,32
|
|
100
|
+
more_compute-0.2.1.dist-info/RECORD,,
|
morecompute/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1
|
|
1
|
+
__version__ = "0.2.1"
|
|
@@ -26,6 +26,7 @@ class NextZmqExecutor:
|
|
|
26
26
|
ctx: object # zmq.Context - untyped due to zmq type limitations
|
|
27
27
|
req: object # zmq.Socket - untyped due to zmq type limitations
|
|
28
28
|
sub: object # zmq.Socket - untyped due to zmq type limitations
|
|
29
|
+
is_remote: bool # Flag to track if connected to remote worker
|
|
29
30
|
|
|
30
31
|
def __init__(self, error_utils: "ErrorUtils", cmd_addr: str | None = None, pub_addr: str | None = None, interrupt_timeout: float = 0.5) -> None:
|
|
31
32
|
self.error_utils = error_utils
|
|
@@ -37,6 +38,7 @@ class NextZmqExecutor:
|
|
|
37
38
|
self.worker_proc = None
|
|
38
39
|
self.interrupted_cell = None
|
|
39
40
|
self.special_handler = None
|
|
41
|
+
self.is_remote = False # Start with local worker
|
|
40
42
|
self._ensure_special_handler()
|
|
41
43
|
self.ctx = zmq.Context.instance() # type: ignore[reportUnknownMemberType]
|
|
42
44
|
self.req = self.ctx.socket(zmq.REQ) # type: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
|
|
@@ -51,6 +53,11 @@ class NextZmqExecutor:
|
|
|
51
53
|
self.special_handler = AsyncSpecialCommandHandler({"__name__": "__main__"})
|
|
52
54
|
|
|
53
55
|
def _ensure_worker(self) -> None:
|
|
56
|
+
"""Ensure a worker is available. If connected to remote pod, skip local worker spawn."""
|
|
57
|
+
# If we're connected to a remote worker, don't try to spawn local worker
|
|
58
|
+
if self.is_remote:
|
|
59
|
+
return
|
|
60
|
+
|
|
54
61
|
# Use a temporary REQ socket for probing to avoid locking self.req's state
|
|
55
62
|
tmp = self.ctx.socket(zmq.REQ) # type: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
|
|
56
63
|
tmp.setsockopt(zmq.LINGER, 0) # type: ignore[reportAttributeAccessIssue]
|
|
@@ -107,32 +114,36 @@ class NextZmqExecutor:
|
|
|
107
114
|
raise RuntimeError('Failed to start/connect ZMQ worker')
|
|
108
115
|
|
|
109
116
|
async def execute_cell(self, cell_index: int, source_code: str, websocket: WebSocket | None = None) -> dict[str, object]:
|
|
110
|
-
import sys
|
|
111
117
|
self._ensure_special_handler()
|
|
112
118
|
handler = self.special_handler
|
|
113
119
|
normalized_source = source_code
|
|
114
120
|
if handler is not None:
|
|
115
121
|
normalized_source = handler._coerce_source_to_text(source_code) # type: ignore[reportPrivateUsage]
|
|
116
122
|
if handler.is_special_command(normalized_source):
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
'
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
123
|
+
# If connected to remote pod, send special commands to remote worker
|
|
124
|
+
# Otherwise they execute locally which gives wrong results
|
|
125
|
+
if not self.is_remote:
|
|
126
|
+
# Execute special command locally
|
|
127
|
+
execution_count = getattr(self, 'execution_count', 0) + 1
|
|
128
|
+
self.execution_count = execution_count
|
|
129
|
+
start_time = time.time()
|
|
130
|
+
result: dict[str, object] = {
|
|
131
|
+
'outputs': [],
|
|
132
|
+
'error': None,
|
|
133
|
+
'status': 'ok',
|
|
134
|
+
'execution_count': execution_count,
|
|
135
|
+
'execution_time': None,
|
|
136
|
+
}
|
|
137
|
+
if websocket:
|
|
138
|
+
await websocket.send_json({'type': 'execution_start', 'data': {'cell_index': cell_index, 'execution_count': execution_count}})
|
|
139
|
+
result = await handler.execute_special_command(
|
|
140
|
+
normalized_source, result, start_time, execution_count, websocket, cell_index
|
|
141
|
+
)
|
|
142
|
+
result['execution_time'] = f"{(time.time()-start_time)*1000:.1f}ms"
|
|
143
|
+
if websocket:
|
|
144
|
+
await websocket.send_json({'type': 'execution_complete', 'data': {'cell_index': cell_index, 'result': result}})
|
|
145
|
+
return result
|
|
146
|
+
# For remote execution, fall through to send via ZMQ
|
|
136
147
|
|
|
137
148
|
execution_count = getattr(self, 'execution_count', 0) + 1
|
|
138
149
|
self.execution_count = execution_count
|