Use "connect":{...} and "listen":{...} to indicate direction of connection in debug configuration.

This commit is contained in:
Pavel Minaev 2020-03-04 16:04:59 -08:00 committed by Pavel Minaev
parent 2d013e58ec
commit dccb5e6198
6 changed files with 83 additions and 47 deletions

View file

@ -284,10 +284,43 @@ class Client(components.Component):
if self.session.no_debug:
raise request.isnt_valid('"noDebug" is not supported for "attach"')
listen = request("listen", False)
if listen:
host = request("host", "127.0.0.1")
port = request("port", int)
host = request("host", unicode, optional=True)
port = request("port", int, optional=True)
listen = request("listen", dict, optional=True)
connect = request("connect", dict, optional=True)
pid = request("processId", (int, unicode), optional=True)
sub_pid = request("subProcessId", int, optional=True)
if host != () or port != ():
if listen != ():
raise request.isnt_valid(
'"listen" and "host"/"port" are mutually exclusive'
)
if connect != ():
raise request.isnt_valid(
'"connect" and "host"/"port" are mutually exclusive'
)
if listen != ():
if connect != ():
raise request.isnt_valid(
'"listen" and "connect" are mutually exclusive'
)
if pid != ():
raise request.isnt_valid(
'"listen" and "processId" are mutually exclusive'
)
if sub_pid != ():
raise request.isnt_valid(
'"listen" and "subProcessId" are mutually exclusive'
)
if pid != () and sub_pid != ():
raise request.isnt_valid(
'"processId" and "subProcessId" are mutually exclusive'
)
if listen != ():
host = listen("host", "127.0.0.1")
port = listen("port", int)
adapter.access_token = None
host, port = servers.serve(host, port)
else:
@ -303,30 +336,22 @@ class Client(components.Component):
# in response to a "debugpyAttach" event. If so, the debug server should be
# connected already, and thus the wait timeout is zero.
#
# If neither is specified, and "listen" is true, this is attach-by-socket
# with the server expected to connect to the adapter via debugpy.connect(). There
# is no PID known in advance, so just wait until the first server connection
# indefinitely, with no timeout.
# If "listen" is specified, this is attach-by-socket with the server expected
# to connect to the adapter via debugpy.connect(). There is no PID known in
# advance, so just wait until the first server connection indefinitely, with
# no timeout.
#
# If neither is specified, and "listen" is false, this is attach-by-socket
# in which the server has spawned the adapter via debugpy.listen(). There
# is no PID known to the client in advance, but the server connection should be
# either be there already, or the server should be connecting shortly, so there
# must be a timeout.
# If "connect" is specified, this is attach-by-socket in which the server has
# spawned the adapter via debugpy.listen(). There is no PID known to the client
# in advance, but the server connection should be either be there already, or
# the server should be connecting shortly, so there must be a timeout.
#
# In the last two cases, if there's more than one server connection already,
# this is a multiprocess re-attach. The client doesn't know the PID, so we just
# connect it to the oldest server connection that we have - in most cases, it
# will be the one for the root debuggee process, but if it has exited already,
# it will be some subprocess.
pid = request("processId", (int, unicode), optional=True)
sub_pid = request("subProcessId", int, optional=True)
if pid != ():
if sub_pid != ():
raise request.isnt_valid(
'"processId" and "subProcessId" are mutually exclusive'
)
if not isinstance(pid, int):
try:
pid = int(pid)
@ -339,7 +364,7 @@ class Client(components.Component):
else:
if sub_pid == ():
pred = lambda conn: True
timeout = None if listen else 10
timeout = 10 if listen == () else None
else:
pred = lambda conn: conn.pid == sub_pid
timeout = 0
@ -447,16 +472,21 @@ class Client(components.Component):
self._known_subprocesses.add(conn)
body.pop("processId", None)
if body.pop("listen", False):
body.pop("host", None)
body.pop("port", None)
body.pop("listen", None)
body["name"] = fmt("Subprocess {0}", conn.pid)
body["request"] = "attach"
body["subProcessId"] = conn.pid
if "host" not in body:
body["host"] = "127.0.0.1"
if "port" not in body:
_, body["port"] = listener.getsockname()
host = body.pop("host", None)
port = body.pop("port", None)
if "connect" not in body:
body["connect"] = {}
if "host" not in body["connect"]:
body["connect"]["host"] = host if host is not None else "127.0.0.1"
if "port" not in body["connect"]:
if port is None:
_, port = listener.getsockname()
body["connect"]["port"] = port
self.channel.send_event("debugpyAttach", body)

View file

@ -63,9 +63,8 @@ class DebugConfig(collections.MutableMapping):
"waitOnNormalExit": False,
"waitOnAbnormalExit": False,
# Attach by socket
"host": (),
"port": (),
"listen": False,
"listen": (),
"connect": (),
# Attach by PID
"processId": (),
}

View file

@ -215,8 +215,9 @@ def attach_connect(session, target, method, cwd=None, wait=True, log_dir=None):
assert method in ("api", "cli")
config = _attach_common_config(session, target, cwd)
config["host"] = host = attach_connect.host
config["port"] = port = attach_connect.port
config["connect"] = {}
config["connect"]["host"] = host = attach_connect.host
config["connect"]["port"] = port = attach_connect.port
if method == "cli":
args = [
@ -267,9 +268,9 @@ def attach_listen(session, target, method, cwd=None, log_dir=None):
assert method in ("api", "cli")
config = _attach_common_config(session, target, cwd)
config["listen"] = True
config["host"] = host = attach_listen.host
config["port"] = port = attach_listen.port
config["listen"] = {}
config["listen"]["host"] = host = attach_listen.host
config["listen"]["port"] = port = attach_listen.port
if method == "cli":
args = [

View file

@ -432,8 +432,8 @@ class Session(object):
config = self.config
request = config.get("request", None)
if request == "attach":
host = config["host"]
port = config["port"]
host = config["connect"]["host"]
port = config["connect"]["port"]
self.connect_to_adapter((host, port))
return self.request_attach()
else:

View file

@ -54,7 +54,7 @@ def test_attach_api(pyfile, target, wait_for_client, is_client_connected, stop_m
with debug.Session() as session:
host, port = runners.attach_connect.host, runners.attach_connect.port
session.config.update({"host": host, "port": port})
session.config.update({"connect": {"host": host, "port": port}})
backchannel = session.open_backchannel()
session.spawn_debuggee(
@ -128,9 +128,9 @@ def test_reattach(pyfile, target, run):
with debug.Session() as session2:
session2.config.update(session1.config)
if "host" in session2.config:
if "connect" in session2.config:
session2.connect_to_adapter(
(session2.config["host"], session2.config["port"])
(session2.config["connect"]["host"], session2.config["connect"]["port"])
)
with session2.request_attach():

View file

@ -109,8 +109,10 @@ def test_multiprocessing(pyfile, target, run, start_method):
"name": some.str,
"request": "attach",
"subProcessId": some.int,
"host": some.str,
"port": some.int,
"connect": {
"host": some.str,
"port": some.int,
}
}
)
@ -129,8 +131,10 @@ def test_multiprocessing(pyfile, target, run, start_method):
"name": some.str,
"request": "attach",
"subProcessId": some.int,
"host": some.str,
"port": some.int,
"connect": {
"host": some.str,
"port": some.int,
}
}
)
@ -191,8 +195,10 @@ def test_subprocess(pyfile, target, run):
"name": some.str,
"request": "attach",
"subProcessId": some.int,
"host": some.str,
"port": some.int,
"connect": {
"host": some.str,
"port": some.int,
}
}
)