txl-kernel 0.1.24__tar.gz → 0.2.1__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.
@@ -0,0 +1,3 @@
1
+ __pycache__
2
+ # pixi environments
3
+ .pixi
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: txl_kernel
3
- Version: 0.1.24
3
+ Version: 0.2.1
4
4
  Summary: TXL plugin for a kernel driver
5
5
  Project-URL: Source, https://github.com/davidbrochart/jpterm/plugins/kernel
6
6
  Author-email: David Brochart <david.brochart@gmail.com>
@@ -10,12 +10,13 @@ Classifier: Development Status :: 4 - Beta
10
10
  Classifier: Programming Language :: Python
11
11
  Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
13
14
  Classifier: Programming Language :: Python :: Implementation :: CPython
14
15
  Classifier: Programming Language :: Python :: Implementation :: PyPy
15
16
  Requires-Python: >=3.10
17
+ Requires-Dist: pycrdt<0.8.0,>=0.7.2
16
18
  Requires-Dist: python-dateutil>=2.8.2
17
19
  Requires-Dist: txl
18
- Requires-Dist: y-py<1,>=0.6.0
19
20
  Description-Content-Type: text/markdown
20
21
 
21
22
  # TXL plugin for a kernel driver
@@ -17,13 +17,14 @@ classifiers = [
17
17
  "Programming Language :: Python",
18
18
  "Programming Language :: Python :: 3.10",
19
19
  "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
20
21
  "Programming Language :: Python :: Implementation :: CPython",
21
22
  "Programming Language :: Python :: Implementation :: PyPy",
22
23
  ]
23
24
  dependencies = [
24
25
  "txl",
25
26
  "python-dateutil >=2.8.2",
26
- "y-py >=0.6.0,<1",
27
+ "pycrdt >=0.7.2,<0.8.0",
27
28
  ]
28
29
  dynamic = ["version"]
29
30
 
@@ -0,0 +1 @@
1
+ __version__ = "0.2.1"
@@ -1,8 +1,8 @@
1
1
  import asyncio
2
2
  import time
3
- from typing import Dict, List
3
+ from typing import Dict
4
4
 
5
- import y_py as Y
5
+ from pycrdt import Array, Map
6
6
 
7
7
  from .message import create_message
8
8
 
@@ -34,7 +34,7 @@ class Comm:
34
34
  class KernelMixin:
35
35
  def __init__(self):
36
36
  self.msg_cnt = 0
37
- self.execute_requests: Dict[str, Dict[str, List[asyncio.Future]]] = {}
37
+ self.execute_requests: Dict[str, Dict[str, asyncio.Queue]] = {}
38
38
  self.recv_queue = asyncio.Queue()
39
39
  self.started = asyncio.Event()
40
40
  asyncio.create_task(self.recv())
@@ -55,18 +55,20 @@ class KernelMixin:
55
55
  await self.send_message(msg, self.shell_channel, change_date_to_str=True)
56
56
  msg_id = msg["header"]["msg_id"]
57
57
  self.execute_requests[msg_id] = {
58
- "iopub": [asyncio.Future()],
59
- "shell": [asyncio.Future()],
58
+ "iopub": asyncio.Queue(),
59
+ "shell": asyncio.Queue(),
60
60
  }
61
61
  try:
62
- msg = await asyncio.wait_for(self.execute_requests[msg_id]["shell"][0], new_timeout)
62
+ msg = await asyncio.wait_for(
63
+ self.execute_requests[msg_id]["shell"].get(), new_timeout
64
+ )
63
65
  except asyncio.TimeoutError:
64
66
  del self.execute_requests[msg_id]
65
67
  error_message = f"Kernel didn't respond in {timeout} seconds"
66
68
  raise RuntimeError(error_message)
67
69
  if msg["header"]["msg_type"] == "kernel_info_reply":
68
70
  try:
69
- msg = await asyncio.wait_for(self.execute_requests[msg_id]["iopub"][0], 0.2)
71
+ msg = await asyncio.wait_for(self.execute_requests[msg_id]["iopub"].get(), 0.2)
70
72
  except asyncio.TimeoutError:
71
73
  pass
72
74
  else:
@@ -91,21 +93,11 @@ class KernelMixin:
91
93
  if msg_id in self.execute_requests:
92
94
  # msg["header"] = str_to_date(msg["header"])
93
95
  # msg["parent_header"] = str_to_date(msg["parent_header"])
94
- future_msgs = self.execute_requests[msg_id][channel]
95
- if future_msgs:
96
- fut = future_msgs[-1]
97
- if fut.done():
98
- fut = asyncio.Future()
99
- future_msgs.append(fut)
100
- else:
101
- fut = asyncio.Future()
102
- future_msgs.append(fut)
103
- fut.set_result(msg)
96
+ self.execute_requests[msg_id][channel].put_nowait(msg)
104
97
 
