mrmd-python 0.3.5__tar.gz → 0.3.7__tar.gz
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.
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/PKG-INFO +1 -1
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/pyproject.toml +1 -1
- mrmd_python-0.3.7/src/mrmd_python/__main__.py +5 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/runtime_client.py +12 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/server.py +23 -3
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/subprocess_manager.py +14 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/worker.py +16 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/uv.lock +1 -1
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/.gitignore +0 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/README.md +0 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/__init__.py +0 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/cli.py +0 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/runtime_daemon.py +0 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/subprocess_worker.py +0 -0
- {mrmd_python-0.3.5 → mrmd_python-0.3.7}/src/mrmd_python/types.py +0 -0
|
@@ -401,6 +401,18 @@ class DaemonRuntimeClient:
|
|
|
401
401
|
"""Check if the daemon runtime is still running."""
|
|
402
402
|
return is_runtime_alive(self.runtime_id)
|
|
403
403
|
|
|
404
|
+
def interrupt(self) -> bool:
|
|
405
|
+
"""Interrupt currently running code in the daemon.
|
|
406
|
+
|
|
407
|
+
Sends interrupt request to the daemon via HTTP.
|
|
408
|
+
Returns True if request was sent successfully.
|
|
409
|
+
"""
|
|
410
|
+
try:
|
|
411
|
+
result = self._post("/mrp/v1/interrupt", {"session": "default"})
|
|
412
|
+
return result.get("interrupted", False)
|
|
413
|
+
except Exception:
|
|
414
|
+
return False
|
|
415
|
+
|
|
404
416
|
def _parse_execute_result(self, data: dict) -> ExecuteResult:
|
|
405
417
|
"""Parse execute result from HTTP response."""
|
|
406
418
|
error = None
|
|
@@ -568,9 +568,29 @@ class MRPServer:
|
|
|
568
568
|
return JSONResponse({"cancelled": False, "error": "No pending input request"})
|
|
569
569
|
|
|
570
570
|
async def handle_interrupt(self, request: Request) -> JSONResponse:
|
|
571
|
-
"""POST /interrupt
|
|
572
|
-
|
|
573
|
-
|
|
571
|
+
"""POST /interrupt
|
|
572
|
+
|
|
573
|
+
Interrupt currently running code in a session.
|
|
574
|
+
Sends SIGINT to subprocess workers or sets interrupt flag for local workers.
|
|
575
|
+
"""
|
|
576
|
+
body = await request.json()
|
|
577
|
+
session_id = body.get("session", "default")
|
|
578
|
+
|
|
579
|
+
# Get the worker for this session (don't create if doesn't exist)
|
|
580
|
+
session = self.session_manager.get_session(session_id)
|
|
581
|
+
if not session:
|
|
582
|
+
return JSONResponse({"interrupted": False, "error": "Session not found"})
|
|
583
|
+
|
|
584
|
+
worker = self.session_manager.workers.get(session_id)
|
|
585
|
+
if not worker:
|
|
586
|
+
return JSONResponse({"interrupted": False, "error": "Worker not found"})
|
|
587
|
+
|
|
588
|
+
# Call interrupt on the worker
|
|
589
|
+
try:
|
|
590
|
+
interrupted = worker.interrupt()
|
|
591
|
+
return JSONResponse({"interrupted": interrupted})
|
|
592
|
+
except Exception as e:
|
|
593
|
+
return JSONResponse({"interrupted": False, "error": str(e)})
|
|
574
594
|
|
|
575
595
|
async def handle_complete(self, request: Request) -> JSONResponse:
|
|
576
596
|
"""POST /complete"""
|
|
@@ -419,6 +419,20 @@ class SubprocessWorker:
|
|
|
419
419
|
self._started = False
|
|
420
420
|
self._pid = None
|
|
421
421
|
|
|
422
|
+
def interrupt(self) -> bool:
|
|
423
|
+
"""Send SIGINT to the subprocess to raise KeyboardInterrupt.
|
|
424
|
+
|
|
425
|
+
Returns True if signal was sent successfully.
|
|
426
|
+
"""
|
|
427
|
+
if self._process and self._process.poll() is None:
|
|
428
|
+
try:
|
|
429
|
+
import signal
|
|
430
|
+
self._process.send_signal(signal.SIGINT)
|
|
431
|
+
return True
|
|
432
|
+
except Exception:
|
|
433
|
+
pass
|
|
434
|
+
return False
|
|
435
|
+
|
|
422
436
|
def is_alive(self) -> bool:
|
|
423
437
|
"""Check if subprocess is still running."""
|
|
424
438
|
return self._process is not None and self._process.poll() is None
|
|
@@ -1438,6 +1438,22 @@ class IPythonWorker:
|
|
|
1438
1438
|
self._subprocess_worker.shutdown()
|
|
1439
1439
|
self._subprocess_worker = None
|
|
1440
1440
|
|
|
1441
|
+
def interrupt(self) -> bool:
|
|
1442
|
+
"""Interrupt currently running code.
|
|
1443
|
+
|
|
1444
|
+
For subprocess workers, sends SIGINT.
|
|
1445
|
+
For local execution, sets interrupt flag (checked in callbacks).
|
|
1446
|
+
|
|
1447
|
+
Returns True if interrupt was initiated.
|
|
1448
|
+
"""
|
|
1449
|
+
if self._subprocess_worker is not None:
|
|
1450
|
+
return self._subprocess_worker.interrupt()
|
|
1451
|
+
|
|
1452
|
+
# For local execution, set the interrupt flag
|
|
1453
|
+
# This will be checked by long-running operations
|
|
1454
|
+
self._interrupt_requested = True
|
|
1455
|
+
return True
|
|
1456
|
+
|
|
1441
1457
|
def get_info(self) -> dict:
|
|
1442
1458
|
"""Get info about this worker."""
|
|
1443
1459
|
return {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|