kalong 0.5.2__py3-none-any.whl → 0.5.4__py3-none-any.whl

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.
kalong/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """A new take on debugging"""
2
2
 
3
- __version__ = "0.5.2"
3
+ __version__ = "0.5.4"
4
4
  import os
5
5
  import sys
6
6
  from pathlib import Path
@@ -111,25 +111,22 @@ def main():
111
111
 
112
112
  elif config.inject:
113
113
  kalong_dir = Path(__file__).resolve().parent.parent
114
- gdb_command = (
115
- ["gdb", "-p", str(config.inject), "-batch"]
116
- + [
117
- "-eval-command=call %s" % hook
118
- for hook in [
119
- "(int) PyGILState_Ensure()", # Getting the GIL
120
- '(int) PyRun_SimpleString("'
121
- f"print('* Kalong injection from {os.getpid()} *');"
122
- "import sys;" # Putting kalong project directory in sys path:
123
- f"sys.path.insert(0, '{kalong_dir}');"
124
- "import kalong;" # Setting breakpoint:
125
- "kalong.break_above(2);"
126
- '")',
127
- # Releasing the GIL with the PyGILState_Ensure handle:
128
- "(void) PyGILState_Release($1)",
129
- ]
114
+ gdb_command = ["gdb", "-p", str(config.inject), "-batch"] + [
115
+ "-eval-command=call %s" % hook
116
+ for hook in [
117
+ "(int) PyGILState_Ensure()", # Getting the GIL
118
+ '(int) PyRun_SimpleString("'
119
+ f"print('* Kalong injection from {os.getpid()} *');"
120
+ "import sys;" # Putting kalong project directory in sys path:
121
+ f"sys.path.insert(0, '{kalong_dir}');"
122
+ "import kalong;" # Setting breakpoint:
123
+ "kalong.break_above(2);"
124
+ '")',
125
+ # Releasing the GIL with the PyGILState_Ensure handle:
126
+ "(void) PyGILState_Release($1)",
130
127
  ]
131
- )
132
- print(f'Running: {" ".join(gdb_command)}')
128
+ ]
129
+ print(f"Running: {' '.join(gdb_command)}")
133
130
  run(gdb_command)
134
131
 
135
132
  else:
kalong/communication.py CHANGED
@@ -25,7 +25,7 @@ from .errors import SetFrameError
25
25
  from .loops import get_loop
26
26
  from .stepping import add_step, clear_step, stop_trace
27
27
  from .utils import basicConfig, get_file_from_code
28
- from .websockets import die, websocket_state
28
+ from .websockets import adie, die, websocket_state
29
29
 
30
30
  log = logging.getLogger(__name__)
31
31
  basicConfig(level=config.log_level)
@@ -161,7 +161,7 @@ async def handle_message(ws, data, frame, event, arg):
161
161
  elif command == "stop":
162
162
  clear_step()
163
163
  stop_trace(frame)
164
- die()
164
+ await adie()
165
165
  else:
166
166
  step_frame = get_frame(frame, data.get("frame"), tb)
167
167
  add_step(command, step_frame)
@@ -194,42 +194,46 @@ async def communication_loop(frame_, event_, arg_, pending=None):
194
194
  # Otherwise if it's new, just wait for HELLO to answer current state
195
195
 
196
196
  stop = False
197
- async for msg in ws:
198
- if msg.type == WSMsgType.TEXT:
199
- data = json.loads(msg.data)
200
- try:
201
- response = await handle_message(ws, data, frame, event, arg)
202
- except Exception as e:
203
- log.error(f"Error handling message {data}", exc_info=e)
204
- response = {
205
- "type": "SET_ANSWER",
206
- "prompt": data.get("prompt", "?").strip(),
207
- "key": data["key"],
208
- "command": data.get("command"),
209
- "frame": data.get("frame"),
210
- "answer": [serialize_exception(*sys.exc_info(), "internal")],
211
- }
212
- log.debug(f"Got {data} answering with {response}")
213
- response["local"] = True
214
-
215
- if response.pop("recursive", False):
216
- await ws.send_json({"type": "PAUSE", "recursive": True})
217
- await init(ws, frame, event, arg)
218
-
219
- stop = response.pop("stop", False)
220
-
221
- try:
222
- await ws.send_json(response)
223
- except ConnectionResetError:
224
- break
225
-
226
- if stop:
197
+ try:
198
+ async for msg in ws:
199
+ if msg.type == WSMsgType.TEXT:
200
+ data = json.loads(msg.data)
201
+ try:
202
+ response = await handle_message(ws, data, frame, event, arg)
203
+ except Exception as e:
204
+ log.error(f"Error handling message {data}", exc_info=e)
205
+ response = {
206
+ "type": "SET_ANSWER",
207
+ "prompt": data.get("prompt", "?").strip(),
208
+ "key": data.get("key"),
209
+ "command": data.get("command"),
210
+ "frame": data.get("frame"),
211
+ "answer": [serialize_exception(*sys.exc_info(), "internal")],
212
+ }
213
+ log.debug(f"Got {data} answering with {response}")
214
+ response["local"] = True
215
+
216
+ if response.pop("recursive", False):
217
+ await ws.send_json({"type": "PAUSE", "recursive": True})
218
+ await init(ws, frame, event, arg)
219
+
220
+ stop = response.pop("stop", False)
221
+
222
+ try:
223
+ await ws.send_json(response)
224
+ except ConnectionResetError:
225
+ break
226
+
227
+ if stop:
228
+ break
229
+
230
+ elif msg.type == WSMsgType.ERROR:
231
+ log.error("WebSocket closed", exc_info=ws.exception())
227
232
  break
228
-
229
- elif msg.type == WSMsgType.ERROR:
230
- log.error("WebSocket closed", exc_info=ws.exception())
231
- break
233
+ except asyncio.CancelledError:
234
+ log.error("WebSocket communication cancelled")
232
235
 
233
236
  # Browser exited, stopping debug if we are not stepping
234
237
  if not stop:
235
238
  stop_trace(frame)
239
+ await adie()
kalong/loops.py CHANGED
@@ -49,7 +49,7 @@ def close_loop():
49
49
  try:
50
50
  loops[origin].close()
51
51
  finally:
52
- del loops[origin]
52
+ loops.pop(origin, None)
53
53
 
54
54
 
55
55
  def clean_loops():
kalong/server.py CHANGED
@@ -67,44 +67,46 @@ async def websocket(request):
67
67
  log.debug(f"{side.title()} app connected for {origin}")
68
68
  request.app[side][origin] = ws
69
69
 
70
- async for msg in ws:
71
- if msg.type == WSMsgType.TEXT:
72
- data = json.loads(msg.data)
73
- log.debug(f"{side} -> {other_side}: {data}")
74
- try:
75
- pair = await peer(request.app, other_side, origin)
76
- except NoClientFoundError:
77
- log.error(
78
- f"No {human_readable_side(other_side)} connection was found, aborting debugger"
79
- )
80
- break
81
- if data["type"] == "DO_COMMAND":
82
- if data["command"] in ["pause", "kill"]:
83
- _, pid, _ = parse_origin(origin)
84
- os.kill(
85
- pid,
86
- signal.SIGTERM if data["command"] == "kill" else USER_SIGNAL,
70
+ try:
71
+ async for msg in ws:
72
+ if msg.type == WSMsgType.TEXT:
73
+ data = json.loads(msg.data)
74
+ log.debug(f"{side} -> {other_side}: {data}")
75
+ try:
76
+ pair = await peer(request.app, other_side, origin)
77
+ except NoClientFoundError:
78
+ log.error(
79
+ f"No {human_readable_side(other_side)} connection was found, aborting debugger"
87
80
  )
88
- continue
89
-
90
- await pair.send_json(data)
91
- elif msg.type == WSMsgType.ERROR:
92
- log.error(f"{side.title()} closed", exc_info=ws.exception())
81
+ break
82
+ if data["type"] == "DO_COMMAND":
83
+ if data["command"] in ["pause", "kill"]:
84
+ _, pid, _ = parse_origin(origin)
85
+ sign = (
86
+ signal.SIGKILL if data["command"] == "kill" else USER_SIGNAL
87
+ )
88
+ log.info(f"Sending signal {sign} to {pid}")
89
+ os.kill(pid, sign)
90
+ continue
91
+
92
+ await pair.send_json(data)
93
+ elif msg.type == WSMsgType.ERROR:
94
+ log.error(f"{side.title()} closed", exc_info=ws.exception())
95
+ except asyncio.CancelledError:
96
+ log.error(f"{side.title()} WebSocket communication cancelled")
93
97
 
94
98
  log.debug(f"Closing {side}")
95
- await ws.close()
96
99
 
97
100
  if side in request.app and origin in request.app[side]:
98
- del request.app[side][origin]
101
+ request.app[side].pop(origin)
99
102
 
100
103
  if not config.detached:
101
104
  if origin in request.app[other_side]:
102
105
  log.debug(f"Closing {other_side} due to {side} closing.")
103
- await request.app[other_side][origin].close()
104
-
105
- if origin in request.app[other_side]:
106
- del request.app[other_side][origin]
106
+ s = request.app[other_side].pop(origin)
107
+ await s.close()
107
108
 
109
+ await ws.close()
108
110
  maybe_bail(request.app)
109
111
  return ws
110
112