Fix for server attach break into debugger (#746)

* Fix server attach break into debugger issue

* More fixes and tweaks

* Added launch module test for break_into_debugger

* Tweak allowing break_into_debugger

* Add more tests

* Switch to using CMD_GET_EXCEPTION_DETAILS (#738)

* Switch to using CMD_GET_EXCEPTION_DETAILS

* Fix exception tests

* Fix breakpoint tests

* Fix ThreadSuspendEventTests

* Fix ExceptionInfoTests

* Fix linter issue

* Some tweaks

* Fix server attach break into debugger issue

* More fixes and tweaks

* Added launch module test for break_into_debugger

* Fix linter issues
This commit is contained in:
Karthik Nadig 2018-08-13 14:10:23 -07:00 committed by GitHub
parent b706081f23
commit 917ac6b019
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 250 additions and 32 deletions

View file

@ -395,3 +395,17 @@ def get_line_for_traceback(file_path, line_no):
return f.readlines()[line_no - 1]
except Exception:
return None
_enable_debug_break = False
def _allow_debug_break(enabled=True):
"""Enable breaking into debugger feature.
"""
global _enable_debug_break
_enable_debug_break = enabled
def _is_debug_break_allowed():
return _enable_debug_break

View file

@ -2,19 +2,16 @@
# Licensed under the MIT License. See LICENSE in the project root
# for license information.
# TODO: Why import run_module & run_file?
from ptvsd._local import run_module, run_file # noqa
from ptvsd._remote import (
enable_attach as ptvsd_enable_attach, _pydevd_settrace,
)
from ptvsd.wrapper import debugger_attached, is_launch
from ptvsd.wrapper import debugger_attached
WAIT_TIMEOUT = 1.0
DEFAULT_HOST = '0.0.0.0'
DEFAULT_PORT = 5678
_enabled = False
_debug_current_thread = None
_pending_threads = set()
@ -60,10 +57,8 @@ def enable_attach(address=(DEFAULT_HOST, DEFAULT_PORT), redirect_output=True):
attached. Any threads that are already running before this function is
called will not be visible.
"""
global _enabled
if _enabled:
if is_attached():
return
_enabled = True
debugger_attached.clear()
# Ensure port is int
@ -88,12 +83,9 @@ def break_into_debugger():
"""If a remote debugger is attached, pauses execution of all threads,
and breaks into the debugger with current thread as active.
"""
if is_launch():
if not is_attached():
return
else:
if not is_attached() or not _enabled:
return
if not is_attached():
return
import sys
_pydevd_settrace(
suspend=True,

View file

@ -44,19 +44,12 @@ from ptvsd.safe_repr import SafeRepr # noqa
from ptvsd.version import __version__ # noqa
from ptvsd.socket import TimeoutError # noqa
WAIT_FOR_THREAD_FINISH_TIMEOUT = 1 # seconds
debug = _util.debug
debugger_attached = threading.Event()
_debugger_start_reason = None
def is_launch():
return _debugger_start_reason == 'launch'
#def ipcjson_trace(s):
# print(s)
#ipcjson._TRACE = ipcjson_trace
@ -1090,9 +1083,6 @@ class VSCLifecycleMsgProcessor(VSCodeMessageProcessorBase):
def on_configurationDone(self, request, args):
# TODO: docstring
debugger_attached.set()
if self.start_reason == 'launch':
global _debugger_start_reason
_debugger_start_reason = 'launch'
self.send_response(request)
self._process_debug_options(self.debug_options)
self._handle_configurationDone(args)
@ -1100,9 +1090,6 @@ class VSCLifecycleMsgProcessor(VSCodeMessageProcessorBase):
def on_disconnect(self, request, args):
debugger_attached.clear()
if self.start_reason == 'launch':
global _debugger_start_reason
_debugger_start_reason = None
self._restart_debugger = args.get('restart', False)
# TODO: docstring

View file

@ -0,0 +1,10 @@
import ptvsd
def main():
print('one')
ptvsd.break_into_debugger()
print('two')
main()

View file

@ -0,0 +1,36 @@
import sys
import ptvsd
import os
import time
ptvsd.enable_attach((sys.argv[1], sys.argv[2]))
loopy = False
if os.getenv('PTVSD_WAIT_FOR_ATTACH', None) is not None:
print('waiting for attach')
ptvsd.wait_for_attach()
elif os.getenv('PTVSD_IS_ATTACHED', None) is not None:
print('checking is attached')
while not ptvsd.is_attached():
time.sleep(0.1)
else:
loopy = True
def main():
if loopy:
count = 0
while count < 50:
print('one')
ptvsd.break_into_debugger()
time.sleep(0.1)
print('two')
count += 1
else:
print('one')
ptvsd.break_into_debugger()
print('two')
main()

View file

@ -0,0 +1,10 @@
import ptvsd
def main():
print('one')
ptvsd.break_into_debugger()
print('two')
main()

View file

@ -0,0 +1,28 @@
import sys
import ptvsd
import os
import time
ptvsd.enable_attach((sys.argv[1], sys.argv[2]))
def main():
count = 0
while count < 50:
if os.getenv('PTVSD_WAIT_FOR_ATTACH', None) is not None:
print('waiting for attach')
ptvsd.wait_for_attach()
elif os.getenv('PTVSD_IS_ATTACHED', None) is not None:
print('checking is attached')
while not ptvsd.is_attached():
time.sleep(0.1)
else:
pass
print('one')
ptvsd.break_into_debugger()
time.sleep(0.5)
print('two')
count += 1
main()

View file

@ -94,6 +94,51 @@ class BreakIntoDebuggerTests(LifecycleTestsBase):
self.new_event('terminated'),
])
class LaunchFileBreakIntoDebuggerTests(BreakIntoDebuggerTests):
def test_launch_and_break(self):
filename = TEST_FILES.resolve('launch_test.py')
cwd = os.path.dirname(filename)
debug_info = DebugInfo(filename=filename, cwd=cwd)
self.run_test_attach_or_launch(debug_info)
class LaunchModuleBreakIntoDebuggerTests(BreakIntoDebuggerTests):
def test_launch_and_break(self):
module_name = 'mypkg_launch'
env = TEST_FILES.env_with_py_path()
cwd = TEST_FILES.parent.root
self.run_test_attach_or_launch(
DebugInfo(modulename=module_name, env=env, cwd=cwd))
class ServerAttachBreakIntoDebuggerTests(BreakIntoDebuggerTests):
def test_attach_and_break(self):
filename = TEST_FILES.resolve('launch_test.py')
cwd = os.path.dirname(filename)
debug_info = DebugInfo(
filename=filename,
cwd=cwd,
starttype='attach',
)
self.run_test_attach_or_launch(debug_info)
class ServerAttachModuleBreakIntoDebuggerTests(BreakIntoDebuggerTests):
def test_attach_and_break(self):
module_name = 'mypkg_launch'
env = TEST_FILES.env_with_py_path()
cwd = TEST_FILES.root
debug_info = DebugInfo(
modulename=module_name,
cwd=cwd,
env=env,
starttype='attach',
)
self.run_test_attach_or_launch(debug_info)
class PTVSDAttachBreakIntoDebuggerTests(BreakIntoDebuggerTests):
def test_attach_enable_wait_and_break(self):
# Uses enable_attach followed by wait_for_attach
# before calling break_into_debugger
@ -138,12 +183,6 @@ class BreakIntoDebuggerTests(LifecycleTestsBase):
)
self.run_test_attach_or_launch(debug_info, end_loop=True)
def test_launch(self):
filename = TEST_FILES.resolve('launch_test.py')
cwd = os.path.dirname(filename)
debug_info = DebugInfo(filename=filename, cwd=cwd)
self.run_test_attach_or_launch(debug_info)
def test_reattach_enable_wait_and_break(self):
# Uses enable_attach followed by wait_for_attach
# before calling break_into_debugger
@ -187,3 +226,105 @@ class BreakIntoDebuggerTests(LifecycleTestsBase):
attachtype='import',
)
self.run_test_reattach(debug_info)
class PTVSDAttachModuleBreakIntoDebuggerTests(BreakIntoDebuggerTests):
def test_attach_enable_wait_and_break(self):
# Uses enable_attach followed by wait_for_attach
# before calling break_into_debugger
module_name = 'mypkg_attach'
env = TEST_FILES.env_with_py_path()
env['PTVSD_WAIT_FOR_ATTACH'] = 'True'
cwd = TEST_FILES.root
debug_info = DebugInfo(
modulename=module_name,
env=env,
cwd=cwd,
argv=['localhost', str(PORT)],
starttype='attach',
attachtype='import',
)
self.run_test_attach_or_launch(debug_info)
def test_attach_enable_check_and_break(self):
# Uses enable_attach followed by a loop that checks if the
# debugger is attached before calling break_into_debugger
module_name = 'mypkg_attach'
env = TEST_FILES.env_with_py_path()
env['PTVSD_IS_ATTACHED'] = 'True'
cwd = TEST_FILES.root
debug_info = DebugInfo(
modulename=module_name,
env=env,
cwd=cwd,
argv=['localhost', str(PORT)],
starttype='attach',
attachtype='import',
)
self.run_test_attach_or_launch(debug_info)
def test_attach_enable_and_break(self):
# Uses enable_attach followed by break_into_debugger
# not is_attached check or wait_for_debugger
module_name = 'mypkg_attach'
env = TEST_FILES.env_with_py_path()
cwd = TEST_FILES.root
debug_info = DebugInfo(
modulename=module_name,
env=env,
cwd=cwd,
argv=['localhost', str(PORT)],
starttype='attach',
attachtype='import',
)
self.run_test_attach_or_launch(debug_info, end_loop=True)
def test_reattach_enable_wait_and_break(self):
# Uses enable_attach followed by wait_for_attach
# before calling break_into_debugger
module_name = 'mypkg_reattach'
env = TEST_FILES.env_with_py_path()
env['PTVSD_WAIT_FOR_ATTACH'] = 'True'
cwd = TEST_FILES.root
debug_info = DebugInfo(
modulename=module_name,
env=env,
cwd=cwd,
argv=['localhost', str(PORT)],
starttype='attach',
attachtype='import',
)
self.run_test_reattach(debug_info)
def test_reattach_enable_check_and_break(self):
# Uses enable_attach followed by a loop that checks if the
# debugger is attached before calling break_into_debugger
module_name = 'mypkg_reattach'
env = TEST_FILES.env_with_py_path()
env['PTVSD_IS_ATTACHED'] = 'True'
cwd = TEST_FILES.root
debug_info = DebugInfo(
modulename=module_name,
env=env,
cwd=cwd,
argv=['localhost', str(PORT)],
starttype='attach',
attachtype='import',
)
self.run_test_reattach(debug_info)
def test_reattach_enable_and_break(self):
# Uses enable_attach followed by break_into_debugger
# not is_attached check or wait_for_debugger
module_name = 'mypkg_reattach'
env = TEST_FILES.env_with_py_path()
cwd = TEST_FILES.root
debug_info = DebugInfo(
modulename=module_name,
env=env,
cwd=cwd,
argv=['localhost', str(PORT)],
starttype='attach',
attachtype='import',
)
self.run_test_reattach(debug_info)