Don't trace <string> files unless it's the one from python -c. Fixes #1398

This commit is contained in:
Fabio Zadrozny 2019-07-05 08:54:37 -03:00 committed by Karthik Nadig
parent 65c50f8769
commit 95c456d2e7
18 changed files with 2071 additions and 1730 deletions

View file

@ -121,7 +121,7 @@ def stop_on_unhandled_exception(py_db, thread, additional_info, arg):
while tb:
frame = tb.tb_frame
if exception_breakpoint.ignore_libraries and py_db.in_project_scope(frame.f_code.co_filename):
if exception_breakpoint.ignore_libraries and py_db.in_project_scope(frame):
user_frame = tb.tb_frame
frames.append(tb.tb_frame)
tb = tb.tb_next

File diff suppressed because it is too large Load diff

View file

@ -793,8 +793,7 @@ cdef class PyDBFrame:
stop = True
elif is_return and frame.f_back is not None:
if main_debugger.get_file_type(
get_abs_path_real_path_and_base_from_frame(frame.f_back)) == main_debugger.PYDEV_FILE:
if main_debugger.get_file_type(frame.f_back) == main_debugger.PYDEV_FILE:
stop = False
else:
if force_check_project_scope or main_debugger.is_files_filter_enabled:
@ -849,8 +848,7 @@ cdef class PyDBFrame:
if stop and step_cmd != -1 and is_return and IS_PY3K and hasattr(frame, "f_back"):
f_code = getattr(frame.f_back, 'f_code', None)
if f_code is not None:
if main_debugger.get_file_type(
get_abs_path_real_path_and_base_from_file(f_code.co_filename)) == main_debugger.PYDEV_FILE:
if main_debugger.get_file_type(frame.f_back) == main_debugger.PYDEV_FILE:
stop = False
if plugin_stop:
@ -1347,11 +1345,11 @@ cdef class ThreadTracer:
abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame)
filename = abs_path_real_path_and_base[1]
file_type = py_db.get_file_type(abs_path_real_path_and_base) # we don't want to debug threading or anything related to pydevd
file_type = py_db.get_file_type(frame, abs_path_real_path_and_base) # we don't want to debug threading or anything related to pydevd
if file_type is not None:
if file_type == 1: # inlining LIB_FILE = 1
if not py_db.in_project_scope(filename):
if not py_db.in_project_scope(frame, abs_path_real_path_and_base[0]):
# if DEBUG: print('skipped: trace_dispatch (not in scope)', abs_path_real_path_and_base[-1], frame.f_lineno, event, frame.f_code.co_name, file_type)
cache_skips[frame_cache_key] = 1
return None if event == 'call' else NO_FTRACE

View file

@ -643,8 +643,7 @@ class PyDBFrame:
stop = True
elif is_return and frame.f_back is not None:
if main_debugger.get_file_type(
get_abs_path_real_path_and_base_from_frame(frame.f_back)) == main_debugger.PYDEV_FILE:
if main_debugger.get_file_type(frame.f_back) == main_debugger.PYDEV_FILE:
stop = False
else:
if force_check_project_scope or main_debugger.is_files_filter_enabled:
@ -699,8 +698,7 @@ class PyDBFrame:
if stop and step_cmd != -1 and is_return and IS_PY3K and hasattr(frame, "f_back"):
f_code = getattr(frame.f_back, 'f_code', None)
if f_code is not None:
if main_debugger.get_file_type(
get_abs_path_real_path_and_base_from_file(f_code.co_filename)) == main_debugger.PYDEV_FILE:
if main_debugger.get_file_type(frame.f_back) == main_debugger.PYDEV_FILE:
stop = False
if plugin_stop:

View file

