Skip to content

Commit c490d18

Browse files
authored
Merge branch 'ipython:main' into cell_meta
2 parents 23d2875 + 327589f commit c490d18

File tree

8 files changed

+78
-61
lines changed

8 files changed

+78
-61
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747

4848
steps:
4949
- name: Checkout
50-
uses: actions/checkout@v5
50+
uses: actions/checkout@v6
5151

5252
- uses: actions/setup-python@v6
5353
with:
@@ -94,7 +94,7 @@ jobs:
9494
needs:
9595
- build
9696
steps:
97-
- uses: actions/checkout@v5
97+
- uses: actions/checkout@v6
9898
- uses: jupyterlab/maintainer-tools/.github/actions/report-coverage@v1
9999
with:
100100
fail_under: 80
@@ -103,7 +103,7 @@ jobs:
103103
name: Test Lint
104104
runs-on: ubuntu-latest
105105
steps:
106-
- uses: actions/checkout@v5
106+
- uses: actions/checkout@v6
107107
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
108108
- name: Run Linters
109109
run: |
@@ -115,7 +115,7 @@ jobs:
115115
check_release:
116116
runs-on: ubuntu-latest
117117
steps:
118-
- uses: actions/checkout@v5
118+
- uses: actions/checkout@v6
119119
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
120120
- uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2
121121
with:
@@ -124,7 +124,7 @@ jobs:
124124
test_docs:
125125
runs-on: ubuntu-latest
126126
steps:
127-
- uses: actions/checkout@v5
127+
- uses: actions/checkout@v6
128128
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
129129
- name: Build API docs
130130
run: |
@@ -146,7 +146,7 @@ jobs:
146146
python-version: ["3.10"]
147147
steps:
148148
- name: Checkout
149-
uses: actions/checkout@v5
149+
uses: actions/checkout@v6
150150

151151
- name: Base Setup
152152
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@@ -169,7 +169,7 @@ jobs:
169169
timeout-minutes: 20
170170
runs-on: ubuntu-latest
171171
steps:
172-
- uses: actions/checkout@v5
172+
- uses: actions/checkout@v6
173173
- name: Base Setup
174174
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
175175
with:
@@ -190,7 +190,7 @@ jobs:
190190
timeout-minutes: 20
191191
steps:
192192
- name: Checkout
193-
uses: actions/checkout@v5
193+
uses: actions/checkout@v6
194194
- name: Base Setup
195195
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
196196
with:
@@ -204,7 +204,7 @@ jobs:
204204
runs-on: ubuntu-latest
205205
timeout-minutes: 20
206206
steps:
207-
- uses: actions/checkout@v5
207+
- uses: actions/checkout@v6
208208
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
209209
- uses: jupyterlab/maintainer-tools/.github/actions/make-sdist@v1
210210

@@ -220,6 +220,6 @@ jobs:
220220
link_check:
221221
runs-on: ubuntu-latest
222222
steps:
223-
- uses: actions/checkout@v5
223+
- uses: actions/checkout@v6
224224
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
225225
- uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1

.github/workflows/downstream.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515
steps:
1616
- name: Checkout
17-
uses: actions/checkout@v5
17+
uses: actions/checkout@v6
1818

1919
- name: Base Setup
2020
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@@ -29,7 +29,7 @@ jobs:
2929
runs-on: ubuntu-latest
3030
steps:
3131
- name: Checkout
32-
uses: actions/checkout@v5
32+
uses: actions/checkout@v6
3333

3434
- name: Base Setup
3535
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@@ -44,7 +44,7 @@ jobs:
4444
runs-on: ubuntu-latest
4545
steps:
4646
- name: Checkout
47-
uses: actions/checkout@v5
47+
uses: actions/checkout@v6
4848

4949
- name: Base Setup
5050
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@@ -60,7 +60,7 @@ jobs:
6060
timeout-minutes: 20
6161
steps:
6262
- name: Checkout
63-
uses: actions/checkout@v5
63+
uses: actions/checkout@v6
6464

6565
- name: Base Setup
6666
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@@ -75,7 +75,7 @@ jobs:
7575
runs-on: ubuntu-latest
7676
steps:
7777
- name: Checkout
78-
uses: actions/checkout@v5
78+
uses: actions/checkout@v6
7979

