示例#1
0
    def test_wait_for_attach(self):
        addr = Address('localhost', PORT)
        filename = self.write_script(
            'spam.py',
            """
            import sys
            sys.path.insert(0, {!r})
            import ptvsd
            ptvsd.enable_attach({}, redirect_output=False)

            ptvsd.wait_for_attach()
            # <ready>
            # <wait>
            """.format(PROJECT_ROOT, tuple(addr)),
        )
        lockfile1 = self.workspace.lockfile()
        _, wait = set_release(filename, lockfile1, 'ready')
        lockfile2 = self.workspace.lockfile()
        done, _ = set_lock(filename, lockfile2, 'wait')

        adapter = DebugAdapter.start_embedded(addr, filename)
        with adapter:
            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter, timeout=1)
                # Ensure that it really does wait.
                with self.assertRaises(LockTimeoutError):
                    wait(timeout=0.5)

                lifecycle_handshake(session, 'attach')
                wait(timeout=1)
                done()
                adapter.wait()
示例#2
0
    def test_attach_started_separately(self):
        lockfile = self.workspace.lockfile()
        done, waitscript = lockfile.wait_in_script()
        filename = self.write_script('spam.py', waitscript)
        addr = Address('localhost', 8888)
        with DebugAdapter.start_for_attach(addr, filename) as adapter:
            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter)

                with session.wait_for_event('thread'):
                    (req_initialize, req_launch, req_config, _, _, _
                     ) = lifecycle_handshake(session, 'attach')

                done()
                adapter.wait()

        received = list(_strip_newline_output_events(session.received))
        self.assert_received(received[:7], [
            self.new_version_event(session.received),
            self.new_response(req_initialize.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_launch.req),
            self.new_response(req_config.req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            self.new_event('thread', reason='started', threadId=1),
            #self.new_event('thread', reason='exited', threadId=1),
            #self.new_event('exited', exitCode=0),
            #self.new_event('terminated'),
        ])
示例#3
0
    def test_attach_embedded(self):
        lockfile = self.workspace.lockfile()
        done, waitscript = lockfile.wait_in_script()
        addr = Address('localhost', 8888)
        script = dedent("""
            from __future__ import print_function
            import sys
            sys.path.insert(0, {!r})
            import ptvsd
            ptvsd.enable_attach({}, redirect_output={})
            ptvsd.wait_for_attach()

            print('success!', end='')

            %s
            """).format(os.getcwd(), tuple(addr), True)
        filename = self.write_script('spam.py', script % waitscript)
        with DebugAdapter.start_embedded(addr, filename) as adapter:
            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter)

                (req_initialize, req_launch, req_config, _, _,
                 _) = lifecycle_handshake(session, 'attach')
                Awaitable.wait_all(req_initialize, req_launch)
                done()
                adapter.wait()

        for i in range(10):
            # It could take some additional time for the adapter
            # to actually get the success output, so, wait for the
            # expected condition in a busy loop.
            out = adapter.output.decode('utf-8')
            if 'success!' in out:
                break
            import time
            time.sleep(.1)

        received = list(_strip_newline_output_events(session.received))
        self.assert_contains(received, [
            self.new_version_event(session.received),
            self.new_response(req_initialize.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_launch.req),
            self.new_response(req_config.req),
            self.new_event(
                'process', **{
                    'isLocalProcess': True,
                    'systemProcessId': adapter.pid,
                    'startMethod': 'attach',
                    'name': filename,
                }),
            self.new_event('output', output='success!', category='stdout'),
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
        self.assertIn('success!', out)
    def test_does_not_block(self):
        addr = Address('localhost', PORT)
        filename = self.write_script('spam.py', """
            import sys
            sys.path.insert(0, {!r})
            import ptvsd
            ptvsd.enable_attach({}, redirect_output=False)
            # <ready>
            """.format(PROJECT_ROOT, tuple(addr)),
        )
        lockfile = self.workspace.lockfile()
        _, wait = set_release(filename, lockfile, 'ready')

        #DebugAdapter.VERBOSE = True
        adapter = DebugAdapter.start_embedded(addr, filename)
        with adapter:
            wait(timeout=3)
            adapter.wait()
示例#5
0
    def test_never_call_wait_for_attach(self):
        addr = Address('localhost', PORT)
        filename = self.write_script(
            'spam.py',
            """
            import sys
            import threading
            import time

            sys.path.insert(0, {!r})
            import ptvsd
            ptvsd.enable_attach({}, redirect_output=False)
            # <ready>
            print('== ready ==')

            # Allow tracing to be triggered.
            def wait():
                # <wait>
                pass
            t = threading.Thread(target=wait)
            t.start()
            for _ in range(100):  # 10 seconds
                print('-----')
                t.join(0.1)
                if not t.is_alive():
                    break
            t.join()

            print('== starting ==')
            # <bp>
            print('== done ==')
            """.format(PROJECT_ROOT, tuple(addr)),
        )
        lockfile1 = self.workspace.lockfile('ready.lock')
        _, wait = set_release(filename, lockfile1, 'ready')
        lockfile2 = self.workspace.lockfile('wait.log')
        done, script = set_lock(filename, lockfile2, 'wait')

        bp = find_line(script, 'bp')
        breakpoints = [{
            'source': {
                'path': filename
            },
            'breakpoints': [
                {
                    'line': bp
                },
            ],
        }]

        #DebugAdapter.VERBOSE = True
        #DebugClient.SESSION.VERBOSE = True
        adapter = DebugAdapter.start_embedded(
            addr,
            filename,
            srvtimeout=None,
        )
        with adapter:
            # Wait longer that WAIT_TIMEOUT, so that debugging isn't
            # immediately enabled in the script's thread.
            wait(timeout=3.0)

            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter, timeout=1)
                stopped = session.get_awaiter_for_event('stopped')
                with session.wait_for_event('thread') as result:
                    lifecycle_handshake(session,
                                        'attach',
                                        breakpoints=breakpoints,
                                        threads=True)
                event = result['msg']
                tid = event.body['threadId']

                stopped.wait(timeout=5.0)
                done()
                session.send_request('continue', threadId=tid)

                adapter.wait()
        out = str(adapter.output)

        self.assertIn('== ready ==', out)
        self.assertIn('== starting ==', out)
示例#6
0
    def test_attach_breakpoints(self):
        # See https://github.com/Microsoft/ptvsd/issues/448.
        addr = Address('localhost', 8888)
        filename = self.write_script('spam.py', """
            import sys
            sys.path.insert(0, {!r})
            import ptvsd

            addr = {}
            ptvsd.enable_attach(addr)
            print('== waiting for attach ==')
            # <waiting>
            ptvsd.wait_for_attach()
            # <attached>
            print('== attached! ==')
            # <bp 2>
            print('== done waiting ==')
            """.format(ROOT, tuple(addr)))
        lockfile1 = self.workspace.lockfile()
        done1, _ = set_lock(filename, lockfile1, 'waiting')
        lockfile2 = self.workspace.lockfile()
        done2, script = set_lock(filename, lockfile2, 'bp 2')

        bp1 = find_line(script, 'attached')
        bp2 = find_line(script, 'bp 2')
        breakpoints = [{
            'source': {'path': filename},
            'breakpoints': [
                {'line': bp1},
                {'line': bp2},
            ],
        }]

        options = {
            'pathMappings': [
                {
                    'localRoot': os.path.dirname(filename),
                    'remoteRoot': os.path.dirname(filename)
                },
                # This specific mapping is for Mac.
                # For some reason temp paths on Mac get prefixed with
                # `private` when returned from ptvsd.
                {
                    'localRoot': os.path.dirname(filename),
                    'remoteRoot': '/private' + os.path.dirname(filename)
                }
            ]
        }

        #DebugAdapter.VERBOSE = True
        adapter = DebugAdapter.start_embedded(addr, filename)
        with adapter:
            with DebugClient() as editor:
                session = editor.attach_socket(addr, adapter, timeout=5)

                with session.wait_for_event('thread') as result:
                    with session.wait_for_event('process'):
                        (req_init, req_attach, req_config,
                         reqs_bps, _, req_threads1,
                         ) = lifecycle_handshake(session, 'attach',
                                                 breakpoints=breakpoints,
                                                 options=options,
                                                 threads=True)
                        Awaitable.wait_all(req_init, req_attach, req_config)
                        req_bps, = reqs_bps  # There should only be one.
                event = result['msg']
                tid = event.body['threadId']

                # Grab the initial output.
                out1 = next(adapter.output)  # "waiting for attach"
                line = adapter.output.readline()
                while line:
                    out1 += line
                    line = adapter.output.readline()

                with session.wait_for_event('stopped'):
                    # Tell the script to proceed (at "# <waiting>").
                    # This leads to the first breakpoint.
                    done1()
                req_threads2, req_stacktrace1 = react_to_stopped(session, tid)
                out2 = str(adapter.output)  # ""

                # Tell the script to proceed (at "# <bp 2>").  This
                # leads to the second breakpoint.  At this point
                # execution is still stopped at the first breakpoint.
                done2()
                with session.wait_for_event('stopped'):
                    with session.wait_for_event('continued'):
                        req_continue1 = session.send_request(
                            'continue',
                            threadId=tid,
                        )
                        req_continue1.wait()
                req_threads3, req_stacktrace2 = react_to_stopped(session, tid)
                out3 = str(adapter.output)  # "attached!"

                with session.wait_for_event('continued'):
                    req_continue2 = session.send_request(
                        'continue',
                        threadId=tid,
                    )
                    req_continue2.wait()

                adapter.wait()
            out4 = str(adapter.output)  # "done waiting"

        # Output between enable_attach() and wait_for_attach() may
        # be sent at a relatively arbitrary time (or not at all).
        # So we ignore it by removing it from the message list.
        received = list(_strip_output_event(session.received,
                                            u'== waiting for attach =='))
        received = list(_strip_newline_output_events(received))
        # There's an ordering race with continue/continued that pops
        # up occasionally.  We work around that by manually fixing the
        # order.
        for pos, msg in _find_events(received, 'continued'):
            prev = received[pos-1]
            if prev.type != 'response' or prev.command != 'continue':
                received.pop(pos-1)
                received.insert(pos + 1, prev)
        # Sometimes the proc ends before the exited and terminated
        # events are received.
        received = list(_strip_exit(received))
        self.assert_contains(received, [
            self.new_version_event(session.received),
            self.new_response(req_init.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_attach.req),
            self.new_event(
                'thread',
                threadId=tid,
                reason='started',
            ),
            self.new_response(req_threads1.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_bps.req, **{
                'breakpoints': [{
                    'id': 1,
                    'line': bp1,
                    'verified': True,
                }, {
                    'id': 2,
                    'line': bp2,
                    'verified': True,
                }],
            }),
            self.new_response(req_config.req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            self.new_event(
                'stopped',
                threadId=tid,
                reason='breakpoint',
                description=None,
                text=None,
            ),
            self.new_response(req_threads2.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_event(
                'module',
                module={
                    'id': 1,
                    'name': '__main__',
                    'path': filename,
                    'package': None,
                },
                reason='new',
            ),
            self.new_response(req_stacktrace1.req, **{
                'totalFrames': 1,
                'stackFrames': [{
                    'id': 1,
                    'name': '<module>',
                    'source': {
                        'path': filename,
                        'sourceReference': 0,
                    },
                    'line': bp1,
                    'column': 1,
                }],
            }),
            self.new_response(req_continue1.req, **{
                'allThreadsContinued': True
            }),
            self.new_event('continued', threadId=tid),
            self.new_event(
                'output',
                category='stdout',
                output='== attached! ==',
            ),
            self.new_event(
                'stopped',
                threadId=tid,
                reason='breakpoint',
                description=None,
                text=None,
            ),
            self.new_response(req_threads3.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_stacktrace2.req, **{
                'totalFrames': 1,
                'stackFrames': [{
                    'id': 2,  # TODO: Isn't this the same frame as before?
                    'name': '<module>',
                    'source': {
                        'path': filename,
                        'sourceReference': 0,
                    },
                    'line': bp2,
                    'column': 1,
                }],
            }),
            self.new_response(req_continue2.req, **{
                'allThreadsContinued': True
            }),
            self.new_event('continued', threadId=tid),
            self.new_event(
                'output',
                category='stdout',
                output='== done waiting ==',
            ),
            #self.new_event(
            #    'thread',
            #    threadId=tid,
            #    reason='exited',
            #),
            #self.new_event('exited', exitCode=0),
            #self.new_event('terminated'),
        ])
        # before attaching
        self.assertIn(b'waiting for attach', out1)
        self.assertNotIn(b'attached!', out1)
        # after attaching
        self.assertNotIn('attached!', out2)
        # after bp1 continue
        self.assertIn('attached!', out3)
        self.assertNotIn('done waiting', out3)
        # after bp2 continue
        self.assertIn('done waiting', out4)
示例#7
0
    def test_detach_clear_and_resume(self):
        addr = Address('localhost', 8888)
        filename = self.write_script('spam.py', """
            import sys
            sys.path.insert(0, {!r})
            import ptvsd

            addr = {}
            ptvsd.enable_attach(addr)
            ptvsd.wait_for_attach()

            # <before>
            print('==before==')

            # <after>
            print('==after==')

            # <done>
            """.format(ROOT, tuple(addr)))
        lockfile2 = self.workspace.lockfile()
        done1, _ = set_lock(filename, lockfile2, 'before')
        lockfile3 = self.workspace.lockfile()
        _, wait2 = set_release(filename, lockfile3, 'done')
        lockfile4 = self.workspace.lockfile()
        done2, script = set_lock(filename, lockfile4, 'done')

        bp1 = find_line(script, 'before')
        bp2 = find_line(script, 'after')

        #DebugAdapter.VERBOSE = True
        adapter = DebugAdapter.start_embedded(addr, filename)
        with adapter:
            with DebugClient() as editor:
                session1 = editor.attach_socket(addr, adapter, timeout=5)
                with session1.wait_for_event('thread') as result:
                    with session1.wait_for_event('process'):
                        (req_init1, req_attach1, req_config1,
                         _, _, req_threads1,
                         ) = lifecycle_handshake(session1, 'attach',
                                                 threads=True)
                event = result['msg']
                tid1 = event.body['threadId']

                stopped_event = session1.get_awaiter_for_event('stopped')
                req_bps = session1.send_request(
                    'setBreakpoints',
                    source={'path': filename},
                    breakpoints=[
                        {'line': bp1},
                        {'line': bp2},
                    ],
                )
                req_bps.wait()

                done1()
                stopped_event.wait()

                req_threads2 = session1.send_request('threads')
                req_stacktrace1 = session1.send_request(
                    'stackTrace',
                    threadId=tid1,
                )
                out1 = str(adapter.output)

                # Detach with execution stopped and 1 breakpoint left.
                req_disconnect = session1.send_request('disconnect')
                Awaitable.wait_all(req_threads2, req_stacktrace1, req_disconnect) # noqa
                editor.detach(adapter)
                try:
                    wait2()
                except LockTimeoutError:
                    self.fail('execution never resumed upon detach '
                              'or breakpoints never cleared')
                out2 = str(adapter.output)
                import time
                time.sleep(2)
                session2 = editor.attach_socket(addr, adapter, timeout=5)
                #session2.VERBOSE = True
                with session2.wait_for_event('thread') as result:
                    with session2.wait_for_event('process'):
                        (req_init2, req_attach2, req_config2,
                         _, _, req_threads3,
                         ) = lifecycle_handshake(session2, 'attach',
                                                 threads=True)
                event = result['msg']
                tid2 = event.body['threadId']

                done2()
                adapter.wait()
            out3 = str(adapter.output)

        received = list(_strip_newline_output_events(session1.received))
        self.assert_contains(received, [
            self.new_version_event(session1.received),
            self.new_response(req_init1.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_attach1.req),
            self.new_event(
                'thread',
                threadId=tid1,
                reason='started',
            ),
            self.new_response(req_threads1.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_config1.req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            self.new_response(req_bps.req, **{
                'breakpoints': [{
                    'id': 1,
                    'line': bp1,
                    'verified': True,
                }, {
                    'id': 2,
                    'line': bp2,
                    'verified': True,
                }],
            }),
            self.new_event(
                'stopped',
                threadId=tid1,
                reason='breakpoint',
                description=None,
                text=None,
            ),
            self.new_response(req_threads2.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_disconnect.req),
        ])
        self.messages.reset_all()
        received = list(_strip_newline_output_events(session2.received))
        # Sometimes the proc ends before the exited and terminated
        # events are received.
        received = list(_strip_exit(received))
        self.assert_contains(received, [
            self.new_version_event(session2.received),
            self.new_response(req_init2.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_attach2.req),
            self.new_event(
                'thread',
                threadId=tid2,
                reason='started',
            ),
            self.new_response(req_threads3.req, **{
                'threads': [{
                    'id': 1,
                    'name': 'MainThread',
                }],
            }),
            self.new_response(req_config2.req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            #self.new_event(
            #    'thread',
            #    threadId=tid2,
            #    reason='exited',
            #),
            #self.new_event('exited', exitCode=0),
            #self.new_event('terminated'),
        ])
        # at breakpoint
        self.assertEqual(out1, '')
        # after detaching
        self.assertIn('==before==', out2)
        self.assertIn('==after==', out2)
        # after reattach
        self.assertEqual(out3, out2)
示例#8
0
    def test_reattach(self):
        lockfile1 = self.workspace.lockfile()
        done1, waitscript1 = lockfile1.wait_in_script(timeout=5)
        lockfile2 = self.workspace.lockfile()
        done2, waitscript2 = lockfile2.wait_in_script(timeout=5)
        filename = self.write_script('spam.py', waitscript1 + waitscript2)
        addr = Address('localhost', 8888)
        #DebugAdapter.VERBOSE = True
        with DebugAdapter.start_for_attach(addr, filename) as adapter:
            with DebugClient() as editor:
                # Attach initially.
                session1 = editor.attach_socket(addr, adapter)
                with session1.wait_for_event('thread'):
                    reqs = lifecycle_handshake(session1, 'attach')
                    reqs[1].wait()
                    done1()
                req_disconnect = session1.send_request('disconnect')
                req_disconnect.wait()
                editor.detach(adapter)

                # Re-attach
                session2 = editor.attach_socket(addr, adapter)
                (req_initialize, req_launch, req_config, _, _, _
                 ) = lifecycle_handshake(session2, 'attach')
                req_launch.wait()
                done2()

                adapter.wait()

        received = list(_strip_newline_output_events(session1.received))

        self.assert_contains(received, [
            self.new_version_event(session1.received),
            self.new_response(reqs[0].req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(reqs[1].req),
            self.new_response(reqs[2].req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            self.new_event('thread', reason='started', threadId=1),
            self.new_response(req_disconnect.req),
        ])
        self.messages.reset_all()
        received = list(_strip_newline_output_events(session2.received))

        self.assert_contains(received, [
            self.new_version_event(session2.received),
            self.new_response(req_initialize.req, **INITIALIZE_RESPONSE),
            self.new_event('initialized'),
            self.new_response(req_launch.req),
            self.new_response(req_config.req),
            self.new_event('process', **{
                'isLocalProcess': True,
                'systemProcessId': adapter.pid,
                'startMethod': 'attach',
                'name': filename,
            }),
            self.new_event('exited', exitCode=0),
            self.new_event('terminated'),
        ])
示例#9
0
    def start_debugging(self, debug_info):
        addr = Address('localhost', debug_info.port)
        cwd = debug_info.cwd
        env = debug_info.env
        wait_for_port_to_free(debug_info.port)

        def _kill_proc(pid):
            """If debugger does not end gracefully, then kill proc and
            wait for socket connections to die out. """
            try:
                os.kill(pid, signal.SIGTERM)
            except Exception:
                pass
            time.sleep(1)  # wait for socket connections to die out.

        def _wrap_and_reraise(session, ex, exc_type, exc_value, exc_traceback):
            """If we have connetion errors, then re-raised wrapped in
            ConnectionTimeoutError. If using py3, then chain exceptions so
            we do not loose the original exception, else try hack approach
            for py27."""
            messages = []
            formatted_ex = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)) # noqa
            try:
                messages = [str(msg) for msg in
                            _strip_newline_output_events(session.received)]
            except Exception:
                pass

            message = """
Session Messages:
-----------------
{}

Original Error:
---------------
{}""".format(os.linesep.join(messages), formatted_ex)

            raise Exception(message)

        def _handle_exception(ex, adapter, session):
            exc_type, exc_value, exc_traceback = sys.exc_info()
            _kill_proc(adapter.pid)
            _wrap_and_reraise(session, ex, exc_type, exc_value, exc_traceback)

        if debug_info.verbose:
            DebugAdapter.VERBOSE = True
        if debug_info.attachtype == 'import' and \
            debug_info.modulename is not None:
            argv = debug_info.argv
            with DebugAdapter.start_wrapper_module(
                    debug_info.modulename,
                    argv,
                    env=env,
                    cwd=cwd) as adapter:
                with DebugClient() as editor:
                    time.sleep(DELAY_WAITING_FOR_SOCKETS)
                    session = editor.attach_socket(addr, adapter)
                    try:
                        yield Debugger(session=session, adapter=adapter)
                        adapter.wait()
                    except Exception as ex:
                        _handle_exception(ex, adapter, session)
        elif debug_info.attachtype == 'import' and \
            debug_info.starttype == 'attach' and \
            debug_info.filename is not None:
            argv = debug_info.argv
            adapter = DebugAdapter.start_embedded(
                addr,
                debug_info.filename,
                argv=argv,
                env=env,
                cwd=cwd,
            )
            with adapter:
                with DebugClient() as editor:
                    time.sleep(DELAY_WAITING_FOR_SOCKETS)
                    session = editor.attach_socket(addr, adapter)
                    try:
                        yield Debugger(session=session, adapter=adapter)
                        adapter.wait()
                    except Exception as ex:
                        _handle_exception(ex, adapter, session)
        elif debug_info.starttype == 'attach':
            if debug_info.modulename is None:
                name = debug_info.filename
                kind = 'script'
            else:
                name = debug_info.modulename
                kind = 'module'
            argv = debug_info.argv
            adapter = DebugAdapter.start_for_attach(
                addr,
                name=name,
                extra=argv,
                kind=kind,
                env=env,
                cwd=cwd,
            )
            with adapter:
                with DebugClient() as editor:
                    time.sleep(DELAY_WAITING_FOR_SOCKETS)
                    session = editor.attach_socket(addr, adapter)
                    try:
                        yield Debugger(session=session, adapter=adapter)
                        adapter.wait()
                    except Exception as ex:
                        _handle_exception(ex, adapter, session)
        else:
            if debug_info.filename is None:
                argv = ['-m', debug_info.modulename] + debug_info.argv
            else:
                argv = [debug_info.filename] + debug_info.argv
            with DebugClient(
                    port=debug_info.port,
                    connecttimeout=CONNECT_TIMEOUT) as editor:
                time.sleep(DELAY_WAITING_FOR_SOCKETS)
                adapter, session = editor.host_local_debugger(
                    argv, cwd=cwd, env=env)
                try:
                    yield Debugger(session=session, adapter=adapter)
                    adapter.wait()
                except Exception as ex:
                    _handle_exception(ex, adapter, session)