@ -1,6 +1,8 @@
from _pydevd_bundle.pydevd_constants import IS_PY3K
class Frame(object):
def __init__(
self,
f_back,
@ -21,9 +23,11 @@ class Frame(object):
class FCode(object):
def __init__(self, name, filename):
self.co_name = name
self.co_filename = filename
self.co_firstlineno = 1
def add_exception_to_frame(frame, exception_info):
@ -36,11 +40,13 @@ def remove_exception_from_frame(frame):
FILES_WITH_IMPORT_HOOKS = ['pydev_monkey_qt.py', 'pydev_import_hook.py']
def just_raised(trace):
if trace is None:
return False
return trace.tb_next is None
def ignore_exception_trace(trace):
while trace is not None:
filename = trace.tb_frame.f_code.co_filename
@ -58,6 +64,7 @@ def ignore_exception_trace(trace):
return False
def cached_call(obj, func, *args):
cached_name = '_cached_' + func.__name__
if not hasattr(obj, cached_name):
@ -65,4 +72,3 @@ def cached_call(obj, func, *args):
return getattr(obj, cached_name)

View file

@ -215,7 +215,7 @@ class NetCommandFactoryJson(NetCommandFactory):
if py_db.is_files_filter_enabled and py_db.apply_files_filter(frame, original_filename, False):
continue
if not py_db.in_project_scope(original_filename):
if not py_db.in_project_scope(frame):
presentation_hint = 'subtle'
formatted_name = self._format_frame_name(fmt, method_name, module_name, lineno, filename_in_utf8)

View file

@ -162,7 +162,7 @@ class NetCommandFactory(object):
continue # IronPython sometimes does not have it!
abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame)
if py_db.get_file_type(abs_path_real_path_and_base) == py_db.PYDEV_FILE:
if py_db.get_file_type(frame, abs_path_real_path_and_base) == py_db.PYDEV_FILE:
# Skip pydevd files.
frame = frame.f_back
continue

View file

@ -174,7 +174,7 @@ def create_signature_message(signature):
def send_signature_call_trace(dbg, frame, filename):
if dbg.signature_factory and dbg.in_project_scope(filename):
if dbg.signature_factory and dbg.in_project_scope(frame):
signature = dbg.signature_factory.create_signature(frame, filename)
if signature is not None:
if dbg.signature_factory.cache is not None:
@ -192,7 +192,7 @@ def send_signature_call_trace(dbg, frame, filename):
def send_signature_return_trace(dbg, frame, filename, return_value):
if dbg.signature_factory and dbg.in_project_scope(filename):
if dbg.signature_factory and dbg.in_project_scope(frame):
signature = dbg.signature_factory.create_signature(frame, filename, with_args=False)
signature.return_type = get_type_of_value(return_value, recursive=True)
dbg.writer.add_command(create_signature_message(signature))

View file

@ -222,9 +222,8 @@ def _schedule_callback(prev, next):
if frame is current_frame:
frame = frame.f_back
if frame is not None:
abs_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame)
# print >>sys.stderr, "SchedCB: %r, %d, '%s', '%s'" % (tasklet, frame.f_lineno, _filename, base)
if debugger.get_file_type(abs_real_path_and_base) is None:
if debugger.get_file_type(frame) is None:
tasklet_info.update_name()
if tasklet_info.frame_id is None:
tasklet_info.frame_id = add_custom_frame(frame, tasklet_info.tasklet_name, tasklet.thread_id)
@ -290,8 +289,7 @@ if not hasattr(stackless.tasklet, "trace_function"):
if tasklet.paused or tasklet.blocked or tasklet.scheduled:
if tasklet.frame and tasklet.frame.f_back:
f_back = tasklet.frame.f_back
abs_real_path_and_base = get_abs_path_real_path_and_base_from_frame(f_back)
if debugger.get_file_type(abs_real_path_and_base) is None:
if debugger.get_file_type(f_back) is None:
if tasklet_info.frame_id is None:
tasklet_info.frame_id = add_custom_frame(f_back, tasklet_info.tasklet_name, tasklet.thread_id)
else:

View file

@ -437,11 +437,11 @@ class ThreadTracer(object):
abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame)
filename = abs_path_real_path_and_base[1]
file_type = py_db.get_file_type(abs_path_real_path_and_base) # we don't want to debug threading or anything related to pydevd
file_type = py_db.get_file_type(frame, abs_path_real_path_and_base) # we don't want to debug threading or anything related to pydevd
if file_type is not None:
if file_type == 1: # inlining LIB_FILE = 1
if not py_db.in_project_scope(filename):
if not py_db.in_project_scope(frame, abs_path_real_path_and_base[0]):
# if DEBUG: print('skipped: trace_dispatch (not in scope)', abs_path_real_path_and_base[-1], frame.f_lineno, event, frame.f_code.co_name, file_type)
cache_skips[frame_cache_key] = 1
return None if event == 'call' else NO_FTRACE

