Fix #351: Python warnings in debugger code

Don't use inspect.getargspec on Python 2.

Close log file objects on exit.

Close os.devnull file objects on exit.

Close the listener socket used to get endpoints info from adapter.

Fix invalid escape sequences.

Run tests with Python warnings treated as errors.

Fix Django deprecation warning in test web app.

Work around pytest issues caused spaces in test names.
This commit is contained in:
Pavel Minaev 2020-09-01 11:37:01 -07:00
parent 7512ab01d6
commit 14ca4f07d1
9 changed files with 105 additions and 74 deletions

View file

@ -24,7 +24,8 @@ def main(args):
# so disable it to avoid the pipe filling and locking up. This must be done
# as early as possible, before the logging module starts writing to it.
if args.port is None:
sys.stderr = open(os.devnull, "w")
sys.stderr = stderr = open(os.devnull, "w")
atexit.register(stderr.close)
from debugpy import adapter
from debugpy.common import compat, log, sockets

View file

@ -4,6 +4,7 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import atexit
import os
import sys
@ -41,8 +42,10 @@ class Client(components.Component):
stream = messaging.JsonIOStream.from_stdio()
# Make sure that nothing else tries to interfere with the stdio streams
# that are going to be used for DAP communication from now on.
sys.stdin = open(os.devnull, "r")
sys.stdout = open(os.devnull, "w")
sys.stdin = stdin = open(os.devnull, "r")
atexit.register(stdin.close)
sys.stdout = stdout = open(os.devnull, "w")
atexit.register(stdout.close)
else:
stream = messaging.JsonIOStream.from_socket(sock)

View file

@ -183,7 +183,13 @@ def kwonly(f):
If the default value is kwonly.required, then the argument must be specified.
"""
try:
inspect.getfullargspec
except AttributeError:
arg_names, args_name, kwargs_name, arg_defaults = inspect.getargspec(f)
else:
arg_names, args_name, kwargs_name, arg_defaults, _, _, _ = inspect.getfullargspec(f)
assert args_name is None and kwargs_name is None
argc = len(arg_names)
pos_argc = argc - len(arg_defaults)

View file

@ -4,6 +4,7 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import atexit
import contextlib
import functools
import inspect
@ -43,11 +44,12 @@ def _update_levels():
class LogFile(object):
def __init__(self, filename, file, levels=LEVELS):
def __init__(self, filename, file, levels=LEVELS, close_file=True):
info("Also logging to {0!j}.", filename)
self.filename = filename
self.file = file
self.close_file = close_file
self._levels = frozenset(levels)
with _lock:
@ -88,6 +90,7 @@ class LogFile(object):
_update_levels()
info("Not logging to {0!j} anymore.", self.filename)
if self.close_file:
try:
self.file.close()
except Exception:
@ -350,9 +353,16 @@ stderr = LogFile(
"<stderr>",
sys.stderr,
levels=os.getenv("DEBUGPY_LOG_STDERR", "warning error").split(),
close_file=False,
)
@atexit.register
def _close_files():
for file in tuple(_files.values()):
file.close()
# The following are helper shortcuts for printf debugging. They must never be used
# in production code.

View file

@ -41,7 +41,7 @@ _adapter_process = None
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)
kwargs.setdefault("notify_stdin", False)
try:
return pydevd.settrace(*args, **kwargs)
except Exception:
@ -159,9 +159,13 @@ def listen(address, settrace_kwargs):
except Exception as exc:
log.swallow_exception("Can't listen for adapter endpoints:")
raise RuntimeError("can't listen for adapter endpoints: " + str(exc))
try:
endpoints_host, endpoints_port = endpoints_listener.getsockname()
log.info(
"Waiting for adapter endpoints on {0}:{1}...", endpoints_host, endpoints_port
"Waiting for adapter endpoints on {0}:{1}...",
endpoints_host,
endpoints_port,
)
host, port = address
@ -222,12 +226,17 @@ def listen(address, settrace_kwargs):
finally:
sockets.close_socket(sock)
except socket.timeout:
log.swallow_exception("Timed out waiting for adapter to connect:", level="info")
log.swallow_exception(
"Timed out waiting for adapter to connect:", level="info"
)
raise RuntimeError("timed out waiting for adapter to connect")
except Exception as exc:
log.swallow_exception("Error retrieving adapter endpoints:", level="info")
raise RuntimeError("error retrieving adapter endpoints: " + str(exc))
finally:
endpoints_listener.close()
log.info("Endpoints received from adapter: {0!j}", endpoints)
if "error" in endpoints:

View file

@ -152,7 +152,7 @@ switches = [
# ====== =========== ======
# Switches that are documented for use by end users.
("-(\?|h|-help)", None, print_help_and_exit),
("-(\\?|h|-help)", None, print_help_and_exit),
("-(V|-version)", None, print_version_and_exit),
("--log-to" , "<path>", set_arg("log_to")),
("--log-to-stderr", None, set_const("log_to_stderr", True)),

View file

@ -310,6 +310,7 @@ class Session(object):
env.update(base_env)
env["PYTHONUNBUFFERED"] = "1"
env["PYTHONWARNINGS"] = "error"
env["DEBUGPY_TEST_SESSION_ID"] = str(self.id)
env.prepend_to("PYTHONPATH", DEBUGGEE_PYTHONPATH.strpath)

View file

@ -139,7 +139,7 @@ def test_sudo(pyfile, tmpdir, run, target):
@pytest.mark.parametrize("run", runners.all_launch_terminal)
@pytest.mark.parametrize("python_args", ["", "-v"])
@pytest.mark.parametrize("python", ["", "custompy", "custompy -O"])
@pytest.mark.parametrize("python", ["", "custompy", "custompy|-O"])
@pytest.mark.parametrize("python_key", ["python", "pythonPath"])
def test_custom_python(pyfile, run, target, python_key, python, python_args):
@pyfile
@ -151,7 +151,7 @@ def test_custom_python(pyfile, run, target, python_key, python, python_args):
debuggee.setup()
backchannel.send([sys.executable, sys.flags.optimize, sys.flags.verbose])
python = python.split()
python = python.split("|")
python_args = python_args.split()
python_cmd = (python if len(python) else [sys.executable]) + python_args

View file

@ -23,6 +23,7 @@ def sigint_handler(signal, frame):
signal.signal(signal.SIGINT, sigint_handler)
settings.configure(
MIDDLEWARE=[],
DEBUG=True,
SECRET_KEY="CD8FF4C1-7E6C-4E45-922D-C796271F2345",
ROOT_URLCONF=sys.modules[__name__],