conkernelclient 0.0.4__tar.gz → 0.0.6__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conkernelclient
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: Concurrent-safe Jupyter KernelClient
5
5
  Author-email: Jeremy Howard <github@jhoward.fastmail.fm>
6
6
  License: Apache-2.0
@@ -0,0 +1,2 @@
1
+ __version__ = "0.0.6"
2
+ from .core import *
@@ -12,6 +12,8 @@ d = { 'settings': { 'branch': 'main',
12
12
  'conkernelclient/core.py'),
13
13
  'conkernelclient.core.ConKernelClient.start_channels': ( 'core.html#conkernelclient.start_channels',
14
14
  'conkernelclient/core.py'),
15
+ 'conkernelclient.core.ConKernelClient.stdin_send': ( 'core.html#conkernelclient.stdin_send',
16
+ 'conkernelclient/core.py'),
15
17
  'conkernelclient.core.ConKernelClient.stop_channels': ( 'core.html#conkernelclient.stop_channels',
16
18
  'conkernelclient/core.py'),
17
19
  'conkernelclient.core.ConKernelManager': ('core.html#conkernelmanager', 'conkernelclient/core.py'),
@@ -15,7 +15,7 @@ from zmq.error import ZMQError
15
15
  from jupyter_client.kernelspec import KernelSpec
16
16
  from jupyter_client import AsyncKernelManager
17
17
  from traitlets import Type
18
- import asyncio, zmq.asyncio
18
+ import asyncio, zmq.asyncio, time
19
19
 
20
20
  # %% ../nbs/00_core.ipynb #374b75d0
21
21
  if not hasattr(Session, '_orig_send'): Session._orig_send = Session.send
@@ -27,7 +27,9 @@ def _send(self, stream, msg_or_type, content=None, parent=None, ident=None,
27
27
  # Force a sync, ensuring the send is fully registered internally
28
28
  # Avoids a race where the lock releases, another thread immediately calls send(),
29
29
  # and now 2 threads are interacting with the internal state before I/O thread has caught up
30
- if stream and hasattr(stream, 'io_thread'): stream.io_thread.socket.get(zmq.EVENTS)
30
+ if stream:
31
+ if hasattr(stream, 'io_thread'): stream.io_thread.socket.get(zmq.EVENTS)
32
+ elif hasattr(stream, 'getsockopt'): stream.getsockopt(zmq.EVENTS)
31
33
  return msg
32
34
 
33
35
  Session.send = _send
@@ -35,6 +37,7 @@ Session.send = _send
35
37
  # %% ../nbs/00_core.ipynb #d6a5fa6a
36
38
  class ConKernelClient(AsyncKernelClient):
37
39
  async def start_channels(self, shell:bool=True, iopub:bool=True, stdin:bool=True, hb:bool=True, control:bool=True):
40
+ "Start channels, wait for ready, and launch background shell-reply reader"
38
41
  super().start_channels(shell=shell, iopub=iopub, stdin=stdin, hb=hb, control=control)
39
42
  await self.wait_for_ready()
40
43
  self._pending = {}
@@ -45,18 +48,23 @@ class ConKernelClient(AsyncKernelClient):
45
48
  try: reply = await self.get_shell_msg(timeout=None)
46
49
  except Exception as e:
47
50
  for q in self._pending.values(): await q.put(e)
51
+ if self._pending: logging.warning(f"_reader died with pending - {self._pending}: {e}")
52
+ else: logging.warning(f"_reader died with no pending: {e}")
48
53
  break
49
54
  q = self._pending.get(reply["parent_header"].get("msg_id"))
50
55
  if q: await q.put(reply)
51
56
  self._shell_reader_task = asyncio.create_task(_reader())
52
57
  await _ready.wait()
58
+ await asyncio.sleep(0.2)
53
59
  return self
54
60
 
55
61
  def stop_channels(self):
62
+ "Stop channels and cancel the background shell-reply reader task"
56
63
  super().stop_channels()
57
64
  if (tk := getattr(self, '_shell_reader_task', None)):
58
65
  tk.cancel()
59
66
  self._shell_reader_task = None
67
+ time.sleep(0.2)
60
68
 
61
69
  async def _async_recv_reply(self, msg_id, timeout=None, channel="shell"):
62
70
  if channel == "control": return await self._async_get_control_msg(timeout=timeout)
@@ -70,6 +78,7 @@ class ConKernelClient(AsyncKernelClient):
70
78
 
71
79
  def execute(self, code, user_expressions=None, allow_stdin=None, reply=False, subsh_id=None,
72
80
  cts_typ='code', timeout=60, msg_id=None, **kw):
81
+ "Send an execute request, returning a coroutine for the reply if `reply`, else the msg_id"
73
82
  if user_expressions is None: user_expressions = {}
74
83
  if allow_stdin is None: allow_stdin = self.allow_stdin
75
84
  content = dict(user_expressions=user_expressions, allow_stdin=allow_stdin, subsh_id=subsh_id, **kw)
@@ -83,5 +92,10 @@ class ConKernelClient(AsyncKernelClient):
83
92
  if not reply: return msg_id
84
93
  return self._async_recv_reply(msg_id, timeout=timeout)
85
94
 
95
+ async def stdin_send(self, msg:dict):
96
+ "Send on `stdin_channel` then ping event loop"
97
+ self.stdin_channel.send(msg)
98
+ await asyncio.sleep(0)
99
+
86
100
  # %% ../nbs/00_core.ipynb #b828c222
87
101
  class ConKernelManager(AsyncKernelManager): client_class,client_factory = ConKernelClient,Type(ConKernelClient)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conkernelclient
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: Concurrent-safe Jupyter KernelClient
5
5
  Author-email: Jeremy Howard <github@jhoward.fastmail.fm>
6
6
  License: Apache-2.0
@@ -1,2 +0,0 @@
1
- __version__ = "0.0.4"
2
- from .core import *
File without changes