105
98
  async def execute(
106
99
  self,
107
- ydoc: Y.YDoc,
108
- ycell: Y.YMap,
100
+ ycell: Map,
109
101
  timeout: float = float("inf"),
110
102
  msg_id: str = "",
111
103
  wait_for_executed: bool = True,
@@ -113,6 +105,7 @@ class KernelMixin:
113
105
  await self.started.wait()
114
106
  if ycell["cell_type"] != "code":
115
107
  return
108
+ ycell["outputs"].clear()
116
109
  code = str(ycell["source"])
117
110
  content = {"code": code, "silent": False}
118
111
  msg = create_message(
@@ -127,77 +120,81 @@ class KernelMixin:
127
120
  msg_id = msg["header"]["msg_id"]
128
121
  self.msg_cnt += 1
129
122
  self.execute_requests[msg_id] = {
130
- "iopub": [asyncio.Future()],
131
- "shell": [asyncio.Future()],
123
+ "iopub": asyncio.Queue(),
124
+ "shell": asyncio.Queue(),
132
125
  }
133
126
  await self.send_message(msg, self.shell_channel, change_date_to_str=True)
134
127
  if wait_for_executed:
135
128
  deadline = time.monotonic() + timeout
129
+ while True:
130
+ try:
131
+ msg = await asyncio.wait_for(
132
+ self.execute_requests[msg_id]["iopub"].get(),
133
+ deadline_to_timeout(deadline),
134
+ )
135
+ except asyncio.TimeoutError:
136
+ del self.execute_requests[msg_id]
137
+ error_message = f"Kernel didn't respond in {timeout} seconds"
138
+ raise RuntimeError(error_message)
139
+ await self._handle_outputs(ycell["outputs"], msg)
140
+ if (
141
+ (msg["header"]["msg_type"] == "status"
142
+ and msg["content"]["execution_state"] == "idle")
143
+ ):
144
+ break
136
145
  try:
137
- await asyncio.wait_for(
138
- self.execute_requests[msg_id]["iopub"][0],
139
- deadline_to_timeout(deadline),
140
- )
141
- except asyncio.TimeoutError:
142
- del self.execute_requests[msg_id]
143
- error_message = f"Kernel didn't respond in {timeout} seconds"
144
- raise RuntimeError(error_message)
145
- await self._handle_outputs(ydoc, ycell, self.execute_requests[msg_id]["iopub"])
146
- try:
147
- await asyncio.wait_for(
148
- self.execute_requests[msg_id]["shell"][0],
146
+ msg = await asyncio.wait_for(
147
+ self.execute_requests[msg_id]["shell"].get(),
149
148
  deadline_to_timeout(deadline),
150
149
  )
151
150
  except asyncio.TimeoutError:
152
151
  del self.execute_requests[msg_id]
153
152
  error_message = f"Kernel didn't respond in {timeout} seconds"
154
153
  raise RuntimeError(error_message)
155
- msg = self.execute_requests[msg_id]["shell"][0].result()
156
- with ydoc.begin_transaction() as txn:
157
- ycell.set(txn, "execution_count", msg["content"]["execution_count"])
154
+ ycell["execution_count"] = msg["content"]["execution_count"]
158
155
  del self.execute_requests[msg_id]
159
156
 
160
- async def _handle_outputs(
161
- self, ydoc: Y.YDoc, ycell: Y.YMap, future_messages: List[asyncio.Future]
162
- ):
163
- with ydoc.begin_transaction() as txn:
164
- ycell.set(txn, "outputs", [])
165
-
166
- while True:
167
- if not future_messages:
168
- future_messages.append(asyncio.Future())
169
- fut = future_messages[0]
170
- if not fut.done():
171
- await fut
172
- future_messages.pop(0)
173
- msg = fut.result()
174
- msg_type = msg["header"]["msg_type"]
175
- content = msg["content"]
176
- outputs = list(ycell["outputs"])
177
- if msg_type == "stream":
178
- if (not outputs) or (outputs[-1]["name"] != content["name"]):
179
- outputs.append({"name": content["name"], "output_type": msg_type, "text": []})
180
- outputs[-1]["text"].append(content["text"])
181
- elif msg_type in ("display_data", "execute_result"):
182
- outputs.append(
183
- {
184
- "data": content["data"],
185
- "execution_count": content["execution_count"],
186
- "metadata": {},
187
- "output_type": msg_type,
188
- }
189
- )
190
- elif msg_type == "error":
191
- outputs.append(
192
- {
193
- "ename": content["ename"],
194
- "evalue": content["evalue"],
195
- "output_type": "error",
196
- "traceback": content["traceback"],
197
- }
198
- )
199
- elif msg_type == "status" and msg["content"]["execution_state"] == "idle":
200
- break
201
-
202
- with ydoc.begin_transaction() as txn:
203
- ycell.set(txn, "outputs", outputs)
157
+ async def _handle_outputs(self, outputs: Array, msg):
158
+ msg_type = msg["header"]["msg_type"]
159
+ content = msg["content"]
160
+ if msg_type == "stream":
161
+ with outputs.doc.transaction():
162
+ # TODO: uncomment when changes are made in jupyter-ydoc
163
+ if (not outputs) or (outputs[-1]["name"] != content["name"]): # type: ignore
164
+ outputs.append(
165
+ #Map(
166
+ # {
167
+ # "name": content["name"],
168
+ # "output_type": msg_type,
169
+ # "text": Array([content["text"]]),
170
+ # }
171
+ #)
172
+ {
173
+ "name": content["name"],
174
+ "output_type": msg_type,
175
+ "text": [content["text"]],
176
+ }
177
+ )
178
+ else:
179
+ #outputs[-1]["text"].append(content["text"]) # type: ignore
180
+ last_output = outputs[-1]
181
+ last_output["text"].append(content["text"]) # type: ignore
182
+ outputs[-1] = last_output
183
+ elif msg_type in ("display_data", "execute_result"):
184
+ outputs.append(
185
+ {
186
+ "data": content["data"],
187
+ "execution_count": content["execution_count"],
188
+ "metadata": {},
189
+ "output_type": msg_type,
190
+ }
191
+ )
192
+ elif msg_type == "error":
193
+ outputs.append(
194
+ {
195
+ "ename": content["ename"],
196
+ "evalue": content["evalue"],
197
+ "output_type": "error",
198
+ "traceback": content["traceback"],
199
+ }
200
+ )
@@ -1 +0,0 @@
1
- __pycache__
@@ -1 +0,0 @@
1
- __version__ = "0.1.24"
File without changes
File without changes