mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Remove debugpy.compat, custom !j formatter for JSON, and related helpers.
This commit is contained in:
parent
1965b47034
commit
0f428178b0
31 changed files with 240 additions and 408 deletions
|
|
@ -26,7 +26,6 @@ import codecs
|
|||
import os
|
||||
|
||||
from debugpy import _version
|
||||
from debugpy.common import compat
|
||||
|
||||
|
||||
# Expose debugpy.server API from subpackage, but do not actually import it unless
|
||||
|
|
@ -111,8 +110,7 @@ def listen(address):
|
|||
return api.listen(address)
|
||||
|
||||
|
||||
@compat.kwonly
|
||||
def connect(address, access_token=None):
|
||||
def connect(address, *, access_token=None):
|
||||
"""Tells an existing debug adapter instance that is listening on the
|
||||
specified address to debug this process.
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ def main(args):
|
|||
atexit.register(stderr.close)
|
||||
|
||||
from debugpy import adapter
|
||||
from debugpy.common import compat, json, log, sockets
|
||||
from debugpy.common import json, log, sockets
|
||||
from debugpy.adapter import clients, servers, sessions
|
||||
|
||||
if args.for_server is not None:
|
||||
|
|
@ -51,7 +51,7 @@ def main(args):
|
|||
|
||||
servers.access_token = args.server_access_token
|
||||
if args.for_server is None:
|
||||
adapter.access_token = compat.force_str(codecs.encode(os.urandom(32), "hex"))
|
||||
adapter.access_token = codecs.encode(os.urandom(32), "hex").decode("ascii")
|
||||
|
||||
endpoints = {}
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ import sys
|
|||
|
||||
import debugpy
|
||||
from debugpy import adapter, common, launcher
|
||||
from debugpy.common import compat, json, log, messaging, sockets
|
||||
from debugpy.common.compat import unicode
|
||||
from debugpy.common import json, log, messaging, sockets
|
||||
from debugpy.adapter import components, servers, sessions
|
||||
|
||||
|
||||
|
|
@ -202,7 +201,7 @@ class Client(components.Component):
|
|||
servers.dont_wait_for_first_connection()
|
||||
|
||||
self.session.debug_options = debug_options = set(
|
||||
request("debugOptions", json.array(unicode))
|
||||
request("debugOptions", json.array(str))
|
||||
)
|
||||
|
||||
f(self, request)
|
||||
|
|
@ -293,7 +292,7 @@ class Client(components.Component):
|
|||
if self.session.id != 1 or len(servers.connections()):
|
||||
raise request.cant_handle('"attach" expected')
|
||||
|
||||
debug_options = set(request("debugOptions", json.array(unicode)))
|
||||
debug_options = set(request("debugOptions", json.array(str)))
|
||||
|
||||
# Handling of properties that can also be specified as legacy "debugOptions" flags.
|
||||
# If property is explicitly set to false, but the flag is in "debugOptions", treat
|
||||
|
|
@ -326,29 +325,29 @@ class Client(components.Component):
|
|||
)
|
||||
elif "pythonPath" in request:
|
||||
python_key = "pythonPath"
|
||||
python = request(python_key, json.array(unicode, vectorize=True, size=(0,)))
|
||||
python = request(python_key, json.array(str, vectorize=True, size=(0,)))
|
||||
if not len(python):
|
||||
python = [compat.filename(sys.executable)]
|
||||
python = [sys.executable]
|
||||
|
||||
python += request("pythonArgs", json.array(unicode, size=(0,)))
|
||||
python += request("pythonArgs", json.array(str, size=(0,)))
|
||||
request.arguments["pythonArgs"] = python[1:]
|
||||
request.arguments["python"] = python
|
||||
|
||||
launcher_python = request("debugLauncherPython", unicode, optional=True)
|
||||
launcher_python = request("debugLauncherPython", str, optional=True)
|
||||
if launcher_python == ():
|
||||
launcher_python = python[0]
|
||||
|
||||
program = module = code = ()
|
||||
if "program" in request:
|
||||
program = request("program", unicode)
|
||||
program = request("program", str)
|
||||
args = [program]
|
||||
request.arguments["processName"] = program
|
||||
if "module" in request:
|
||||
module = request("module", unicode)
|
||||
module = request("module", str)
|
||||
args = ["-m", module]
|
||||
request.arguments["processName"] = module
|
||||
if "code" in request:
|
||||
code = request("code", json.array(unicode, vectorize=True, size=(1,)))
|
||||
code = request("code", json.array(str, vectorize=True, size=(1,)))
|
||||
args = ["-c", "\n".join(code)]
|
||||
request.arguments["processName"] = "-c"
|
||||
|
||||
|
|
@ -367,10 +366,10 @@ class Client(components.Component):
|
|||
"argsExpansion", json.enum("shell", "none", optional=True)
|
||||
)
|
||||
if args_expansion == "shell":
|
||||
args += request("args", json.array(unicode))
|
||||
args += request("args", json.array(str))
|
||||
request.arguments.pop("args", None)
|
||||
|
||||
cwd = request("cwd", unicode, optional=True)
|
||||
cwd = request("cwd", str, optional=True)
|
||||
if cwd == ():
|
||||
# If it's not specified, but we're launching a file rather than a module,
|
||||
# and the specified path has a directory in it, use that.
|
||||
|
|
@ -421,11 +420,11 @@ class Client(components.Component):
|
|||
if self.session.no_debug:
|
||||
raise request.isnt_valid('"noDebug" is not supported for "attach"')
|
||||
|
||||
host = request("host", unicode, optional=True)
|
||||
host = request("host", str, 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)
|
||||
pid = request("processId", (int, str), optional=True)
|
||||
sub_pid = request("subProcessId", int, optional=True)
|
||||
|
||||
if host != () or port != ():
|
||||
|
|
@ -494,7 +493,7 @@ class Client(components.Component):
|
|||
pid = int(pid)
|
||||
except Exception:
|
||||
raise request.isnt_valid('"processId" must be parseable as int')
|
||||
debugpy_args = request("debugpyArgs", json.array(unicode))
|
||||
debugpy_args = request("debugpyArgs", json.array(str))
|
||||
servers.inject(pid, debugpy_args)
|
||||
timeout = common.PROCESS_SPAWN_TIMEOUT
|
||||
pred = lambda conn: conn.pid == pid
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import subprocess
|
|||
import sys
|
||||
|
||||
from debugpy import adapter, common
|
||||
from debugpy.common import compat, json, log, messaging, sockets
|
||||
from debugpy.common import json, log, messaging, sockets
|
||||
from debugpy.adapter import components, servers
|
||||
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ def spawn_debuggee(
|
|||
cmdline += args
|
||||
|
||||
if log.log_dir is not None:
|
||||
env[str("DEBUGPY_LOG_DIR")] = compat.filename_str(log.log_dir)
|
||||
env[str("DEBUGPY_LOG_DIR")] = log.log_dir
|
||||
if log.stderr.levels != {"warning", "error"}:
|
||||
env[str("DEBUGPY_LOG_STDERR")] = str(" ".join(log.stderr.levels))
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ def spawn_debuggee(
|
|||
try:
|
||||
for i, arg in enumerate(cmdline):
|
||||
try:
|
||||
cmdline[i] = compat.filename_str(arg)
|
||||
cmdline[i] = arg
|
||||
except UnicodeEncodeError as exc:
|
||||
raise start_request.cant_handle(
|
||||
"Invalid command line argument {0}: {1}", json.repr(arg), exc
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import time
|
|||
|
||||
import debugpy
|
||||
from debugpy import adapter
|
||||
from debugpy.common import compat, json, log, messaging, sockets
|
||||
from debugpy.common import json, log, messaging, sockets
|
||||
from debugpy.adapter import components
|
||||
|
||||
|
||||
|
|
@ -445,7 +445,7 @@ def inject(pid, debugpy_args):
|
|||
|
||||
cmdline = [
|
||||
sys.executable,
|
||||
compat.filename(os.path.dirname(debugpy.__file__)),
|
||||
os.path.dirname(debugpy.__file__),
|
||||
"--connect",
|
||||
host + ":" + str(port),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,210 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# # Licensed under the MIT License. See LICENSE in the project root
|
||||
# for license information.
|
||||
|
||||
"""Python 2/3 compatibility helpers.
|
||||
"""
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import itertools
|
||||
import sys
|
||||
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
# Py2
|
||||
import __builtin__ as builtins # noqa
|
||||
from __builtin__ import unicode, bytes, xrange, reload # noqa
|
||||
|
||||
izip = itertools.izip
|
||||
|
||||
import Queue as queue # noqa
|
||||
|
||||
def force_str(s, encoding="ascii", errors="strict"):
|
||||
"""Converts s to str (which is bytes on Python 2, and unicode on Python 3), using
|
||||
the provided encoding if necessary. If s is already str, it is returned as is.
|
||||
|
||||
If errors="strict", str is bytes, and s is str, its encoding is verified by decoding
|
||||
it; UnicodeError is raised if it cannot be decoded.
|
||||
"""
|
||||
return force_bytes(s, encoding, errors)
|
||||
|
||||
|
||||
else:
|
||||
# Py3
|
||||
import builtins # noqa
|
||||
from builtins import bytes # noqa
|
||||
|
||||
unicode = str
|
||||
xrange = range
|
||||
izip = zip
|
||||
from importlib import reload # noqa
|
||||
import queue # noqa
|
||||
|
||||
def force_str(s, encoding="ascii", errors="strict"):
|
||||
"""Converts s to str (which is bytes on Python 2, and unicode on Python 3), using
|
||||
the provided encoding if necessary. If s is already str, it is returned as is.
|
||||
|
||||
If errors="strict", str is bytes, and s is str, its encoding is verified by decoding
|
||||
it; UnicodeError is raised if it cannot be decoded.
|
||||
"""
|
||||
return force_unicode(s, encoding, errors)
|
||||
|
||||
|
||||
def force_unicode(s, encoding, errors="strict"):
|
||||
"""Converts s to Unicode, using the provided encoding. If s is already Unicode,
|
||||
it is returned as is.
|
||||
"""
|
||||
return s.decode(encoding, errors) if isinstance(s, bytes) else unicode(s)
|
||||
|
||||
|
||||
def force_bytes(s, encoding, errors="strict"):
|
||||
"""Converts s to bytes, using the provided encoding. If s is already bytes,
|
||||
it is returned as is.
|
||||
|
||||
If errors="strict" and s is bytes, its encoding is verified by decoding it;
|
||||
UnicodeError is raised if it cannot be decoded.
|
||||
"""
|
||||
if isinstance(s, unicode):
|
||||
return s.encode(encoding, errors)
|
||||
else:
|
||||
s = bytes(s)
|
||||
if errors == "strict":
|
||||
# Return value ignored - invoked solely for verification.
|
||||
s.decode(encoding, errors)
|
||||
return s
|
||||
|
||||
|
||||
def force_ascii(s, errors="strict"):
|
||||
"""Same as force_bytes(s, "ascii", errors)
|
||||
"""
|
||||
return force_bytes(s, "ascii", errors)
|
||||
|
||||
|
||||
def force_utf8(s, errors="strict"):
|
||||
"""Same as force_bytes(s, "utf8", errors)
|
||||
"""
|
||||
return force_bytes(s, "utf8", errors)
|
||||
|
||||
|
||||
def filename(s, errors="strict"):
|
||||
"""Same as force_unicode(s, sys.getfilesystemencoding(), errors)
|
||||
"""
|
||||
return force_unicode(s, sys.getfilesystemencoding(), errors)
|
||||
|
||||
|
||||
def filename_bytes(s, errors="strict"):
|
||||
"""Same as force_bytes(s, sys.getfilesystemencoding(), errors)
|
||||
"""
|
||||
return force_bytes(s, sys.getfilesystemencoding(), errors)
|
||||
|
||||
|
||||
def filename_str(s, errors="strict"):
|
||||
"""Same as force_str(s, sys.getfilesystemencoding(), errors)
|
||||
"""
|
||||
return force_str(s, sys.getfilesystemencoding(), errors)
|
||||
|
||||
|
||||
def nameof(obj, quote=False):
|
||||
"""Returns the most descriptive name of a Python module, class, or function,
|
||||
as a Unicode string
|
||||
|
||||
If quote=True, name is quoted with repr().
|
||||
|
||||
Best-effort, but guaranteed to not fail - always returns something.
|
||||
"""
|
||||
|
||||
try:
|
||||
name = obj.__qualname__
|
||||
except Exception:
|
||||
try:
|
||||
name = obj.__name__
|
||||
except Exception:
|
||||
# Fall back to raw repr(), and skip quoting.
|
||||
try:
|
||||
name = repr(obj)
|
||||
except Exception:
|
||||
return "<unknown>"
|
||||
else:
|
||||
quote = False
|
||||
|
||||
if quote:
|
||||
try:
|
||||
name = repr(name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return force_unicode(name, "utf-8", "replace")
|
||||
|
||||
|
||||
def unicode_repr(obj):
|
||||
"""Like repr(), but guarantees that the result is Unicode even on Python 2.
|
||||
"""
|
||||
return force_unicode(repr(obj), "ascii")
|
||||
|
||||
|
||||
def srcnameof(obj):
|
||||
"""Returns the most descriptive name of a Python module, class, or function,
|
||||
including source information (filename and linenumber), if available.
|
||||
|
||||
Best-effort, but guaranteed to not fail - always returns something.
|
||||
"""
|
||||
|
||||
name = nameof(obj, quote=True)
|
||||
|
||||
# Get the source information if possible.
|
||||
try:
|
||||
src_file = filename(inspect.getsourcefile(obj), "replace")
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
name += " (file {0!r}".format(src_file)
|
||||
try:
|
||||
_, src_lineno = inspect.getsourcelines(obj)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
name += ", line {0}".format(src_lineno)
|
||||
name += ")"
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def kwonly(f):
|
||||
"""Makes all arguments with default values keyword-only.
|
||||
|
||||
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)
|
||||
required_names = {
|
||||
name
|
||||
for name, val in zip(arg_names[pos_argc:], arg_defaults)
|
||||
if val is kwonly.required
|
||||
}
|
||||
|
||||
@functools.wraps(f)
|
||||
def kwonly_f(*args, **kwargs):
|
||||
if len(args) > pos_argc:
|
||||
raise TypeError("too many positional arguments")
|
||||
if not required_names.issubset(kwargs):
|
||||
missing_names = required_names.difference(kwargs)
|
||||
missing_names = ", ".join(repr(s) for s in missing_names)
|
||||
raise TypeError("missing required keyword-only arguments: " + missing_names)
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return kwonly_f
|
||||
|
||||
|
||||
kwonly.required = object()
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
"""Improved JSON serialization.
|
||||
"""
|
||||
|
||||
import builtins
|
||||
import json
|
||||
import operator
|
||||
|
||||
|
|
@ -23,9 +24,10 @@ class JsonEncoder(json.JSONEncoder):
|
|||
try:
|
||||
get_state = value.__getstate__
|
||||
except AttributeError:
|
||||
return super(JsonEncoder, self).default(value)
|
||||
pass
|
||||
else:
|
||||
return get_state()
|
||||
return super(JsonEncoder, self).default(value)
|
||||
|
||||
|
||||
class JsonObject(object):
|
||||
|
|
@ -40,10 +42,14 @@ class JsonObject(object):
|
|||
"""The default encoder used by __format__ when format_spec is empty."""
|
||||
|
||||
def __init__(self, value):
|
||||
assert not isinstance(value, JsonObject)
|
||||
self.value = value
|
||||
|
||||
def __getstate__(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.value)
|
||||
return builtins.repr(self.value)
|
||||
|
||||
def __str__(self):
|
||||
return format(self)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import threading
|
|||
import traceback
|
||||
|
||||
import debugpy
|
||||
from debugpy.common import compat, json, timestamp, util
|
||||
from debugpy.common import json, timestamp, util
|
||||
|
||||
|
||||
LEVELS = ("debug", "info", "warning", "error")
|
||||
|
|
@ -304,7 +304,7 @@ def describe_environment(header):
|
|||
except Exception:
|
||||
swallow_exception(
|
||||
"Error evaluating {0}",
|
||||
repr(expr) if expr else compat.srcnameof(get_paths),
|
||||
repr(expr) if expr else util.srcnameof(get_paths),
|
||||
)
|
||||
return
|
||||
|
||||
|
|
@ -331,7 +331,7 @@ def describe_environment(header):
|
|||
p
|
||||
for p in sys.path
|
||||
if os.path.exists(p)
|
||||
and os.path.basename(p) == compat.filename_str("site-packages")
|
||||
and os.path.basename(p) == "site-packages"
|
||||
]
|
||||
report_paths(lambda: site_packages, "sys.path (site-packages)")
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ import socket
|
|||
import sys
|
||||
import threading
|
||||
|
||||
from debugpy.common import compat, json, log
|
||||
from debugpy.common.compat import unicode
|
||||
from debugpy.common import json, log, util
|
||||
|
||||
|
||||
class JsonIOError(IOError):
|
||||
|
|
@ -157,16 +156,10 @@ class JsonIOStream(object):
|
|||
finally:
|
||||
self._cleanup()
|
||||
except Exception:
|
||||
# On Python 2, close() will raise an exception if there is a concurrent
|
||||
# read() or write(), which is a common and expected occurrence with
|
||||
# JsonMessageChannel, so don't even bother logging it.
|
||||
log.reraise_exception("Error while closing {0} message stream", self.name)
|
||||
|
||||
def _log_message(self, dir, data, logger=log.debug):
|
||||
format_string = "{0} {1} " + (
|
||||
"{2:indent=None}" if isinstance(data, list) else "{2}"
|
||||
)
|
||||
return logger(format_string, self.name, dir, json.repr(data))
|
||||
return logger("{0} {1} {2}", self.name, dir, data)
|
||||
|
||||
def _read_line(self, reader):
|
||||
line = b""
|
||||
|
|
@ -277,7 +270,7 @@ class JsonIOStream(object):
|
|||
|
||||
Value is written as encoded by encoder.encode().
|
||||
"""
|
||||
|
||||
|
||||
if self._closed:
|
||||
# Don't log this - it's a common pattern to write to a stream while
|
||||
# anticipating EOFError from it in case it got closed concurrently.
|
||||
|
|
@ -293,9 +286,8 @@ class JsonIOStream(object):
|
|||
try:
|
||||
body = encoder.encode(value)
|
||||
except Exception:
|
||||
self._log_message("<--", value, logger=log.reraise_exception)
|
||||
if not isinstance(body, bytes):
|
||||
body = body.encode("utf-8")
|
||||
self._log_message("<--", repr(value), logger=log.reraise_exception)
|
||||
body = body.encode("utf-8")
|
||||
|
||||
header = f"Content-Length: {len(body)}\r\n\r\n".encode("ascii")
|
||||
data = header + body
|
||||
|
|
@ -355,7 +347,10 @@ class MessageDict(collections.OrderedDict):
|
|||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return json.repr(self)
|
||||
try:
|
||||
return format(json.repr(self))
|
||||
except Exception:
|
||||
return super().__repr__()
|
||||
|
||||
def __call__(self, key, validate, optional=False):
|
||||
"""Like get(), but with validation.
|
||||
|
|
@ -583,7 +578,7 @@ class Event(Message):
|
|||
@staticmethod
|
||||
def _parse(channel, message_dict):
|
||||
seq = message_dict("seq", int)
|
||||
event = message_dict("event", unicode)
|
||||
event = message_dict("event", str)
|
||||
body = message_dict("body", _payload)
|
||||
message = Event(channel, seq, event, body, json=message_dict)
|
||||
channel._enqueue_handlers(message, message._handle)
|
||||
|
|
@ -595,20 +590,20 @@ class Event(Message):
|
|||
try:
|
||||
result = handler(self)
|
||||
assert result is None, \
|
||||
f"Handler {compat.srcnameof(handler)} tried to respond to {self.describe()}."
|
||||
f"Handler {util.srcnameof(handler)} tried to respond to {self.describe()}."
|
||||
except MessageHandlingError as exc:
|
||||
if not exc.applies_to(self):
|
||||
raise
|
||||
log.error(
|
||||
"Handler {0}\ncouldn't handle {1}:\n{2}",
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self.describe(),
|
||||
str(exc),
|
||||
)
|
||||
except Exception:
|
||||
log.reraise_exception(
|
||||
"Handler {0}\ncouldn't handle {1}:",
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self.describe(),
|
||||
)
|
||||
|
||||
|
|
@ -688,16 +683,7 @@ class Request(Message):
|
|||
|
||||
if isinstance(body, Exception):
|
||||
d["success"] = False
|
||||
err_text = str(body)
|
||||
try:
|
||||
err_text = compat.force_unicode(err_text, "utf-8")
|
||||
except Exception:
|
||||
# On Python 2, the error message might not be Unicode, and we don't
|
||||
# really know what encoding it is. So if treating it as UTF-8 failed,
|
||||
# use repr() as a fallback - it should escape all non-ASCII chars in
|
||||
# the string.
|
||||
err_text = compat.force_unicode(repr(body), "ascii", errors="replace")
|
||||
d["message"] = err_text
|
||||
d["message"] = str(body)
|
||||
else:
|
||||
d["success"] = True
|
||||
if body is not None and body != {}:
|
||||
|
|
@ -710,7 +696,7 @@ class Request(Message):
|
|||
@staticmethod
|
||||
def _parse(channel, message_dict):
|
||||
seq = message_dict("seq", int)
|
||||
command = message_dict("command", unicode)
|
||||
command = message_dict("command", str)
|
||||
arguments = message_dict("arguments", _payload)
|
||||
message = Request(channel, seq, command, arguments, json=message_dict)
|
||||
channel._enqueue_handlers(message, message._handle)
|
||||
|
|
@ -727,7 +713,7 @@ class Request(Message):
|
|||
result = exc
|
||||
log.error(
|
||||
"Handler {0}\ncouldn't handle {1}:\n{2}",
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self.describe(),
|
||||
str(exc),
|
||||
)
|
||||
|
|
@ -736,7 +722,7 @@ class Request(Message):
|
|||
assert self.response is None, (
|
||||
"Handler {0} for {1} must not return NO_RESPONSE if it has already "
|
||||
"invoked request.respond().".format(
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self.describe()
|
||||
)
|
||||
)
|
||||
|
|
@ -744,7 +730,7 @@ class Request(Message):
|
|||
assert result is None or result is self.response.body, (
|
||||
"Handler {0} for {1} must not return a response body if it has "
|
||||
"already invoked request.respond().".format(
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self.describe()
|
||||
)
|
||||
)
|
||||
|
|
@ -752,7 +738,7 @@ class Request(Message):
|
|||
assert result is not None, (
|
||||
"Handler {0} for {1} must either call request.respond() before it "
|
||||
"returns, or return the response body, or return NO_RESPONSE.".format(
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self.describe()
|
||||
)
|
||||
)
|
||||
|
|
@ -761,14 +747,14 @@ class Request(Message):
|
|||
except NoMoreMessages:
|
||||
log.warning(
|
||||
"Channel was closed before the response from handler {0} to {1} could be sent",
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self.describe(),
|
||||
)
|
||||
|
||||
except Exception:
|
||||
log.reraise_exception(
|
||||
"Handler {0}\ncouldn't handle {1}:",
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self.describe(),
|
||||
)
|
||||
|
||||
|
|
@ -844,14 +830,14 @@ class OutgoingRequest(Request):
|
|||
raise
|
||||
log.error(
|
||||
"Handler {0}\ncouldn't handle {1}:\n{2}",
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
response.describe(),
|
||||
str(exc),
|
||||
)
|
||||
except Exception:
|
||||
log.reraise_exception(
|
||||
"Handler {0}\ncouldn't handle {1}:",
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
response.describe(),
|
||||
)
|
||||
|
||||
|
|
@ -937,13 +923,13 @@ class Response(Message):
|
|||
def _parse(channel, message_dict, body=None):
|
||||
seq = message_dict("seq", int) if (body is None) else None
|
||||
request_seq = message_dict("request_seq", int)
|
||||
command = message_dict("command", unicode)
|
||||
command = message_dict("command", str)
|
||||
success = message_dict("success", bool)
|
||||
if body is None:
|
||||
if success:
|
||||
body = message_dict("body", _payload)
|
||||
else:
|
||||
error_message = message_dict("message", unicode)
|
||||
error_message = message_dict("message", str)
|
||||
exc_type = MessageHandlingError
|
||||
if error_message.startswith(InvalidMessageError.PREFIX):
|
||||
error_message = error_message[len(InvalidMessageError.PREFIX) :]
|
||||
|
|
@ -1326,7 +1312,7 @@ class JsonMessageChannel(object):
|
|||
log.debug("Exiting message loop for channel {0}: {1}", self, exc)
|
||||
with self:
|
||||
# Generate dummy responses for all outstanding requests.
|
||||
err_message = compat.force_unicode(str(exc), "utf-8", errors="replace")
|
||||
err_message = str(exc)
|
||||
|
||||
# Response._parse() will remove items from _sent_requests, so
|
||||
# make a snapshot before iterating.
|
||||
|
|
@ -1502,7 +1488,7 @@ class JsonMessageChannel(object):
|
|||
|
||||
raise AttributeError(
|
||||
"handler object {0} for channel {1} has no handler for {2} {3!r}".format(
|
||||
compat.srcnameof(handlers),
|
||||
util.srcnameof(handlers),
|
||||
self,
|
||||
type,
|
||||
name,
|
||||
|
|
@ -1516,7 +1502,7 @@ class JsonMessageChannel(object):
|
|||
except Exception:
|
||||
log.reraise_exception(
|
||||
"Handler {0}\ncouldn't handle disconnect from {1}:",
|
||||
compat.srcnameof(handler),
|
||||
util.srcnameof(handler),
|
||||
self,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
# Licensed under the MIT License. See LICENSE in the project root
|
||||
# for license information.
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
|
||||
from debugpy.common import compat
|
||||
|
||||
|
||||
def evaluate(code, path=__file__, mode="eval"):
|
||||
# Setting file path here to avoid breaking here if users have set
|
||||
|
|
@ -59,8 +58,97 @@ class Env(dict):
|
|||
tail = ""
|
||||
self[key] = entry + tail
|
||||
|
||||
def for_popen(self):
|
||||
"""Returns a copy of this dict, with all strings converted to the type
|
||||
suitable for subprocess.Popen() and other similar APIs.
|
||||
"""
|
||||
return {compat.filename_str(k): compat.filename_str(v) for k, v in self.items()}
|
||||
|
||||
def force_str(s, encoding, errors="strict"):
|
||||
"""Converts s to str, using the provided encoding. If s is already str,
|
||||
it is returned as is.
|
||||
"""
|
||||
return s.decode(encoding, errors) if isinstance(s, bytes) else str(s)
|
||||
|
||||
|
||||
def force_bytes(s, encoding, errors="strict"):
|
||||
"""Converts s to bytes, using the provided encoding. If s is already bytes,
|
||||
it is returned as is.
|
||||
|
||||
If errors="strict" and s is bytes, its encoding is verified by decoding it;
|
||||
UnicodeError is raised if it cannot be decoded.
|
||||
"""
|
||||
if isinstance(s, str):
|
||||
return s.encode(encoding, errors)
|
||||
else:
|
||||
s = bytes(s)
|
||||
if errors == "strict":
|
||||
# Return value ignored - invoked solely for verification.
|
||||
s.decode(encoding, errors)
|
||||
return s
|
||||
|
||||
|
||||
def force_ascii(s, errors="strict"):
|
||||
"""Same as force_bytes(s, "ascii", errors)
|
||||
"""
|
||||
return force_bytes(s, "ascii", errors)
|
||||
|
||||
|
||||
def force_utf8(s, errors="strict"):
|
||||
"""Same as force_bytes(s, "utf8", errors)
|
||||
"""
|
||||
return force_bytes(s, "utf8", errors)
|
||||
|
||||
|
||||
def nameof(obj, quote=False):
|
||||
"""Returns the most descriptive name of a Python module, class, or function,
|
||||
as a Unicode string
|
||||
|
||||
If quote=True, name is quoted with repr().
|
||||
|
||||
Best-effort, but guaranteed to not fail - always returns something.
|
||||
"""
|
||||
|
||||
try:
|
||||
name = obj.__qualname__
|
||||
except Exception:
|
||||
try:
|
||||
name = obj.__name__
|
||||
except Exception:
|
||||
# Fall back to raw repr(), and skip quoting.
|
||||
try:
|
||||
name = repr(obj)
|
||||
except Exception:
|
||||
return "<unknown>"
|
||||
else:
|
||||
quote = False
|
||||
|
||||
if quote:
|
||||
try:
|
||||
name = repr(name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return force_str(name, "utf-8", "replace")
|
||||
|
||||
|
||||
def srcnameof(obj):
|
||||
"""Returns the most descriptive name of a Python module, class, or function,
|
||||
including source information (filename and linenumber), if available.
|
||||
|
||||
Best-effort, but guaranteed to not fail - always returns something.
|
||||
"""
|
||||
|
||||
name = nameof(obj, quote=True)
|
||||
|
||||
# Get the source information if possible.
|
||||
try:
|
||||
src_file = inspect.getsourcefile(obj)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
name += f" (file {src_file!r}"
|
||||
try:
|
||||
_, src_lineno = inspect.getsourcelines(obj)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
name += f", line {src_lineno}"
|
||||
name += ")"
|
||||
|
||||
return name
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import sys
|
|||
import threading
|
||||
|
||||
from debugpy import launcher
|
||||
from debugpy.common import log, messaging, compat
|
||||
from debugpy.common import log, messaging
|
||||
from debugpy.launcher import output
|
||||
|
||||
if sys.platform == "win32":
|
||||
|
|
@ -147,7 +147,7 @@ def spawn(process_name, cmdline, env, redirect_output):
|
|||
"isLocalProcess": True,
|
||||
"systemProcessId": process.pid,
|
||||
"name": process_name,
|
||||
"pointerSize": struct.calcsize(compat.force_str("P")) * 8,
|
||||
"pointerSize": struct.calcsize("P") * 8,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ import sys
|
|||
|
||||
import debugpy
|
||||
from debugpy import launcher
|
||||
from debugpy.common import compat, json
|
||||
from debugpy.common.compat import unicode
|
||||
from debugpy.common import json
|
||||
from debugpy.launcher import debuggee
|
||||
|
||||
|
||||
def launch_request(request):
|
||||
debug_options = set(request("debugOptions", json.array(unicode)))
|
||||
debug_options = set(request("debugOptions", json.array(str)))
|
||||
|
||||
# Handling of properties that can also be specified as legacy "debugOptions" flags.
|
||||
# If property is explicitly set to false, but the flag is in "debugOptions", treat
|
||||
|
|
@ -36,13 +35,13 @@ def launch_request(request):
|
|||
|
||||
return value
|
||||
|
||||
python = request("python", json.array(unicode, size=(1,)))
|
||||
python = request("python", json.array(str, size=(1,)))
|
||||
cmdline = list(python)
|
||||
|
||||
if not request("noDebug", json.default(False)):
|
||||
port = request("port", int)
|
||||
cmdline += [
|
||||
compat.filename(os.path.dirname(debugpy.__file__)),
|
||||
os.path.dirname(debugpy.__file__),
|
||||
"--connect",
|
||||
launcher.adapter_host + ":" + str(port),
|
||||
]
|
||||
|
|
@ -58,11 +57,11 @@ def launch_request(request):
|
|||
)
|
||||
cmdline += ["--configure-qt", qt_mode]
|
||||
|
||||
adapter_access_token = request("adapterAccessToken", unicode, optional=True)
|
||||
adapter_access_token = request("adapterAccessToken", str, optional=True)
|
||||
if adapter_access_token != ():
|
||||
cmdline += ["--adapter-access-token", compat.filename(adapter_access_token)]
|
||||
cmdline += ["--adapter-access-token", adapter_access_token]
|
||||
|
||||
debugpy_args = request("debugpyArgs", json.array(unicode))
|
||||
debugpy_args = request("debugpyArgs", json.array(str))
|
||||
cmdline += debugpy_args
|
||||
|
||||
# Further arguments can come via two channels: the launcher's own command line, or
|
||||
|
|
@ -70,12 +69,12 @@ def launch_request(request):
|
|||
# Arguments for debugpy (such as -m) always come via CLI, but those specified by the
|
||||
# user via "args" are passed differently by the adapter depending on "argsExpansion".
|
||||
cmdline += sys.argv[1:]
|
||||
cmdline += request("args", json.array(unicode))
|
||||
cmdline += request("args", json.array(str))
|
||||
|
||||
process_name = request("processName", compat.filename(sys.executable))
|
||||
process_name = request("processName", sys.executable)
|
||||
|
||||
env = os.environ.copy()
|
||||
env_changes = request("env", json.object((unicode, type(None))))
|
||||
env_changes = request("env", json.object((str, type(None))))
|
||||
if sys.platform == "win32":
|
||||
# Environment variables are case-insensitive on Win32, so we need to normalize
|
||||
# both dicts to make sure that env vars specified in the debug configuration
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import threading
|
|||
|
||||
import debugpy
|
||||
from debugpy import adapter
|
||||
from debugpy.common import compat, json, log, sockets
|
||||
from debugpy.common import json, log, sockets
|
||||
from _pydevd_bundle.pydevd_constants import get_global_debugger
|
||||
from pydevd_file_utils import absolute_path
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ def listen(address, settrace_kwargs):
|
|||
|
||||
import subprocess
|
||||
|
||||
server_access_token = compat.force_str(codecs.encode(os.urandom(32), "hex"))
|
||||
server_access_token = codecs.encode(os.urandom(32), "hex").decode("ascii")
|
||||
|
||||
try:
|
||||
endpoints_listener = sockets.create_server("127.0.0.1", 0, timeout=10)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ assert "pydevd" in sys.modules
|
|||
import pydevd
|
||||
|
||||
import debugpy
|
||||
from debugpy.common import compat, log
|
||||
from debugpy.common import log
|
||||
from debugpy.server import api
|
||||
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ class Options(object):
|
|||
address = None
|
||||
log_to = None
|
||||
log_to_stderr = False
|
||||
target = None # unicode
|
||||
target = None
|
||||
target_kind = None
|
||||
wait_for_client = False
|
||||
adapter_access_token = None
|
||||
|
|
@ -203,7 +203,7 @@ def parse_argv():
|
|||
except StopIteration:
|
||||
raise ValueError("missing target: " + TARGET)
|
||||
|
||||
switch = compat.filename(arg)
|
||||
switch = arg
|
||||
if not switch.startswith("-"):
|
||||
switch = ""
|
||||
for pattern, placeholder, action in switches:
|
||||
|
|
@ -244,7 +244,7 @@ def start_debugging(argv_0):
|
|||
# We need to set up sys.argv[0] before invoking either listen() or connect(),
|
||||
# because they use it to report the "process" event. Thus, we can't rely on
|
||||
# run_path() and run_module() doing that, even though they will eventually.
|
||||
sys.argv[0] = compat.filename_str(argv_0)
|
||||
sys.argv[0] = argv_0
|
||||
|
||||
log.debug("sys.argv after patching: {0!r}", sys.argv)
|
||||
|
||||
|
|
@ -265,15 +265,13 @@ def run_file():
|
|||
target = options.target
|
||||
start_debugging(target)
|
||||
|
||||
target_as_str = compat.filename_str(target)
|
||||
|
||||
# run_path has one difference with invoking Python from command-line:
|
||||
# if the target is a file (rather than a directory), it does not add its
|
||||
# parent directory to sys.path. Thus, importing other modules from the
|
||||
# same directory is broken unless sys.path is patched here.
|
||||
|
||||
if os.path.isfile(target_as_str):
|
||||
dir = os.path.dirname(target_as_str)
|
||||
if os.path.isfile(target):
|
||||
dir = os.path.dirname(target)
|
||||
sys.path.insert(0, dir)
|
||||
else:
|
||||
log.debug("Not a file: {0!r}", target)
|
||||
|
|
@ -281,7 +279,7 @@ def run_file():
|
|||
log.describe_environment("Pre-launch environment:")
|
||||
|
||||
log.info("Running file {0!r}", target)
|
||||
runpy.run_path(target_as_str, run_name=compat.force_str("__main__"))
|
||||
runpy.run_path(target, run_name="__main__")
|
||||
|
||||
|
||||
def run_module():
|
||||
|
|
@ -292,20 +290,14 @@ def run_module():
|
|||
# We want to do the same thing that run_module() would do here, without
|
||||
# actually invoking it.
|
||||
argv_0 = sys.argv[0]
|
||||
target_as_str = compat.filename_str(options.target)
|
||||
try:
|
||||
spec = find_spec(target_as_str)
|
||||
spec = find_spec(options.target)
|
||||
if spec is not None:
|
||||
argv_0 = spec.origin
|
||||
except Exception:
|
||||
log.swallow_exception("Error determining module path for sys.argv")
|
||||
|
||||
start_debugging(argv_0)
|
||||
|
||||
# On Python 2, module name must be a non-Unicode string, because it ends up
|
||||
# a part of module's __package__, and Python will refuse to run the module
|
||||
# if __package__ is Unicode.
|
||||
|
||||
log.describe_environment("Pre-launch environment:")
|
||||
log.info("Running module {0!r}", options.target)
|
||||
|
||||
|
|
@ -318,9 +310,9 @@ def run_module():
|
|||
run_module_as_main = runpy._run_module_as_main
|
||||
except AttributeError:
|
||||
log.warning("runpy._run_module_as_main is missing, falling back to run_module.")
|
||||
runpy.run_module(target_as_str, alter_sys=True)
|
||||
runpy.run_module(options.target, alter_sys=True)
|
||||
else:
|
||||
run_module_as_main(target_as_str, alter_argv=True)
|
||||
run_module_as_main(options.target, alter_argv=True)
|
||||
|
||||
|
||||
def run_code():
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
import py.path
|
||||
import re
|
||||
|
||||
from debugpy.common import compat
|
||||
|
||||
_marked_line_numbers_cache = {}
|
||||
|
||||
|
||||
|
|
@ -34,13 +32,13 @@ def get_marked_line_numbers(path):
|
|||
except KeyError:
|
||||
pass
|
||||
|
||||
# Read as bytes, to avoid decoding errors on Python 3.
|
||||
# Read as bytes to avoid decoding errors.
|
||||
with open(path, "rb") as f:
|
||||
lines = {}
|
||||
for i, line in enumerate(f):
|
||||
match = re.search(br"#\s*@(.+?)\s*$", line)
|
||||
if match:
|
||||
markers = compat.force_unicode(match.group(1), "ascii")
|
||||
markers = match.group(1).decode("ascii")
|
||||
for marker in markers.split(","):
|
||||
lines[marker] = i + 1
|
||||
|
||||
|
|
|
|||
|
|
@ -86,27 +86,27 @@ class CapturedOutput(object):
|
|||
def stdout(self, encoding=None):
|
||||
"""Returns stdout captured from the debugged process, as a single string.
|
||||
|
||||
If encoding is None, returns bytes. Otherwise, returns unicode.
|
||||
If encoding is None, returns bytes. Otherwise, returns str.
|
||||
"""
|
||||
return self._output("stdout", encoding, lines=False)
|
||||
|
||||
def stderr(self, encoding=None):
|
||||
"""Returns stderr captured from the debugged process, as a single string.
|
||||
|
||||
If encoding is None, returns bytes. Otherwise, returns unicode.
|
||||
If encoding is None, returns bytes. Otherwise, returns str.
|
||||
"""
|
||||
return self._output("stderr", encoding, lines=False)
|
||||
|
||||
def stdout_lines(self, encoding=None):
|
||||
"""Returns stdout captured from the debugged process, as a list of lines.
|
||||
|
||||
If encoding is None, each line is bytes. Otherwise, each line is unicode.
|
||||
If encoding is None, each line is bytes. Otherwise, each line is str.
|
||||
"""
|
||||
return self._output("stdout", encoding, lines=True)
|
||||
|
||||
def stderr_lines(self, encoding=None):
|
||||
"""Returns stderr captured from the debugged process, as a list of lines.
|
||||
|
||||
If encoding is None, each line is bytes. Otherwise, each line is unicode.
|
||||
If encoding is None, each line is bytes. Otherwise, each line is str.
|
||||
"""
|
||||
return self._output("stderr", encoding, lines=True)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ import pytest
|
|||
import sys
|
||||
|
||||
import debugpy
|
||||
from debugpy.common import compat, json, log
|
||||
from debugpy.common import json, log
|
||||
from tests import net, timeline
|
||||
from tests.debug import session
|
||||
from tests.patterns import some
|
||||
|
|
@ -218,7 +218,7 @@ def attach_connect(session, target, method, cwd=None, wait=True, log_dir=None):
|
|||
args = [
|
||||
os.path.dirname(debugpy.__file__),
|
||||
"--listen",
|
||||
compat.filename_str(host) + ":" + str(port),
|
||||
f"{host}:{port}",
|
||||
]
|
||||
if wait:
|
||||
args += ["--wait-for-client"]
|
||||
|
|
@ -282,7 +282,7 @@ def attach_listen(session, target, method, cwd=None, log_dir=None):
|
|||
args = [
|
||||
os.path.dirname(debugpy.__file__),
|
||||
"--connect",
|
||||
compat.filename_str(host) + ":" + str(port),
|
||||
f"{host}:{port}",
|
||||
]
|
||||
if log_dir is not None:
|
||||
args += ["--log-to", log_dir]
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import sys
|
|||
import time
|
||||
|
||||
import debugpy.adapter
|
||||
from debugpy.common import compat, json, log, messaging, sockets, util
|
||||
from debugpy.common.compat import unicode
|
||||
from debugpy.common import json, log, messaging, sockets, util
|
||||
import tests
|
||||
from tests import code, timeline, watchdog
|
||||
from tests.debug import comms, config, output
|
||||
|
|
@ -343,16 +342,15 @@ class Session(object):
|
|||
assert not len(self.captured_output - {"stdout", "stderr"})
|
||||
|
||||
args = [exe] + [
|
||||
compat.filename_str(s.strpath if isinstance(s, py.path.local) else s)
|
||||
str(s.strpath if isinstance(s, py.path.local) else s)
|
||||
for s in args
|
||||
]
|
||||
|
||||
cwd = compat.filename_str(cwd) if isinstance(cwd, py.path.local) else cwd
|
||||
cwd = cwd.strpath if isinstance(cwd, py.path.local) else cwd
|
||||
|
||||
env = self._make_env(self.spawn_debuggee.env, codecov=False)
|
||||
env["DEBUGPY_ADAPTER_ENDPOINTS"] = self.adapter_endpoints = (
|
||||
self.tmpdir / "adapter_endpoints"
|
||||
)
|
||||
self.adapter_endpoints = self.tmpdir / "adapter_endpoints"
|
||||
env["DEBUGPY_ADAPTER_ENDPOINTS"] = self.adapter_endpoints.strpath
|
||||
if setup is not None:
|
||||
env["DEBUGPY_TEST_DEBUGGEE_SETUP"] = setup
|
||||
|
||||
|
|
@ -376,7 +374,7 @@ class Session(object):
|
|||
self.debuggee = psutil.Popen(
|
||||
args,
|
||||
cwd=cwd,
|
||||
env=env.for_popen(),
|
||||
env=env,
|
||||
bufsize=0,
|
||||
stdin=subprocess.PIPE,
|
||||
**popen_fds
|
||||
|
|
@ -416,7 +414,7 @@ class Session(object):
|
|||
bufsize=0,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
env=env.for_popen(),
|
||||
env=env,
|
||||
)
|
||||
log.info("Spawned {0} with PID={1}", self.adapter_id, self.adapter.pid)
|
||||
watchdog.register_spawn(self.adapter.pid, self.adapter_id)
|
||||
|
|
@ -497,9 +495,9 @@ class Session(object):
|
|||
def _process_request(self, request):
|
||||
self.timeline.record_request(request, block=False)
|
||||
if request.command == "runInTerminal":
|
||||
args = request("args", json.array(unicode))
|
||||
args = request("args", json.array(str))
|
||||
cwd = request("cwd", ".")
|
||||
env = request("env", json.object(unicode))
|
||||
env = request("env", json.object(str))
|
||||
try:
|
||||
return self.run_in_terminal(args, cwd, env)
|
||||
except Exception as exc:
|
||||
|
|
@ -578,7 +576,7 @@ class Session(object):
|
|||
all the "output" events received for that category so far.
|
||||
"""
|
||||
events = self.all_events("output", some.dict.containing({"category": category}))
|
||||
return "".join(event("output", unicode) for event in events)
|
||||
return "".join(event("output", str) for event in events)
|
||||
|
||||
def _request_start(self, method):
|
||||
self.config.normalize()
|
||||
|
|
@ -718,7 +716,7 @@ class Session(object):
|
|||
)("variables", json.array())
|
||||
|
||||
variables = collections.OrderedDict(
|
||||
((v("name", unicode), v) for v in variables)
|
||||
((v("name", str), v) for v in variables)
|
||||
)
|
||||
if varnames:
|
||||
assert set(varnames) <= set(variables.keys())
|
||||
|
|
@ -765,7 +763,7 @@ class Session(object):
|
|||
expected_stopped["text"] = expected_text
|
||||
if expected_description is not None:
|
||||
expected_stopped["description"] = expected_description
|
||||
if stopped("reason", unicode) not in [
|
||||
if stopped("reason", str) not in [
|
||||
"step",
|
||||
"exception",
|
||||
"breakpoint",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import py
|
||||
import os
|
||||
|
||||
from debugpy.common import compat, json
|
||||
from debugpy.common import json
|
||||
from tests.patterns import some
|
||||
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ class Program(Target):
|
|||
|
||||
def _get_relative_program(self):
|
||||
assert self._cwd
|
||||
relative_filename = compat.filename(self.filename.strpath)[len(self._cwd) :]
|
||||
relative_filename = self.filename.strpath[len(self._cwd) :]
|
||||
assert not relative_filename.startswith(("/", "\\"))
|
||||
return relative_filename
|
||||
|
||||
|
|
@ -110,14 +110,14 @@ class Program(Target):
|
|||
if self._cwd:
|
||||
return f"program (relative) {json.repr(self._cwd)} / {json.repr(self._get_relative_program())}"
|
||||
else:
|
||||
return f"program {json.repr(compat.filename(self.filename.strpath))}"
|
||||
return f"program {json.repr(self.filename.strpath)}"
|
||||
|
||||
def configure(self, session):
|
||||
if self._cwd:
|
||||
session.config["cwd"] = self._cwd
|
||||
session.config["program"] = self._get_relative_program()
|
||||
else:
|
||||
session.config["program"] = compat.filename(self.filename.strpath)
|
||||
session.config["program"] = self.filename.strpath
|
||||
|
||||
session.config["args"] = self.args
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ def cli(pyfile):
|
|||
os.write(1, pickle.dumps(exc))
|
||||
sys.exit(1)
|
||||
|
||||
# Check that sys.argv has the correct type after parsing - there should be
|
||||
# no bytes on Python 3, nor unicode on Python 2.
|
||||
# Check that sys.argv has the correct type after parsing - there should be no bytes.
|
||||
assert all(isinstance(s, str) for s in sys.argv)
|
||||
|
||||
# We only care about options that correspond to public switches.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from debugpy.common import compat
|
||||
from tests import code, debug, log, net, test_data
|
||||
from tests.debug import runners, targets
|
||||
from tests.patterns import some
|
||||
|
|
@ -50,7 +49,7 @@ def test_django_breakpoint_no_multiproc(start_django, bp_target):
|
|||
"code": (paths.app_py, lines.app_py["bphome"], "home"),
|
||||
"template": (paths.hello_html, 8, "Django Template"),
|
||||
}[bp_target]
|
||||
bp_var_content = compat.force_str("Django-Django-Test")
|
||||
bp_var_content = "Django-Django-Test"
|
||||
|
||||
with debug.Session() as session:
|
||||
with start_django(session):
|
||||
|
|
@ -79,7 +78,7 @@ def test_django_breakpoint_no_multiproc(start_django, bp_target):
|
|||
{
|
||||
"name": "content",
|
||||
"type": "str",
|
||||
"value": compat.unicode_repr(bp_var_content),
|
||||
"value": repr(bp_var_content),
|
||||
"presentationHint": {"attributes": ["rawString"]},
|
||||
"evaluateName": "content",
|
||||
"variablesReference": 0,
|
||||
|
|
@ -188,7 +187,7 @@ def test_django_exception_no_multiproc(start_django, exc_type):
|
|||
|
||||
def test_django_breakpoint_multiproc(start_django):
|
||||
bp_line = lines.app_py["bphome"]
|
||||
bp_var_content = compat.force_str("Django-Django-Test")
|
||||
bp_var_content = "Django-Django-Test"
|
||||
|
||||
with debug.Session() as parent_session:
|
||||
with start_django(parent_session, multiprocess=True):
|
||||
|
|
@ -214,7 +213,7 @@ def test_django_breakpoint_multiproc(start_django):
|
|||
{
|
||||
"name": "content",
|
||||
"type": "str",
|
||||
"value": compat.unicode_repr(bp_var_content),
|
||||
"value": repr(bp_var_content),
|
||||
"presentationHint": {"attributes": ["rawString"]},
|
||||
"evaluateName": "content",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,15 +275,12 @@ def test_return_values(pyfile, target, run, ret_vis):
|
|||
|
||||
|
||||
# On Python 3, variable names can contain Unicode characters.
|
||||
# On Python 2, they must be ASCII, but using a Unicode character in an expression should not crash debugger.
|
||||
def test_unicode(pyfile, target, run):
|
||||
@pyfile
|
||||
def code_to_debug():
|
||||
import debuggee
|
||||
import debugpy
|
||||
|
||||
# Since Unicode variable name is a SyntaxError at parse time in Python 2,
|
||||
# this needs to do a roundabout way of setting it to avoid parse issues.
|
||||
globals()["\u16A0"] = 123
|
||||
debuggee.setup()
|
||||
debugpy.breakpoint()
|
||||
|
|
@ -634,8 +631,8 @@ def test_evaluate_thread_locks(pyfile, target, run):
|
|||
"""
|
||||
|
||||
import debuggee
|
||||
import queue
|
||||
import threading
|
||||
from debugpy.common.compat import queue
|
||||
|
||||
debuggee.setup()
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
import pytest
|
||||
import sys
|
||||
|
||||
from debugpy.common import compat
|
||||
from tests import code, debug, log, net, test_data
|
||||
from tests.debug import runners, targets
|
||||
from tests.patterns import some
|
||||
|
|
@ -73,7 +72,7 @@ def test_flask_breakpoint_no_multiproc(start_flask, bp_target):
|
|||
"code": (paths.app_py, lines.app_py["bphome"], "home"),
|
||||
"template": (paths.hello_html, 8, "template"),
|
||||
}[bp_target]
|
||||
bp_var_content = compat.force_str("Flask-Jinja-Test")
|
||||
bp_var_content = "Flask-Jinja-Test"
|
||||
|
||||
with debug.Session() as session:
|
||||
with start_flask(session):
|
||||
|
|
@ -217,7 +216,7 @@ def test_flask_exception_no_multiproc(start_flask, exc_type):
|
|||
|
||||
def test_flask_breakpoint_multiproc(start_flask):
|
||||
bp_line = lines.app_py["bphome"]
|
||||
bp_var_content = compat.force_str("Flask-Jinja-Test")
|
||||
bp_var_content = "Flask-Jinja-Test"
|
||||
|
||||
with debug.Session() as parent_session:
|
||||
with start_flask(parent_session, multiprocess=True):
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@ def test_log_dir_env(pyfile, tmpdir, run, target):
|
|||
with check_logs(tmpdir, run, pydevd_log=True):
|
||||
with debug.Session() as session:
|
||||
session.log_dir = None
|
||||
session.spawn_adapter.env["DEBUGPY_LOG_DIR"] = tmpdir
|
||||
session.spawn_adapter.env["DEBUGPY_LOG_DIR"] = tmpdir.strpath
|
||||
if run.request != "launch":
|
||||
session.spawn_debuggee.env["DEBUGPY_LOG_DIR"] = tmpdir
|
||||
session.spawn_debuggee.env["DEBUGPY_LOG_DIR"] = tmpdir.strpath
|
||||
|
||||
backchannel = session.open_backchannel()
|
||||
with run(session, target(code_to_debug)):
|
||||
|
|
|
|||
|
|
@ -330,15 +330,12 @@ def test_frame_eval(pyfile, target, run, frame_eval):
|
|||
|
||||
@pytest.mark.parametrize("run", [runners.all_launch[0]])
|
||||
def test_unicode_dir(tmpdir, run, target):
|
||||
from debugpy.common import compat
|
||||
|
||||
unicode_chars = "á"
|
||||
|
||||
directory = os.path.join(compat.force_unicode(str(tmpdir), "ascii"), unicode_chars)
|
||||
directory = compat.filename_str(directory)
|
||||
directory = os.path.join(str(tmpdir), unicode_chars)
|
||||
os.makedirs(directory)
|
||||
|
||||
code_to_debug = os.path.join(directory, compat.filename_str("experiment.py"))
|
||||
code_to_debug = os.path.join(directory, "experiment.py")
|
||||
with open(code_to_debug, "wb") as stream:
|
||||
stream.write(
|
||||
b"""
|
||||
|
|
@ -352,7 +349,7 @@ backchannel.send('ok')
|
|||
|
||||
with debug.Session() as session:
|
||||
backchannel = session.open_backchannel()
|
||||
with run(session, target(compat.filename_str(code_to_debug))):
|
||||
with run(session, target(code_to_debug)):
|
||||
pass
|
||||
|
||||
received = backchannel.receive()
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import socket
|
|||
import threading
|
||||
import time
|
||||
|
||||
from debugpy.common import compat, log
|
||||
from debugpy.common import log, util
|
||||
from tests.patterns import some
|
||||
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ def get_test_server_port(start, stop):
|
|||
"""
|
||||
|
||||
try:
|
||||
worker_id = compat.force_ascii(os.environ["PYTEST_XDIST_WORKER"])
|
||||
worker_id = util.force_ascii(os.environ["PYTEST_XDIST_WORKER"])
|
||||
except KeyError:
|
||||
n = 0
|
||||
else:
|
||||
|
|
@ -56,7 +56,7 @@ def wait_until_port_is_listening(port, interval=1, max_attempts=1000):
|
|||
Connection is immediately closed before returning.
|
||||
"""
|
||||
|
||||
for i in compat.xrange(1, max_attempts + 1):
|
||||
for i in range(1, max_attempts + 1):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
log.info("Probing localhost:{0} (attempt {1})...", port, i)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import py.path
|
|||
import re
|
||||
import sys
|
||||
|
||||
from debugpy.common import compat
|
||||
from debugpy.common.compat import unicode, xrange
|
||||
from debugpy.common import util
|
||||
import pydevd_file_utils
|
||||
|
||||
|
||||
|
|
@ -166,26 +165,18 @@ class Path(Some):
|
|||
"""Matches any string that matches the specified path.
|
||||
|
||||
Uses os.path.normcase() to normalize both strings before comparison.
|
||||
|
||||
If one string is unicode, but the other one is not, both strings are normalized
|
||||
to unicode using sys.getfilesystemencoding().
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
if isinstance(path, py.path.local):
|
||||
path = path.strpath
|
||||
if isinstance(path, bytes):
|
||||
path = path.encode(sys.getfilesystemencoding())
|
||||
assert isinstance(path, unicode)
|
||||
assert isinstance(path, str)
|
||||
self.path = path
|
||||
|
||||
def __repr__(self):
|
||||
return "path({self.path!r})"
|
||||
|
||||
def __str__(self):
|
||||
return compat.filename_str(self.path)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.path
|
||||
|
||||
def __getstate__(self):
|
||||
|
|
@ -195,7 +186,7 @@ class Path(Some):
|
|||
if isinstance(other, py.path.local):
|
||||
other = other.strpath
|
||||
|
||||
if isinstance(other, unicode):
|
||||
if isinstance(other, str):
|
||||
pass
|
||||
elif isinstance(other, bytes):
|
||||
other = other.encode(sys.getfilesystemencoding())
|
||||
|
|
@ -242,8 +233,8 @@ class ListContaining(Some):
|
|||
# tuples of equal length with items - i.e. all potential subsequences. So,
|
||||
# given other=[1, 2, 3, 4, 5] and items=(2, 3, 4), we want to get a list
|
||||
# like [(1, 2, 3), (2, 3, 4), (3, 4, 5)] - and then search for items in it.
|
||||
iters = [itertools.islice(other, i, None) for i in xrange(0, len(items))]
|
||||
subseqs = compat.izip(*iters)
|
||||
iters = [itertools.islice(other, i, None) for i in range(0, len(items))]
|
||||
subseqs = zip(*iters)
|
||||
return any(subseq == items for subseq in subseqs)
|
||||
|
||||
|
||||
|
|
@ -302,7 +293,7 @@ class SuchThat(Also):
|
|||
try:
|
||||
return self.name
|
||||
except AttributeError:
|
||||
return f"({self.pattern!r} if {compat.nameof(self.condition)})"
|
||||
return f"({self.pattern!r} if {util.nameof(self.condition)})"
|
||||
|
||||
def _also(self, value):
|
||||
return self.condition(value)
|
||||
|
|
@ -341,9 +332,6 @@ class EqualTo(Also):
|
|||
def __str__(self):
|
||||
return str(self.obj)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.obj)
|
||||
|
||||
def __getstate__(self):
|
||||
return self.obj
|
||||
|
||||
|
|
@ -386,7 +374,7 @@ class Matching(Also):
|
|||
"""
|
||||
|
||||
def __init__(self, pattern, regex, flags=0):
|
||||
assert isinstance(regex, bytes) or isinstance(regex, unicode)
|
||||
assert isinstance(regex, bytes) or isinstance(regex, str)
|
||||
super(Matching, self).__init__(pattern)
|
||||
self.regex = regex
|
||||
self.flags = flags
|
||||
|
|
@ -407,8 +395,8 @@ class Matching(Also):
|
|||
if not isinstance(value, bytes):
|
||||
return NotImplemented
|
||||
regex += b"$"
|
||||
elif isinstance(regex, unicode):
|
||||
if not isinstance(value, unicode):
|
||||
elif isinstance(regex, str):
|
||||
if not isinstance(value, str):
|
||||
return NotImplemented
|
||||
regex += "$"
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import py.path
|
||||
|
||||
from debugpy.common.compat import unicode
|
||||
from tests import code
|
||||
from tests.patterns import some, _impl
|
||||
|
||||
|
|
@ -33,14 +32,14 @@ def frame(source, line, **kwargs):
|
|||
|
||||
If source is py.path.local, it's automatically wrapped with some.dap.source().
|
||||
|
||||
If line is unicode, it is treated as a line marker, and translated to a line
|
||||
If line is str, it is treated as a line marker, and translated to a line
|
||||
number via get_marked_line_numbers(source["path"]) if possible.
|
||||
"""
|
||||
|
||||
if isinstance(source, py.path.local):
|
||||
source = some.dap.source(source)
|
||||
|
||||
if isinstance(line, unicode):
|
||||
if isinstance(line, str):
|
||||
if isinstance(source, dict):
|
||||
path = source["path"]
|
||||
elif isinstance(source, _impl.DictContaining):
|
||||
|
|
|
|||
|
|
@ -79,10 +79,10 @@ __all__ = [
|
|||
"tuple",
|
||||
]
|
||||
|
||||
import builtins
|
||||
import numbers
|
||||
import re
|
||||
|
||||
from debugpy.common.compat import builtins
|
||||
from tests.patterns import _impl
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import sys
|
|||
import threading
|
||||
import types
|
||||
|
||||
from debugpy.common import compat, log, timestamp
|
||||
from debugpy.common import log, timestamp
|
||||
import tests
|
||||
from tests import code, logs
|
||||
from tests.debug import runners, session, targets
|
||||
|
|
@ -151,7 +151,7 @@ else:
|
|||
def long_tmpdir(request, tmpdir):
|
||||
"""Like tmpdir, but ensures that it's a long rather than short filename on Win32.
|
||||
"""
|
||||
path = compat.filename(tmpdir.strpath)
|
||||
path = tmpdir.strpath
|
||||
buffer = ctypes.create_unicode_buffer(512)
|
||||
if GetLongPathNameW(path, buffer, len(buffer)):
|
||||
path = buffer.value
|
||||
|
|
@ -222,7 +222,7 @@ def pyfile(request, long_tmpdir):
|
|||
|
||||
# Write it to file.
|
||||
tmpfile = long_tmpdir / (name + ".py")
|
||||
tmpfile.strpath = compat.filename(tmpfile.strpath)
|
||||
tmpfile.strpath = tmpfile.strpath
|
||||
assert not tmpfile.check()
|
||||
tmpfile.write(source)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
import collections
|
||||
import contextlib
|
||||
import itertools
|
||||
import queue
|
||||
import threading
|
||||
|
||||
from debugpy.common import compat, json, log, messaging, timestamp
|
||||
from debugpy.common.compat import queue
|
||||
from debugpy.common import json, log, messaging, timestamp
|
||||
|
||||
from tests.patterns import some
|
||||
|
||||
|
|
@ -831,7 +831,7 @@ def Response(request, body=some.object):
|
|||
elif body is some.error or body == some.error:
|
||||
items += (("success", False),)
|
||||
if body == some.error:
|
||||
items += (("message", compat.force_str(body)),)
|
||||
items += (("message", str(body)),)
|
||||
else:
|
||||
items += (("body", body),)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue