wslink 2.2.2__tar.gz → 2.3.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. {wslink-2.2.2 → wslink-2.3.0}/PKG-INFO +1 -1
  2. {wslink-2.2.2 → wslink-2.3.0}/setup.cfg +1 -1
  3. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/generic/core.py +1 -1
  4. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/jupyter/core.py +1 -41
  5. wslink-2.3.0/src/wslink/emitter.py +63 -0
  6. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/protocol.py +15 -3
  7. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/websocket.py +12 -3
  8. {wslink-2.2.2 → wslink-2.3.0}/src/wslink.egg-info/PKG-INFO +1 -1
  9. {wslink-2.2.2 → wslink-2.3.0}/src/wslink.egg-info/SOURCES.txt +1 -0
  10. {wslink-2.2.2 → wslink-2.3.0}/MANIFEST.in +0 -0
  11. {wslink-2.2.2 → wslink-2.3.0}/README.rst +0 -0
  12. {wslink-2.2.2 → wslink-2.3.0}/setup.py +0 -0
  13. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/LICENSE +0 -0
  14. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/__init__.py +0 -0
  15. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/__init__.py +0 -0
  16. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/aiohttp/__init__.py +0 -0
  17. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/aiohttp/launcher.py +0 -0
  18. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/aiohttp/relay.py +0 -0
  19. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/generic/__init__.py +0 -0
  20. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/jupyter/__init__.py +0 -0
  21. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/tornado/__init__.py +0 -0
  22. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/backends/tornado/core.py +0 -0
  23. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/chunking.py +0 -0
  24. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/launcher.py +0 -0
  25. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/publish.py +0 -0
  26. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/relay.py +0 -0
  27. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/server.py +0 -0
  28. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/ssl_context.py +0 -0
  29. {wslink-2.2.2 → wslink-2.3.0}/src/wslink/uri.py +0 -0
  30. {wslink-2.2.2 → wslink-2.3.0}/src/wslink.egg-info/dependency_links.txt +0 -0
  31. {wslink-2.2.2 → wslink-2.3.0}/src/wslink.egg-info/requires.txt +0 -0
  32. {wslink-2.2.2 → wslink-2.3.0}/src/wslink.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wslink
3
- Version: 2.2.2
3
+ Version: 2.3.0
4
4
  Summary: Python/JavaScript library for communicating over WebSocket
5
5
  Home-page: https://github.com/kitware/wslink
6
6
  Author: Kitware, Inc.
@@ -1,5 +1,5 @@
1
1
  [metadata]
2
- version = 2.2.2
2
+ version = 2.3.0
3
3
 
4
4
  [egg_info]
5
5
  tag_build =
@@ -56,7 +56,7 @@ class WsConnection:
56
56
 
57
57
 
58
58
  class WsEndpoint(WslinkHandler):
59
- def __init__(self, protocol=None, web_app=None):
59
+ def __init__(self, protocol, web_app=None):
60
60
  super().__init__(protocol, web_app)
61
61
 
62
62
  async def connect(self):
@@ -1,49 +1,9 @@
1
- import asyncio
2
1
  from functools import partial
2
+ from wslink.emitter import EventEmitter
3
3
  from wslink.backends.generic.core import GenericServer
4
4
  from IPython.core.getipython import get_ipython
5
5
 
6
6
 
7
- class EventEmitter:
8
- def __init__(self):
9
- self._listeners = {}
10
-
11
- def clear(self):
12
- self._listeners = {}
13
-
14
- def emit(self, event, *args, **kwargs):
15
- listeners = self._listeners.get(event)
16
- if listeners is None:
17
- return
18
-
19
- loop = asyncio.get_running_loop()
20
- coroutine_run = (
21
- loop.create_task if (loop and loop.is_running()) else asyncio.run
22
- )
23
-
24
- for listener in listeners:
25
- if asyncio.iscoroutinefunction(listener):
26
- coroutine_run(listener(*args, **kwargs))
27
- else:
28
- listener(*args, **kwargs)
29
-
30
- def add_event_listener(self, event, listener):
31
- listeners = self._listeners.get(event)
32
- if listeners is None:
33
- listeners = set()
34
- self._listeners[event] = listeners
35
-
36
- listeners.add(listener)
37
-
38
- def remove_event_listener(self, event, listener):
39
- listeners = self._listeners.get(event)
40
- if listeners is None:
41
- return
42
-
43
- if listener in listeners:
44
- listeners.remove(listener)
45
-
46
-
47
7
  class WsJupyterComm(EventEmitter):
