Skip to content

Commit

Permalink
Don't patch stdin on debugpy. Fixes microsoft#296
Browse files Browse the repository at this point in the history
  • Loading branch information
fabioz committed Jul 23, 2020
1 parent 1bef8e5 commit 499bbb2
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def convert_ppid(ppid):
ArgHandlerBool('print-in-debugger-startup'),
ArgHandlerBool('cmd-line'),
ArgHandlerBool('module'),
ArgHandlerBool('skip-notify-stdin'),

# The ones below should've been just one setting to specify the protocol, but for compatibility
# reasons they're passed as a flag but are mutually exclusive.
Expand Down
18 changes: 16 additions & 2 deletions src/debugpy/_vendored/pydevd/pydevd.py
Original file line number Diff line number Diff line change
Expand Up @@ -2531,6 +2531,7 @@ def settrace(
dont_trace_end_patterns=(),
access_token=None,
client_access_token=None,
notify_stdin=True,
**kwargs
):
'''Sets the tracing function with the pydev debug function and initializes needed facilities.
Expand Down Expand Up @@ -2577,6 +2578,14 @@ def settrace(
:param client_access_token: token to be sent from the debugger to the client (i.e.: IDE) when
a connection is established (verified by the client).
:param notify_stdin:
If True sys.stdin will be patched to notify the client when a message is requested
from the IDE. This is done so that when reading the stdin the client is notified.
Clients may need this to know when something that is being written should be interpreted
as an input to the process or as a command to be evaluated.
Note that parallel-python has issues with this (because it tries to assert that sys.stdin
is of a given type instead of just checking that it has what it needs).
'''

stdout_to_server = stdout_to_server or kwargs.get('stdoutToServer', False) # Backward compatibility
Expand All @@ -2602,6 +2611,7 @@ def settrace(
access_token,
client_access_token,
__setup_holder__=__setup_holder__,
notify_stdin=notify_stdin,
)


Expand All @@ -2624,6 +2634,7 @@ def _locked_settrace(
access_token,
client_access_token,
__setup_holder__,
notify_stdin,
):
if patch_multiprocessing:
try:
Expand Down Expand Up @@ -2653,6 +2664,7 @@ def _locked_settrace(
'server': False,
'port': int(port),
'multiprocess': patch_multiprocessing,
'skip-notify-stdin': not notify_stdin,
}
SetupHolder.setup = setup

Expand Down Expand Up @@ -2682,7 +2694,8 @@ def _locked_settrace(
if _global_redirect_stderr_to_server:
_init_stderr_redirect()

patch_stdin()
if notify_stdin:
patch_stdin()

t = threadingCurrentThread()
additional_info = set_additional_thread_info(t)
Expand Down Expand Up @@ -3130,7 +3143,8 @@ def main():
pass

is_module = setup['module']
patch_stdin()
if not setup['skip-notify-stdin']:
patch_stdin()

if setup[pydevd_constants.ARGUMENT_JSON_PROTOCOL]:
PyDevdAPI().set_protocol(debugger, 0, JSON_PROTOCOL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ def create_process(self, args, writer):
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
cwd=writer.get_cwd() if writer is not None else '.',
env=env,
)
Expand Down
32 changes: 31 additions & 1 deletion src/debugpy/_vendored/pydevd/tests_python/test_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
CMD_THREAD_RESUME_SINGLE_NOTIFICATION, REASON_STEP_RETURN, REASON_STEP_RETURN_MY_CODE,
REASON_STEP_OVER_MY_CODE, REASON_STEP_INTO, CMD_THREAD_KILL, IS_PYPY, REASON_STOP_ON_START)
from _pydevd_bundle.pydevd_constants import IS_WINDOWS, IS_PY38_OR_GREATER, IS_PY39_OR_GREATER
from _pydevd_bundle.pydevd_comm_constants import CMD_RELOAD_CODE
from _pydevd_bundle.pydevd_comm_constants import CMD_RELOAD_CODE, CMD_INPUT_REQUESTED
import json
import pydevd_file_utils
import subprocess
Expand Down Expand Up @@ -3931,6 +3931,36 @@ def test_asyncio_step_return(case_setup, target_filename):
writer.write_run_thread(hit.thread_id)
writer.finished_ok = True


