1313from IPython .utils .tokenutil import token_at_cursor , line_at_cursor
1414from tornado import gen
1515from traitlets import Instance , Type , Any , List , Bool , observe , observe_compat
16+ from zmq .eventloop .zmqstream import ZMQStream
1617
1718from .comm import CommManager
1819from .kernelbase import Kernel as KernelBase
1920from .zmqshell import ZMQInteractiveShell
2021from .eventloops import _use_appnope
21-
22+ from . debugger import Debugger
2223from .compiler import XCachingCompiler
2324
2425try :
@@ -44,6 +45,8 @@ class IPythonKernel(KernelBase):
4445 help = "Set this flag to False to deactivate the use of experimental IPython completion APIs." ,
4546 ).tag (config = True )
4647
48+ debugpy_stream = Instance (ZMQStream , allow_none = True )
49+
4750 user_module = Any ()
4851 @observe ('user_module' )
4952 @observe_compat
@@ -67,6 +70,13 @@ def _user_ns_changed(self, change):
6770 def __init__ (self , ** kwargs ):
6871 super (IPythonKernel , self ).__init__ (** kwargs )
6972
73+ # Initialize the Debugger
74+ self .debugger = Debugger (self .log ,
75+ self .debugpy_stream ,
76+ self ._publish_debug_event ,
77+ self .debug_shell_socket ,
78+ self .session )
79+
7080 # Initialize the InteractiveShell subclass
7181 self .shell = self .shell_class .instance (parent = self ,
7282 profile_dir = self .profile_dir ,
@@ -140,12 +150,20 @@ def __init__(self, **kwargs):
140150 'file_extension' : '.py'
141151 }
142152
153+ @gen .coroutine
154+ def dispatch_debugpy (self , msg ):
155+ # The first frame is the socket id, we can drop it
156+ frame = msg [1 ].bytes .decode ('utf-8' )
157+ self .log .debug ("Debugpy received: %s" , frame )
158+ self .debugger .tcp_client .receive_dap_frame (frame )
159+
143160 @property
144161 def banner (self ):
145162 return self .shell .banner
146163
147164 def start (self ):
148165 self .shell .exit_now = False
166+ self .debugpy_stream .on_recv (self .dispatch_debugpy , copy = False )
149167 super (IPythonKernel , self ).start ()
150168
151169 def set_parent (self , ident , parent , channel = 'shell' ):
@@ -381,6 +399,10 @@ def do_complete(self, code, cursor_pos):
381399 'metadata' : {},
382400 'status' : 'ok' }
383401
402+ @gen .coroutine
403+ def do_debug_request (self , msg ):
404+ return (yield self .debugger .process_request (msg ))
405+
384406 def _experimental_do_complete (self , code , cursor_pos ):
385407 """
386408 Experimental completions from IPython, using Jedi.
0 commit comments