8080
- name: Base Setup
8181
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@@ -92,7 +92,7 @@ jobs:
9292
timeout-minutes: 20
9393
steps:
9494
- name: Checkout
95-
uses: actions/checkout@v5
95+
uses: actions/checkout@v6
9696
- name: Setup Python
9797
uses: actions/setup-python@v6
9898
with:
@@ -125,7 +125,7 @@ jobs:
125125
timeout-minutes: 20
126126
steps:
127127
- name: Checkout
128-
uses: actions/checkout@v5
128+
uses: actions/checkout@v6
129129
- name: Setup Python
130130
uses: actions/setup-python@v6
131131
with:

.github/workflows/nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
python-version: ["3.12"]
1818
steps:
1919
- name: Checkout
20-
uses: actions/checkout@v5
20+
uses: actions/checkout@v6
2121

2222
- name: Base Setup
2323
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1

ipykernel/debugger.py

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,15 @@ class Debugger:
326326
]
327327

328328
def __init__(
329-
self, log, debugpy_stream, event_callback, shell_socket, session, just_my_code=True
329+
self,
330+
log,
331+
debugpy_stream,
332+
event_callback,
333+
shell_socket,
334+
session,
335+
kernel_modules,
336+
just_my_code=False,
337+
filter_internal_frames=True,
330338
):
331339
"""Initialize the debugger."""
332340
self.log = log
@@ -335,7 +343,9 @@ def __init__(
335343
self.session = session
336344
self.is_started = False
337345
self.event_callback = event_callback
346+
self.kernel_modules = kernel_modules
338347
self.just_my_code = just_my_code
348+
self.filter_internal_frames = filter_internal_frames
339349
self.stopped_queue: Queue[t.Any] = Queue()
340350

341351
self.started_debug_handlers = {}
@@ -498,25 +508,7 @@ async def source(self, message):
498508

499509
async def stackTrace(self, message):
500510
"""Handle a stack trace message."""
501-
reply = await self._forward_message(message)
502-
# The stackFrames array can have the following content:
503-
# { frames from the notebook}
504-
# ...
505-
# { 'id': xxx, 'name': '<module>', ... } <= this is the first frame of the code from the notebook
506-
# { frames from ipykernel }
507-
# ...
508-
# {'id': yyy, 'name': '<module>', ... } <= this is the first frame of ipykernel code
509-
# or only the frames from the notebook.
510-
# We want to remove all the frames from ipykernel when they are present.
511-
try:
512-
sf_list = reply["body"]["stackFrames"]
513-
module_idx = len(sf_list) - next(
514-
i for i, v in enumerate(reversed(sf_list), 1) if v["name"] == "<module>" and i != 1
515-
)
516-
reply["body"]["stackFrames"] = reply["body"]["stackFrames"][: module_idx + 1]
517-
except StopIteration:
518-
pass
519-
return reply
511+
return await self._forward_message(message)
520512

521513
def accept_variable(self, variable_name):
522514
"""Accept a variable by name."""
@@ -574,6 +566,12 @@ async def attach(self, message):
574566
# Set debugOptions for breakpoints in python standard library source.
575567
if not self.just_my_code:
576568
message["arguments"]["debugOptions"] = ["DebugStdLib"]
569+
570+
# Dynamic skip rules (computed at kernel startup)
571+
if self.filter_internal_frames:
572+
rules = [{"path": path, "include": False} for path in self.kernel_modules]
573+
message["arguments"]["rules"] = rules
574+
577575
return await self._forward_message(message)
578576

579577
async def configurationDone(self, message):

ipykernel/eventloops.py

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -184,39 +184,45 @@ def _loop_wx(app):
184184
@register_integration("wx")
185185
def loop_wx(kernel):
186186
"""Start a kernel with wx event loop support."""
187-
188187
import wx
189188

190-
# Wx uses milliseconds
191-
poll_interval = int(1000 * kernel._poll_interval)
192-
193-
shell_stream = get_shell_stream(kernel)
194-
195-
def wake(shell_stream):
196-
"""wake from wx"""
197-
if shell_stream.flush(limit=1):
198-
kernel.app.ExitMainLoop()
199-
return
200-
201189
# We have to put the wx.Timer in a wx.Frame for it to fire properly.
202190
# We make the Frame hidden when we create it in the main app below.
203191
class TimerFrame(wx.Frame): # type:ignore[misc]
204-
def __init__(self, func):
192+
def __init__(self, kernel):
193+
self.kernel = kernel
194+
self.shell_stream = get_shell_stream(kernel)
195+
205196
wx.Frame.__init__(self, None, -1)
206197
self.timer = wx.Timer(self)
207-
# Units for the timer are in milliseconds
208-
self.timer.Start(poll_interval)
198+
199+
self.Bind(wx.EVT_CLOSE, self.on_exit)
209200
self.Bind(wx.EVT_TIMER, self.on_timer)
210-
self.func = func
201+
202+
# Units for the timer are in milliseconds
203+
self.timer.Start(int(1000 * self.kernel._poll_interval))
204+
205+
def wake(self):
206+
"""wake from wx"""
207+
try:
208+
if self.shell_stream.flush(limit=1):
209+
self.kernel.app.ExitMainLoop()
210+
except Exception:
211+
pass
211212

212213
def on_timer(self, event):
213-
self.func()
214+
self.wake()
215+
216+
def on_exit(self, event):
217+
self.timer.Stop()
218+
self.wake()
219+
self.Destroy()
214220

215221
# We need a custom wx.App to create our Frame subclass that has the
216222
# wx.Timer to defer back to the tornado event loop.
217223
class IPWxApp(wx.App): # type:ignore[misc]
218224
def OnInit(self):
219-
self.frame = TimerFrame(partial(wake, shell_stream))
225+
self.frame = TimerFrame(kernel)
220226
self.frame.Show(False)
221227
return True
222228

ipykernel/ipkernel.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ def __init__(self, **kwargs):
119119

120120
from .debugger import _is_debugpy_available
121121

122+
self._kernel_modules = [
123+
m.__file__ for m in sys.modules.values() if hasattr(m, "__file__") and m.__file__
124+
]
125+
122126
# Initialize the Debugger
123127
if _is_debugpy_available:
124128
self.debugger = self.debugger_class(
@@ -127,7 +131,9 @@ def __init__(self, **kwargs):
127131
self._publish_debug_event,
128132
self.debug_shell_socket,
129133
self.session,
134+
self._kernel_modules,
130135
self.debug_just_my_code,
136+
self.filter_internal_frames,
131137
)
132138

133139
# Initialize the InteractiveShell subclass

ipykernel/kernelbase.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,18 @@ def _default_ident(self):
179179
# The ipykernel source is in the call stack, so the user
180180
# has to manipulate the step-over and step-into in a wize way.
181181
debug_just_my_code = Bool(
182-
True,
182+
False,
183183
help="""Set to False if you want to debug python standard and dependent libraries.
184184
""",
185185
).tag(config=True)
186186

187+
# Experimental option to filter internal frames from the stack trace and stepping.
188+
filter_internal_frames = Bool(
189+
True,
190+
help="""Set to False if you want to debug kernel modules.
191+
""",
192+
).tag(config=True)
193+
187194
# track associations with current request
188195
# Private interface
189196

ipykernel/zmqshell.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def edit(self, parameter_s="", last_call=None):
352352

353353
payload = {"source": "edit_magic", "filename": filename, "line_number": lineno}
354354
assert self.shell is not None
355-
self.shell.payload_manager.write_payload(payload) # type: ignore[unreachable]
355+
self.shell.payload_manager.write_payload(payload) # type: ignore[union-attr]
356356

357357
# A few magics that are adapted to the specifics of using pexpect and a
358358
# remote terminal
@@ -361,7 +361,7 @@ def edit(self, parameter_s="", last_call=None):
361361
def clear(self, arg_s):
362362
"""Clear the terminal."""
363363
assert self.shell is not None
364-
if os.name == "posix": # type: ignore[unreachable]
364+
if os.name == "posix":
365365
self.shell.system("clear")
366366
else:
367367
self.shell.system("cls")
@@ -383,7 +383,7 @@ def less(self, arg_s):
383383

384384
if arg_s.endswith(".py"):
385385
assert self.shell is not None
386-
cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False)) # type: ignore[unreachable]
386+
cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
387387
else:
388388
with open(arg_s) as fid:
389389
cont = fid.read()
@@ -398,7 +398,7 @@ def less(self, arg_s):
398398
def man(self, arg_s):
399399
"""Find the man page for the given command and display in pager."""
400400
assert self.shell is not None
401-
page.page(self.shell.getoutput("man %s | col -b" % arg_s, split=False)) # type: ignore[unreachable]
401+
page.page(self.shell.getoutput("man %s | col -b" % arg_s, split=False))
402402

403403
@line_magic
404404
def connect_info(self, arg_s):

0 commit comments

Comments
 (0)