more-compute 0.2.6__py3-none-any.whl → 0.3.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.
@@ -10,6 +10,91 @@ import matplotlib
10
10
  matplotlib.use('Agg')
11
11
  import matplotlib.pyplot as plt
12
12
  import re
13
+ import subprocess
14
+ import shlex
15
+ import platform
16
+
17
+ # Import shared shell command utilities
18
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
19
+ from utils.shell_utils import prepare_shell_command, prepare_shell_environment
20
+
21
+ def _preprocess_shell_commands(code: str) -> str:
22
+ """
23
+ Preprocess code to transform IPython-style shell commands (!cmd) into Python function calls.
24
+ Returns transformed code with shell commands converted to _run_shell_command() calls.
25
+ """
26
+ lines = code.split('\n')
27
+ transformed_lines = []
28
+
29
+ for line in lines:
30
+ # Match shell commands: " !pip install pandas"
31
+ shell_match = re.match(r'^(\s*)!(.+)$', line)
32
+
33
+ if shell_match:
34
+ indent = shell_match.group(1)
35
+ shell_cmd = shell_match.group(2).strip()
36
+ # Use repr() for proper escaping
37
+ shell_cmd_repr = repr(shell_cmd)
38
+ # Transform to function call
39
+ transformed = f"{indent}_run_shell_command({shell_cmd_repr})"
40
+ transformed_lines.append(transformed)
41
+ else:
42
+ transformed_lines.append(line)
43
+
44
+ return '\n'.join(transformed_lines)
45
+
46
+ def _inject_shell_command_function(globals_dict: dict):
47
+ """Inject the _run_shell_command function into globals if not present."""
48
+ if '_run_shell_command' not in globals_dict:
49
+ def _run_shell_command(cmd: str):
50
+ """Execute a shell command synchronously with streaming output"""
51
+ # Prepare command and environment (using shared utilities)
52
+ shell_cmd = prepare_shell_command(cmd)
53
+ env = prepare_shell_environment(cmd)
54
+
55
+ # Use Popen for real-time streaming
56
+ process = subprocess.Popen(
57
+ shell_cmd,
58
+ stdout=subprocess.PIPE,
59
+ stderr=subprocess.PIPE,
60
+ text=True,
61
+ bufsize=1, # Line buffered
62
+ env=env
63
+ )
64
+
65
+ # Stream output line by line
66
+ import threading
67
+
68
+ def read_stream(stream, output_type):
69
+ try:
70
+ for line in iter(stream.readline, ''):
71
+ if not line:
72
+ break
73
+ if output_type == 'stdout':
74
+ print(line, end='')
75
+ sys.stdout.flush()
76
+ else:
77
+ print(line, end='', file=sys.stderr)
78
+ sys.stderr.flush()
79
+ except Exception:
80
+ pass
81
+ finally:
82
+ stream.close()
83
+
84
+ stdout_thread = threading.Thread(target=read_stream, args=(process.stdout, 'stdout'))
85
+ stderr_thread = threading.Thread(target=read_stream, args=(process.stderr, 'stderr'))
86
+ stdout_thread.daemon = True
87
+ stderr_thread.daemon = True
88
+ stdout_thread.start()
89
+ stderr_thread.start()
90
+
91
+ return_code = process.wait()
92
+ stdout_thread.join()
93
+ stderr_thread.join()
94
+
95
+ return return_code
96
+
97
+ globals_dict['_run_shell_command'] = _run_shell_command
13
98
 
14
99
  def _setup_signals():
15
100
  def _handler(signum, frame):
@@ -232,7 +317,14 @@ def worker_main():
232
317
  error_payload = None
233
318
  start = time.time()
234
319
  try:
235
- compiled = compile(code, '<cell>', 'exec')
320
+ # Preprocess shell commands (!cmd) to Python function calls
321
+ # This allows code like "import os; !pip install pandas" to work
322
+ preprocessed_code = _preprocess_shell_commands(code)
323
+
324
+ # Inject shell command function into globals if needed
325
+ _inject_shell_command_function(g)
326
+
327
+ compiled = compile(preprocessed_code, '<cell>', 'exec')
236
328
  exec(compiled, g, l)
237
329
 
238
330
  # Try to evaluate last expression for display (like Jupyter)
morecompute/server.py CHANGED
@@ -119,6 +119,10 @@ async def list_installed_packages(force_refresh: bool = False):
119
119
  global pod_manager
120
120
  cache_key = "packages_list"
121
121
 
122
+ # Clear cache if force refresh is requested
123
+ if force_refresh and cache_key in packages_cache:
124
+ del packages_cache[cache_key]
125
+
122
126
  # Check cache first unless force refresh is requested
123
127
  if not force_refresh and cache_key in packages_cache:
124
128
  return packages_cache[cache_key]