mrmd-python 0.3.2__tar.gz → 0.3.4__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.4}/PKG-INFO +1 -1
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/pyproject.toml +1 -1
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/worker.py +79 -29
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/.gitignore +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/README.md +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/__init__.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/cli.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/runtime_client.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/runtime_daemon.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/server.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/subprocess_manager.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/subprocess_worker.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/src/mrmd_python/types.py +0 -0
- {mrmd_python-0.3.2 → mrmd_python-0.3.4}/uv.lock +0 -0
|
@@ -647,8 +647,8 @@ class IPythonWorker:
|
|
|
647
647
|
return ExecuteResult(
|
|
648
648
|
success=False,
|
|
649
649
|
error=ExecuteError(
|
|
650
|
-
|
|
651
|
-
|
|
650
|
+
type="VenvError",
|
|
651
|
+
message="Could not find Python executable in venv",
|
|
652
652
|
traceback=[]
|
|
653
653
|
)
|
|
654
654
|
)
|
|
@@ -657,24 +657,37 @@ 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
|
|
661
|
+
# Use .strip() to remove any leading/trailing whitespace from the embedded code
|
|
660
662
|
wrapper_code = '''
|
|
661
|
-
import sys
|
|
662
|
-
import
|
|
663
|
+
import sys as _sys
|
|
664
|
+
import ast as _ast
|
|
663
665
|
|
|
664
|
-
|
|
665
|
-
_mrmd_result = None
|
|
666
|
-
_mrmd_error = None
|
|
667
|
-
_mrmd_stdout = ""
|
|
666
|
+
_code = """''' + code.replace('\\', '\\\\').replace('"""', '\\"\\"\\"') + '''""".strip()
|
|
668
667
|
|
|
669
668
|
try:
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
669
|
+
_tree = _ast.parse(_code)
|
|
670
|
+
if _tree.body and isinstance(_tree.body[-1], _ast.Expr):
|
|
671
|
+
# Last statement is an expression - capture its value
|
|
672
|
+
if len(_tree.body) > 1:
|
|
673
|
+
# Execute all but last statement
|
|
674
|
+
_exec_code = _ast.Module(body=_tree.body[:-1], type_ignores=[])
|
|
675
|
+
exec(compile(_exec_code, "<cell>", "exec"))
|
|
676
|
+
# Evaluate and print last expression
|
|
677
|
+
_expr_code = _ast.Expression(body=_tree.body[-1].value)
|
|
678
|
+
_result = eval(compile(_expr_code, "<cell>", "eval"))
|
|
679
|
+
if _result is not None:
|
|
680
|
+
print(f"Out[''' + str(self._execution_count) + ''']: " + repr(_result))
|
|
681
|
+
else:
|
|
682
|
+
# No trailing expression, just exec everything
|
|
683
|
+
exec(compile(_code, "<cell>", "exec"))
|
|
684
|
+
except SyntaxError:
|
|
685
|
+
# Fall back to simple exec
|
|
686
|
+
exec(compile(_code, "<cell>", "exec"))
|
|
687
|
+
except Exception as _e:
|
|
688
|
+
import traceback as _tb
|
|
689
|
+
print("".join(_tb.format_exception(type(_e), _e, _e.__traceback__)), file=_sys.stderr)
|
|
690
|
+
_sys.exit(1)
|
|
678
691
|
'''
|
|
679
692
|
|
|
680
693
|
try:
|
|
@@ -704,8 +717,8 @@ except Exception as e:
|
|
|
704
717
|
stdout=result.stdout,
|
|
705
718
|
stderr=result.stderr,
|
|
706
719
|
error=ExecuteError(
|
|
707
|
-
|
|
708
|
-
|
|
720
|
+
type="ExecutionError",
|
|
721
|
+
message=error_lines[-1] if error_lines else "Unknown error",
|
|
709
722
|
traceback=error_lines
|
|
710
723
|
),
|
|
711
724
|
executionCount=self._execution_count,
|
|
@@ -716,8 +729,8 @@ except Exception as e:
|
|
|
716
729
|
return ExecuteResult(
|
|
717
730
|
success=False,
|
|
718
731
|
error=ExecuteError(
|
|
719
|
-
|
|
720
|
-
|
|
732
|
+
type="TimeoutError",
|
|
733
|
+
message="Execution timed out after 5 minutes",
|
|
721
734
|
traceback=[]
|
|
722
735
|
),
|
|
723
736
|
executionCount=self._execution_count,
|
|
@@ -726,8 +739,8 @@ except Exception as e:
|
|
|
726
739
|
return ExecuteResult(
|
|
727
740
|
success=False,
|
|
728
741
|
error=ExecuteError(
|
|
729
|
-
|
|
730
|
-
|
|
742
|
+
type=type(e).__name__,
|
|
743
|
+
message=str(e),
|
|
731
744
|
traceback=[]
|
|
732
745
|
),
|
|
733
746
|
executionCount=self._execution_count,
|
|
@@ -742,13 +755,17 @@ except Exception as e:
|
|
|
742
755
|
"""Execute code in subprocess with streaming output."""
|
|
743
756
|
import subprocess
|
|
744
757
|
|
|
758
|
+
print(f"[IPythonWorker._execute_subprocess_streaming] Starting subprocess execution", flush=True)
|
|
759
|
+
|
|
745
760
|
python_exe = self._get_venv_python()
|
|
761
|
+
print(f"[IPythonWorker._execute_subprocess_streaming] python_exe={python_exe}", flush=True)
|
|
762
|
+
|
|
746
763
|
if not python_exe:
|
|
747
764
|
return ExecuteResult(
|
|
748
765
|
success=False,
|
|
749
766
|
error=ExecuteError(
|
|
750
|
-
|
|
751
|
-
|
|
767
|
+
type="VenvError",
|
|
768
|
+
message="Could not find Python executable in venv",
|
|
752
769
|
traceback=[]
|
|
753
770
|
)
|
|
754
771
|
)
|
|
@@ -758,10 +775,43 @@ except Exception as e:
|
|
|
758
775
|
accumulated_stdout = ""
|
|
759
776
|
accumulated_stderr = ""
|
|
760
777
|
|
|
778
|
+
# Wrap code to capture expression results like IPython does
|
|
779
|
+
# This handles cases like "import sys; sys.executable" which need to print
|
|
780
|
+
# Use .strip() to remove any leading/trailing whitespace from the embedded code
|
|
781
|
+
wrapper_code = '''
|
|
782
|
+
import sys as _sys
|
|
783
|
+
import ast as _ast
|
|
784
|
+
|
|
785
|
+
_code = """''' + code.replace('\\', '\\\\').replace('"""', '\\"\\"\\"') + '''""".strip()
|
|
786
|
+
|
|
787
|
+
# Parse to check if last statement is an expression
|
|
788
|
+
try:
|
|
789
|
+
_tree = _ast.parse(_code)
|
|
790
|
+
if _tree.body and isinstance(_tree.body[-1], _ast.Expr):
|
|
791
|
+
# Last statement is an expression - capture its value
|
|
792
|
+
if len(_tree.body) > 1:
|
|
793
|
+
# Execute all but last statement
|
|
794
|
+
_exec_code = _ast.Module(body=_tree.body[:-1], type_ignores=[])
|
|
795
|
+
exec(compile(_exec_code, "<cell>", "exec"))
|
|
796
|
+
# Evaluate and print last expression
|
|
797
|
+
_expr_code = _ast.Expression(body=_tree.body[-1].value)
|
|
798
|
+
_result = eval(compile(_expr_code, "<cell>", "eval"))
|
|
799
|
+
if _result is not None:
|
|
800
|
+
print(f"Out[{''' + str(self._execution_count) + '''}]: " + repr(_result))
|
|
801
|
+
else:
|
|
802
|
+
# No trailing expression, just exec everything
|
|
803
|
+
exec(compile(_code, "<cell>", "exec"))
|
|
804
|
+
except SyntaxError as _e:
|
|
805
|
+
# Fall back to simple exec for syntax errors in wrapper
|
|
806
|
+
exec(compile(_code, "<cell>", "exec"))
|
|
807
|
+
'''
|
|
808
|
+
|
|
809
|
+
print(f"[IPythonWorker._execute_subprocess_streaming] Running: {python_exe} -c ...", flush=True)
|
|
810
|
+
|
|
761
811
|
try:
|
|
762
812
|
# Start subprocess
|
|
763
813
|
process = subprocess.Popen(
|
|
764
|
-
[python_exe, "-c",
|
|
814
|
+
[python_exe, "-c", wrapper_code],
|
|
765
815
|
stdout=subprocess.PIPE,
|
|
766
816
|
stderr=subprocess.PIPE,
|
|
767
817
|
text=True,
|
|
@@ -807,8 +857,8 @@ except Exception as e:
|
|
|
807
857
|
stdout=accumulated_stdout,
|
|
808
858
|
stderr=accumulated_stderr,
|
|
809
859
|
error=ExecuteError(
|
|
810
|
-
|
|
811
|
-
|
|
860
|
+
type="ExecutionError",
|
|
861
|
+
message=error_lines[-1] if error_lines else "Unknown error",
|
|
812
862
|
traceback=error_lines
|
|
813
863
|
),
|
|
814
864
|
executionCount=self._execution_count,
|
|
@@ -827,8 +877,8 @@ except Exception as e:
|
|
|
827
877
|
return ExecuteResult(
|
|
828
878
|
success=False,
|
|
829
879
|
error=ExecuteError(
|
|
830
|
-
|
|
831
|
-
|
|
880
|
+
type=type(e).__name__,
|
|
881
|
+
message=str(e),
|
|
832
882
|
traceback=[]
|
|
833
883
|
),
|
|
834
884
|
executionCount=self._execution_count,
|
|
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
|