48
8
  def __init__(self, kernel=None):
49
9
  super().__init__()
@@ -0,0 +1,63 @@
1
+ from typing import TypeVar, Generic, LiteralString
2
+
3
+ import asyncio
4
+ import functools
5
+
6
+
7
+ T = TypeVar("T", bound=LiteralString)
8
+
9
+
10
+ class EventEmitter(Generic[T]):
11
+ def __init__(self):
12
+ self._listeners = {}
13
+
14
+ def clear(self):
15
+ self._listeners = {}
16
+
17
+ def __call__(self, event: T, *args, **kwargs):
18
+ self.emit(event, *args, **kwargs)
19
+
20
+ def __getattr__(self, name: T):
21
+ return functools.partial(self.emit, name)
22
+
23
+ def emit(self, event: T, *args, **kwargs):
24
+ listeners = self._listeners.get(event)
25
+ if listeners is None:
26
+ return
27
+
28
+ loop = asyncio.get_running_loop()
29
+ coroutine_run = (
30
+ loop.create_task if (loop and loop.is_running()) else asyncio.run
31
+ )
32
+
33
+ for listener in listeners:
34
+ if asyncio.iscoroutinefunction(listener):
35
+ coroutine_run(listener(*args, **kwargs))
36
+ else:
37
+ listener(*args, **kwargs)
38
+
39
+ def add_event_listener(self, event: T, listener):
40
+ listeners = self._listeners.get(event)
41
+ if listeners is None:
42
+ listeners = set()
43
+ self._listeners[event] = listeners
44
+
45
+ listeners.add(listener)
46
+
47
+ def remove_event_listener(self, event: T, listener):
48
+ listeners = self._listeners.get(event)
49
+ if listeners is None:
50
+ return
51
+
52
+ if listener in listeners:
53
+ listeners.remove(listener)
54
+
55
+ def has(self, event: T):
56
+ return self.listeners_count(event) > 0
57
+
58
+ def listeners_count(self, event: T):
59
+ listeners = self._listeners.get(event)
60
+ if listeners is None:
61
+ return 0
62
+
63
+ return len(listeners)
@@ -9,6 +9,7 @@ import traceback
9
9
  from wslink import schedule_coroutine
10
10
  from wslink.publish import PublishManager
11
11
  from wslink.chunking import generate_chunks, UnChunker
12
+ from wslink.websocket import ServerProtocol
12
13
 
13
14
  # from http://www.jsonrpc.org/specification, section 5.1
14
15
  METHOD_NOT_FOUND = -32601
@@ -141,7 +142,7 @@ class AbstractWebApp:
141
142
 
142
143
 
143
144
  class WslinkHandler(object):
144
- def __init__(self, protocol=None, web_app=None):
145
+ def __init__(self, protocol: ServerProtocol, web_app=None):
145
146
  self.serverProtocol = protocol
146
147
  self.web_app = web_app
147
148
  self.functionMap = {}
@@ -153,6 +154,7 @@ class WslinkHandler(object):
153
154
  self.pub_manager = PublishManager()
154
155
  self.unchunkers = {}
155
156
  self.network_monitor = protocol.network_monitor
157
+ self.log_emitter = protocol.log_emitter
156
158
 
157
159
  # Build the rpc method dictionary, assuming we were given a serverprotocol
158
160
  if self.getServerProtocol():
@@ -253,7 +255,9 @@ class WslinkHandler(object):
253
255
 
254
256
  async def onMessage(self, is_binary, msg, client_id):
255
257
  if not is_binary:
