Fix issues with django and jinja2 exceptions with just-my-code turned on. Fixes #1181 (#1243)

* Fix issues with django and jinja2 exceptions with just-my-code turned on. Fixes #1181

* Modules don't have __qualname__.

* Fix test to do a step out.

* Fix test for Jython.
This commit is contained in:
Fabio Zadrozny 2019-03-18 23:55:40 -03:00 committed by Karthik Nadig
parent 1173a2b913
commit 6d2062bb37
23 changed files with 2225 additions and 1897 deletions

File diff suppressed because it is too large Load diff

View file

@ -593,8 +593,9 @@ cdef class PyDBFrame:
or (step_cmd in (108, 109, 159, 160) and stop_frame is not frame)
if can_skip:
if plugin_manager is not None and main_debugger.has_plugin_line_breaks:
can_skip = not plugin_manager.can_not_skip(main_debugger, frame)
if plugin_manager is not None and (
main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks):
can_skip = plugin_manager.can_skip(main_debugger, frame)
# CMD_STEP_OVER = 108, CMD_STEP_OVER_MY_CODE = 159
if can_skip and main_debugger.show_return_values and info.pydev_step_cmd in (108, 159) and frame.f_back is info.pydev_step_stop:

View file

@ -442,8 +442,9 @@ class PyDBFrame:
or (step_cmd in (108, 109, 159, 160) and stop_frame is not frame)
if can_skip:
if plugin_manager is not None and main_debugger.has_plugin_line_breaks:
can_skip = not plugin_manager.can_not_skip(main_debugger, frame)
if plugin_manager is not None and (
main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks):
can_skip = plugin_manager.can_skip(main_debugger, frame)
# CMD_STEP_OVER = 108, CMD_STEP_OVER_MY_CODE = 159
if can_skip and main_debugger.show_return_values and info.pydev_step_cmd in (108, 159) and frame.f_back is info.pydev_step_stop:

View file