View file

@ -140,16 +140,16 @@ def decref_py(obj):
Py_DECREF(obj)
def get_func_code_info_py(code_obj) -> FuncCodeInfo:
def get_func_code_info_py(frame, code_obj) -> FuncCodeInfo:
'''
Helper to be called from Python.
'''
return get_func_code_info(<PyCodeObject *> code_obj)
return get_func_code_info(<PyFrameObject *> frame, <PyCodeObject *> code_obj)
_code_extra_index: Py_SIZE = -1
cdef FuncCodeInfo get_func_code_info(PyCodeObject * code_obj):
cdef FuncCodeInfo get_func_code_info(PyFrameObject * frame_obj, PyCodeObject * code_obj):
'''
Provides code-object related info.
@ -181,6 +181,8 @@ cdef FuncCodeInfo get_func_code_info(PyCodeObject * code_obj):
cdef str co_filename = <str> code_obj.co_filename
cdef str co_name = <str> code_obj.co_name
cdef set break_at_lines
cdef dict cache_file_type
cdef tuple cache_file_type_key
func_code_info = FuncCodeInfo()
func_code_info.breakpoints_mtime = main_debugger.mtime
@ -194,8 +196,16 @@ cdef FuncCodeInfo get_func_code_info(PyCodeObject * code_obj):
abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(co_filename)
func_code_info.real_path = abs_path_real_path_and_base[1]
cache_file_type = main_debugger.get_cache_file_type()
# Note: this cache key must be the same from PyDB.get_file_type() -- see it for comments
# on the cache.
cache_file_type_key = (frame_obj.f_code.co_firstlineno, abs_path_real_path_and_base[0], <object>frame_obj.f_code)
try:
file_type = cache_file_type[cache_file_type_key] # Make it faster
except:
file_type = main_debugger.get_file_type(<object>frame_obj, abs_path_real_path_and_base) # we don't want to debug anything related to pydevd
file_type = main_debugger.get_file_type(abs_path_real_path_and_base) # we don't want to debug anything related to pydevd
if file_type is not None:
func_code_info.always_skip_code = True
@ -311,7 +321,7 @@ cdef PyObject * get_bytecode_while_frame_eval(PyFrameObject * frame_obj, int exc
else:
frame.f_trace = <object> main_debugger.trace_dispatch
else:
func_code_info: FuncCodeInfo = get_func_code_info(frame_obj.f_code)
func_code_info: FuncCodeInfo = get_func_code_info(frame_obj, frame_obj.f_code)
# if DEBUG:
# print('get_bytecode_while_frame_eval always skip', func_code_info.always_skip_code)
if not func_code_info.always_skip_code:

View file

@ -39,7 +39,7 @@ from _pydevd_bundle.pydevd_constants import (IS_JYTH_LESS25, get_thread_id, get_
NO_FTRACE, IS_IRONPYTHON, JSON_PROTOCOL, IS_CPYTHON)
from _pydevd_bundle.pydevd_defaults import PydevdCustomization
from _pydevd_bundle.pydevd_custom_frames import CustomFramesContainer, custom_frames_container_init
from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE, PYDEV_FILE
from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE, PYDEV_FILE, LIB_FILE
from _pydevd_bundle.pydevd_extension_api import DebuggerEventHandler
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, remove_exception_from_frame
from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads
@ -521,6 +521,7 @@ class PyDB(object):
self.get_exception_breakpoint = get_exception_breakpoint
self._dont_trace_get_file_type = DONT_TRACE.get
self.PYDEV_FILE = PYDEV_FILE
self.LIB_FILE = LIB_FILE
self._in_project_scope_cache = {}
self._exclude_by_filter_cache = {}
@ -632,7 +633,7 @@ class PyDB(object):
# be changed for another function in PyDevdAPI.set_dont_trace_start_end_patterns.
return False
def get_file_type(self, abs_real_path_and_basename, _cache_file_type=_CACHE_FILE_TYPE):
def get_file_type(self, frame, abs_real_path_and_basename=None, _cache_file_type=_CACHE_FILE_TYPE):
'''
:param abs_real_path_and_basename:
The result from get_abs_path_real_path_and_base_from_file or
@ -649,18 +650,66 @@ class PyDB(object):
None:
If it's a regular user file which should be traced.
'''
if abs_real_path_and_basename is None:
try:
# Make fast path faster!
abs_real_path_and_basename = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename]
except:
abs_real_path_and_basename = get_abs_path_real_path_and_base_from_frame(frame)
# Note 1: we have to take into account that we may have files as '<string>', and that in
# this case the cache key can't rely only on the filename. With the current cache, there's
# still a potential miss if 2 functions which have exactly the same content are compiled
# with '<string>', but in practice as we only separate the one from python -c from the rest
# this shouldn't be a problem in practice.
# Note 2: firstlineno added to make misses faster in the first comparison.
# Note 3: this cache key is repeated in pydevd_frame_evaluator.pyx:get_func_code_info (for
# speedups).
cache_key = (frame.f_code.co_firstlineno, abs_real_path_and_basename[0], frame.f_code)
try:
return _cache_file_type[abs_real_path_and_basename[0]]
return _cache_file_type[cache_key]
except:
if abs_real_path_and_basename[0] == '<string>':
# Consider it an untraceable file unless there's no back frame (ignoring
# internal files and runpy.py).
f = frame.f_back
while f is not None:
if (self.get_file_type(f) != self.PYDEV_FILE and
get_abs_path_real_path_and_base_from_file(f.f_code.co_filename)[2] != 'runpy.py'):
# We found some back frame that's not internal, which means we must consider
# this a library file.
# This is done because we only want to trace files as <string> if they don't
# have any back frame (which is the case for python -c ...), for all other
# cases we don't want to trace them because we can't show the source to the
# user (at least for now...).
# Note that we return as a LIB_FILE and not PYDEV_FILE because we still want
# to show it in the stack.
_cache_file_type[cache_key] = LIB_FILE
return LIB_FILE
f = f.f_back
else:
# This is a top-level file (used in python -c), so, trace it as usual... we
# still won't be able to show the sources, but some tests require this to work.
_cache_file_type[cache_key] = None
return None
file_type = self._internal_get_file_type(abs_real_path_and_basename)
if file_type is None:
file_type = PYDEV_FILE if self.dont_trace_external_files(abs_real_path_and_basename[0]) else None
_cache_file_type[abs_real_path_and_basename[0]] = file_type
if self.dont_trace_external_files(abs_real_path_and_basename[0]):
file_type = PYDEV_FILE
_cache_file_type[cache_key] = file_type
return file_type
def is_cache_file_type_empty(self):
return not _CACHE_FILE_TYPE
def get_cache_file_type(self, _cache=_CACHE_FILE_TYPE): # i.e.: Make it local.
return _cache
def get_thread_local_trace_func(self):
try:
thread_trace_func = self._local_thread_trace_func.thread_trace_func
@ -681,7 +730,7 @@ class PyDB(object):
If True we'll set the tracing function in all threads, not only in the current thread.
If False only the tracing for the current function should be changed.
In general apply_to_all_threads should only be true if this is the first time
this function is called on a multi-threaded program (either programatically or attach
this function is called on a multi-threaded program (either programmatically or attach
to pid).
'''
if self.frame_eval_func is not None:
@ -765,23 +814,54 @@ class PyDB(object):
self.plugin = PluginManager(self)
return self.plugin
def in_project_scope(self, filename):
def in_project_scope(self, frame, filename=None):
'''
Note: in general this method should not be used (apply_files_filter should be used
in most cases as it also handles the project scope check).
:param frame:
The frame we want to check.
:param filename:
Must be the result from get_abs_path_real_path_and_base_from_frame(frame)[0] (can
be used to speed this function a bit if it's already available to the caller, but
in general it's not needed).
'''
try:
return self._in_project_scope_cache[filename]
if filename is None:
try:
# Make fast path faster!
abs_real_path_and_basename = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename]
except:
abs_real_path_and_basename = get_abs_path_real_path_and_base_from_frame(frame)
filename = abs_real_path_and_basename[0]
cache_key = (frame.f_code.co_firstlineno, filename, frame.f_code)
return self._in_project_scope_cache[cache_key]
except KeyError:
cache = self._in_project_scope_cache
abs_real_path_and_basename = get_abs_path_real_path_and_base_from_file(filename)
# pydevd files are never considered to be in the project scope.
if self.get_file_type(abs_real_path_and_basename) == self.PYDEV_FILE:
cache[filename] = False
else:
cache[filename] = self._files_filtering.in_project_roots(filename)
try:
abs_real_path_and_basename # If we've gotten it previously, use it again.
except NameError:
abs_real_path_and_basename = get_abs_path_real_path_and_base_from_frame(frame)
return cache[filename]
# pydevd files are never considered to be in the project scope.
file_type = self.get_file_type(frame, abs_real_path_and_basename)
if file_type == self.PYDEV_FILE:
cache[cache_key] = False
elif file_type == self.LIB_FILE and filename == '<string>':
# This means it's a <string> which should be considered to be a library file and
# shouldn't be considered as a part of the project.
# (i.e.: lib files must be traced if they're put inside a project).
cache[cache_key] = False
else:
cache[cache_key] = self._files_filtering.in_project_roots(filename)
return cache[cache_key]
def _clear_filters_caches(self):
self._in_project_scope_cache.clear()
@ -814,9 +894,8 @@ class PyDB(object):
except KeyError:
cache = self._exclude_by_filter_cache
abs_real_path_and_basename = get_abs_path_real_path_and_base_from_file(filename)
# pydevd files are always filtered out
if self.get_file_type(abs_real_path_and_basename) == self.PYDEV_FILE:
if self.get_file_type(frame) == self.PYDEV_FILE:
cache[cache_key] = True
else:
module_name = None
@ -841,7 +920,7 @@ class PyDB(object):
True if it should be excluded when stepping and False if it should be
included.
'''
cache_key = (frame.f_code.co_firstlineno, frame.f_code.co_name, filename, force_check_project_scope)
cache_key = (frame.f_code.co_firstlineno, filename, force_check_project_scope, frame.f_code)
try:
return self._apply_filter_cache[cache_key]
except KeyError:
@ -867,7 +946,7 @@ class PyDB(object):
self._apply_filter_cache[cache_key] = False
return False
if (self._is_libraries_filter_enabled or force_check_project_scope) and not self.in_project_scope(filename):
if (self._is_libraries_filter_enabled or force_check_project_scope) and not self.in_project_scope(frame):
# ignore library files while stepping
self._apply_filter_cache[cache_key] = True
if force_check_project_scope:
@ -899,7 +978,7 @@ class PyDB(object):
ignore_libraries = exception_breakpoint.ignore_libraries
exclude_filters_enabled = self._exclude_filters_enabled
if (ignore_libraries and not self.in_project_scope(trace.tb_frame.f_code.co_filename)) \
if (ignore_libraries and not self.in_project_scope(trace.tb_frame)) \
or (exclude_filters_enabled and self._exclude_by_filter(trace.tb_frame, trace.tb_frame.f_code.co_filename)):
return True
@ -1652,14 +1731,8 @@ class PyDB(object):
assert not kwargs
while frame is not None:
try:
# Make fast path faster!
abs_path_real_path_and_base = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename]
except:
abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame)
# Don't change the tracing on debugger-related files
file_type = self.get_file_type(abs_path_real_path_and_base)
file_type = self.get_file_type(frame)
if file_type is None:
if disable:

View file

@ -0,0 +1,6 @@
from collections import namedtuple
MyTup = namedtuple('MyTup', 'a, b, c')
tup = MyTup(1, 2, 3) # break here
assert tup.a == 1
assert tup.b == 2
print('TEST SUCEEDED!')

View file

@ -310,8 +310,8 @@ def test_source_mapping():
from _pydevd_bundle.pydevd_source_mapping import SourceMapping, SourceMappingEntry
source_mapping = SourceMapping()
mapping = [
SourceMappingEntry(source_filename='file1.py', line=3, end_line=6, runtime_line=5, runtime_source='<cell1>'),
SourceMappingEntry(source_filename='file1.py', line=10, end_line=11, runtime_line=1, runtime_source='<cell2>'),
SourceMappingEntry(line=3, end_line=6, runtime_line=5, runtime_source='<cell1>'),
SourceMappingEntry(line=10, end_line=11, runtime_line=1, runtime_source='<cell2>'),
]
source_mapping.set_source_mapping('file1.py', mapping)

View file

@ -3307,6 +3307,29 @@ def test_step_over_my_code_global_setting_and_explicit_include(case_setup):
writer.finished_ok = True
def test_namedtuple(case_setup):
'''
Check that we don't step into <string> in the namedtuple constructor.
'''
with case_setup.test_file('_debugger_case_namedtuple.py') as writer:
line = writer.get_line_index_with_content('break here')
writer.write_add_breakpoint(line)
writer.write_make_initial_run()
hit = writer.wait_for_breakpoint_hit()
expected_line = line
for _ in range(2):
expected_line += 1
writer.write_step_in(hit.thread_id)
hit = writer.wait_for_breakpoint_hit(
reason=REASON_STEP_INTO, file='_debugger_case_namedtuple.py', line=expected_line)
writer.write_run_thread(hit.thread_id)
writer.finished_ok = True
def test_matplotlib_activation(case_setup):
try:
import matplotlib

View file

@ -41,7 +41,7 @@ def test_thread_info(_times):
def method():
pass
return sys._getframe()
@pytest.fixture
@ -60,17 +60,17 @@ def test_func_code_info(_times, _custom_global_dbg):
# Must be called before get_func_code_info_py to initialize the _code_extra_index.
pydevd_frame_evaluator.get_thread_info_py()
func_info = pydevd_frame_evaluator.get_func_code_info_py(method.__code__)
func_info = pydevd_frame_evaluator.get_func_code_info_py(method(), method.__code__)
assert func_info.co_filename is method.__code__.co_filename
func_info2 = pydevd_frame_evaluator.get_func_code_info_py(method.__code__)
func_info2 = pydevd_frame_evaluator.get_func_code_info_py(method(), method.__code__)
assert func_info is func_info2
some_func = eval('lambda:0')
func_info3 = pydevd_frame_evaluator.get_func_code_info_py(some_func.__code__)
some_func = eval('lambda:sys._getframe()')
func_info3 = pydevd_frame_evaluator.get_func_code_info_py(some_func(), some_func.__code__)
del some_func
del func_info3
some_func = eval('lambda:0')
pydevd_frame_evaluator.get_func_code_info_py(some_func.__code__)
func_info = pydevd_frame_evaluator.get_func_code_info_py(some_func.__code__)
assert pydevd_frame_evaluator.get_func_code_info_py(some_func.__code__) is func_info
some_func = eval('lambda:sys._getframe()')
pydevd_frame_evaluator.get_func_code_info_py(some_func(), some_func.__code__)
func_info = pydevd_frame_evaluator.get_func_code_info_py(some_func(), some_func.__code__)
assert pydevd_frame_evaluator.get_func_code_info_py(some_func(), some_func.__code__) is func_info

View file

@ -14,7 +14,6 @@ from ptvsd.wrapper import debugger_attached
import pydevd
from _pydevd_bundle.pydevd_constants import get_global_debugger
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame
WAIT_TIMEOUT = 1.0
@ -28,6 +27,7 @@ _redirect_output_deprecation_msg = (
"This can be set using redirectOutput in Launch config in VS Code, using Tee output option in Visual Studio, "
"or debugOptions configuration for any client.")
def wait_for_attach(timeout=None):
"""If a remote debugger is attached, returns immediately. Otherwise,
blocks until a remote debugger attaches to this process, or until the
@ -54,7 +54,7 @@ def enable_attach(address=(DEFAULT_HOST, DEFAULT_PORT), redirect_output=None, lo
``(hostname, port)``. On client side, the server is identified by the
Qualifier string in the usual ``'hostname:port'`` format, e.g.:
``'myhost.cloudapp.net:5678'``. Default is ``('0.0.0.0', 5678)``.
redirect_output : bool, optional
redirect_output : bool, optional
(Deprecated) Specifies whether any output (on both `stdout` and `stderr`) produced
by this program should be sent to the debugger. Default is ``True``.
log_dir : str, optional
@ -162,10 +162,9 @@ def break_into_debugger():
global_debugger = get_global_debugger()
stop_at_frame = sys._getframe().f_back
while stop_at_frame is not None and global_debugger.get_file_type(
get_abs_path_real_path_and_base_from_frame(stop_at_frame)) == global_debugger.PYDEV_FILE:
stop_at_frame) == global_debugger.PYDEV_FILE:
stop_at_frame = stop_at_frame.f_back
# pydevd.settrace() only enables debugging of the current
# thread and all future threads. PyDevd is not enabled for
# existing threads (other than the current one). Consequently,