Skip to content

Commit 0529b8f

Browse files
committed
Redirect I/O during repl evaluation in DAP. Fixes microsoft/ptvsd#2036
1 parent 77654f6 commit 0529b8f

7 files changed

Lines changed: 436 additions & 227 deletions

File tree

src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@
8282
from _pydevd_bundle._debug_adapter import pydevd_base_schema, pydevd_schema
8383
from _pydevd_bundle.pydevd_net_command import NetCommand
8484
from _pydevd_bundle.pydevd_xml import ExceptionOnEvaluate
85-
from _pydevd_bundle.pydevd_constants import ForkSafeLock
85+
from _pydevd_bundle.pydevd_constants import ForkSafeLock, NULL
8686
try:
8787
from urllib import quote_plus, unquote_plus
8888
except:
8989
from urllib.parse import quote_plus, unquote_plus # @Reimport @UnresolvedImport
9090

9191
import pydevconsole
92-
from _pydevd_bundle import pydevd_vars, pydevd_utils
92+
from _pydevd_bundle import pydevd_vars, pydevd_utils, pydevd_io
9393
import pydevd_tracing
9494
from _pydevd_bundle import pydevd_xml
9595
from _pydevd_bundle import pydevd_vm_type
@@ -976,64 +976,70 @@ def internal_evaluate_expression_json(py_db, request, thread_id):
976976
if hasattr(fmt, 'to_dict'):
977977
fmt = fmt.to_dict()
978978

979-
if IS_PY2 and isinstance(expression, unicode):
980-
try:
981-
expression.encode('utf-8')
982-
except:
983-
_evaluate_response(py_db, request, '', error_message='Expression is not valid utf-8.')
984-
raise
979+
if context == 'repl':
980+
ctx = pydevd_io.redirect_stream_to_pydb_io_messages_context()
981+
else:
982+
ctx = NULL
985983

986-
try_exec = False
987-
if frame_id is None:
988-
if _global_frame is None:
989-
# Lazily create a frame to be used for evaluation with no frame id.
984+
with ctx:
985+
if IS_PY2 and isinstance(expression, unicode):
986+
try:
987+
expression.encode('utf-8')
988+
except:
989+
_evaluate_response(py_db, request, '', error_message='Expression is not valid utf-8.')
990+
raise
990991

991-
def __create_frame():
992-
yield sys._getframe()
992+
try_exec = False
993+
if frame_id is None:
994+
if _global_frame is None:
995+
# Lazily create a frame to be used for evaluation with no frame id.
993996

994-
_global_frame = next(__create_frame())
997+
def __create_frame():
998+
yield sys._getframe()
995999

996-
frame = _global_frame
997-
try_exec = True # Always exec in this case
998-
eval_result = None
999-
else:
1000-
frame = py_db.find_frame(thread_id, frame_id)
1001-
eval_result = pydevd_vars.evaluate_expression(py_db, frame, expression, is_exec=False)
1002-
is_error = isinstance(eval_result, ExceptionOnEvaluate)
1003-
if is_error:
1004-
if context == 'hover': # In a hover it doesn't make sense to do an exec.
1005-
_evaluate_response(py_db, request, result='', error_message='Exception occurred during evaluation.')
1006-
return
1007-
elif context == 'watch':
1008-
# If it's a watch, don't show it as an exception object, rather, format
1009-
# it and show it as a string (with success=False).
1010-
msg = '%s: %s' % (
1011-
eval_result.result.__class__.__name__, eval_result.result,)
1012-
_evaluate_response(py_db, request, result=msg, error_message=msg)
1013-
return
1014-
else:
1015-
try_exec = context == 'repl'
1000+
_global_frame = next(__create_frame())
10161001

1017-
if try_exec:
1018-
try:
1019-
pydevd_vars.evaluate_expression(py_db, frame, expression, is_exec=True)
1020-
except Exception as ex:
1021-
err = ''.join(traceback.format_exception_only(type(ex), ex))
1022-
# Currently there is an issue in VSC where returning success=false for an
1023-
# eval request, in repl context, VSC does not show the error response in
1024-
# the debug console. So return the error message in result as well.
1025-
_evaluate_response(py_db, request, result=err, error_message=err)
1002+
frame = _global_frame
1003+
try_exec = True # Always exec in this case
1004+
eval_result = None
1005+
else:
1006+
frame = py_db.find_frame(thread_id, frame_id)
1007+
eval_result = pydevd_vars.evaluate_expression(py_db, frame, expression, is_exec=False)
1008+
is_error = isinstance(eval_result, ExceptionOnEvaluate)
1009+
if is_error:
1010+
if context == 'hover': # In a hover it doesn't make sense to do an exec.
1011+
_evaluate_response(py_db, request, result='', error_message='Exception occurred during evaluation.')
1012+
return
1013+
elif context == 'watch':
1014+
# If it's a watch, don't show it as an exception object, rather, format
1015+
# it and show it as a string (with success=False).
1016+
msg = '%s: %s' % (
1017+
eval_result.result.__class__.__name__, eval_result.result,)
1018+
_evaluate_response(py_db, request, result=msg, error_message=msg)
1019+
return
1020+
else:
1021+
try_exec = context == 'repl'
1022+
1023+
if try_exec:
1024+
try:
1025+
pydevd_vars.evaluate_expression(py_db, frame, expression, is_exec=True)
1026+
except Exception as ex:
1027+
err = ''.join(traceback.format_exception_only(type(ex), ex))
1028+
# Currently there is an issue in VSC where returning success=false for an
1029+
# eval request, in repl context, VSC does not show the error response in
1030+
# the debug console. So return the error message in result as well.
1031+
_evaluate_response(py_db, request, result=err, error_message=err)
1032+
return
1033+
# No result on exec.
1034+
_evaluate_response(py_db, request, result='')
10261035
return
1027-
# No result on exec.
1028-
_evaluate_response(py_db, request, result='')
1029-
return
10301036

1031-
# Ok, we have the result (could be an error), let's put it into the saved variables.
1032-
frame_tracker = py_db.suspended_frames_manager.get_frame_tracker(thread_id)
1033-
if frame_tracker is None:
1034-
# This is not really expected.
1035-
_evaluate_response(py_db, request, result='', error_message='Thread id: %s is not current thread id.' % (thread_id,))
1036-
return
1037+
# Ok, we have the result (could be an error), let's put it into the saved variables.
1038+
frame_tracker = py_db.suspended_frames_manager.get_frame_tracker(thread_id)
1039+
if frame_tracker is None:
1040+
# This is not really expected.
1041+
_evaluate_response(py_db, request, result='', error_message='Thread id: %s is not current thread id.' % (thread_id,))
1042+
return
10371043

10381044
variable = frame_tracker.obtain_as_variable(expression, eval_result, frame=frame)
10391045
var_data = variable.get_var_data(fmt=fmt)

src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_cython.c

Lines changed: 20 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)