def test_notify_stdin(case_setup, pyfile):

@pyfile
def case_stdin():
import sys
print('Write something:')
contents = sys.stdin.readline()
print('Found: ' + contents)

print('TEST SUCEEDED')

def additional_output_checks(writer, stdout, stderr):
assert 'Found: foo' in stdout

with case_setup.test_file(
case_stdin,
additional_output_checks=additional_output_checks,
) as writer:
writer.write_make_initial_run()
msg = writer.wait_for_message(CMD_INPUT_REQUESTED, expect_xml=False)
assert msg.split('\t')[-1] == 'True'
process = writer.process
process.stdin.write(b'foo\n')
process.stdin.flush()
msg = writer.wait_for_message(CMD_INPUT_REQUESTED, expect_xml=False)
assert msg.split('\t')[-1] == 'False'

writer.finished_ok = True

# Jython needs some vars to be set locally.
# set JAVA_HOME=c:\bin\jdk1.8.0_172
# set PATH=%PATH%;C:\bin\jython2.7.0\bin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def test_monkey_patch_args_indc():
original = SetupHolder.setup

try:
SetupHolder.setup = {'client': '127.0.0.1', 'port': '0', 'ppid': os.getpid(), 'protocol-quoted-line': True}
SetupHolder.setup = {'client': '127.0.0.1', 'port': '0', 'ppid': os.getpid(), 'protocol-quoted-line': True, 'skip-notify-stdin': True}
check = ['C:\\bin\\python.exe', '-u', '-c', 'connect("127.0.0.1")']
debug_command = (
"import sys; sys.path.insert(0, r\'%s\'); import pydevd; pydevd.PydevdCustomization.DEFAULT_PROTOCOL='quoted-line'; "
Expand All @@ -86,7 +86,7 @@ def test_monkey_patch_args_module():
original = SetupHolder.setup

try:
SetupHolder.setup = {'client': '127.0.0.1', 'port': '0', 'multiprocess': True}
SetupHolder.setup = {'client': '127.0.0.1', 'port': '0', 'multiprocess': True, 'skip-notify-stdin': True}
check = ['C:\\bin\\python.exe', '-m', 'test']
from _pydevd_bundle.pydevd_command_line_handling import get_pydevd_file
assert pydev_monkey.patch_args(check) == [
Expand All @@ -100,6 +100,7 @@ def test_monkey_patch_args_module():
'--client',
'127.0.0.1',
'--multiprocess',
'--skip-notify-stdin',
'--protocol-quoted-line',
'--file',
'test',
Expand Down
2 changes: 2 additions & 0 deletions src/debugpy/server/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@

def _settrace(*args, **kwargs):
log.debug("pydevd.settrace(*{0!r}, **{1!r})", args, kwargs)
# The stdin in notification is not acted upon in debugpy, so, disable it.
kwargs.setdefault('notify_stdin', False)
try:
return pydevd.settrace(*args, **kwargs)
except Exception:
Expand Down
18 changes: 18 additions & 0 deletions tests/debugpy/test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@ def code_to_debug():
)


def test_stdin_not_patched(pyfile, target, run):
@pyfile
def code_to_debug():
import sys
import debuggee
from debuggee import backchannel

debuggee.setup()
backchannel.send(sys.stdin == sys.__stdin__)

with debug.Session() as session:
backchannel = session.open_backchannel()
with run(session, target(code_to_debug)):
pass
is_original_stdin = backchannel.receive()
assert is_original_stdin, 'Expected sys.stdin and sys.__stdin__ to be the same.'


if sys.platform == "win32":

@pytest.mark.parametrize("redirect_output", ["", "redirect_output"])
Expand Down

0 comments on commit 499bbb2

Please sign in to comment.