Skip to content

Commit acf027b

Browse files
pankaj-bindpre-commit-ci[bot]ianthomas23
authored
Tests: Add robust tests for silent flag in subshells (#1424)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Ian Thomas <[email protected]>
1 parent 415c363 commit acf027b

File tree

2 files changed

+90
-12
lines changed

2 files changed

+90
-12
lines changed

CHANGELOG.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ Note the changelog here is not correct, presumably due to the recent branch rena
5353
- Fix expected text depending on IPython version. [#1354](https://github.com/ipython/ipykernel/pull/1354) ([@Carreau](https://github.com/Carreau))
5454
- Another try at tracking down ResourceWarning with tracemalloc. [#1353](https://github.com/ipython/ipykernel/pull/1353) ([@Carreau](https://github.com/Carreau))
5555
- Remove deprecated modules since 4.3 (2016). [#1352](https://github.com/ipython/ipykernel/pull/1352) ([@Carreau](https://github.com/Carreau))
56-
- Try to reenable tests from downstream ipywidgets [#1350](https://github.com/ipython/ipykernel/pull/1350) ([@Carreau](https://github.com/Carreau))
56+
- Try to re-enable tests from downstream ipywidgets [#1350](https://github.com/ipython/ipykernel/pull/1350) ([@Carreau](https://github.com/Carreau))
5757
- Disable 3 failing downstream tests, but keep testing the rest. [#1349](https://github.com/ipython/ipykernel/pull/1349) ([@Carreau](https://github.com/Carreau))
58-
- Licence :: * trove classifers are deprecated [#1348](https://github.com/ipython/ipykernel/pull/1348) ([@Carreau](https://github.com/Carreau))
58+
- Licence :: * trove classifiers are deprecated [#1348](https://github.com/ipython/ipykernel/pull/1348) ([@Carreau](https://github.com/Carreau))
5959
- Pin sphinx to resolve docs build failures [#1347](https://github.com/ipython/ipykernel/pull/1347) ([@krassowski](https://github.com/krassowski))
6060
- Make our own mock kernel methods async [#1346](https://github.com/ipython/ipykernel/pull/1346) ([@Carreau](https://github.com/Carreau))
6161
- Try to debug non-closed iopub socket [#1345](https://github.com/ipython/ipykernel/pull/1345) ([@Carreau](https://github.com/Carreau))
6262
- Email is @python.org since 2018 [#1343](https://github.com/ipython/ipykernel/pull/1343) ([@Carreau](https://github.com/Carreau))
6363
- Remove unused ignores lints. [#1342](https://github.com/ipython/ipykernel/pull/1342) ([@Carreau](https://github.com/Carreau))
64-
- Enable ruff G002 and fix 6 occurences [#1341](https://github.com/ipython/ipykernel/pull/1341) ([@Carreau](https://github.com/Carreau))
64+
- Enable ruff G002 and fix 6 occurrences [#1341](https://github.com/ipython/ipykernel/pull/1341) ([@Carreau](https://github.com/Carreau))
6565
- Check ignores warnings are still relevant. [#1340](https://github.com/ipython/ipykernel/pull/1340) ([@Carreau](https://github.com/Carreau))
6666
- Move mypy disablinging error codes on a per-file basis [#1338](https://github.com/ipython/ipykernel/pull/1338) ([@Carreau](https://github.com/Carreau))
6767
- try to fix spyder kernel install [#1337](https://github.com/ipython/ipykernel/pull/1337) ([@Carreau](https://github.com/Carreau))
@@ -70,7 +70,7 @@ Note the changelog here is not correct, presumably due to the recent branch rena
7070
- Bump mypy [#1333](https://github.com/ipython/ipykernel/pull/1333) ([@Carreau](https://github.com/Carreau))
7171
- Remove dead code. [#1332](https://github.com/ipython/ipykernel/pull/1332) ([@Carreau](https://github.com/Carreau))
7272
- Ignore or fix most of the remaining ruff 0.9.6 errors [#1331](https://github.com/ipython/ipykernel/pull/1331) ([@Carreau](https://github.com/Carreau))
73-
- minor code reformating valid ruff 0.9.6 [#1330](https://github.com/ipython/ipykernel/pull/1330) ([@Carreau](https://github.com/Carreau))
73+
- minor code reformatting valid ruff 0.9.6 [#1330](https://github.com/ipython/ipykernel/pull/1330) ([@Carreau](https://github.com/Carreau))
7474
- Some formatting changes to prepare bumping ruff pre-commit. [#1329](https://github.com/ipython/ipykernel/pull/1329) ([@Carreau](https://github.com/Carreau))
7575
- Manually update Codespell and fix new errors. [#1328](https://github.com/ipython/ipykernel/pull/1328) ([@Carreau](https://github.com/Carreau))
7676
- Manually update mdformat pre-commit and run it. [#1327](https://github.com/ipython/ipykernel/pull/1327) ([@Carreau](https://github.com/Carreau))

tests/test_subshells.py

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,20 @@
77
import platform
88
import time
99
from collections import Counter
10+
from queue import Empty
1011

1112
import pytest
1213
from jupyter_client.blocking.client import BlockingKernelClient
1314

14-
from .utils import TIMEOUT, assemble_output, get_replies, get_reply, new_kernel, wait_for_idle
15+
from .utils import (
16+
TIMEOUT,
17+
assemble_output,
18+
flush_channels,
19+
get_replies,
20+
get_reply,
21+
new_kernel,
22+
wait_for_idle,
23+
)
1524

1625
# Helpers
1726

@@ -40,8 +49,10 @@ def list_subshell_helper(kc: BlockingKernelClient):
4049
return reply["content"]
4150

4251

43-
def execute_request(kc: BlockingKernelClient, code: str, subshell_id: str | None):
44-
msg = kc.session.msg("execute_request", {"code": code})
52+
def execute_request(
53+
kc: BlockingKernelClient, code: str, subshell_id: str | None, silent: bool = False
54+
):
55+
msg = kc.session.msg("execute_request", {"code": code, "silent": silent})
4556
msg["header"]["subshell_id"] = subshell_id
4657
kc.shell_channel.send(msg)
4758
return msg
@@ -224,16 +235,16 @@ def test_execute_stop_on_error(are_subshells):
224235
msg = execute_request(
225236
kc, "import asyncio; await asyncio.sleep(1); raise ValueError()", subshell_ids[0]
226237
)
227-
msg_ids.append(msg["msg_id"])
238+
msg_ids.append(msg["header"]["msg_id"])
228239
msg = execute_request(kc, "print('hello')", subshell_ids[0])
229-
msg_ids.append(msg["msg_id"])
240+
msg_ids.append(msg["header"]["msg_id"])
230241
msg = execute_request(kc, "print('goodbye')", subshell_ids[0])
231-
msg_ids.append(msg["msg_id"])
242+
msg_ids.append(msg["header"]["msg_id"])
232243

233244
msg = execute_request(kc, "import time; time.sleep(1.5)", subshell_ids[1])
234-
msg_ids.append(msg["msg_id"])
245+
msg_ids.append(msg["header"]["msg_id"])
235246
msg = execute_request(kc, "print('other')", subshell_ids[1])
236-
msg_ids.append(msg["msg_id"])
247+
msg_ids.append(msg["header"]["msg_id"])
237248

238249
replies = get_replies(kc, msg_ids)
239250

@@ -313,3 +324,70 @@ def test_idle_message_parent_headers(are_subshells):
313324
for subshell_id in subshell_ids:
314325
if subshell_id:
315326
delete_subshell_helper(kc, subshell_id)
327+
328+
329+
def test_silent_flag_in_subshells():
330+
"""Verifies that the 'silent' flag suppresses output in main and subshell contexts."""
331+
with new_kernel() as kc:
332+
subshell_id = None
333+
try:
334+
flush_channels(kc)
335+
# Test silent execution in main shell
336+
msg_main_silent = execute_request(kc, "a=1", None, silent=True)
337+
reply_main_silent = get_reply(kc, msg_main_silent["header"]["msg_id"])
338+
assert reply_main_silent["content"]["status"] == "ok"
339+
340+
# Test silent execution in subshell
341+
subshell_id = create_subshell_helper(kc)["subshell_id"]
342+
msg_sub_silent = execute_request(kc, "b=2", subshell_id, silent=True)
343+
reply_sub_silent = get_reply(kc, msg_sub_silent["header"]["msg_id"])
344+
assert reply_sub_silent["content"]["status"] == "ok"
345+
346+
# Check for no iopub messages (other than status) from the silent requests
347+
for msg_id in [msg_main_silent["header"]["msg_id"], msg_sub_silent["header"]["msg_id"]]:
348+
while True:
349+
try:
350+
msg = kc.get_iopub_msg(timeout=0.2)
351+
if msg["header"]["msg_type"] == "status":
352+
continue
353+
pytest.fail(
354+
f"Silent execution produced unexpected IOPub message: {msg['header']['msg_type']}"
355+
)
356+
except Empty:
357+
break
358+
359+
# Test concurrent silent and non-silent execution
360+
msg_silent = execute_request(
361+
kc, "import time; time.sleep(0.5); c=3", subshell_id, silent=True
362+
)
363+
msg_noisy = execute_request(kc, "print('noisy')", None, silent=False)
364+
365+
# Wait for both replies
366+
get_replies(kc, [msg_silent["header"]["msg_id"], msg_noisy["header"]["msg_id"]])
367+
368+
# Verify that we only receive stream output from the noisy message
369+
stdout, stderr = assemble_output(
370+
kc.get_iopub_msg, parent_msg_id=msg_noisy["header"]["msg_id"]
371+
)
372+
assert "noisy" in stdout
373+
assert not stderr
374+
375+
# Verify there is no output from the concurrent silent message
376+
while True:
377+
try:
378+
msg = kc.get_iopub_msg(timeout=0.2)
379+
if (
380+
msg["header"]["msg_type"] == "status"
381+
and msg["parent_header"].get("msg_id") == msg_silent["header"]["msg_id"]
382+
):
383+
continue
384+
if msg["parent_header"].get("msg_id") == msg_silent["header"]["msg_id"]:
385+
pytest.fail(
386+
"Silent execution in concurrent setting produced unexpected IOPub message"
387+
)
388+
except Empty:
389+
break
390+
finally:
391+
# Ensure subshell is always deleted
392+
if subshell_id:
393+
delete_subshell_helper(kc, subshell_id)

0 commit comments

Comments
 (0)