@ -1,4 +1,5 @@
from _pydevd_bundle import pydevd_constants
from _pydev_imps._pydev_saved_modules import threading
IS_PY3K = pydevd_constants.IS_PY3K
@ -20,6 +21,8 @@ class IORedirector:
Whether to create a buffer attribute (needed to mimick python 3 s
tdout/stderr which has a buffer to write binary data).
'''
self._lock = threading.RLock()
self._writing = False
self._redirect_to = (original, new_redirect)
if wrap_buffer and hasattr(original, 'buffer'):
self.buffer = IORedirector(original.buffer, new_redirect.buffer, False)
@ -27,9 +30,16 @@ class IORedirector:
def write(self, s):
# Note that writing to the original stream may fail for some reasons
# (such as trying to write something that's not a string or having it closed).
for r in self._redirect_to:
if hasattr(r, 'write'):
r.write(s)
with self._lock:
if self._writing:
return
self._writing = True
try:
for r in self._redirect_to:
if hasattr(r, 'write'):
r.write(s)
finally:
self._writing = False
def isatty(self):
for r in self._redirect_to:

View file

@ -5,13 +5,15 @@ from _pydev_bundle._pydev_imports_tipper import TYPE_IMPORT, TYPE_CLASS, TYPE_FU
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
from _pydev_bundle.pydev_override import overrides
from _pydevd_bundle._debug_adapter import pydevd_schema
from _pydevd_bundle.pydevd_comm_constants import CMD_THREAD_CREATE, CMD_RETURN, CMD_MODULE_EVENT
from _pydevd_bundle.pydevd_comm_constants import CMD_THREAD_CREATE, CMD_RETURN, CMD_MODULE_EVENT, \
CMD_WRITE_TO_CONSOLE
from _pydevd_bundle.pydevd_constants import get_thread_id, dict_values
from _pydevd_bundle.pydevd_net_command import NetCommand
from _pydevd_bundle.pydevd_net_command_factory_xml import NetCommandFactory
from _pydevd_bundle.pydevd_utils import get_non_pydevd_threads
from _pydev_imps._pydev_saved_modules import threading
from _pydevd_bundle._debug_adapter.pydevd_schema import ModuleEvent, ModuleEventBody, Module
from _pydevd_bundle._debug_adapter.pydevd_schema import ModuleEvent, ModuleEventBody, Module, \
OutputEventBody, OutputEvent
from functools import partial
import itertools
import pydevd_file_utils
@ -178,17 +180,16 @@ class NetCommandFactoryJson(NetCommandFactory):
py_db, topmost_frame, frame_id_to_lineno
):
module_name = frame.f_globals.get('__qualname__', '')
if not module_name:
module_name = frame.f_globals.get('__name__', '')
module_name = frame.f_globals.get('__name__', '')
module_events.extend(self.modules_manager.track_module(filename_in_utf8, module_name, frame))
presentation_hint = None
if not py_db.in_project_scope(filename_in_utf8):
if py_db.get_use_libraries_filter():
continue
presentation_hint = 'subtle'
if not getattr(frame, 'IS_PLUGIN_FRAME', False): # Never filter out plugin frames!
if not py_db.in_project_scope(filename_in_utf8):
if py_db.get_use_libraries_filter():
continue
presentation_hint = 'subtle'
formatted_name = self._format_frame_name(fmt, method_name, module_name, lineno, filename_in_utf8)
frames.append(pydevd_schema.StackFrame(
@ -209,3 +210,10 @@ class NetCommandFactoryJson(NetCommandFactory):
command='stackTrace',
body=pydevd_schema.StackTraceResponseBody(stackFrames=frames, totalFrames=len(frames)))
return NetCommand(CMD_RETURN, 0, response.to_dict(), is_json=True)
@overrides(NetCommandFactory.make_io_message)
def make_io_message(self, v, ctx):
category = 'stdout' if int(ctx) == 1 else 'stderr'
body = OutputEventBody(v, category)
event = OutputEvent(body)
return NetCommand(CMD_WRITE_TO_CONSOLE, 0, event.to_dict(), is_json=True)

View file

@ -89,7 +89,7 @@ class DefaultResolver:
def resolve(self, var, attribute):
return getattr(var, attribute)
def get_contents_debug_adapter_protocol(self, obj, fmt={}):
def get_contents_debug_adapter_protocol(self, obj, fmt=None):
if MethodWrapperType:
dct, used___dict__ = self._get_py_dictionary(obj)
else:
@ -260,17 +260,18 @@ class DictResolver:
raise UnableToResolveVariableException()
def key_to_str(self, key, fmt={}):
if fmt.get('hex', False):
safe_repr = SafeRepr()
safe_repr.convert_to_hex = True
return safe_repr(key)
def key_to_str(self, key, fmt=None):
if fmt is not None:
if fmt.get('hex', False):
safe_repr = SafeRepr()
safe_repr.convert_to_hex = True
return safe_repr(key)
return '%r' % (key,)
def init_dict(self):
return {}
def get_contents_debug_adapter_protocol(self, dct, fmt={}):
def get_contents_debug_adapter_protocol(self, dct, fmt=None):
'''
This method is to be used in the case where the variables are all saved by its id (and as
such don't need to have the `resolve` method called later on, so, keys don't need to
@ -286,7 +287,7 @@ class DictResolver:
for key, val in dict_iter_items(dct):
i += 1
key_as_str = self.key_to_str(key, fmt)
eval_key_str = self.key_to_str(key) # do not format the key
eval_key_str = self.key_to_str(key) # do not format the key
ret.append((key_as_str, val, '[%s]' % (eval_key_str,)))
if i > MAX_ITEMS_TO_HANDLE:
ret.append((TOO_LARGE_ATTR, TOO_LARGE_MSG))
@ -342,7 +343,7 @@ class TupleResolver: # to enumerate tuples and lists
except:
return getattr(var, attribute)
def get_contents_debug_adapter_protocol(self, lst, fmt={}):
def get_contents_debug_adapter_protocol(self, lst, fmt=None):
'''
This method is to be used in the case where the variables are all saved by its id (and as
such don't need to have the `resolve` method called later on, so, keys don't need to

View file

@ -14,8 +14,8 @@ def get_breakpoints(plugin, pydb):
return None
def can_not_skip(plugin, pydb, frame):
return False
def can_skip(plugin, pydb, frame):
return True
def has_exception_breaks(plugin):

View file

@ -1425,6 +1425,7 @@ static const char __pyx_k_reduce[] = "__reduce__";
static const char __pyx_k_thread[] = "thread";
static const char __pyx_k_update[] = "update";
static const char __pyx_k_f_trace[] = "f_trace";
static const char __pyx_k_can_skip[] = "can_skip";
static const char __pyx_k_code_obj[] = "code_obj";
static const char __pyx_k_getstate[] = "__getstate__";
static const char __pyx_k_pyx_type[] = "__pyx_type";
@ -1442,7 +1443,6 @@ static const char __pyx_k_breakpoints[] = "breakpoints";
static const char __pyx_k_insert_code[] = "insert_code";
static const char __pyx_k_thread_info[] = "thread_info";
static const char __pyx_k_FuncCodeInfo[] = "FuncCodeInfo";
static const char __pyx_k_can_not_skip[] = "can_not_skip";
static const char __pyx_k_pyx_checksum[] = "__pyx_checksum";
static const char __pyx_k_stringsource[] = "stringsource";
static const char __pyx_k_get_file_type[] = "get_file_type";
@ -1506,7 +1506,7 @@ static PyObject *__pyx_n_s_arg;
static PyObject *__pyx_n_s_break_on_caught_exceptions;
static PyObject *__pyx_n_s_breakpoints;
static PyObject *__pyx_n_s_call;
static PyObject *__pyx_n_s_can_not_skip;
static PyObject *__pyx_n_s_can_skip;
static PyObject *__pyx_n_s_clear_thread_local_info;
static PyObject *__pyx_n_s_cline_in_traceback;
static PyObject *__pyx_n_s_code_extra_index;
@ -6738,7 +6738,7 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
* # print('get_bytecode_while_frame_eval always skip', func_code_info.always_skip_code)
* if not func_code_info.always_skip_code: # <<<<<<<<<<<<<<
*
* if main_debugger.has_plugin_line_breaks:
* if main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks:
*/
__pyx_t_4 = ((!(__pyx_v_func_code_info->always_skip_code != 0)) != 0);
if (__pyx_t_4) {
@ -6746,26 +6746,37 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":319
* if not func_code_info.always_skip_code:
*
* if main_debugger.has_plugin_line_breaks: # <<<<<<<<<<<<<<
* can_skip = not main_debugger.plugin.can_not_skip(main_debugger, <object> frame_obj)
* if main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks: # <<<<<<<<<<<<<<
* can_skip = main_debugger.plugin.can_skip(main_debugger, <object> frame_obj)
*
*/
__pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_main_debugger, __pyx_n_s_has_plugin_line_breaks); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 319, __pyx_L23_error)
__Pyx_GOTREF(__pyx_t_10);
__pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 319, __pyx_L23_error)
__pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 319, __pyx_L23_error)
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
if (!__pyx_t_3) {
} else {
__pyx_t_4 = __pyx_t_3;
goto __pyx_L45_bool_binop_done;
}
__pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_main_debugger, __pyx_n_s_has_plugin_exception_breaks); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 319, __pyx_L23_error)
__Pyx_GOTREF(__pyx_t_10);
__pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 319, __pyx_L23_error)
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_t_4 = __pyx_t_3;
__pyx_L45_bool_binop_done:;
if (__pyx_t_4) {
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":320
*
* if main_debugger.has_plugin_line_breaks:
* can_skip = not main_debugger.plugin.can_not_skip(main_debugger, <object> frame_obj) # <<<<<<<<<<<<<<
* if main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks:
* can_skip = main_debugger.plugin.can_skip(main_debugger, <object> frame_obj) # <<<<<<<<<<<<<<
*
* if not can_skip:
*/
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_main_debugger, __pyx_n_s_plugin); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 320, __pyx_L23_error)
__Pyx_GOTREF(__pyx_t_2);
__pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_can_not_skip); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 320, __pyx_L23_error)
__pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_can_skip); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 320, __pyx_L23_error)
__Pyx_GOTREF(__pyx_t_9);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = NULL;
@ -6813,12 +6824,12 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely(__pyx_t_4 < 0)) __PYX_ERR(0, 320, __pyx_L23_error)
__pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_10); if (unlikely((__pyx_t_4 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 320, __pyx_L23_error)
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_v_can_skip = (!__pyx_t_4);
__pyx_v_can_skip = __pyx_t_4;
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":322
* can_skip = not main_debugger.plugin.can_not_skip(main_debugger, <object> frame_obj)
* can_skip = main_debugger.plugin.can_skip(main_debugger, <object> frame_obj)
*
* if not can_skip: # <<<<<<<<<<<<<<
* # if DEBUG:
@ -6857,7 +6868,7 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
* frame.f_trace = thread_info.thread_trace_func
* else:
*/
goto __pyx_L46;
goto __pyx_L48;
}
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":328
@ -6876,10 +6887,10 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
if (__Pyx_PyObject_SetAttrStr(__pyx_v_frame, __pyx_n_s_f_trace, __pyx_t_9) < 0) __PYX_ERR(0, 328, __pyx_L23_error)
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
}
__pyx_L46:;
__pyx_L48:;
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":322
* can_skip = not main_debugger.plugin.can_not_skip(main_debugger, <object> frame_obj)
* can_skip = main_debugger.plugin.can_skip(main_debugger, <object> frame_obj)
*
* if not can_skip: # <<<<<<<<<<<<<<
* # if DEBUG:
@ -6890,8 +6901,8 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":319
* if not func_code_info.always_skip_code:
*
* if main_debugger.has_plugin_line_breaks: # <<<<<<<<<<<<<<
* can_skip = not main_debugger.plugin.can_not_skip(main_debugger, <object> frame_obj)
* if main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks: # <<<<<<<<<<<<<<
* can_skip = main_debugger.plugin.can_skip(main_debugger, <object> frame_obj)
*
*/
}
@ -6907,11 +6918,11 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
if (__pyx_t_4) {
} else {
__pyx_t_3 = __pyx_t_4;
goto __pyx_L48_bool_binop_done;
goto __pyx_L50_bool_binop_done;
}
__pyx_t_4 = (__pyx_v_func_code_info->breakpoint_found != 0);
__pyx_t_3 = __pyx_t_4;
__pyx_L48_bool_binop_done:;
__pyx_L50_bool_binop_done:;
if (__pyx_t_3) {
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":337
@ -6955,7 +6966,7 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
* frame.f_trace = thread_info.thread_trace_func
* else:
*/
goto __pyx_L51;
goto __pyx_L53;
}
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":341
@ -6974,7 +6985,7 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
if (__Pyx_PyObject_SetAttrStr(__pyx_v_frame, __pyx_n_s_f_trace, __pyx_t_10) < 0) __PYX_ERR(0, 341, __pyx_L23_error)
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
}
__pyx_L51:;
__pyx_L53:;
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":337
* # this means we weren't able to actually add the code
@ -6983,7 +6994,7 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
* if thread_info.thread_trace_func is not None:
* frame.f_trace = thread_info.thread_trace_func
*/
goto __pyx_L50;
goto __pyx_L52;
}
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":344
@ -7055,7 +7066,7 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
*/
Py_DECREF(__pyx_v_old);
}
__pyx_L50:;
__pyx_L52:;
/* "_pydevd_frame_eval/pydevd_frame_evaluator.pyx":330
* frame.f_trace = <object> main_debugger.trace_dispatch
@ -7071,7 +7082,7 @@ static PyObject *__pyx_f_18_pydevd_frame_eval_22pydevd_frame_evaluator_get_bytec
* # print('get_bytecode_while_frame_eval always skip', func_code_info.always_skip_code)
* if not func_code_info.always_skip_code: # <<<<<<<<<<<<<<
*
* if main_debugger.has_plugin_line_breaks:
* if main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks:
*/
}
}
@ -8691,7 +8702,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
{&__pyx_n_s_break_on_caught_exceptions, __pyx_k_break_on_caught_exceptions, sizeof(__pyx_k_break_on_caught_exceptions), 0, 0, 1, 1},
{&__pyx_n_s_breakpoints, __pyx_k_breakpoints, sizeof(__pyx_k_breakpoints), 0, 0, 1, 1},
{&__pyx_n_s_call, __pyx_k_call, sizeof(__pyx_k_call), 0, 0, 1, 1},
{&__pyx_n_s_can_not_skip, __pyx_k_can_not_skip, sizeof(__pyx_k_can_not_skip), 0, 0, 1, 1},
{&__pyx_n_s_can_skip, __pyx_k_can_skip, sizeof(__pyx_k_can_skip), 0, 0, 1, 1},
{&__pyx_n_s_clear_thread_local_info, __pyx_k_clear_thread_local_info, sizeof(__pyx_k_clear_thread_local_info), 0, 0, 1, 1},
{&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1},
{&__pyx_n_s_code_extra_index, __pyx_k_code_extra_index, sizeof(__pyx_k_code_extra_index), 0, 0, 1, 1},

View file

@ -316,8 +316,8 @@ cdef PyObject * get_bytecode_while_frame_eval(PyFrameObject * frame_obj, int exc
# print('get_bytecode_while_frame_eval always skip', func_code_info.always_skip_code)
if not func_code_info.always_skip_code:
if main_debugger.has_plugin_line_breaks:
can_skip = not main_debugger.plugin.can_not_skip(main_debugger, <object> frame_obj)
if main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks:
can_skip = main_debugger.plugin.can_skip(main_debugger, <object> frame_obj)
if not can_skip:
# if DEBUG:

View file

@ -707,9 +707,9 @@ class PyDB(object):
try:
return self._apply_filter_cache[cache_key]
except KeyError:
if self.plugin is not None and self.has_plugin_line_breaks:
if self.plugin is not None and (self.has_plugin_line_breaks or self.has_plugin_exception_breaks):
# If it's explicitly needed by some plugin, we can't skip it.
if self.plugin.can_not_skip(self, frame):
if not self.plugin.can_skip(self, frame):
# print('include (include by plugins): %s' % filename)
self._apply_filter_cache[cache_key] = False
return False

View file

@ -7,7 +7,6 @@ from _pydevd_bundle.pydevd_comm import CMD_SET_BREAK, CMD_ADD_EXCEPTION_BREAK
from _pydevd_bundle.pydevd_constants import STATE_SUSPEND, dict_iter_items, DJANGO_SUSPEND, IS_PY2
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, FCode, just_raised, ignore_exception_trace
from pydevd_file_utils import get_abs_path_real_path_and_base_from_file, normcase
import os
IS_DJANGO18 = False
IS_DJANGO19 = False
@ -223,6 +222,13 @@ def _get_source_django_18_or_lower(frame):
return None
def _convert_to_str(s):
if IS_PY2:
if isinstance(s, unicode):
s = s.encode('utf-8')
return s
def _get_template_file_name(frame):
try:
if IS_DJANGO19:
@ -238,26 +244,26 @@ def _get_template_file_name(frame):
self = locals['self']
if self.__class__.__name__ == 'Template' and hasattr(self, 'origin') and \
hasattr(self.origin, 'name'):
return normcase(self.origin.name)
return normcase(_convert_to_str(self.origin.name))
back = back.f_back
else:
if hasattr(context, 'template') and hasattr(context.template, 'origin') and \
hasattr(context.template.origin, 'name'):
return normcase(context.template.origin.name)
return normcase(_convert_to_str(context.template.origin.name))
return None
elif IS_DJANGO19_OR_HIGHER:
# For Django 1.10 and later there is much simpler way to get template name
if 'self' in frame.f_locals:
self = frame.f_locals['self']
if hasattr(self, 'origin') and hasattr(self.origin, 'name'):
return normcase(self.origin.name)
return normcase(_convert_to_str(self.origin.name))
return None
source = _get_source_django_18_or_lower(frame)
if source is None:
pydev_log.debug("Source is None\n")
return None
fname = source[0].name
fname = _convert_to_str(source[0].name)
if fname == '<unknown source>':
pydev_log.debug("Source name is %s\n" % fname)
@ -288,6 +294,8 @@ def _get_template_line(frame):
class DjangoTemplateFrame(object):
IS_PLUGIN_FRAME = True
def __init__(self, frame):
file_name = _get_template_file_name(frame)
self._back_context = frame.f_locals['context']
@ -317,6 +325,8 @@ class DjangoTemplateFrame(object):
class DjangoTemplateSyntaxErrorFrame(object):
IS_PLUGIN_FRAME = True
def __init__(self, frame, filename, lineno, f_locals):
self.f_code = FCode('Django TemplateSyntaxError', filename)
self.f_lineno = lineno
@ -346,8 +356,19 @@ def _is_django_variable_does_not_exist_exception_break_context(frame):
#=======================================================================================================================
def can_not_skip(plugin, main_debugger, frame):
return main_debugger.django_breakpoints and _is_django_render_call(frame)
def can_skip(plugin, main_debugger, frame):
if main_debugger.django_breakpoints:
if _is_django_render_call(frame):
return False
if main_debugger.django_exception_break:
module_name = frame.f_globals.get('__name__', '')
if module_name == 'django.template.base':
# Exceptions raised at django.template.base must be checked.
return False
return True
def has_exception_breaks(plugin):
@ -463,7 +484,7 @@ def exception_break(plugin, main_debugger, pydb_frame, frame, args, arg):
origin = get_template_frame.f_locals.get('origin')
if hasattr(origin, 'name') and origin.name is not None:
filename = normcase(origin.name)
filename = normcase(_convert_to_str(origin.name))
if filename is not None and lineno is not None:
syntax_error_frame = DjangoTemplateSyntaxErrorFrame(

View file

@ -1,8 +1,8 @@
import traceback
from _pydevd_bundle.pydevd_breakpoints import LineBreakpoint
from _pydevd_bundle.pydevd_constants import get_current_thread_id, STATE_SUSPEND, dict_iter_items, dict_keys, JINJA2_SUSPEND
from _pydevd_bundle.pydevd_constants import STATE_SUSPEND, dict_iter_items, dict_keys, JINJA2_SUSPEND, \
IS_PY2
from _pydevd_bundle.pydevd_comm import CMD_SET_BREAK, CMD_ADD_EXCEPTION_BREAK
from _pydevd_bundle import pydevd_vars
from pydevd_file_utils import get_abs_path_real_path_and_base_from_file
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, FCode
@ -114,7 +114,9 @@ def _find_jinja2_render_frame(frame):
#=======================================================================================================================
class Jinja2TemplateFrame:
class Jinja2TemplateFrame(object):
IS_PLUGIN_FRAME = True
def __init__(self, frame):
file_name = _get_jinja2_template_filename(frame)
@ -166,6 +168,19 @@ class Jinja2TemplateFrame:
frame.f_locals[l_name] = value
class Jinja2TemplateSyntaxErrorFrame(object):
IS_PLUGIN_FRAME = True
def __init__(self, frame, exception_cls_name, filename, lineno, f_locals):
self.f_code = FCode('Jinja2 %s' % (exception_cls_name,), filename)
self.f_lineno = lineno
self.f_back = frame
self.f_globals = {}
self.f_locals = f_locals
self.f_trace = None
def change_variable(plugin, frame, attr, expression):
if isinstance(frame, Jinja2TemplateFrame):
result = eval(expression, frame.f_globals, frame.f_locals)
@ -214,9 +229,16 @@ def _get_jinja2_template_line(frame):
return None
def _convert_to_str(s):
if IS_PY2:
if isinstance(s, unicode):
s = s.encode('utf-8', 'replace')
return s
def _get_jinja2_template_filename(frame):
if '__jinja_template__' in frame.f_globals:
fname = frame.f_globals['__jinja_template__'].filename
fname = _convert_to_str(frame.f_globals['__jinja_template__'].filename)
abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(fname)
return abs_path_real_path_and_base[1]
return None
@ -239,13 +261,32 @@ def has_line_breaks(plugin):
return False
def can_not_skip(plugin, pydb, frame):
def can_skip(plugin, pydb, frame):
if pydb.jinja2_breakpoints and _is_jinja2_render_call(frame):
filename = _get_jinja2_template_filename(frame)
jinja2_breakpoints_for_file = pydb.jinja2_breakpoints.get(filename)
if jinja2_breakpoints_for_file:
return True
return False
return False
if pydb.jinja2_exception_break:
name = frame.f_code.co_name
if IS_PY2:
if name == 'fail':
module_name = frame.f_globals.get('__name__', '')
if module_name == 'jinja2.parser':
return False
else:
# errors in compile time
if name in ('template', 'top-level template code', '<module>') or name.startswith('block '):
f_back = frame.f_back
module_name = ''
if f_back is not None:
module_name = f_back.f_globals.get('__name__', '')
if module_name.startswith('jinja2.'):
return False
return True
def cmd_step_into(plugin, pydb, frame, event, args, stop_info, stop):
@ -378,19 +419,42 @@ def exception_break(plugin, pydb, pydb_frame, frame, args, arg):
suspend_frame = _suspend_jinja2(pydb, thread, render_frame, CMD_ADD_EXCEPTION_BREAK, message=exception_type)
if suspend_frame:
add_exception_to_frame(suspend_frame, (exception, value, trace))
flag = True
suspend_frame.f_back = frame
frame = suspend_frame
return flag, frame
return True, frame
elif exception.__name__ in ('TemplateSyntaxError', 'TemplateAssertionError'):
# errors in compile time
name = frame.f_code.co_name
if name in ('template', 'top-level template code', '<module>') or name.startswith('block '):
# Jinja2 translates exception info and creates fake frame on his own
pydb_frame.set_suspend(thread, CMD_ADD_EXCEPTION_BREAK)
add_exception_to_frame(frame, (exception, value, trace))
thread.additional_info.suspend_type = JINJA2_SUSPEND
thread.additional_info.pydev_message = str(exception_type)
flag = True
return flag, frame
if IS_PY2:
if name == 'fail':
module_name = frame.f_globals.get('__name__', '')
if module_name == 'jinja2.parser':
filename = value.filename
lineno = value.lineno
syntax_error_frame = Jinja2TemplateSyntaxErrorFrame(
frame, exception.__name__, filename, lineno, {'name': value.name, 'exception': value})
pydb_frame.set_suspend(thread, CMD_ADD_EXCEPTION_BREAK)
add_exception_to_frame(syntax_error_frame, (exception, value, trace))
thread.additional_info.suspend_type = JINJA2_SUSPEND
thread.additional_info.pydev_message = str(exception_type)
return True, syntax_error_frame
else:
# errors in compile time
if name in ('template', 'top-level template code', '<module>') or name.startswith('block '):
f_back = frame.f_back
if f_back is not None:
module_name = f_back.f_globals.get('__name__', '')
if module_name.startswith('jinja2.'):
# Jinja2 translates exception info and creates fake frame on his own
pydb_frame.set_suspend(thread, CMD_ADD_EXCEPTION_BREAK)
add_exception_to_frame(frame, (exception, value, trace))
thread.additional_info.suspend_type = JINJA2_SUSPEND
thread.additional_info.pydev_message = str(exception_type)
return True, frame
return None

View file

@ -6,7 +6,8 @@ import pytest
from tests_python import debugger_unittest
from tests_python.debugger_unittest import get_free_port, overrides, IS_CPYTHON, IS_JYTHON, IS_IRONPYTHON, \
IS_PY3K, CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK
IS_PY3K, CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK, \
CMD_ADD_EXCEPTION_BREAK
import sys
@ -80,6 +81,9 @@ class AbstractWriterThreadCaseFlask(debugger_unittest.AbstractWriterThread):
self.log.append('write_add_breakpoint_jinja: %s line: %s func: %s' % (breakpoint_id, line, func))
return breakpoint_id
def write_add_exception_breakpoint_jinja2(self, exception='jinja2-Exception'):
self.write('%s\t%s\t%s\t%s\t%s\t%s' % (CMD_ADD_EXCEPTION_BREAK, self.next_seq(), exception, 2, 0, 0))
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
import platform
@ -125,7 +129,7 @@ class AbstractWriterThreadCaseFlask(debugger_unittest.AbstractWriterThread):
return False
def create_request_thread(self):
def create_request_thread(self, url=''):
outer = self
class T(threading.Thread):
@ -137,7 +141,7 @@ class AbstractWriterThreadCaseFlask(debugger_unittest.AbstractWriterThread):
from urllib import urlopen
for _ in range(10):
try:
stream = urlopen('http://127.0.0.1:%s' % (outer.flask_port,))
stream = urlopen('http://127.0.0.1:%s%s' % (outer.flask_port, url))
contents = stream.read()
if IS_PY3K:
contents = contents.decode('utf-8')

View file

@ -1,7 +1,6 @@
from flask import Flask
from flask import render_template
app = Flask(__name__)
@ -38,6 +37,15 @@ def bad_route_unhandled():
)
@app.route("/bad_template")
def bad_template():
return render_template(
"bad.html",
title='Bad',
content='Flask-Jinja-Test'
)
@app.route("/exit")
def exit_app():
from flask import request
@ -46,3 +54,7 @@ def exit_app():
raise RuntimeError('No shutdown')
func()
return 'Done'
if __name__ == '__main__':
app.run()

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
{% doesnotexist %}
</body>
</html>

View file

@ -954,14 +954,28 @@ def test_case_django_b(case_setup_django):
@pytest.mark.skipif(not TEST_DJANGO, reason='No django available')
def test_case_django_no_attribute_exception_breakpoint(case_setup_django):
@pytest.mark.parametrize("jmc", [False, True])
def test_case_django_no_attribute_exception_breakpoint(case_setup_django, jmc):
django_version = [int(x) for x in django.get_version().split('.')][:2]
if django_version < [2, 1]:
pytest.skip('Template exceptions only supporting Django 2.1 onwards.')
with case_setup_django.test_file(EXPECTED_RETURNCODE='any') as writer:
kwargs = {}
if jmc:
def get_environ(writer):
env = os.environ.copy()
env.update({
'PYDEVD_FILTER_LIBRARIES': '1', # Global setting for in project or not
})
return env
kwargs['get_environ'] = get_environ
with case_setup_django.test_file(EXPECTED_RETURNCODE='any', **kwargs) as writer:
writer.write_add_exception_breakpoint_django()
writer.write_make_initial_run()
t = writer.create_request_thread('my_app/template_error')
@ -1010,13 +1024,26 @@ def test_case_django_no_attribute_exception_breakpoint_and_regular_exceptions(ca
@pytest.mark.skipif(not TEST_DJANGO, reason='No django available')
def test_case_django_invalid_template_exception_breakpoint(case_setup_django):
@pytest.mark.parametrize("jmc", [False, True])
def test_case_django_invalid_template_exception_breakpoint(case_setup_django, jmc):
django_version = [int(x) for x in django.get_version().split('.')][:2]
if django_version < [2, 1]:
pytest.skip('Template exceptions only supporting Django 2.1 onwards.')
with case_setup_django.test_file(EXPECTED_RETURNCODE='any') as writer:
kwargs = {}
if jmc:
def get_environ(writer):
env = os.environ.copy()
env.update({
'PYDEVD_FILTER_LIBRARIES': '1', # Global setting for in project or not
})
return env
kwargs['get_environ'] = get_environ
with case_setup_django.test_file(EXPECTED_RETURNCODE='any', **kwargs) as writer:
writer.write_add_exception_breakpoint_django()
writer.write_make_initial_run()

View file

@ -1,11 +1,12 @@
# coding: utf-8
import pytest
from _pydevd_bundle._debug_adapter import pydevd_schema, pydevd_base_schema
from _pydevd_bundle._debug_adapter.pydevd_base_schema import from_json
from _pydevd_bundle._debug_adapter.pydevd_schema import ThreadEvent, ModuleEvent, StoppedEvent
from tests_python import debugger_unittest
from tests_python.debugger_unittest import IS_JYTHON, REASON_STEP_INTO, REASON_STEP_OVER, \
REASON_CAUGHT_EXCEPTION, REASON_THREAD_SUSPEND, REASON_STEP_RETURN
REASON_CAUGHT_EXCEPTION, REASON_THREAD_SUSPEND, REASON_STEP_RETURN, IS_APPVEYOR, overrides
from _pydevd_bundle._debug_adapter.pydevd_schema import ThreadEvent, ModuleEvent, OutputEvent
from tests_python import debugger_unittest
import json
from collections import namedtuple
from _pydevd_bundle.pydevd_constants import int_types
@ -178,7 +179,10 @@ def test_case_json_logpoints(case_setup):
# Should only print, not stop on logpoints.
messages = []
while True:
msg, ctx = writer.wait_for_output()
output_event = json_facade.wait_for_json_message(OutputEvent)
msg = output_event.body.output
ctx = output_event.body.category
if ctx == 'stdout':
msg = msg.strip()
if msg == "var '_a' is 2":
@ -257,7 +261,7 @@ def test_case_skipping_filters(case_setup, custom_setup):
writer.write_set_protocol('http_json')
if custom_setup == 'set_exclude_launch_path_match_filename':
json_facade.write_launch(
debugStdLib=True,
debugOptions=['DebugStdLib'],
rules=[
{'path': '**/other.py', 'include':False},
]
@ -265,7 +269,7 @@ def test_case_skipping_filters(case_setup, custom_setup):
elif custom_setup == 'set_exclude_launch_path_match_folder':
json_facade.write_launch(
debugStdLib=True,
debugOptions=['DebugStdLib'],
rules=[
{'path': debugger_unittest._get_debugger_test_file('not_my_code'), 'include':False},
]
@ -273,7 +277,7 @@ def test_case_skipping_filters(case_setup, custom_setup):
elif custom_setup == 'set_exclude_launch_module_full':
json_facade.write_launch(
debugStdLib=True,
debugOptions=['DebugStdLib'],
rules=[
{'module': 'not_my_code.other', 'include':False},
]
@ -281,7 +285,7 @@ def test_case_skipping_filters(case_setup, custom_setup):
elif custom_setup == 'set_exclude_launch_module_prefix':
json_facade.write_launch(
debugStdLib=True,
debugOptions=['DebugStdLib'],
rules=[
{'module': 'not_my_code', 'include':False},
]
@ -289,13 +293,13 @@ def test_case_skipping_filters(case_setup, custom_setup):
elif custom_setup == 'set_just_my_code':
writer.write_set_project_roots([debugger_unittest._get_debugger_test_file('my_code')])
json_facade.write_launch(debugStdLib=False)
json_facade.write_launch(debugOptions=[])
elif custom_setup == 'set_just_my_code_and_include':
# I.e.: nothing in my_code (add it with rule).
writer.write_set_project_roots([debugger_unittest._get_debugger_test_file('launch')])
json_facade.write_launch(
debugStdLib=False,
debugOptions=[],
rules=[
{'module': '__main__', 'include':True},
]
@ -848,13 +852,14 @@ def test_pause_and_continue(case_setup):
scope = pydevd_schema.Scope(**next(iter(scopes_response.body.scopes)))
frame_variables_reference = scope.variablesReference
set_variable_request = json_facade.write_request(
pydevd_schema.SetVariableRequest(pydevd_schema.SetVariableArguments(
frame_variables_reference, 'loop', 'False'
)))
set_variable_response = json_facade.wait_for_response(set_variable_request)
set_variable_response_as_dict = set_variable_response.to_dict()['body']
assert set_variable_response_as_dict == {'value': "False", 'type': 'bool'}
if not IS_JYTHON:
set_variable_request = json_facade.write_request(
pydevd_schema.SetVariableRequest(pydevd_schema.SetVariableArguments(
frame_variables_reference, 'loop', 'False'
)))
set_variable_response = json_facade.wait_for_response(set_variable_request)
set_variable_response_as_dict = set_variable_response.to_dict()['body']
assert set_variable_response_as_dict == {'value': "False", 'type': 'bool'}
continue_request = json_facade.write_request(
pydevd_schema.ContinueRequest(pydevd_schema.ContinueArguments('*')))
@ -920,7 +925,7 @@ def test_stepping(case_setup):
assert stack_frame['name'] == 'step_out'
stepout_request = json_facade.write_request(
pydevd_schema.StepInRequest(pydevd_schema.StepInArguments(hit.thread_id)))
pydevd_schema.StepOutRequest(pydevd_schema.StepOutArguments(hit.thread_id)))
stepout_response = json_facade.wait_for_response(stepout_request)
hit = writer.wait_for_breakpoint_hit(REASON_STEP_RETURN)
@ -1010,7 +1015,8 @@ def test_path_translation_and_source_reference(case_setup):
@pytest.mark.skipif(not TEST_DJANGO, reason='No django available')
def test_case_django_no_attribute_exception_breakpoint(case_setup_django):
@pytest.mark.parametrize("jmc", [False, True])
def test_case_django_no_attribute_exception_breakpoint(case_setup_django, jmc):
django_version = [int(x) for x in django.get_version().split('.')][:2]
if django_version < [2, 1]:
@ -1020,6 +1026,12 @@ def test_case_django_no_attribute_exception_breakpoint(case_setup_django):
json_facade = JsonFacade(writer)
writer.write_set_protocol('http_json')
if jmc:
writer.write_set_project_roots([debugger_unittest._get_debugger_test_file('my_code')])
json_facade.write_launch(debugOptions=[])
else:
json_facade.write_launch(debugOptions=['DebugStdLib'])
writer.write_add_exception_breakpoint_django()
writer.write_make_initial_run()
@ -1053,6 +1065,112 @@ def test_case_django_no_attribute_exception_breakpoint(case_setup_django):
writer.finished_ok = True
@pytest.mark.skipif(not TEST_FLASK, reason='No flask available')
@pytest.mark.parametrize("jmc", [False, True])
def test_case_flask_exceptions(case_setup_flask, jmc):
with case_setup_flask.test_file(EXPECTED_RETURNCODE='any') as writer:
json_facade = JsonFacade(writer)
writer.write_set_protocol('http_json')
if jmc:
writer.write_set_project_roots([debugger_unittest._get_debugger_test_file('my_code')])
json_facade.write_launch(debugOptions=[])
else:
json_facade.write_launch(debugOptions=['DebugStdLib'])
writer.write_add_exception_breakpoint_jinja2()
writer.write_make_initial_run()
t = writer.create_request_thread('/bad_template')
time.sleep(2) # Give flask some time to get to startup before requesting the page
t.start()
hit = writer.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION, line=8, file='bad.html')
writer.write_run_thread(hit.thread_id)
writer.finished_ok = True
@pytest.mark.skipif(IS_APPVEYOR or IS_JYTHON, reason='Flaky on appveyor / Jython encoding issues (needs investigation).')
def test_redirect_output(case_setup):
def get_environ(writer):
env = os.environ.copy()
env["PYTHONIOENCODING"] = 'utf-8'
return env
with case_setup.test_file('_debugger_case_redirect.py', get_environ=get_environ) as writer:
original_ignore_stderr_line = writer._ignore_stderr_line
writer.write_set_protocol('http_json')
json_facade = JsonFacade(writer)
@overrides(writer._ignore_stderr_line)
def _ignore_stderr_line(line):
if original_ignore_stderr_line(line):
return True
return line.startswith((
'text',
'binary',
'a'
))
writer._ignore_stderr_line = _ignore_stderr_line
# Note: writes to stdout and stderr are now synchronous (so, the order
# must always be consistent and there's a message for each write).
expected = [
'text\n',
'binary or text\n',
'ação1\n',
]
if sys.version_info[0] >= 3:
expected.extend((
'binary\n',
'ação2\n'.encode(encoding='latin1').decode('utf-8', 'replace'),
'ação3\n',
))
new_expected = [(x, 'stdout') for x in expected]
new_expected.extend([(x, 'stderr') for x in expected])
writer.write_start_redirect()
writer.write_make_initial_run()
msgs = []
ignored = []
while len(msgs) < len(new_expected):
try:
output_event = json_facade.wait_for_json_message(OutputEvent)
output = output_event.body.output
category = output_event.body.category
if IS_PY2:
if isinstance(output, unicode):
output = output.encode('utf-8')
if isinstance(category, unicode):
category = category.encode('utf-8')
msg = (output, category)
except Exception:
for msg in msgs:
sys.stderr.write('Found: %s\n' % (msg,))
for msg in new_expected:
sys.stderr.write('Expected: %s\n' % (msg,))
for msg in ignored:
sys.stderr.write('Ignored: %s\n' % (msg,))
raise
if msg not in new_expected:
ignored.append(msg)
continue
msgs.append(msg)
if msgs != new_expected:
print(msgs)
print(new_expected)
assert msgs == new_expected
writer.finished_ok = True
if __name__ == '__main__':
pytest.main(['-k', 'test_case_skipping_filters', '-s'])

View file

@ -54,7 +54,6 @@ from ptvsd.pathutils import PathUnNormcase # noqa
from ptvsd.version import __version__ # noqa
from ptvsd.socket import TimeoutError # noqa
WAIT_FOR_THREAD_FINISH_TIMEOUT = 1 # seconds
STEP_REASONS = {
@ -350,10 +349,13 @@ class PydevdSocket(object):
# are encoded first and then quoted as individual bytes. In Python 3,
# however, we just get a properly UTF-8-encoded string.
if sys.version_info < (3,):
@staticmethod
def _decode_and_unquote(data):
return unquote(data).decode('utf8')
else:
@staticmethod
def _decode_and_unquote(data):
return unquote(data.decode('utf8'))
@ -511,11 +513,15 @@ class ExceptionsManager(object):
self.exceptions = {}
self.lock = threading.Lock()
def remove_exception_break(self, ex_type='python', exception='BaseException'):
cmdargs = (ex_type, exception)
msg = '{}-{}'.format(*cmdargs)
self.proc.pydevd_notify(pydevd_comm.CMD_REMOVE_EXCEPTION_BREAK, msg)
def remove_all_exception_breaks(self):
with self.lock:
for exception in self.exceptions.keys():
self.proc.pydevd_notify(pydevd_comm.CMD_REMOVE_EXCEPTION_BREAK,
'python-{}'.format(exception))
self.remove_exception_break(exception=exception)
self.exceptions = {}
def _find_exception(self, name):
@ -540,25 +546,27 @@ class ExceptionsManager(object):
return 'unhandled'
def add_exception_break(self, exception, break_raised, break_uncaught,
skip_stdlib=False):
skip_stdlib=False, ex_type='python'):
notify_on_handled_exceptions = 1 if break_raised else 0
notify_on_unhandled_exceptions = 1 if break_uncaught else 0
ignore_libraries = 1 if skip_stdlib else 0
cmdargs = (
ex_type,
exception,
notify_on_handled_exceptions,
notify_on_unhandled_exceptions,
ignore_libraries,
)
break_mode = 'never'
if break_raised:
break_mode = 'always'
elif break_uncaught:
break_mode = 'unhandled'
msg = 'python-{}\t{}\t{}\t{}'.format(*cmdargs)
msg = '{}-{}\t{}\t{}\t{}'.format(*cmdargs)
with self.lock:
self.proc.pydevd_notify(
pydevd_comm.CMD_ADD_EXCEPTION_BREAK, msg)
@ -992,7 +1000,7 @@ INITIALIZE_RESPONSE = dict(
supportsSetVariable=True,
supportsValueFormattingOptions=True,
supportTerminateDebuggee=True,
supportsGotoTargetsRequest=False, # https://github.com/Microsoft/ptvsd/issues/1163
supportsGotoTargetsRequest=False, # https://github.com/Microsoft/ptvsd/issues/1163
exceptionBreakpointFilters=[
{
'filter': 'raised',
@ -1823,6 +1831,13 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
breakpoints = resp_args['body']['breakpoints']
self.send_response(request, breakpoints=breakpoints)
def _get_pydevex_type(self):
if self.debug_options.get('DJANGO_DEBUG', False):
return 'django'
elif self.debug_options.get('FLASK_DEBUG', False):
return 'jinja2'
return 'python'
@async_handler
def on_setExceptionBreakpoints(self, request, args):
# TODO: docstring
@ -1830,9 +1845,15 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
exception_options = args.get('exceptionOptions', [])
jmc = self._is_just_my_code_stepping_enabled()
pydevex_type = self._get_pydevex_type()
if exception_options:
self.exceptions_mgr.apply_exception_options(
exception_options, jmc)
if pydevex_type != 'python':
self.exceptions_mgr.remove_exception_break(ex_type=pydevex_type)
self.exceptions_mgr.add_exception_break(
'BaseException', True, True,
skip_stdlib=jmc, ex_type=pydevex_type)
else:
self.exceptions_mgr.remove_all_exception_breaks()
break_raised = 'raised' in filters
@ -1841,6 +1862,12 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
self.exceptions_mgr.add_exception_break(
'BaseException', break_raised, break_uncaught,
skip_stdlib=jmc)
if pydevex_type != 'python':
self.exceptions_mgr.remove_exception_break(ex_type=pydevex_type)
self.exceptions_mgr.add_exception_break(
'BaseException', break_raised, break_uncaught,
skip_stdlib=jmc, ex_type=pydevex_type)
if request is not None:
self.send_response(request)
@ -2162,11 +2189,8 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
@pydevd_events.handler(pydevd_comm.CMD_WRITE_TO_CONSOLE)
def on_pydevd_cmd_write_to_console2(self, seq, args):
"""Handle console output"""
xml = self.parse_xml_response(args)
ctx = xml.io['ctx']
category = 'stdout' if ctx == '1' else 'stderr'
content = unquote(xml.io['s'])
self.send_event('output', category=category, output=content)
body = args.get('body', {})
self.send_event('output', **body)
@pydevd_events.handler(pydevd_comm.CMD_GET_BREAKPOINT_EXCEPTION)
def on_pydevd_get_breakpoint_exception(self, seq, args):

View file

@ -6,7 +6,6 @@ from __future__ import print_function, with_statement, absolute_import
import os.path
import pytest
import sys
import tests.helpers
from tests.helpers.pattern import ANY, Path
@ -25,7 +24,6 @@ DJANGO_LINK = 'http://127.0.0.1:{}/'.format(DJANGO_PORT)
@pytest.mark.parametrize('bp_target', ['code', 'template'])
@pytest.mark.parametrize('start_method', ['launch', 'attach_socket_cmdline'])
@pytest.mark.skipif(sys.version_info < (3, 0), reason='Bug #923')
@pytest.mark.timeout(60)
def test_django_breakpoint_no_multiproc(bp_target, start_method):
bp_file, bp_line, bp_name = {
@ -50,18 +48,10 @@ def test_django_breakpoint_no_multiproc(bp_target, start_method):
# wait for Django server to start
wait_for_connection(DJANGO_PORT)
web_request = get_web_content(DJANGO_LINK, {})
web_request = get_web_content(DJANGO_LINK + 'home', {})
thread_stopped = session.wait_for_next(Event('stopped', ANY.dict_with({'reason': 'breakpoint'})))
assert thread_stopped.body['threadId'] is not None
tid = thread_stopped.body['threadId']
resp_stacktrace = session.send_request('stackTrace', arguments={
'threadId': tid,
}).wait_for_response()
assert resp_stacktrace.body['totalFrames'] >= 1
frames = resp_stacktrace.body['stackFrames']
hit = session.wait_for_thread_stopped()
frames = hit.stacktrace.body['stackFrames']
assert frames[0] == {
'id': ANY.int,
'name': bp_name,
@ -105,7 +95,6 @@ def test_django_breakpoint_no_multiproc(bp_target, start_method):
@pytest.mark.parametrize('start_method', ['launch', 'attach_socket_cmdline'])
@pytest.mark.skip(reason='Bug #694')
@pytest.mark.timeout(60)
def test_django_template_exception_no_multiproc(start_method):
with DebugSession() as session:
@ -127,40 +116,36 @@ def test_django_template_exception_no_multiproc(start_method):
wait_for_connection(DJANGO_PORT)
base_link = DJANGO_LINK
part = 'badtemplate'
link = base_link + part if base_link.endswith('/') else ('/' + part)
link = DJANGO_LINK + 'badtemplate'
web_request = get_web_content(link, {})
hit = session.wait_for_thread_stopped()
frames = hit.stacktrace.body['stackFrames']
assert frames[0] == {
'id': ANY,
'name': 'bad_template',
'source': {
'sourceReference': ANY,
assert frames[0] == ANY.dict_with({
'id': ANY.int,
'name': 'Django TemplateSyntaxError',
'source': ANY.dict_with({
'sourceReference': ANY.int,
'path': Path(DJANGO1_BAD_TEMPLATE),
},
}),
'line': 8,
'column': 1,
}
})
resp_exception_info = session.send_request(
'exceptionInfo',
arguments={'threadId': hit.thread_id, }
).wait_for_response()
exception = resp_exception_info.body
assert exception == {
assert exception == ANY.dict_with({
'exceptionId': ANY.such_that(lambda s: s.endswith('TemplateSyntaxError')),
'breakMode': 'always',
'description': ANY.such_that(lambda s: s.find('doesnotexist') > -1),
'details': {
'details': ANY.dict_with({
'message': ANY.such_that(lambda s: s.endswith('doesnotexist') > -1),
'typeName': ANY.such_that(lambda s: s.endswith('TemplateSyntaxError')),
'source': Path(DJANGO1_BAD_TEMPLATE),
'stackTrace': ANY.such_that(lambda s: True),
}
}
})
})
session.send_request('continue').wait_for_response(freeze=False)
@ -168,7 +153,7 @@ def test_django_template_exception_no_multiproc(start_method):
web_request.wait_for_response()
# shutdown to web server
link = base_link + 'exit' if base_link.endswith('/') else '/exit'
link = DJANGO_LINK + 'exit'
get_web_content(link).wait_for_response()
session.wait_for_exit()
@ -176,7 +161,6 @@ def test_django_template_exception_no_multiproc(start_method):
@pytest.mark.parametrize('ex_type', ['handled', 'unhandled'])
@pytest.mark.parametrize('start_method', ['launch', 'attach_socket_cmdline'])
@pytest.mark.skipif(sys.version_info < (3, 0), reason='Bug #923')
@pytest.mark.timeout(60)
def test_django_exception_no_multiproc(ex_type, start_method):
ex_line = {
@ -203,8 +187,7 @@ def test_django_exception_no_multiproc(ex_type, start_method):
wait_for_connection(DJANGO_PORT)
base_link = DJANGO_LINK
link = base_link + ex_type if base_link.endswith('/') else ('/' + ex_type)
link = DJANGO_LINK + ex_type
web_request = get_web_content(link, {})
thread_stopped = session.wait_for_next(Event('stopped', ANY.dict_with({'reason': 'exception'})))
@ -238,10 +221,10 @@ def test_django_exception_no_multiproc(ex_type, start_method):
assert resp_stacktrace.body['totalFrames'] > 1
frames = resp_stacktrace.body['stackFrames']
assert frames[0] == {
'id': ANY,
'id': ANY.int,
'name': 'bad_route_' + ex_type,
'source': {
'sourceReference': ANY,
'sourceReference': ANY.int,
'path': Path(DJANGO1_MANAGE),
},
'line': ex_line,
@ -254,7 +237,7 @@ def test_django_exception_no_multiproc(ex_type, start_method):
web_request.wait_for_response()
# shutdown to web server
link = base_link + 'exit' if base_link.endswith('/') else '/exit'
link = DJANGO_LINK + 'exit'
get_web_content(link).wait_for_response()
session.wait_for_exit()
@ -295,7 +278,7 @@ def test_django_breakpoint_multiproc(start_method):
if get_url_from_str(o.body['output']) is not None:
break
web_request = get_web_content(DJANGO_LINK, {})
web_request = get_web_content(DJANGO_LINK + 'home', {})
thread_stopped = child_session.wait_for_next(Event('stopped', ANY.dict_with({'reason': 'breakpoint'})))
assert thread_stopped.body['threadId'] is not None

View file

@ -16,7 +16,6 @@ from tests.helpers.timeline import Event
from tests.helpers.webhelper import get_web_content, wait_for_connection
from tests.helpers.pathutils import get_test_root
FLASK1_ROOT = get_test_root('flask1')
FLASK1_APP = os.path.join(FLASK1_ROOT, 'app.py')
FLASK1_TEMPLATE = os.path.join(FLASK1_ROOT, 'templates', 'hello.html')
@ -124,7 +123,6 @@ def test_flask_breakpoint_no_multiproc(bp_target, start_method):
@pytest.mark.parametrize('start_method', ['launch', 'attach_socket_cmdline'])
@pytest.mark.skip(reason='Bug #694')
@pytest.mark.timeout(60)
def test_flask_template_exception_no_multiproc(start_method):
with DebugSession() as session:
@ -145,33 +143,31 @@ def test_flask_template_exception_no_multiproc(start_method):
hit = session.wait_for_thread_stopped()
frames = hit.stacktrace.body['stackFrames']
assert frames[0] == {
assert frames[0] == ANY.dict_with({
'id': ANY.int,
'name': 'bad_template',
'source': {
'name': 'template' if sys.version_info[0] >= 3 else 'Jinja2 TemplateSyntaxError',
'source': ANY.dict_with({
'sourceReference': ANY.int,
'path': Path(FLASK1_BAD_TEMPLATE),
},
}),
'line': 8,
'column': 1,
}
})
resp_exception_info = session.send_request(
'exceptionInfo',
arguments={'threadId': hit.thread_id, }
).wait_for_response()
exception = resp_exception_info.body
assert exception == {
assert exception == ANY.dict_with({
'exceptionId': ANY.such_that(lambda s: s.endswith('TemplateSyntaxError')),
'breakMode': 'always',
'description': ANY.such_that(lambda s: s.find('doesnotexist') > -1),
'details': {
'details': ANY.dict_with({
'message': ANY.such_that(lambda s: s.find('doesnotexist') > -1),
'typeName': ANY.such_that(lambda s: s.endswith('TemplateSyntaxError')),
'source': Path(FLASK1_BAD_TEMPLATE),
'stackTrace': ANY.such_that(lambda s: True)
}
}
})
})
session.send_request('continue').wait_for_response(freeze=False)

View file

@ -1,8 +1,8 @@
import os
import signal
import sys
from django.conf import settings
from django.urls import path
from django.core.management import execute_from_command_line
from django.http import HttpResponse
from django.template import loader
@ -17,11 +17,11 @@ def sigint_handler(signal, frame):
signal.signal(signal.SIGINT, sigint_handler)
settings.configure(
DEBUG=True,
SECRET_KEY='CD8FF4C1-7E6C-4E45-922D-C796271F2345',
ROOT_URLCONF=sys.modules[__name__],
SETTINGS_MODULE='', # Added to avoid a KeyError during shutdown on the bad template test.
TEMPLATES=[
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
@ -91,13 +91,24 @@ def exit_app(request):
return HttpResponse('Done')
urlpatterns = [
path('', home, name='home'),
path('handled', bad_route_handled, name='bad_route_handled'),
path('unhandled', bad_route_unhandled, name='bad_route_unhandled'),
path('badtemplate', bad_template, name='bad_template'),
path('exit', exit_app, name='exit_app'),
]
if sys.version_info < (3, 0):
from django.conf.urls import url
urlpatterns = [
url(r'home', home, name='home'),
url(r'^handled$', bad_route_handled, name='bad_route_handled'),
url(r'^unhandled$', bad_route_unhandled, name='bad_route_unhandled'),
url(r'badtemplate', bad_template, name='bad_template'),
url(r'exit', exit_app, name='exit_app'),
]
else:
from django.urls import path
urlpatterns = [
path('home', home, name='home'),
path('handled', bad_route_handled, name='bad_route_handled'),
path('unhandled', bad_route_unhandled, name='bad_route_unhandled'),
path('badtemplate', bad_template, name='bad_template'),
path('exit', exit_app, name='exit_app'),
]
if __name__ == '__main__':
execute_from_command_line(sys.argv)

View file

@ -47,6 +47,7 @@ def get_web_content(link, web_result=None, timeout=1):
name='test.webClient'
)
response._web_client_thread.start()
print('Opening link: ' + link)
return response