jupyterpack 0.3.0 → 0.5.1
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.
- package/README.md +1 -1
- package/lib/document/commands.d.ts +8 -0
- package/lib/document/commands.js +76 -0
- package/lib/document/iframePanel.d.ts +4 -1
- package/lib/document/plugin.d.ts +2 -1
- package/lib/document/plugin.js +22 -4
- package/lib/document/toolbar.d.ts +9 -0
- package/lib/document/toolbar.js +20 -0
- package/lib/document/widgetFactory.d.ts +2 -1
- package/lib/document/widgetFactory.js +14 -6
- package/lib/index.d.ts +1 -1
- package/lib/pythonServer/baseServer.d.ts +82 -0
- package/lib/pythonServer/baseServer.js +141 -0
- package/lib/pythonServer/dash/dashServer.d.ts +5 -17
- package/lib/pythonServer/dash/dashServer.js +19 -24
- package/lib/pythonServer/index.d.ts +3 -3
- package/lib/pythonServer/index.js +5 -1
- package/lib/pythonServer/kernelExecutor.d.ts +2 -53
- package/lib/pythonServer/kernelExecutor.js +5 -70
- package/lib/pythonServer/shiny/shinyServer.d.ts +14 -0
- package/lib/pythonServer/shiny/shinyServer.js +49 -0
- package/lib/pythonServer/starlette/starletteServer.d.ts +13 -0
- package/lib/pythonServer/starlette/starletteServer.js +49 -0
- package/lib/pythonServer/streamlit/streamlitServer.d.ts +6 -26
- package/lib/pythonServer/streamlit/streamlitServer.js +33 -41
- package/lib/pythonServer/tornado/tornadoServer.d.ts +6 -26
- package/lib/pythonServer/tornado/tornadoServer.js +28 -36
- package/lib/pythonWidget/comm.d.ts +11 -0
- package/lib/pythonWidget/comm.js +52 -0
- package/lib/pythonWidget/pythonWidget.d.ts +5 -0
- package/lib/pythonWidget/pythonWidget.js +19 -0
- package/lib/pythonWidget/pythonWidgetModel.d.ts +16 -4
- package/lib/pythonWidget/pythonWidgetModel.js +77 -13
- package/lib/sandpackWidget/sandpackFilesModel.d.ts +6 -2
- package/lib/sandpackWidget/sandpackFilesModel.js +13 -2
- package/lib/sandpackWidget/sandpackPanel.d.ts +10 -1
- package/lib/sandpackWidget/sandpackPanel.js +38 -3
- package/lib/swConnection/mainConnectionManager.d.ts +4 -4
- package/lib/swConnection/mainConnectionManager.js +23 -12
- package/lib/token.d.ts +2 -1
- package/lib/token.js +1 -0
- package/lib/tools.d.ts +6 -0
- package/lib/tools.js +25 -0
- package/lib/type.d.ts +39 -4
- package/lib/type.js +2 -0
- package/lib/websocket/websocket.js +5 -1
- package/package.json +6 -6
- package/src/document/commands.ts +91 -0
- package/src/document/iframePanel.ts +4 -1
- package/src/document/plugin.ts +28 -7
- package/src/document/toolbar.ts +39 -0
- package/src/document/widgetFactory.ts +16 -6
- package/src/global.d.ts +5 -0
- package/src/pythonServer/baseServer.ts +245 -0
- package/src/pythonServer/dash/dashServer.ts +25 -35
- package/src/pythonServer/index.ts +9 -5
- package/src/pythonServer/kernelExecutor.ts +8 -147
- package/src/pythonServer/shiny/shinyServer.ts +62 -0
- package/src/pythonServer/starlette/starletteServer.ts +59 -0
- package/src/pythonServer/streamlit/streamlitServer.ts +40 -62
- package/src/pythonServer/tornado/tornadoServer.ts +33 -60
- package/src/pythonWidget/comm.ts +65 -0
- package/src/pythonWidget/pythonWidget.ts +19 -1
- package/src/pythonWidget/pythonWidgetModel.ts +107 -20
- package/src/sandpackWidget/sandpackFilesModel.ts +17 -3
- package/src/sandpackWidget/sandpackPanel.ts +45 -4
- package/src/swConnection/mainConnectionManager.ts +28 -20
- package/src/token.ts +5 -1
- package/src/tools.ts +31 -0
- package/src/type.ts +46 -7
- package/src/websocket/websocket.ts +9 -1
- package/style/base.css +7 -0
- package/style/icons/autoreload.svg +16 -0
- package/style/icons/box.svg +12 -0
- package/style/icons/externallink.svg +10 -0
- package/lib/pythonServer/common/generatedPythonFiles.d.ts +0 -2
- package/lib/pythonServer/common/generatedPythonFiles.js +0 -72
- package/lib/pythonServer/dash/generatedPythonFiles.d.ts +0 -2
- package/lib/pythonServer/dash/generatedPythonFiles.js +0 -31
- package/lib/pythonServer/streamlit/generatedPythonFiles.d.ts +0 -2
- package/lib/pythonServer/streamlit/generatedPythonFiles.js +0 -147
- package/lib/pythonServer/tornado/generatedPythonFiles.d.ts +0 -3
- package/lib/pythonServer/tornado/generatedPythonFiles.js +0 -456
- package/src/pythonServer/common/generatedPythonFiles.ts +0 -73
- package/src/pythonServer/dash/generatedPythonFiles.ts +0 -32
- package/src/pythonServer/streamlit/generatedPythonFiles.ts +0 -148
- package/src/pythonServer/tornado/generatedPythonFiles.ts +0 -457
|
@@ -1,456 +0,0 @@
|
|
|
1
|
-
// Auto-generated TypeScript file from Python files
|
|
2
|
-
export const bootstrap = `
|
|
3
|
-
import sys
|
|
4
|
-
|
|
5
|
-
if "tornado.gen" in sys.modules:
|
|
6
|
-
del sys.modules["tornado.gen"]
|
|
7
|
-
|
|
8
|
-
tornado = __jupyterpack_import_from_path(
|
|
9
|
-
"tornado", "/lib/python3.13/site-packages/tornado/__init__.py"
|
|
10
|
-
)
|
|
11
|
-
`;
|
|
12
|
-
export const tornadoBridge = `
|
|
13
|
-
import asyncio
|
|
14
|
-
import base64
|
|
15
|
-
import json
|
|
16
|
-
import logging
|
|
17
|
-
import tornado
|
|
18
|
-
|
|
19
|
-
from tornado.http1connection import HTTP1Connection, HTTP1ConnectionParameters
|
|
20
|
-
from tornado.iostream import BaseIOStream, IOStream
|
|
21
|
-
from tornado.httputil import HTTPHeaders, RequestStartLine, HTTPServerRequest
|
|
22
|
-
from tornado.websocket import WebSocketHandler
|
|
23
|
-
import tornado.escape
|
|
24
|
-
import pyjs
|
|
25
|
-
from typing import Any, Dict, List, Optional, Tuple
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
logger = logging.getLogger(__name__)
|
|
29
|
-
logger.setLevel(logging.WARN)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def convert_headers(
|
|
33
|
-
headers: List[Tuple[str, str]],
|
|
34
|
-
) -> HTTPHeaders:
|
|
35
|
-
tornado_headers = HTTPHeaders()
|
|
36
|
-
for k, v in headers:
|
|
37
|
-
tornado_headers.add(k, v)
|
|
38
|
-
return tornado_headers
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def encode_broadcast_message(
|
|
42
|
-
kernel_client_id: str,
|
|
43
|
-
ws_url: str,
|
|
44
|
-
msg: str | bytes,
|
|
45
|
-
action: str = "backend_message",
|
|
46
|
-
):
|
|
47
|
-
if isinstance(msg, bytes):
|
|
48
|
-
is_binary = True
|
|
49
|
-
b64_msg = base64.b64encode(msg).decode("ascii")
|
|
50
|
-
elif isinstance(msg, str):
|
|
51
|
-
is_binary = False
|
|
52
|
-
b64_msg = msg
|
|
53
|
-
|
|
54
|
-
return json.dumps(
|
|
55
|
-
{
|
|
56
|
-
"action": action,
|
|
57
|
-
"dest": kernel_client_id,
|
|
58
|
-
"wsUrl": ws_url,
|
|
59
|
-
"payload": {"isBinary": is_binary, "data": b64_msg},
|
|
60
|
-
}
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def decode_broadcast_message(payload_message: str):
|
|
65
|
-
msg_object = json.loads(payload_message)
|
|
66
|
-
is_binary = msg_object["isBinary"]
|
|
67
|
-
data = msg_object["data"]
|
|
68
|
-
if is_binary:
|
|
69
|
-
return base64.b64decode(data)
|
|
70
|
-
else:
|
|
71
|
-
return data
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class DumpStream(BaseIOStream):
|
|
75
|
-
max_buffer_size = 1048576000
|
|
76
|
-
|
|
77
|
-
def close_fd(*args, **kwargs):
|
|
78
|
-
pass
|
|
79
|
-
|
|
80
|
-
def write_to_fd(self, buf):
|
|
81
|
-
raise NotImplementedError("Not supported!")
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
class ConnectionState:
|
|
85
|
-
def __init__(self):
|
|
86
|
-
self._reply_body = b""
|
|
87
|
-
self._finish_future = asyncio.Future()
|
|
88
|
-
self._reply_headers = []
|
|
89
|
-
self._status: Optional[int] = None
|
|
90
|
-
|
|
91
|
-
@property
|
|
92
|
-
def reply_body(self):
|
|
93
|
-
return base64.b64encode(self._reply_body).decode("ascii")
|
|
94
|
-
|
|
95
|
-
@property
|
|
96
|
-
def reply_headers(self):
|
|
97
|
-
reply_headers = json.dumps(dict(self._reply_headers)).encode("utf-8")
|
|
98
|
-
return base64.b64encode(reply_headers).decode("ascii")
|
|
99
|
-
|
|
100
|
-
@property
|
|
101
|
-
def status(self):
|
|
102
|
-
return self._status
|
|
103
|
-
|
|
104
|
-
@property
|
|
105
|
-
def finish_future(self):
|
|
106
|
-
return self._finish_future
|
|
107
|
-
|
|
108
|
-
def append_reply_body(self, chunk: bytes):
|
|
109
|
-
self._reply_body += chunk
|
|
110
|
-
|
|
111
|
-
def append_reply_header(self, headers: List[Tuple[str, str]]):
|
|
112
|
-
self._reply_headers.extend(headers)
|
|
113
|
-
|
|
114
|
-
def set_status(self, status: int):
|
|
115
|
-
self._status = status
|
|
116
|
-
|
|
117
|
-
def finish(self):
|
|
118
|
-
self._finish_future.set_result(None)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
class PatchedConnection(HTTP1Connection):
|
|
122
|
-
def __init__(
|
|
123
|
-
self,
|
|
124
|
-
stream: IOStream,
|
|
125
|
-
is_client: bool,
|
|
126
|
-
params: Optional[HTTP1ConnectionParameters] = None,
|
|
127
|
-
context: Optional[object] = None,
|
|
128
|
-
initial_request_data: Optional[Dict] = None,
|
|
129
|
-
) -> None:
|
|
130
|
-
super().__init__(stream, is_client, params, context)
|
|
131
|
-
self._connection_state = ConnectionState()
|
|
132
|
-
if initial_request_data is not None:
|
|
133
|
-
self._request_start_line = RequestStartLine(
|
|
134
|
-
initial_request_data.get("request_method"),
|
|
135
|
-
initial_request_data.get("request_url"),
|
|
136
|
-
"HTTP/1.1",
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
@property
|
|
140
|
-
def connection_state(self):
|
|
141
|
-
return self._connection_state
|
|
142
|
-
|
|
143
|
-
def write(self, chunk: bytes):
|
|
144
|
-
self._connection_state.append_reply_body(chunk)
|
|
145
|
-
f = asyncio.Future()
|
|
146
|
-
f.set_result(None)
|
|
147
|
-
return f
|
|
148
|
-
|
|
149
|
-
def write_headers(self, start_line, headers, chunk=None):
|
|
150
|
-
self._connection_state.set_status(int(start_line.code))
|
|
151
|
-
self._connection_state.append_reply_header(headers.get_all())
|
|
152
|
-
if chunk is not None:
|
|
153
|
-
self._connection_state.append_reply_body(chunk)
|
|
154
|
-
f = asyncio.Future()
|
|
155
|
-
f.set_result(None)
|
|
156
|
-
return f
|
|
157
|
-
|
|
158
|
-
def finish(self):
|
|
159
|
-
self._connection_state.finish()
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
class WSConnection:
|
|
163
|
-
def __init__(
|
|
164
|
-
self,
|
|
165
|
-
instance_id: str,
|
|
166
|
-
kernel_client_id: str,
|
|
167
|
-
ws_url: str,
|
|
168
|
-
broadcast_channel: Any,
|
|
169
|
-
):
|
|
170
|
-
self.instance_id = instance_id
|
|
171
|
-
self.kernel_client_id = kernel_client_id
|
|
172
|
-
self.ws_url = ws_url
|
|
173
|
-
self.broadcast_channel = broadcast_channel
|
|
174
|
-
|
|
175
|
-
client_terminated = False
|
|
176
|
-
|
|
177
|
-
def is_closing(self):
|
|
178
|
-
return False
|
|
179
|
-
|
|
180
|
-
def write_message(self, msg, binary=False):
|
|
181
|
-
if isinstance(msg, dict):
|
|
182
|
-
msg = tornado.escape.json_encode(msg)
|
|
183
|
-
self.broadcast_channel.postMessage(
|
|
184
|
-
encode_broadcast_message(self.kernel_client_id, self.ws_url, msg)
|
|
185
|
-
)
|
|
186
|
-
f = asyncio.Future()
|
|
187
|
-
f.set_result(None)
|
|
188
|
-
return f
|
|
189
|
-
|
|
190
|
-
def write_ping(self, data):
|
|
191
|
-
pass
|
|
192
|
-
|
|
193
|
-
def close(self, code, reason=None):
|
|
194
|
-
pass
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class TornadoBridge:
|
|
198
|
-
"""
|
|
199
|
-
Encapsulates Tornado app lifecycle, request/response bridging, and WebSocket handling.
|
|
200
|
-
"""
|
|
201
|
-
|
|
202
|
-
def __init__(self, tornado_app: tornado.web.Application, base_url: str):
|
|
203
|
-
self.base_url = base_url
|
|
204
|
-
self.tornado_app = tornado_app
|
|
205
|
-
self.websocket_handlers: Dict[str, tornado.websocket.WebSocketHandler] = {}
|
|
206
|
-
self._patched = False
|
|
207
|
-
self._ws_handlers = {}
|
|
208
|
-
self._ws_broadcast_channels = {}
|
|
209
|
-
|
|
210
|
-
# ---------------------------
|
|
211
|
-
# Fetch Handling
|
|
212
|
-
# ---------------------------
|
|
213
|
-
|
|
214
|
-
async def fetch(self, request: Dict):
|
|
215
|
-
"""
|
|
216
|
-
request: {body: Optional[bytes], headers: List[Tuple[str, str]], method: str, url: str}
|
|
217
|
-
"""
|
|
218
|
-
|
|
219
|
-
request_headers = convert_headers(request.get("headers", []))
|
|
220
|
-
request_method = request.get("method", "GET").upper()
|
|
221
|
-
request_url: str = request.get("url", "/")
|
|
222
|
-
|
|
223
|
-
request_body = request.get("body", None)
|
|
224
|
-
stream = DumpStream()
|
|
225
|
-
|
|
226
|
-
connection = PatchedConnection(
|
|
227
|
-
stream,
|
|
228
|
-
is_client=False,
|
|
229
|
-
params=None,
|
|
230
|
-
context=None,
|
|
231
|
-
initial_request_data={
|
|
232
|
-
"request_method": request_method,
|
|
233
|
-
"request_url": request_url,
|
|
234
|
-
},
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
request = HTTPServerRequest(
|
|
238
|
-
method=request_method,
|
|
239
|
-
uri=request_url,
|
|
240
|
-
headers=request_headers,
|
|
241
|
-
body=request_body,
|
|
242
|
-
connection=connection,
|
|
243
|
-
)
|
|
244
|
-
try:
|
|
245
|
-
handler = self.tornado_app.find_handler(request)
|
|
246
|
-
handler.execute()
|
|
247
|
-
connection_state = connection.connection_state
|
|
248
|
-
await connection_state.finish_future
|
|
249
|
-
|
|
250
|
-
return {
|
|
251
|
-
"content": connection_state.reply_body,
|
|
252
|
-
"headers": connection_state.reply_headers,
|
|
253
|
-
"status_code": connection_state.status,
|
|
254
|
-
}
|
|
255
|
-
except Exception as e:
|
|
256
|
-
return {
|
|
257
|
-
"headers": "e30=", # {}
|
|
258
|
-
"content": base64.b64encode(str(e).encode("utf-8")).decode("ascii"),
|
|
259
|
-
"status_code": 500,
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
# ---------------------------
|
|
263
|
-
# Websocket Handling
|
|
264
|
-
# ---------------------------
|
|
265
|
-
async def open_ws(
|
|
266
|
-
self,
|
|
267
|
-
instance_id: str,
|
|
268
|
-
kernel_client_id: str,
|
|
269
|
-
ws_url: str,
|
|
270
|
-
protocols_str: str | None,
|
|
271
|
-
):
|
|
272
|
-
handler_key = f"{instance_id}@{kernel_client_id}@{ws_url}"
|
|
273
|
-
broadcast_channel = self._ws_broadcast_channels.get(handler_key, None)
|
|
274
|
-
|
|
275
|
-
if broadcast_channel is None:
|
|
276
|
-
broadcast_channel = pyjs.js.BroadcastChannel.new(
|
|
277
|
-
f"/jupyterpack/ws/{instance_id}"
|
|
278
|
-
)
|
|
279
|
-
self._ws_broadcast_channels[handler_key] = broadcast_channel
|
|
280
|
-
|
|
281
|
-
headers = convert_headers(
|
|
282
|
-
[
|
|
283
|
-
("X-Sec-WebSocket-Protocol", protocols_str),
|
|
284
|
-
("Upgrade", "websocket"),
|
|
285
|
-
("Connection", "Upgrade"),
|
|
286
|
-
("Sec-WebSocket-Key", ""),
|
|
287
|
-
("Sec-WebSocket-Version", "13"),
|
|
288
|
-
]
|
|
289
|
-
)
|
|
290
|
-
protocols = []
|
|
291
|
-
if protocols_str is not None:
|
|
292
|
-
protocols = protocols_str.split(",")
|
|
293
|
-
|
|
294
|
-
stream = DumpStream()
|
|
295
|
-
ws_connection = WSConnection(
|
|
296
|
-
instance_id, kernel_client_id, ws_url, broadcast_channel
|
|
297
|
-
)
|
|
298
|
-
connection = PatchedConnection(
|
|
299
|
-
stream,
|
|
300
|
-
is_client=False,
|
|
301
|
-
params=None,
|
|
302
|
-
context=None,
|
|
303
|
-
initial_request_data={
|
|
304
|
-
"request_method": "GET",
|
|
305
|
-
"request_url": ws_url,
|
|
306
|
-
},
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
request = tornado.httputil.HTTPServerRequest(
|
|
310
|
-
method="GET",
|
|
311
|
-
uri=ws_url,
|
|
312
|
-
headers=headers,
|
|
313
|
-
body=None,
|
|
314
|
-
connection=connection,
|
|
315
|
-
)
|
|
316
|
-
|
|
317
|
-
handler = self.tornado_app.find_handler(request)
|
|
318
|
-
ret = handler.execute()
|
|
319
|
-
if ret is not None:
|
|
320
|
-
await ret
|
|
321
|
-
connection_state = connection.connection_state
|
|
322
|
-
await connection_state.finish_future
|
|
323
|
-
|
|
324
|
-
if isinstance(handler.handler, WebSocketHandler):
|
|
325
|
-
handler.handler.select_subprotocol(protocols)
|
|
326
|
-
handler.handler.ws_connection = ws_connection
|
|
327
|
-
ret = handler.handler.open(
|
|
328
|
-
*handler.handler.open_args, **handler.handler.open_kwargs
|
|
329
|
-
)
|
|
330
|
-
if ret is not None:
|
|
331
|
-
try:
|
|
332
|
-
await ret
|
|
333
|
-
except Exception:
|
|
334
|
-
raise ("Failed to open websocket")
|
|
335
|
-
|
|
336
|
-
self._ws_handlers[handler_key] = handler
|
|
337
|
-
|
|
338
|
-
self.send_ws_message_to_js(
|
|
339
|
-
instance_id, kernel_client_id, ws_url, "", "connected"
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
def send_ws_message_to_js(
|
|
343
|
-
self,
|
|
344
|
-
instance_id: str,
|
|
345
|
-
kernel_client_id: str,
|
|
346
|
-
ws_url: str,
|
|
347
|
-
msg: str | bytes,
|
|
348
|
-
action: str = "backend_message",
|
|
349
|
-
):
|
|
350
|
-
handler_key = f"{instance_id}@{kernel_client_id}@{ws_url}"
|
|
351
|
-
broadcast_channel = self._ws_broadcast_channels.get(handler_key, None)
|
|
352
|
-
if broadcast_channel is not None:
|
|
353
|
-
broadcast_channel.postMessage(
|
|
354
|
-
encode_broadcast_message(kernel_client_id, ws_url, msg, action)
|
|
355
|
-
)
|
|
356
|
-
|
|
357
|
-
async def receive_ws_message_from_js(
|
|
358
|
-
self, instance_id: str, kernel_client_id: str, ws_url: str, payload_message: str
|
|
359
|
-
):
|
|
360
|
-
handler_key = f"{instance_id}@{kernel_client_id}@{ws_url}"
|
|
361
|
-
handler = self._ws_handlers.get(handler_key, None)
|
|
362
|
-
if handler is not None:
|
|
363
|
-
data = decode_broadcast_message(payload_message)
|
|
364
|
-
future = handler.handler.on_message(data)
|
|
365
|
-
if future is not None:
|
|
366
|
-
await future
|
|
367
|
-
`;
|
|
368
|
-
export const tornadoLoader = `
|
|
369
|
-
import base64
|
|
370
|
-
import json
|
|
371
|
-
|
|
372
|
-
try:
|
|
373
|
-
# Check if __jupyterpack_tornado_instance defined from previous run
|
|
374
|
-
__jupyterpack_tornado_instance
|
|
375
|
-
except NameError:
|
|
376
|
-
__jupyterpack_tornado_instance = {
|
|
377
|
-
"tornado_bridge": None,
|
|
378
|
-
"tornado_server": None,
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
def __jupyterpack_tornado_dispose():
|
|
382
|
-
global __jupyterpack_tornado_instance
|
|
383
|
-
__jupyterpack_tornado_instance = {
|
|
384
|
-
"tornado_bridge": None,
|
|
385
|
-
"tornado_server": None,
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
async def __jupyterpack_tornado_open_ws(
|
|
391
|
-
instance_id: str, kernel_client_id: str, ws_url: str, protocols_str: str | None
|
|
392
|
-
):
|
|
393
|
-
tornado_bridge = __jupyterpack_tornado_instance["tornado_bridge"]
|
|
394
|
-
if tornado_bridge is None:
|
|
395
|
-
raise Exception("Missing tornado instance")
|
|
396
|
-
await tornado_bridge.open_ws(instance_id, kernel_client_id, ws_url, protocols_str)
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
async def __jupyterpack_tornado_receive_ws_message(
|
|
400
|
-
instance_id: str, kernel_client_id: str, ws_url: str, payload_message: str
|
|
401
|
-
):
|
|
402
|
-
tornado_bridge = __jupyterpack_tornado_instance["tornado_bridge"]
|
|
403
|
-
if tornado_bridge is None:
|
|
404
|
-
raise Exception("Missing tornado instance")
|
|
405
|
-
await tornado_bridge.receive_ws_message_from_js(
|
|
406
|
-
instance_id, kernel_client_id, ws_url, payload_message
|
|
407
|
-
)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
async def __jupyterpack_tornado_get_response(
|
|
411
|
-
method, url, headers, content=None, params=None
|
|
412
|
-
):
|
|
413
|
-
global __jupyterpack_tornado_instance
|
|
414
|
-
if __jupyterpack_tornado_instance["tornado_server"] is None:
|
|
415
|
-
__jupyterpack_tornado_instance["tornado_server"] = app # noqa
|
|
416
|
-
__jupyterpack_tornado_instance["tornado_bridge"] = TornadoBridge( # noqa
|
|
417
|
-
app, "{{base_url}}" # noqa
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
tornado_bridge = __jupyterpack_tornado_instance["tornado_bridge"]
|
|
421
|
-
req_dict = {
|
|
422
|
-
"method": method,
|
|
423
|
-
"url": url,
|
|
424
|
-
"headers": list(headers.items()),
|
|
425
|
-
"body": content,
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
try:
|
|
429
|
-
res_body, res_headers, res_status = await tornado_bridge.fetch(req_dict)
|
|
430
|
-
response = {
|
|
431
|
-
"headers": dict(res_headers),
|
|
432
|
-
"content": res_body,
|
|
433
|
-
"status_code": res_status,
|
|
434
|
-
"original_request": {
|
|
435
|
-
"method": method,
|
|
436
|
-
"url": url,
|
|
437
|
-
"params": params,
|
|
438
|
-
"headers": headers,
|
|
439
|
-
},
|
|
440
|
-
}
|
|
441
|
-
except Exception as e:
|
|
442
|
-
response = {
|
|
443
|
-
"headers": {},
|
|
444
|
-
"content": str(e),
|
|
445
|
-
"status_code": 500,
|
|
446
|
-
"original_request": {
|
|
447
|
-
"method": method,
|
|
448
|
-
"url": url,
|
|
449
|
-
"params": params,
|
|
450
|
-
"headers": headers,
|
|
451
|
-
},
|
|
452
|
-
}
|
|
453
|
-
json_str = json.dumps(response)
|
|
454
|
-
b64_str = base64.b64encode(json_str.encode("utf-8")).decode("utf-8")
|
|
455
|
-
return b64_str
|
|
456
|
-
`;
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// Auto-generated TypeScript file from Python files
|
|
2
|
-
|
|
3
|
-
export const patch = `
|
|
4
|
-
import pyodide_http
|
|
5
|
-
import collections
|
|
6
|
-
|
|
7
|
-
if not hasattr(collections, "MutableSet"):
|
|
8
|
-
import collections.abc
|
|
9
|
-
|
|
10
|
-
collections.MutableSet = collections.abc.MutableSet
|
|
11
|
-
|
|
12
|
-
pyodide_http.patch_all()`;
|
|
13
|
-
export const tools = `
|
|
14
|
-
import importlib.util
|
|
15
|
-
import sys
|
|
16
|
-
from types import ModuleType
|
|
17
|
-
|
|
18
|
-
import tempfile
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
from typing import List
|
|
21
|
-
import os
|
|
22
|
-
|
|
23
|
-
os.environ.setdefault("JUPYTERPACK_BASE_URL", "{{base_url}}")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def __jupyterpack_import_from_path(module_name: str, path: str) -> ModuleType:
|
|
27
|
-
"""
|
|
28
|
-
Import a Python module from a given file path.
|
|
29
|
-
Always reloads (does not use sys.modules cache).
|
|
30
|
-
"""
|
|
31
|
-
# Remove from sys.modules if already loaded
|
|
32
|
-
if module_name in sys.modules:
|
|
33
|
-
del sys.modules[module_name]
|
|
34
|
-
|
|
35
|
-
spec = importlib.util.spec_from_file_location(module_name, path)
|
|
36
|
-
if spec is None or spec.loader is None:
|
|
37
|
-
raise ImportError(f"Cannot import module {module_name} from {path}")
|
|
38
|
-
|
|
39
|
-
module = importlib.util.module_from_spec(spec)
|
|
40
|
-
sys.modules[module_name] = module
|
|
41
|
-
spec.loader.exec_module(module)
|
|
42
|
-
return module
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def __jupyterpack_create_mock_module(
|
|
46
|
-
module_names: List[str], mock_content: str, patch_parent=True
|
|
47
|
-
):
|
|
48
|
-
tmpdir = tempfile.TemporaryDirectory()
|
|
49
|
-
package_dir = Path(tmpdir.name) / "__jupyterpack_mock_module"
|
|
50
|
-
package_dir.mkdir()
|
|
51
|
-
(package_dir / "__init__.py").write_text(mock_content)
|
|
52
|
-
|
|
53
|
-
sys.path.insert(0, tmpdir.name)
|
|
54
|
-
mock_module = importlib.import_module("__jupyterpack_mock_module")
|
|
55
|
-
sys.path.pop(0)
|
|
56
|
-
for module_name in module_names:
|
|
57
|
-
if patch_parent:
|
|
58
|
-
parts = module_name.split(".")
|
|
59
|
-
for i in range(1, len(parts) + 1):
|
|
60
|
-
subpath = ".".join(parts[:i])
|
|
61
|
-
sys.modules[subpath] = mock_module
|
|
62
|
-
|
|
63
|
-
for i in range(1, len(parts)):
|
|
64
|
-
parent_name = ".".join(parts[:i])
|
|
65
|
-
child_name = ".".join(parts[: i + 1])
|
|
66
|
-
parent_mod = sys.modules[parent_name]
|
|
67
|
-
child_mod = sys.modules[child_name]
|
|
68
|
-
setattr(parent_mod, parts[i], child_mod)
|
|
69
|
-
else:
|
|
70
|
-
sys.modules[module_name] = mock_module
|
|
71
|
-
|
|
72
|
-
return tmpdir
|
|
73
|
-
`;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// Auto-generated TypeScript file from Python files
|
|
2
|
-
|
|
3
|
-
export const bootstrap = `
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
os.environ["DASH_URL_BASE_PATHNAME"] = "{{base_url}}"
|
|
7
|
-
`;
|
|
8
|
-
export const dashLoader = `
|
|
9
|
-
import httpx, json, base64
|
|
10
|
-
__jupyterpack_dash_transport = httpx.WSGITransport(app=app.server) # noqa
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def __jupyterpack_dash_get_response(method, url, headers, content=None, params=None):
|
|
14
|
-
decoded_content = None
|
|
15
|
-
if content is not None:
|
|
16
|
-
decoded_content = base64.b64decode(content)
|
|
17
|
-
# decoded_content = content.decode()
|
|
18
|
-
with httpx.Client(
|
|
19
|
-
transport=__jupyterpack_dash_transport, base_url="http://testserver"
|
|
20
|
-
) as client:
|
|
21
|
-
r = client.request(
|
|
22
|
-
method, url, headers=headers, content=decoded_content, params=params
|
|
23
|
-
)
|
|
24
|
-
reply_headers = json.dumps(dict(r.headers)).encode("utf-8")
|
|
25
|
-
response = {
|
|
26
|
-
"headers": base64.b64encode(reply_headers).decode("ascii"),
|
|
27
|
-
"content": base64.b64encode(r.content).decode("ascii"),
|
|
28
|
-
"status_code": r.status_code,
|
|
29
|
-
}
|
|
30
|
-
json_str = json.dumps(response)
|
|
31
|
-
return json_str
|
|
32
|
-
`;
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
// Auto-generated TypeScript file from Python files
|
|
2
|
-
|
|
3
|
-
export const bootstrap = `
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
import threading
|
|
7
|
-
import streamlit.watcher.path_watcher
|
|
8
|
-
import contextlib
|
|
9
|
-
import streamlit.elements.spinner
|
|
10
|
-
|
|
11
|
-
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "python"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class MockedThread(threading.Thread):
|
|
15
|
-
def start(self):
|
|
16
|
-
threading.current_thread = lambda: self
|
|
17
|
-
try:
|
|
18
|
-
self.run()
|
|
19
|
-
except Exception as e:
|
|
20
|
-
raise e
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
threading.Thread = MockedThread
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class WatcherMock:
|
|
27
|
-
def __init__(
|
|
28
|
-
self,
|
|
29
|
-
path,
|
|
30
|
-
callback,
|
|
31
|
-
glob_pattern: str | None = None,
|
|
32
|
-
allow_nonexistent: bool = False,
|
|
33
|
-
) -> None:
|
|
34
|
-
pass
|
|
35
|
-
|
|
36
|
-
def close(self) -> None:
|
|
37
|
-
pass
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
streamlit.watcher.path_watcher.watchdog_available = False
|
|
41
|
-
streamlit.watcher.path_watcher.EventBasedPathWatcher = WatcherMock
|
|
42
|
-
streamlit.watcher.path_watcher._is_watchdog_available = lambda: False
|
|
43
|
-
streamlit.watcher.path_watcher.get_path_watcher_class = lambda x: WatcherMock
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class MockThreading:
|
|
47
|
-
class Timer:
|
|
48
|
-
def __init__(self, delay, cb):
|
|
49
|
-
cb()
|
|
50
|
-
|
|
51
|
-
def start(self):
|
|
52
|
-
pass
|
|
53
|
-
|
|
54
|
-
Lock = contextlib.nullcontext
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
streamlit.elements.spinner.threading = MockThreading
|
|
58
|
-
`;
|
|
59
|
-
export const streamlitLoader = `
|
|
60
|
-
import json
|
|
61
|
-
from streamlit import config
|
|
62
|
-
import streamlit.web.server.server as st_server
|
|
63
|
-
from streamlit.runtime.runtime import Runtime
|
|
64
|
-
|
|
65
|
-
try:
|
|
66
|
-
# Check if __jupyterpack_streamlit_instance defined from previous run
|
|
67
|
-
__jupyterpack_streamlit_instance
|
|
68
|
-
except NameError:
|
|
69
|
-
__jupyterpack_streamlit_instance = {
|
|
70
|
-
"tornado_bridge": None,
|
|
71
|
-
"streamlit_server": None,
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def __jupyterpack_create_streamlit_app(base_url, script_path):
|
|
76
|
-
if Runtime._instance is not None:
|
|
77
|
-
Runtime._instance.stop()
|
|
78
|
-
Runtime._instance = None
|
|
79
|
-
config.set_option("server.baseUrlPath", base_url)
|
|
80
|
-
|
|
81
|
-
config.set_option("server.port", 6789)
|
|
82
|
-
config.set_option("server.enableCORS", False)
|
|
83
|
-
config.set_option("server.enableXsrfProtection", False)
|
|
84
|
-
|
|
85
|
-
streamlit_server = st_server.Server(script_path, True)
|
|
86
|
-
return streamlit_server
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def __jupyterpack_streamlit_dispose():
|
|
90
|
-
global __jupyterpack_streamlit_instance
|
|
91
|
-
streamlit_server = __jupyterpack_streamlit_instance.get("streamlit_server", None)
|
|
92
|
-
if streamlit_server:
|
|
93
|
-
streamlit_server._runtime.stop()
|
|
94
|
-
|
|
95
|
-
__jupyterpack_streamlit_instance = {
|
|
96
|
-
"tornado_bridge": None,
|
|
97
|
-
"streamlit_server": None,
|
|
98
|
-
}
|
|
99
|
-
del streamlit_server
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
async def __jupyterpack_streamlit_open_ws(
|
|
103
|
-
instance_id: str, kernel_client_id: str, ws_url: str, protocols_str: str | None
|
|
104
|
-
):
|
|
105
|
-
tornado_bridge = __jupyterpack_streamlit_instance["tornado_bridge"]
|
|
106
|
-
if tornado_bridge is None:
|
|
107
|
-
raise Exception("Missing tornado instance")
|
|
108
|
-
await tornado_bridge.open_ws(instance_id, kernel_client_id, ws_url, protocols_str)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
async def __jupyterpack_streamlit_receive_ws_message(
|
|
112
|
-
instance_id: str, kernel_client_id: str, ws_url: str, payload_message: str
|
|
113
|
-
):
|
|
114
|
-
tornado_bridge = __jupyterpack_streamlit_instance["tornado_bridge"]
|
|
115
|
-
if tornado_bridge is None:
|
|
116
|
-
raise Exception("Missing tornado instance")
|
|
117
|
-
await tornado_bridge.receive_ws_message_from_js(
|
|
118
|
-
instance_id, kernel_client_id, ws_url, payload_message
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
async def __jupyterpack_streamlit_get_response(
|
|
123
|
-
method, url, headers, content=None, params=None
|
|
124
|
-
):
|
|
125
|
-
global __jupyterpack_streamlit_instance
|
|
126
|
-
if not __jupyterpack_streamlit_instance["streamlit_server"]:
|
|
127
|
-
streamlit_server = __jupyterpack_create_streamlit_app(
|
|
128
|
-
"{{base_url}}", "{{script_path}}"
|
|
129
|
-
) # noqa
|
|
130
|
-
app = streamlit_server._create_app()
|
|
131
|
-
await streamlit_server._runtime.start()
|
|
132
|
-
__jupyterpack_streamlit_instance["streamlit_server"] = streamlit_server
|
|
133
|
-
__jupyterpack_streamlit_instance["tornado_bridge"] = TornadoBridge(
|
|
134
|
-
app, "{{base_url}}"
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
tornado_bridge = __jupyterpack_streamlit_instance["tornado_bridge"]
|
|
138
|
-
req_dict = {
|
|
139
|
-
"method": method,
|
|
140
|
-
"url": url,
|
|
141
|
-
"headers": list(headers.items()),
|
|
142
|
-
"body": content,
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
response = await tornado_bridge.fetch(req_dict)
|
|
146
|
-
json_str = json.dumps(response)
|
|
147
|
-
return json_str
|
|
148
|
-
`;
|