256
- logger.critical("wslink is not expecting text message:\n> %s", msg.data)
258
+ error_message = "wslink is not expecting text message:\n> %s"
259
+ logger.critical(error_message, msg.data)
260
+ self.log_emitter.critical(error_message % msg.data)
257
261
  return
258
262
 
259
263
  full_message = self.unchunkers[client_id].process_chunk(msg.data)
@@ -262,7 +266,13 @@ class WslinkHandler(object):
262
266
  await self.onCompleteMessage(full_message, client_id)
263
267
 
264
268
  async def onCompleteMessage(self, rpc, client_id):
265
- logger.debug("wslink incoming msg %s", self.payloadWithSecretStripped(rpc))
269
+ debug_message = "wslink incoming msg %s"
270
+ stripped_payload = self.payloadWithSecretStripped(rpc)
271
+ logger.debug(debug_message, stripped_payload)
272
+
273
+ if self.log_emitter.has("debug"):
274
+ self.log_emitter.debug(debug_message % stripped_payload)
275
+
266
276
  if "id" not in rpc:
267
277
  return
268
278
 
@@ -295,6 +305,7 @@ class WslinkHandler(object):
295
305
 
296
306
  # No matching method found
297
307
  if not methodName in self.functionMap:
308
+ self.log_emitter.error(f"Method not found: {methodName}")
298
309
  with self.network_monitor:
299
310
  await self.sendWrappedError(
300
311
  rpcid,
@@ -328,6 +339,7 @@ class WslinkHandler(object):
328
339
  logger.error("Exception raised")
329
340
  logger.error(repr(e_inst))
330
341
  logger.error(captured_trace)
342
+ self.log_emitter.exception(e_inst)
331
343
  with self.network_monitor:
332
344
  await self.sendWrappedError(
333
345
  rpcid,
@@ -6,9 +6,12 @@ ServerProtocol to hook all the needed LinkProtocols together.
6
6
 
7
7
  import logging
8
8
  import asyncio
9
+ from typing import Literal
10
+ from dataclasses import dataclass
9
11
 
10
- from . import register as exportRpc
11
- from . import schedule_callback
12
+ from wslink import register as exportRpc
13
+ from wslink import schedule_callback
14
+ from wslink.emitter import EventEmitter
12
15
 
13
16
  logger = logging.getLogger(__name__)
14
17
 
@@ -117,6 +120,9 @@ class NetworkMonitor:
117
120
  await self.event.wait()
118
121
 
119
122
 
123
+ LogEmitterEvents = Literal["exception", "error", "critical", "info", "debug"]
124
+
125
+
120
126
  class ServerProtocol(object):
121
127
  """
122
128
  Defines the core server protocol for wslink. Gathers a list of LinkProtocol
@@ -125,6 +131,7 @@ class ServerProtocol(object):
125
131
 
126
132
  def __init__(self):
127
133
  self.network_monitor = NetworkMonitor()
134
+ self.log_emitter = EventEmitter[LogEmitterEvents]()
128
135
  self.linkProtocols = []
129
136
  self.secret = None
130
137
  self.initialize()
@@ -169,7 +176,9 @@ class ServerProtocol(object):
169
176
  try:
170
177
  self.linkProtocols.remove(protocol)
171
178
  except ValueError as e:
172
- logger.error("Link protocol missing from registered list.")
179
+ error_message = "Link protocol missing from registered list."
180
+ logger.error(error_message)
181
+ self.log_emitter("error", error_message)
173
182
 
174
183
  def getLinkProtocols(self):
175
184
  return self.linkProtocols
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wslink
3
- Version: 2.2.2
3
+ Version: 2.3.0
4
4
  Summary: Python/JavaScript library for communicating over WebSocket
5
5
  Home-page: https://github.com/kitware/wslink
6
6
  Author: Kitware, Inc.
@@ -5,6 +5,7 @@ setup.py
5
5
  src/wslink/LICENSE
6
6
  src/wslink/__init__.py
7
7
  src/wslink/chunking.py
8
+ src/wslink/emitter.py
8
9
  src/wslink/launcher.py
9
10
  src/wslink/protocol.py
10
11
  src/wslink/publish.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes