|
4 | 4 |
|
5 | 5 | import asyncio |
6 | 6 | import builtins |
7 | | -import gc |
8 | 7 | import getpass |
9 | 8 | import os |
10 | 9 | import signal |
|
17 | 16 | import comm |
18 | 17 | from IPython.core import release |
19 | 18 | from IPython.utils.tokenutil import line_at_cursor, token_at_cursor |
20 | | -from jupyter_client.session import extract_header |
21 | 19 | from traitlets import Any, Bool, HasTraits, Instance, List, Type, default, observe, observe_compat |
22 | 20 | from zmq.eventloop.zmqstream import ZMQStream |
23 | 21 |
|
24 | 22 | from .comm.comm import BaseComm |
25 | 23 | from .comm.manager import CommManager |
26 | 24 | from .compiler import XCachingCompiler |
27 | 25 | from .eventloops import _use_appnope |
28 | | -from .iostream import OutStream |
29 | 26 | from .kernelbase import Kernel as KernelBase |
30 | 27 | from .kernelbase import _accepts_parameters |
31 | 28 | from .zmqshell import ZMQInteractiveShell |
@@ -167,14 +164,6 @@ def __init__(self, **kwargs): |
167 | 164 |
|
168 | 165 | appnope.nope() |
169 | 166 |
|
170 | | - self._new_threads_parent_header = {} |
171 | | - self._initialize_thread_hooks() |
172 | | - |
173 | | - if hasattr(gc, "callbacks"): |
174 | | - # while `gc.callbacks` exists since Python 3.3, pypy does not |
175 | | - # implement it even as of 3.9. |
176 | | - gc.callbacks.append(self._clean_thread_parent_frames) |
177 | | - |
178 | 167 | help_links = List( |
179 | 168 | [ |
180 | 169 | { |
@@ -374,8 +363,6 @@ def _dummy_context_manager(self, *args): |
374 | 363 |
|
375 | 364 | async def execute_request(self, stream, ident, parent): |
376 | 365 | """Override for cell output - cell reconciliation.""" |
377 | | - parent_header = extract_header(parent) |
378 | | - self._associate_new_top_level_threads_with(parent_header) |
379 | 366 | await super().execute_request(stream, ident, parent) |
380 | 367 |
|
381 | 368 | async def do_execute( |
@@ -750,83 +737,6 @@ def do_clear(self): |
750 | 737 | self.shell.reset(False) |
751 | 738 | return dict(status="ok") |
752 | 739 |
|
753 | | - def _associate_new_top_level_threads_with(self, parent_header): |
754 | | - """Store the parent header to associate it with new top-level threads""" |
755 | | - self._new_threads_parent_header = parent_header |
756 | | - |
757 | | - def _initialize_thread_hooks(self): |
758 | | - """Store thread hierarchy and thread-parent_header associations.""" |
759 | | - stdout = self._stdout |
760 | | - stderr = self._stderr |
761 | | - kernel_thread_ident = threading.get_ident() |
762 | | - kernel = self |
763 | | - _threading_Thread_run = threading.Thread.run |
764 | | - _threading_Thread__init__ = threading.Thread.__init__ |
765 | | - |
766 | | - def run_closure(self: threading.Thread): |
767 | | - """Wrap the `threading.Thread.start` to intercept thread identity. |
768 | | -
|
769 | | - This is needed because there is no "start" hook yet, but there |
770 | | - might be one in the future: https://bugs.python.org/issue14073 |
771 | | -
|
772 | | - This is a no-op if the `self._stdout` and `self._stderr` are not |
773 | | - sub-classes of `OutStream`. |
774 | | - """ |
775 | | - |
776 | | - try: |
777 | | - parent = self._ipykernel_parent_thread_ident # type:ignore[attr-defined] |
778 | | - except AttributeError: |
779 | | - return |
780 | | - for stream in [stdout, stderr]: |
781 | | - if isinstance(stream, OutStream): |
782 | | - if parent == kernel_thread_ident: |
783 | | - stream._thread_to_parent_header[self.ident] = ( |
784 | | - kernel._new_threads_parent_header |
785 | | - ) |
786 | | - else: |
787 | | - stream._thread_to_parent[self.ident] = parent |
788 | | - _threading_Thread_run(self) |
789 | | - |
790 | | - def init_closure(self: threading.Thread, *args, **kwargs): |
791 | | - _threading_Thread__init__(self, *args, **kwargs) |
792 | | - self._ipykernel_parent_thread_ident = threading.get_ident() # type:ignore[attr-defined] |
793 | | - |
794 | | - threading.Thread.__init__ = init_closure # type:ignore[method-assign] |
795 | | - threading.Thread.run = run_closure # type:ignore[method-assign] |
796 | | - |
797 | | - def _clean_thread_parent_frames( |
798 | | - self, phase: t.Literal["start", "stop"], info: dict[str, t.Any] |
799 | | - ): |
800 | | - """Clean parent frames of threads which are no longer running. |
801 | | - This is meant to be invoked by garbage collector callback hook. |
802 | | -
|
803 | | - The implementation enumerates the threads because there is no "exit" hook yet, |
804 | | - but there might be one in the future: https://bugs.python.org/issue14073 |
805 | | -
|
806 | | - This is a no-op if the `self._stdout` and `self._stderr` are not |
807 | | - sub-classes of `OutStream`. |
808 | | - """ |
809 | | - # Only run before the garbage collector starts |
810 | | - if phase != "start": |
811 | | - return |
812 | | - active_threads = {thread.ident for thread in threading.enumerate()} |
813 | | - for stream in [self._stdout, self._stderr]: |
814 | | - if isinstance(stream, OutStream): |
815 | | - thread_to_parent_header = stream._thread_to_parent_header |
816 | | - for identity in list(thread_to_parent_header.keys()): |
817 | | - if identity not in active_threads: |
818 | | - try: |
819 | | - del thread_to_parent_header[identity] |
820 | | - except KeyError: |
821 | | - pass |
822 | | - thread_to_parent = stream._thread_to_parent |
823 | | - for identity in list(thread_to_parent.keys()): |
824 | | - if identity not in active_threads: |
825 | | - try: |
826 | | - del thread_to_parent[identity] |
827 | | - except KeyError: |
828 | | - pass |
829 | | - |
830 | 740 |
|
831 | 741 | # This exists only for backwards compatibility - use IPythonKernel instead |
832 | 742 |
|
|
0 commit comments