mrmd-python 0.3.2__tar.gz → 0.3.3__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.2 → mrmd_python-0.3.3}/PKG-INFO +1 -1
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/pyproject.toml +1 -1
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/worker.py +63 -15
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/.gitignore +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/README.md +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/__init__.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/cli.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/runtime_client.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/runtime_daemon.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/server.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/subprocess_manager.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/subprocess_worker.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/src/mrmd_python/types.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.3}/uv.lock +0 -0
|
@@ -657,24 +657,36 @@ class IPythonWorker:
|
|
|
657
657
|
start_time = time.time()
|
|
658
658
|
|
|
659
659
|
# Create a wrapper script that executes the code and captures output
|
|
660
|
+
# Uses AST to detect trailing expressions and print their results like IPython
|
|
660
661
|
wrapper_code = '''
|
|
661
|
-
import sys
|
|
662
|
-
import
|
|
662
|
+
import sys as _sys
|
|
663
|
+
import ast as _ast
|
|
663
664
|
|
|
664
|
-
|
|
665
|
-
_mrmd_result = None
|
|
666
|
-
_mrmd_error = None
|
|
667
|
-
_mrmd_stdout = ""
|
|
665
|
+
_code = """ ''' + code.replace('\\', '\\\\').replace('"""', '\\"\\"\\"') + ''' """
|
|
668
666
|
|
|
669
667
|
try:
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
668
|
+
_tree = _ast.parse(_code)
|
|
669
|
+
if _tree.body and isinstance(_tree.body[-1], _ast.Expr):
|
|
670
|
+
# Last statement is an expression - capture its value
|
|
671
|
+
if len(_tree.body) > 1:
|
|
672
|
+
# Execute all but last statement
|
|
673
|
+
_exec_code = _ast.Module(body=_tree.body[:-1], type_ignores=[])
|
|
674
|
+
exec(compile(_exec_code, "<cell>", "exec"))
|
|
675
|
+
# Evaluate and print last expression
|
|
676
|
+
_expr_code = _ast.Expression(body=_tree.body[-1].value)
|
|
677
|
+
_result = eval(compile(_expr_code, "<cell>", "eval"))
|
|
678
|
+
if _result is not None:
|
|
679
|
+
print(f"Out[''' + str(self._execution_count) + ''']: " + repr(_result))
|
|
680
|
+
else:
|
|
681
|
+
# No trailing expression, just exec everything
|
|
682
|
+
exec(compile(_code, "<cell>", "exec"))
|
|
683
|
+
except SyntaxError:
|
|
684
|
+
# Fall back to simple exec
|
|
685
|
+
exec(compile(_code, "<cell>", "exec"))
|
|
686
|
+
except Exception as _e:
|
|
687
|
+
import traceback as _tb
|
|
688
|
+
print("".join(_tb.format_exception(type(_e), _e, _e.__traceback__)), file=_sys.stderr)
|
|
689
|
+
_sys.exit(1)
|
|
678
690
|
'''
|
|
679
691
|
|
|
680
692
|
try:
|
|
@@ -742,7 +754,11 @@ except Exception as e:
|
|
|
742
754
|
"""Execute code in subprocess with streaming output."""
|
|
743
755
|
import subprocess
|
|
744
756
|
|
|
757
|
+
print(f"[IPythonWorker._execute_subprocess_streaming] Starting subprocess execution", flush=True)
|
|
758
|
+
|
|
745
759
|
python_exe = self._get_venv_python()
|
|
760
|
+
print(f"[IPythonWorker._execute_subprocess_streaming] python_exe={python_exe}", flush=True)
|
|
761
|
+
|
|
746
762
|
if not python_exe:
|
|
747
763
|
return ExecuteResult(
|
|
748
764
|
success=False,
|
|
@@ -758,10 +774,42 @@ except Exception as e:
|
|
|
758
774
|
accumulated_stdout = ""
|
|
759
775
|
accumulated_stderr = ""
|
|
760
776
|
|
|
777
|
+
# Wrap code to capture expression results like IPython does
|
|
778
|
+
# This handles cases like "import sys; sys.executable" which need to print
|
|
779
|
+
wrapper_code = '''
|
|
780
|
+
import sys as _sys
|
|
781
|
+
import ast as _ast
|
|
782
|
+
|
|
783
|
+
_code = """ ''' + code.replace('\\', '\\\\').replace('"""', '\\"\\"\\"') + ''' """
|
|
784
|
+
|
|
785
|
+
# Parse to check if last statement is an expression
|
|
786
|
+
try:
|
|
787
|
+
_tree = _ast.parse(_code)
|
|
788
|
+
if _tree.body and isinstance(_tree.body[-1], _ast.Expr):
|
|
789
|
+
# Last statement is an expression - capture its value
|
|
790
|
+
if len(_tree.body) > 1:
|
|
791
|
+
# Execute all but last statement
|
|
792
|
+
_exec_code = _ast.Module(body=_tree.body[:-1], type_ignores=[])
|
|
793
|
+
exec(compile(_exec_code, "<cell>", "exec"))
|
|
794
|
+
# Evaluate and print last expression
|
|
795
|
+
_expr_code = _ast.Expression(body=_tree.body[-1].value)
|
|
796
|
+
_result = eval(compile(_expr_code, "<cell>", "eval"))
|
|
797
|
+
if _result is not None:
|
|
798
|
+
print(f"Out[{''' + str(self._execution_count) + '''}]: " + repr(_result))
|
|
799
|
+
else:
|
|
800
|
+
# No trailing expression, just exec everything
|
|
801
|
+
exec(compile(_code, "<cell>", "exec"))
|
|
802
|
+
except SyntaxError as _e:
|
|
803
|
+
# Fall back to simple exec for syntax errors in wrapper
|
|
804
|
+
exec(compile(_code, "<cell>", "exec"))
|
|
805
|
+
'''
|
|
806
|
+
|
|
807
|
+
print(f"[IPythonWorker._execute_subprocess_streaming] Running: {python_exe} -c ...", flush=True)
|
|
808
|
+
|
|
761
809
|
try:
|
|
762
810
|
# Start subprocess
|
|
763
811
|
process = subprocess.Popen(
|
|
764
|
-
[python_exe, "-c",
|
|
812
|
+
[python_exe, "-c", wrapper_code],
|
|
765
813
|
stdout=subprocess.PIPE,
|
|
766
814
|
stderr=subprocess.PIPE,
|
|
767
815
|
text=True,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|