Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions ipykernel/iostream.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import atexit
import contextvars
import io
import logging
import os
import sys
import threading
Expand All @@ -33,6 +34,8 @@

PIPE_BUFFER_SIZE = 1000

logger = logging.getLogger(__name__)

# -----------------------------------------------------------------------------
# IO classes
# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -355,8 +358,20 @@ def _really_send(self, msg, *args, **kwargs):
mp_mode = self._check_mp_mode()

if mp_mode != CHILD:
# we are master, do a regular send
self.socket.send_multipart(msg, *args, **kwargs)
# we are master, do a regular send.
# The closed check above is racy: once the IO thread has been
# joined, _really_send runs on the caller's thread while close()
# may run concurrently on another, so the socket can be closed
# (or become None) between the check and the send. Swallow that
# specific case rather than logging a noisy traceback during
# shutdown.
try:
self.socket.send_multipart(msg, *args, **kwargs)
except (AttributeError, zmq.error.ZMQError) as e:
if isinstance(e, AttributeError) or e.errno == zmq.ENOTSOCK:
logger.debug("IOPub socket closed during send (likely shutdown): %s", e)
return
raise
else:
# we are a child, pipe to master
# new context/socket for every pipe-out
Expand Down
Loading