mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
* 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:
parent
1173a2b913
commit
6d2062bb37
23 changed files with 2225 additions and 1897 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
{% doesnotexist %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue