Skip to content

Commit 1000581

Browse files
committed
Switch to tslab
1 parent 51adafc commit 1000581

File tree

6 files changed

+72
-20
lines changed

6 files changed

+72
-20
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
start-template-server:
2-
docker run --rm -e E2B_LOCAL=true -p 49999:49999 -it $$(docker build . -q -f ./template/test.Dockerfile)
2+
docker run --platform linux/amd64 --rm -e E2B_LOCAL=true -p 49999:49999 -it $$(docker build . --platform linux/amd64 -q -f ./template/test.Dockerfile)
33

44
kill-template-server:
55
docker kill $(shell docker ps --filter expose=49999 --format {{.ID}})

python/tests/sync/test_default_kernels.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,13 @@
44
def test_js_kernel(sandbox: Sandbox):
55
execution = sandbox.run_code("console.log('Hello, World!')", language="js")
66
assert execution.logs.stdout == ["Hello, World!\n"]
7+
8+
9+
def test_r_kernel(sandbox: Sandbox):
10+
execution = sandbox.run_code('print("Hello, World!")', language="r")
11+
assert execution.logs.stdout == ['[1] "Hello, World!"\n']
12+
13+
14+
def test_java_kernel(sandbox: Sandbox):
15+
execution = sandbox.run_code('System.out.println("Hello, World!")', language="java")
16+
assert execution.logs.stdout[0] == "Hello, World!"

template/server/contexts.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ def normalize_language(language: Optional[str]) -> str:
2525

2626

2727
async def create_context(client, websockets: dict, language: str, cwd: str) -> Context:
28+
if language == "typescript":
29+
language = "tslab"
30+
if language == "javascript":
31+
language = "jslab"
32+
2833
data = {
2934
"path": str(uuid.uuid4()),
3035
"kernel": {"name": language},
@@ -53,7 +58,7 @@ async def create_context(client, websockets: dict, language: str, cwd: str) -> C
5358

5459
logger.info(f"Setting working directory to {cwd}")
5560
try:
56-
await ws.change_current_directory(cwd)
61+
await ws.change_current_directory(cwd, language)
5762
except ExecutionError as e:
5863
return PlainTextResponse(
5964
"Failed to set working directory",

template/server/main.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,11 @@ async def post_execute(request: ExecutionRequest):
104104
)
105105

106106
return StreamingListJsonResponse(
107-
ws.execute(request.code, env_vars=request.env_vars)
107+
ws.execute(
108+
request.code,
109+
env_vars=request.env_vars,
110+
sends_input_accepted="lab" not in ws.language,
111+
)
108112
)
109113

110114

template/server/messaging.py

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,12 @@ def _get_execute_request(
108108
}
109109
)
110110

111-
async def _wait_for_result(self, message_id: str):
111+
async def _wait_for_result(
112+
self, message_id: str, sends_input_accepted: bool = False
113+
):
112114
queue = self._executions[message_id].queue
115+
if not sends_input_accepted:
116+
self._executions[message_id].input_accepted = True
113117

114118
while True:
115119
output = await queue.get()
@@ -127,21 +131,37 @@ async def _wait_for_result(self, message_id: str):
127131

128132
yield output.model_dump(exclude_none=True)
129133

130-
async def change_current_directory(self, path: Union[str, StrictStr]):
134+
async def change_current_directory(
135+
self, path: Union[str, StrictStr], language: str
136+
):
131137
message_id = str(uuid.uuid4())
132138
self._executions[message_id] = Execution(in_background=True)
133-
request = self._get_execute_request(message_id, f"%cd {path}", True)
139+
if language == "python":
140+
request = self._get_execute_request(message_id, f"%cd {path}", True)
141+
elif language == "jslab" or language == "tslab":
142+
request = self._get_execute_request(
143+
message_id, f"process.chdir('{path}')", True
144+
)
145+
elif language == "r":
146+
request = self._get_execute_request(message_id, f"setwd('{path}')", True)
147+
elif language == "java":
148+
request = self._get_execute_request(
149+
message_id, f"System.setProperty('user.dir', '{path}')", True
150+
)
151+
else:
152+
return
134153

135154
await self._ws.send(request)
136155

137-
async for item in self._wait_for_result(message_id):
156+
async for item in self._wait_for_result(message_id, False):
138157
if item["type"] == "error":
139158
raise ExecutionError(f"Error during execution: {item}")
140159

141160
async def execute(
142161
self,
143162
code: Union[str, StrictStr],
144163
env_vars: Dict[StrictStr, str] = None,
164+
sends_input_accepted: bool = False,
145165
):
146166
message_id = str(uuid.uuid4())
147167
logger.debug(f"Sending code for the execution ({message_id}): {code}")
@@ -165,11 +185,12 @@ async def execute(
165185
indent = len(line) - len(line.lstrip())
166186
break
167187

168-
code = (
169-
indent * " "
170-
+ f"os.environ.set_envs_for_execution({vars_to_set})\n"
171-
+ code
172-
)
188+
if self.language == "python":
189+
code = (
190+
indent * " "
191+
+ f"os.environ.set_envs_for_execution({vars_to_set})\n"
192+
+ code
193+
)
173194

174195
logger.info(code)
175196
request = self._get_execute_request(message_id, code, False)
@@ -178,7 +199,7 @@ async def execute(
178199
await self._ws.send(request)
179200

180201
# Stream the results
181-
async for item in self._wait_for_result(message_id):
202+
async for item in self._wait_for_result(message_id, sends_input_accepted):
182203
yield item
183204

184205
del self._executions[message_id]
@@ -192,7 +213,9 @@ async def _receive_message(self):
192213
async for message in self._ws:
193214
await self._process_message(json.loads(message))
194215
except Exception as e:
195-
logger.error(f"WebSocket received error while receiving messages: {e}")
216+
logger.error(
217+
f"WebSocket received error while receiving messages: {type(e)}: {str(e)}"
218+
)
196219

197220
async def _process_message(self, data: dict):
198221
"""
@@ -308,11 +331,21 @@ async def _process_message(self, data: dict):
308331
execution.errored = True
309332
await queue.put(
310333
Error(
311-
name=data["content"]["ename"],
312-
value=data["content"]["evalue"],
313-
traceback="".join(data["content"]["traceback"]),
334+
name=data["content"].get("ename", ""),
335+
value=data["content"].get("evalue", ""),
336+
traceback="".join(data["content"].get("traceback", [])),
314337
)
315338
)
339+
elif data["content"]["status"] == "abort":
340+
logger.debug(f"Execution {parent_msg_ig} was aborted")
341+
await queue.put(
342+
Error(
343+
name="ExecutionAborted",
344+
value="Execution was aborted",
345+
traceback="",
346+
)
347+
)
348+
await queue.put(EndOfExecution())
316349
elif data["content"]["status"] == "ok":
317350
pass
318351

template/test.Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ COPY ./template/requirements.txt requirements.txt
1919
RUN pip install --no-cache-dir -r requirements.txt && ipython kernel install --name "python3" --user
2020

2121
# Javascript Kernel
22-
RUN npm install -g node-gyp
23-
RUN npm install -g --unsafe-perm ijavascript
24-
RUN ijsinstall --install=global
22+
RUN apt install -y cmake ninja-build curl zip unzip tar
23+
RUN npm install -g tslab --unsafe-perm=true
24+
RUN tslab install
2525

2626
# Create separate virtual environment for server
2727
RUN python -m venv $SERVER_PATH/.venv

0 commit comments

Comments
 (0)