Get rid of fmt() and use idiomatic format() and f"" instead.

This commit is contained in:
Pavel Minaev 2022-04-08 16:34:45 -07:00 committed by Pavel Minaev
parent 98087352cb
commit 1965b47034
34 changed files with 221 additions and 359 deletions

View file

@ -5,7 +5,6 @@
import argparse
import atexit
import codecs
import json
import locale
import os
import sys
@ -26,7 +25,7 @@ def main(args):
atexit.register(stderr.close)
from debugpy import adapter
from debugpy.common import compat, log, sockets
from debugpy.common import compat, json, log, sockets
from debugpy.adapter import clients, servers, sessions
if args.for_server is not None:
@ -73,9 +72,9 @@ def main(args):
endpoints["server"] = {"host": server_host, "port": server_port}
log.info(
"Sending endpoints info to debug server at localhost:{0}:\n{1!j}",
"Sending endpoints info to debug server at localhost:{0}:\n{1}",
args.for_server,
endpoints,
json.repr(endpoints),
)
try:
@ -99,7 +98,7 @@ def main(args):
listener_file = os.getenv("DEBUGPY_ADAPTER_ENDPOINTS")
if listener_file is not None:
log.info("Writing endpoints info to {0!r}:\n{1!j}", listener_file, endpoints)
log.info("Writing endpoints info to {0!r}:\n{1}", listener_file, json.repr(endpoints))
def delete_listener_file():
log.info("Listener ports closed; deleting {0!r}", listener_file)

View file

@ -8,7 +8,7 @@ import sys
import debugpy
from debugpy import adapter, common, launcher
from debugpy.common import compat, fmt, json, log, messaging, sockets
from debugpy.common import compat, json, log, messaging, sockets
from debugpy.common.compat import unicode
from debugpy.adapter import components, servers, sessions
@ -244,10 +244,9 @@ class Client(components.Component):
# here at this point, either, so just bail out.
request.respond({})
self.session.finalize(
fmt(
"{0} disconnected before responding to {1!j}",
"{0} disconnected before responding to {1}".format(
self.server,
request.command,
json.repr(request.command),
)
)
return
@ -309,9 +308,9 @@ class Client(components.Component):
if flag_name in debug_options:
if value is False:
raise request.isnt_valid(
'{0!j}:false and "debugOptions":[{1!j}] are mutually exclusive',
prop_name,
flag_name,
'{0}:false and "debugOptions":[{1}] are mutually exclusive',
json.repr(prop_name),
json.repr(flag_name),
)
value = True
@ -517,7 +516,7 @@ class Client(components.Component):
# request was successful, but that the session terminated immediately.
request.respond({})
self.session.finalize(
fmt('No known subprocess with "subProcessId":{0}', sub_pid)
'No known subprocess with "subProcessId":{0}'.format(sub_pid)
)
return
@ -555,10 +554,9 @@ class Client(components.Component):
request.respond({})
self.start_request.respond({})
self.session.finalize(
fmt(
"{0} disconnected before responding to {1!j}",
"{0} disconnected before responding to {1}".format(
self.server,
request.command,
json.repr(request.command),
)
)
return
@ -651,7 +649,7 @@ class Client(components.Component):
for key in "processId", "listen", "preLaunchTask", "postDebugTask":
body.pop(key, None)
body["name"] = fmt("Subprocess {0}", conn.pid)
body["name"] = "Subprocess {0}".format(conn.pid)
body["request"] = "attach"
body["subProcessId"] = conn.pid

View file

@ -4,7 +4,7 @@
import functools
from debugpy.common import fmt, json, log, messaging, util
from debugpy.common import json, log, messaging, util
ACCEPT_CONNECTIONS_TIMEOUT = 10
@ -13,7 +13,7 @@ ACCEPT_CONNECTIONS_TIMEOUT = 10
class ComponentNotAvailable(Exception):
def __init__(self, type):
super(ComponentNotAvailable, self).__init__(
fmt("{0} is not available", type.__name__)
f"{type.__name__} is not available"
)
@ -60,7 +60,7 @@ class Component(util.Observable):
self.observers += [lambda *_: self.session.notify_changed()]
def __str__(self):
return fmt("{0}[{1}]", type(self).__name__, self.session.id)
return f"{type(self).__name__}[{self.session.id}]"
@property
def client(self):
@ -108,7 +108,7 @@ class Component(util.Observable):
def disconnect(self):
with self.session:
self.is_connected = False
self.session.finalize(fmt("{0} has disconnected", self))
self.session.finalize("{0} has disconnected".format(self))
def missing(session, type):
@ -165,21 +165,19 @@ class Capabilities(dict):
try:
value = validate(value)
except Exception as exc:
raise message.isnt_valid("{0!j} {1}", name, exc)
raise message.isnt_valid("{0} {1}", json.repr(name), exc)
assert value != (), fmt(
"{0!j} must provide a default value for missing properties.", validate
)
assert value != (), f"{validate} must provide a default value for missing properties."
self[name] = value
log.debug("{0}", self)
def __repr__(self):
return fmt("{0}: {1!j}", type(self).__name__, dict(self))
return f"{type(self).__name__}: {json.repr(dict(self))}"
def require(self, *keys):
for key in keys:
if not self[key]:
raise messaging.MessageHandlingError(
fmt("{0} does not have capability {1!j}", self.component, key)
f"{self.component} does not have capability {json.repr(key)}",
)

View file

@ -7,7 +7,7 @@ import subprocess
import sys
from debugpy import adapter, common
from debugpy.common import compat, fmt, log, messaging, sockets
from debugpy.common import compat, json, log, messaging, sockets
from debugpy.adapter import components, servers
@ -106,7 +106,7 @@ def spawn_debuggee(
launcher_addr = (
launcher_port
if launcher_host == "127.0.0.1"
else fmt("{0}:{1}", launcher_host, launcher_port)
else f"{launcher_host}:{launcher_port}"
)
cmdline += [str(launcher_addr), "--"]
cmdline += args
@ -124,7 +124,7 @@ def spawn_debuggee(
cmdline[i] = compat.filename_str(arg)
except UnicodeEncodeError as exc:
raise start_request.cant_handle(
"Invalid command line argument {0!j}: {1}", arg, exc
"Invalid command line argument {0}: {1}", json.repr(arg), exc
)
# If we are talking to the client over stdio, sys.stdin and sys.stdout

View file

@ -10,7 +10,7 @@ import time
import debugpy
from debugpy import adapter
from debugpy.common import compat, fmt, json, log, messaging, sockets
from debugpy.common import compat, json, log, messaging, sockets
from debugpy.adapter import components
@ -89,7 +89,7 @@ if 'debugpy' not in sys.modules:
finally:
del sys.path[0]
"""
inject_debugpy = fmt(inject_debugpy, debugpy_dir=debugpy_dir)
inject_debugpy = inject_debugpy.format(debugpy_dir=debugpy_dir)
try:
self.channel.request("evaluate", {"expression": inject_debugpy})
@ -111,7 +111,7 @@ if 'debugpy' not in sys.modules:
if any(conn.pid == self.pid for conn in _connections):
raise KeyError(
fmt("{0} is already connected to this adapter", self)
f"{self} is already connected to this adapter"
)
is_first_server = len(_connections) == 0
@ -167,7 +167,7 @@ if 'debugpy' not in sys.modules:
self.channel.close()
def __str__(self):
return "Server" + fmt("[?]" if self.pid is None else "[pid={0}]", self.pid)
return "Server" + ("[?]" if self.pid is None else f"[pid={self.pid}]")
def authenticate(self):
if access_token is None and adapter.access_token is None:
@ -468,9 +468,7 @@ def inject(pid, debugpy_args):
"Failed to inject debug server into process with PID={0}", pid
)
raise messaging.MessageHandlingError(
fmt(
"Failed to inject debug server into process with PID={0}: {1}", pid, exc
)
"Failed to inject debug server into process with PID={0}: {1}".format(pid, exc)
)
# We need to capture the output of the injector - otherwise it can get blocked
@ -485,7 +483,7 @@ def inject(pid, debugpy_args):
log.info("Injector[PID={0}] exited.", pid)
thread = threading.Thread(
target=capture_output, name=fmt("Injector[PID={0}] output", pid)
target=capture_output, name=f"Injector[PID={pid}] output",
)
thread.daemon = True
thread.start()

View file

@ -9,7 +9,7 @@ import threading
import time
from debugpy import common
from debugpy.common import fmt, log, util
from debugpy.common import log, util
from debugpy.adapter import components, launchers, servers
@ -64,7 +64,7 @@ class Session(util.Observable):
self.observers += [lambda *_: self.notify_changed()]
def __str__(self):
return fmt("Session[{0}]", self.id)
return f"Session[{self.id}]"
def __enter__(self):
"""Lock the session for exclusive access."""

View file

@ -10,7 +10,6 @@ import inspect
import itertools
import sys
from debugpy.common import fmt
if sys.version_info[0] < 3:
# Py2
@ -159,13 +158,13 @@ def srcnameof(obj):
except Exception:
pass
else:
name += fmt(" (file {0!r}", src_file)
name += " (file {0!r}".format(src_file)
try:
_, src_lineno = inspect.getsourcelines(obj)
except Exception:
pass
else:
name += fmt(", line {0}", src_lineno)
name += ", line {0}".format(src_lineno)
name += ")"
return name

View file

@ -1,55 +0,0 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE in the project root
# for license information.
"""Provides a custom string.Formatter with JSON support.
The formatter object is directly exposed as a module, such that all its members
can be invoked directly after it has been imported::
from debugpy.common import fmt
fmt("{0} is {value}", name, value=x)
"""
import string
import sys
import types
class Formatter(string.Formatter, types.ModuleType):
"""A custom string.Formatter with support for JSON pretty-printing.
Adds {!j} format specification. When used, the corresponding value is converted
to string using json_encoder.encode().
Since string.Formatter in Python <3.4 does not support unnumbered placeholders,
they must always be numbered explicitly - "{0} {1}" rather than "{} {}". Named
placeholders are supported.
"""
# Because globals() go away after the module object substitution, all method bodies
# below must access globals via self instead, or re-import modules locally.
from debugpy.common import json
def __init__(self):
# Set self up as a proper module, and copy globals.
# types must be re-imported, because globals aren't there yet at this point.
import types
types.ModuleType.__init__(self, __name__)
self.__dict__.update(sys.modules[__name__].__dict__)
def __call__(self, format_string, *args, **kwargs):
"""Same as self.format().
"""
return self.format(format_string, *args, **kwargs)
def convert_field(self, value, conversion):
if conversion == "j":
return self.json.JsonObject(value)
return super(self.Formatter, self).convert_field(value, conversion)
# Replace the standard module object for this module with a Formatter instance.
sys.modules[__name__] = Formatter()

View file

@ -56,7 +56,7 @@ class JsonObject(object):
Example::
fmt("{0!j} {0!j:indent=4,sort_keys=True}", x)
format("{0} {0:indent=4,sort_keys=True}", json.repr(x))
"""
if format_spec:
# At this point, format_spec is a string that looks something like
@ -223,7 +223,7 @@ def array(validate_item=False, vectorize=False, size=None):
try:
value[i] = validate_item(item)
except (TypeError, ValueError) as exc:
raise type(exc)(fmt("[{0!j}] {1}", i, exc))
raise type(exc)(f"[{repr(i)}] {exc}")
return value
return validate
@ -257,15 +257,15 @@ def object(validate_value=False):
try:
value[k] = validate_value(v)
except (TypeError, ValueError) as exc:
raise type(exc)(fmt("[{0!j}] {1}", k, exc))
raise type(exc)(f"[{repr(k)}] {exc}")
return value
return validate
# A helper to resolve the circular dependency between common.fmt and common.json
# on Python 2.
def fmt(*args, **kwargs):
from debugpy.common import fmt
def repr(value):
return JsonObject(value)
return fmt(*args, **kwargs)
dumps = json.dumps
loads = json.loads

View file

@ -14,7 +14,7 @@ import threading
import traceback
import debugpy
from debugpy.common import compat, fmt, timestamp, util
from debugpy.common import compat, json, timestamp, util
LEVELS = ("debug", "info", "warning", "error")
@ -43,8 +43,7 @@ def _update_levels():
class LogFile(object):
def __init__(self, filename, file, levels=LEVELS, close_file=True):
info("Also logging to {0!j}.", filename)
info("Also logging to {0}.", json.repr(filename))
self.filename = filename
self.file = file
self.close_file = close_file
@ -86,7 +85,7 @@ class LogFile(object):
with _lock:
del _files[self.filename]
_update_levels()
info("Not logging to {0!j} anymore.", self.filename)
info("Not logging to {0} anymore.", json.repr(self.filename))
if self.close_file:
try:
@ -128,7 +127,7 @@ def write(level, text, _to_files=all):
t = timestamp.current()
format_string = "{0}+{1:" + timestamp_format + "}: "
prefix = fmt(format_string, level[0].upper(), t)
prefix = format_string.format(level[0].upper(), t)
text = getattr(_tls, "prefix", "") + text
indent = "\n" + (" " * len(prefix))
@ -151,7 +150,7 @@ def write_format(level, format_string, *args, **kwargs):
return
try:
text = fmt(format_string, *args, **kwargs)
text = format_string.format(*args, **kwargs)
except Exception:
reraise_exception()
@ -168,12 +167,12 @@ def error(*args, **kwargs):
Returns the output wrapped in AssertionError. Thus, the following::
raise log.error(...)
raise log.error(s, ...)
has the same effect as::
log.error(...)
assert False, fmt(...)
assert False, (s.format(...))
"""
return AssertionError(write_format("error", *args, **kwargs))
@ -203,7 +202,7 @@ def _exception(format_string="", *args, **kwargs):
def swallow_exception(format_string="", *args, **kwargs):
"""Logs an exception with full traceback.
If format_string is specified, it is formatted with fmt(*args, **kwargs), and
If format_string is specified, it is formatted with format(*args, **kwargs), and
prepended to the exception traceback on a separate line.
If exc_info is specified, the exception it describes will be logged. Otherwise,
@ -257,7 +256,7 @@ def to_file(filename=None, prefix=None, levels=LEVELS):
os.makedirs(log_dir)
except OSError:
pass
filename = fmt("{0}/{1}-{2}.log", log_dir, prefix, os.getpid())
filename = f"{log_dir}/{prefix}-{os.getpid()}.log"
file = _files.get(filename)
if file is None:
@ -272,7 +271,7 @@ def prefixed(format_string, *args, **kwargs):
"""Adds a prefix to all messages logged from the current thread for the duration
of the context manager.
"""
prefix = fmt(format_string, *args, **kwargs)
prefix = format_string.format(*args, **kwargs)
old_prefix = getattr(_tls, "prefix", "")
_tls.prefix = prefix + old_prefix
try:
@ -287,11 +286,11 @@ def describe_environment(header):
result = [header, "\n\n"]
def report(*args, **kwargs):
result.append(fmt(*args, **kwargs))
def report(s, *args, **kwargs):
result.append(s.format(*args, **kwargs))
def report_paths(get_paths, label=None):
prefix = fmt(" {0}: ", label or get_paths)
prefix = f" {label or get_paths}: "
expr = None
if not callable(get_paths):
@ -337,7 +336,7 @@ def describe_environment(header):
report_paths(lambda: site_packages, "sys.path (site-packages)")
for name in sysconfig.get_path_names():
expr = fmt("sysconfig.get_path({0!r})", name)
expr = "sysconfig.get_path({0!r})".format(name)
report_paths(expr)
report_paths("os.__file__")

View file

@ -18,7 +18,7 @@ import socket
import sys
import threading
from debugpy.common import compat, fmt, json, log
from debugpy.common import compat, json, log
from debugpy.common.compat import unicode
@ -125,7 +125,7 @@ class JsonIOStream(object):
"""
if name is None:
name = fmt("reader={0!r}, writer={1!r}", reader, writer)
name = f"reader={reader!r}, writer={writer!r}"
self.name = name
self._reader = reader
@ -164,9 +164,9 @@ class JsonIOStream(object):
def _log_message(self, dir, data, logger=log.debug):
format_string = "{0} {1} " + (
"{2!j:indent=None}" if isinstance(data, list) else "{2!j}"
"{2:indent=None}" if isinstance(data, list) else "{2}"
)
return logger(format_string, self.name, dir, data)
return logger(format_string, self.name, dir, json.repr(data))
def _read_line(self, reader):
line = b""
@ -297,9 +297,7 @@ class JsonIOStream(object):
if not isinstance(body, bytes):
body = body.encode("utf-8")
header = fmt("Content-Length: {0}\r\n\r\n", len(body))
header = header.encode("ascii")
header = f"Content-Length: {len(body)}\r\n\r\n".encode("ascii")
data = header + body
data_written = 0
try:
@ -319,7 +317,7 @@ class JsonIOStream(object):
self._log_message("<--", value)
def __repr__(self):
return fmt("{0}({1!r})", type(self).__name__, self.name)
return f"{type(self).__name__}({self.name!r})"
class MessageDict(collections.OrderedDict):
@ -357,7 +355,7 @@ class MessageDict(collections.OrderedDict):
"""
def __repr__(self):
return fmt("{0!j}", self)
return json.repr(self)
def __call__(self, key, validate, optional=False):
"""Like get(), but with validation.
@ -396,10 +394,10 @@ class MessageDict(collections.OrderedDict):
value = validate(value)
except (TypeError, ValueError) as exc:
message = Message if self.message is None else self.message
err = fmt("{0}", exc)
err = str(exc)
if not err.startswith("["):
err = " " + err
raise message.isnt_valid("{0!j}{1}", key, err)
raise message.isnt_valid("{0}{1}", json.repr(key), err)
return value
def _invalid_if_no_key(func):
@ -463,7 +461,7 @@ class Message(object):
"""
def __str__(self):
return fmt("{0!j}", self.json) if self.json is not None else repr(self)
return json.repr(self.json) if self.json is not None else repr(self)
def describe(self):
"""A brief description of the message that is enough to identify it.
@ -523,7 +521,7 @@ class Message(object):
assert issubclass(exc_type, MessageHandlingError)
silent = kwargs.pop("silent", False)
reason = fmt(format_string, *args, **kwargs)
reason = format_string.format(*args, **kwargs)
exc = exc_type(reason, self, silent) # will log it
if isinstance(self, Request):
@ -576,7 +574,7 @@ class Event(Message):
self.body = body
def describe(self):
return fmt("#{0} event {1!j} from {2}", self.seq, self.event, self.channel)
return f"#{self.seq} event {json.repr(self.event)} from {self.channel}"
@property
def payload(self):
@ -596,11 +594,8 @@ class Event(Message):
try:
try:
result = handler(self)
assert result is None, fmt(
"Handler {0} tried to respond to {1}.",
compat.srcnameof(handler),
self.describe(),
)
assert result is None, \
f"Handler {compat.srcnameof(handler)} tried to respond to {self.describe()}."
except MessageHandlingError as exc:
if not exc.applies_to(self):
raise
@ -681,7 +676,7 @@ class Request(Message):
"""
def describe(self):
return fmt("#{0} request {1!j} from {2}", self.seq, self.command, self.channel)
return f"#{self.seq} request {json.repr(self.command)} from {self.channel}"
@property
def payload(self):
@ -738,25 +733,28 @@ class Request(Message):
)
if result is NO_RESPONSE:
assert self.response is None, fmt(
assert self.response is None, (
"Handler {0} for {1} must not return NO_RESPONSE if it has already "
"invoked request.respond().",
"invoked request.respond().".format(
compat.srcnameof(handler),
self.describe(),
self.describe()
)
)
elif self.response is not None:
assert result is None or result is self.response.body, fmt(
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().",
"already invoked request.respond().".format(
compat.srcnameof(handler),
self.describe(),
self.describe()
)
)
else:
assert result is not None, fmt(
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.",
"returns, or return the response body, or return NO_RESPONSE.".format(
compat.srcnameof(handler),
self.describe(),
self.describe()
)
)
try:
self.respond(result)
@ -787,7 +785,7 @@ class OutgoingRequest(Request):
self._response_handlers = []
def describe(self):
return fmt("#{0} request {1!j} to {2}", self.seq, self.command, self.channel)
return f"{self.seq} request {json.repr(self.command)} to {self.channel}"
def wait_for_response(self, raise_if_failed=True):
"""Waits until a response is received for this request, records the Response
@ -913,7 +911,7 @@ class Response(Message):
"""
def describe(self):
return fmt("#{0} response to {1}", self.seq, self.request.describe())
return f"#{self.seq} response to {self.request.describe()}"
@property
def payload(self):
@ -988,7 +986,7 @@ class Disconnect(Message):
super(Disconnect, self).__init__(channel, None)
def describe(self):
return fmt("disconnect from {0}", self.channel)
return f"disconnect from {self.channel}"
class MessageHandlingError(Exception):
@ -1068,14 +1066,9 @@ class MessageHandlingError(Exception):
def __repr__(self):
s = type(self).__name__
if self.cause is None:
s += fmt("(reason={0!r})", self.reason)
s += f"reason={self.reason!r})"
else:
s += fmt(
"(channel={0!r}, cause={1!r}, reason={2!r})",
self.cause.channel.name,
self.cause.seq,
self.reason,
)
s += f"channel={self.cause.channel.name!r}, cause={self.cause.seq!r}, reason={self.reason!r})"
return s
def applies_to(self, message):
@ -1145,7 +1138,7 @@ class JsonMessageChannel(object):
return self.name
def __repr__(self):
return fmt("{0}({1!r})", type(self).__name__, self.name)
return f"{type(self).__name__}({self.name!r})"
def __enter__(self):
self._lock.acquire()
@ -1180,7 +1173,7 @@ class JsonMessageChannel(object):
self.started = True
self._parser_thread = threading.Thread(
target=self._parse_incoming_messages, name=fmt("{0} message parser", self)
target=self._parse_incoming_messages, name=f"{self} message parser"
)
self._parser_thread.pydev_do_not_trace = True
self._parser_thread.is_pydev_daemon_thread = True
@ -1404,16 +1397,16 @@ class JsonMessageChannel(object):
parser(self, message_dict)
except InvalidMessageError as exc:
log.error(
"Failed to parse message in channel {0}: {1} in:\n{2!j}",
"Failed to parse message in channel {0}: {1} in:\n{2}",
self,
str(exc),
message_dict,
json.repr(message_dict),
)
except Exception as exc:
if isinstance(exc, NoMoreMessages) and exc.stream is self.stream:
raise
log.swallow_exception(
"Fatal error in channel {0} while parsing:\n{1!j}", self, message_dict
"Fatal error in channel {0} while parsing:\n{1}", self, json.repr(message_dict)
)
os._exit(1)
@ -1440,7 +1433,7 @@ class JsonMessageChannel(object):
# of handlers to run.
if len(self._handler_queue) and self._handler_thread is None:
self._handler_thread = threading.Thread(
target=self._run_handlers, name=fmt("{0} message handler", self)
target=self._run_handlers, name=f"{self} message handler",
)
self._handler_thread.pydev_do_not_trace = True
self._handler_thread.is_pydev_daemon_thread = True
@ -1508,8 +1501,7 @@ class JsonMessageChannel(object):
continue
raise AttributeError(
fmt(
"handler object {0} for channel {1} has no handler for {2} {3!r}",
"handler object {0} for channel {1} has no handler for {2} {3!r}".format(
compat.srcnameof(handlers),
self,
type,

View file

@ -1,52 +0,0 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE in the project root
# for license information.
"""Provides facilities to use objects as modules, enabling __getattr__, __call__
etc on module level.
"""
import sys
import types
def module(name):
"""A decorator for classes that implement modules.
Idiomatic usage is with __name__, so that an instance of the class replaces the
module in which it is defined::
# foo.py
@module(__name__)
class Foo(object):
def __call__(self): ...
# bar.py
import foo
foo()
"Regular" globals, including imports, don't work with class modules. Class or
instance attributes must be used consistently for this purpose, and accessed via
self inside method bodies::
@module(__name__)
class Foo(object):
import sys
def __call__(self):
if self.sys.version_info < (3,): ...
"""
def decorate(cls):
class Module(cls, types.ModuleType):
def __init__(self):
# Set self up as a proper module, and copy pre-existing globals.
types.ModuleType.__init__(self, name)
self.__dict__.update(sys.modules[name].__dict__)
cls.__init__(self)
Module.__name__ = cls.__name__
sys.modules[name] = Module()
return decorate

View file

@ -12,7 +12,7 @@ import sys
import threading
from debugpy import launcher
from debugpy.common import fmt, log, messaging, compat
from debugpy.common import log, messaging, compat
from debugpy.launcher import output
if sys.platform == "win32":
@ -34,7 +34,7 @@ returns True, the launcher pauses and waits for user input before exiting.
def describe():
return fmt("Debuggee[PID={0}]", process.pid)
return f"Debuggee[PID={process.pid}]"
def spawn(process_name, cmdline, env, redirect_output):
@ -91,7 +91,7 @@ def spawn(process_name, cmdline, env, redirect_output):
process = subprocess.Popen(cmdline, env=env, bufsize=0, **kwargs)
except Exception as exc:
raise messaging.MessageHandlingError(
fmt("Couldn't spawn debuggee: {0}\n\nCommand line:{1!r}", exc, cmdline)
"Couldn't spawn debuggee: {0}\n\nCommand line:{1!r}".format(exc, cmdline)
)
log.info("Spawned {0}.", describe())

View file

@ -28,9 +28,9 @@ def launch_request(request):
if flag_name in debug_options:
if value is False:
raise request.isnt_valid(
'{0!j}:false and "debugOptions":[{1!j}] are mutually exclusive',
prop_name,
flag_name,
'{0}:false and "debugOptions":[{1}] are mutually exclusive',
json.repr(prop_name),
json.repr(flag_name),
)
value = True

View file

@ -3,7 +3,6 @@
# for license information.
import codecs
import json
import os
import pydevd
import socket
@ -12,7 +11,7 @@ import threading
import debugpy
from debugpy import adapter
from debugpy.common import compat, fmt, log, sockets
from debugpy.common import compat, json, log, sockets
from _pydevd_bundle.pydevd_constants import get_global_debugger
from pydevd_file_utils import absolute_path
@ -91,13 +90,13 @@ def configure(properties, **kwargs):
for k, v in properties.items():
if k not in _config:
raise ValueError(fmt("Unknown property {0!r}", k))
raise ValueError("Unknown property {0!r}".format(k))
expected_type = type(_config[k])
if type(v) is not expected_type:
raise ValueError(fmt("{0!r} must be a {1}", k, expected_type.__name__))
raise ValueError("{0!r} must be a {1}".format(k, expected_type.__name__))
valid_values = _config_valid_values.get(k)
if (valid_values is not None) and (v not in valid_values):
raise ValueError(fmt("{0!r} must be one of: {1!r}", k, valid_values))
raise ValueError("{0!r} must be one of: {1!r}".format(k, valid_values))
_config[k] = v
@ -120,7 +119,7 @@ def _starts_debugging(func):
ensure_logging()
log.debug("{0}({1!r}, **{2!r})", func.__name__, address, kwargs)
log.info("Initial debug configuration: {0!j}", _config)
log.info("Initial debug configuration: {0}", json.repr(_config))
qt_mode = _config.get("qt", "none")
if qt_mode != "none":
@ -181,7 +180,7 @@ def listen(address, settrace_kwargs):
]
if log.log_dir is not None:
adapter_args += ["--log-dir", log.log_dir]
log.info("debugpy.listen() spawning adapter: {0!j}", adapter_args)
log.info("debugpy.listen() spawning adapter: {0}", json.repr(adapter_args))
# On Windows, detach the adapter from our console, if any, so that it doesn't
# receive Ctrl+C from it, and doesn't keep it open once we exit.
@ -235,7 +234,7 @@ def listen(address, settrace_kwargs):
finally:
endpoints_listener.close()
log.info("Endpoints received from adapter: {0!j}", endpoints)
log.info("Endpoints received from adapter: {0}", json.repr(endpoints))
if "error" in endpoints:
raise RuntimeError(str(endpoints["error"]))
@ -247,7 +246,7 @@ def listen(address, settrace_kwargs):
client_port = int(endpoints["client"]["port"])
except Exception as exc:
log.swallow_exception(
"Error parsing adapter endpoints:\n{0!j}\n", endpoints, level="info"
"Error parsing adapter endpoints:\n{0}\n", json.repr(endpoints), level="info"
)
raise RuntimeError("error parsing adapter endpoints: " + str(exc))
log.info(

View file

@ -57,7 +57,7 @@ def attach(setup):
try:
import debugpy
import debugpy.server
from debugpy.common import log
from debugpy.common import json, log
import pydevd
finally:
assert sys.path[0] == _debugpy_dir
@ -69,7 +69,7 @@ def attach(setup):
if setup["log_to"] is not None:
debugpy.log_to(setup["log_to"])
log.info("Configuring injected debugpy: {0!j}", setup)
log.info("Configuring injected debugpy: {0}", json.repr(setup))
if setup["mode"] == "listen":
debugpy.listen(setup["address"])

View file

@ -16,7 +16,7 @@ assert "pydevd" in sys.modules
import pydevd
import debugpy
from debugpy.common import compat, fmt, log
from debugpy.common import compat, log
from debugpy.server import api
@ -56,9 +56,9 @@ def in_range(parser, start, stop):
def parse(s):
n = parser(s)
if start is not None and n < start:
raise ValueError(fmt("must be >= {0}", start))
raise ValueError("must be >= {0}".format(start))
if stop is not None and n >= stop:
raise ValueError(fmt("must be < {0}", stop))
raise ValueError("must be < {0}".format(stop))
return n
return parse
@ -123,7 +123,7 @@ def set_config(arg, it):
value = next(it)
if name not in options.config:
raise ValueError(fmt("unknown property {0!r}", name))
raise ValueError("unknown property {0!r}".format(name))
expected_type = type(options.config[name])
try:
@ -132,7 +132,7 @@ def set_config(arg, it):
else:
value = expected_type(value)
except Exception:
raise ValueError(fmt("{0!r} must be a {1}", name, expected_type.__name__))
raise ValueError("{0!r} must be a {1}".format(name, expected_type.__name__))
options.config[name] = value
@ -221,9 +221,9 @@ def parse_argv():
action(arg, it)
except StopIteration:
assert placeholder is not None
raise ValueError(fmt("{0}: missing {1}", switch, placeholder))
raise ValueError("{0}: missing {1}".format(switch, placeholder))
except Exception as exc:
raise ValueError(fmt("invalid {0} {1}: {2}", switch, placeholder, exc))
raise ValueError("invalid {0} {1}: {2}".format(switch, placeholder, exc))
if options.target is not None:
break

View file

@ -13,7 +13,7 @@ import os
import socket
import debuggee
from debugpy.common import fmt, log, messaging
from debugpy.common import log, messaging
def send(value):
@ -52,7 +52,7 @@ class _stream:
close = lambda: None
name = fmt("backchannel-{0}", debuggee.session_id)
name = f"backchannel-{debuggee.session_id}"
port = os.environ.pop("DEBUGPY_TEST_BACKCHANNEL_PORT", None)
if port is not None:
port = int(port)

View file

@ -7,7 +7,7 @@
import threading
import socket
from debugpy.common import fmt, log, messaging, sockets
from debugpy.common import log, messaging, sockets
class BackChannel(object):
@ -21,7 +21,7 @@ class BackChannel(object):
self._server_socket = None
def __str__(self):
return fmt("BackChannel[{0}]", self.session.id)
return f"BackChannel[{self.session.id}]"
def listen(self):
self._server_socket = sockets.create_server("127.0.0.1", 0, self.TIMEOUT)
@ -59,7 +59,7 @@ class BackChannel(object):
self._setup_stream()
accept_thread = threading.Thread(
target=accept_worker, name=fmt("{0} listener", self)
target=accept_worker, name=f"{self} listener"
)
accept_thread.daemon = True
accept_thread.start()
@ -118,5 +118,5 @@ class ScratchPad(object):
"""Sets debuggee.scratchpad[key] = value inside the debugged process.
"""
log.info("{0} debuggee.scratchpad[{1!r}] = {2!r}", self.session, key, value)
expr = fmt("sys.modules['debuggee'].scratchpad[{0!r}] = {1!r}", key, value)
expr = f"sys.modules['debuggee'].scratchpad[{key!r}] = {value!r}"
self.session.request("evaluate", {"context": "repl", "expression": expr})

View file

@ -6,7 +6,7 @@ import os
import re
import threading
from debugpy.common import fmt, log
from debugpy.common import log
class CapturedOutput(object):
@ -24,7 +24,7 @@ class CapturedOutput(object):
self._capture(fd, stream_name)
def __str__(self):
return fmt("CapturedOutput[{0}]", self.session.id)
return f"CapturedOutput[{self.session.id}]"
def _worker(self, fd, name):
chunks = self._chunks[name]
@ -52,7 +52,7 @@ class CapturedOutput(object):
self._chunks[name] = []
thread = threading.Thread(
target=lambda: self._worker(fd, name), name=fmt("{0} {1}", self, name)
target=lambda: self._worker(fd, name), name=f"{self} {name}"
)
thread.daemon = True
thread.start()
@ -73,7 +73,7 @@ class CapturedOutput(object):
result = self._chunks[which]
except KeyError:
raise AssertionError(
fmt("{0} was not captured for {1}", which, self.session.debuggee_id)
f"{which} was not captured for {self.session.debuggee_id}"
)
with self._lock:

View file

@ -56,7 +56,7 @@ import pytest
import sys
import debugpy
from debugpy.common import compat, fmt, log
from debugpy.common import compat, json, log
from tests import net, timeline
from tests.debug import session
from tests.patterns import some
@ -100,7 +100,7 @@ def _runner(f):
def __repr__(self):
result = type(self).__name__
args = [str(x) for x in self._args] + [
fmt("{0}={1}", k, v) for k, v in self._kwargs.items()
f"{k}={v}" for k, v in self._kwargs.items()
]
if len(args):
result += "(" + ", ".join(args) + ")"
@ -118,7 +118,7 @@ def _runner(f):
def launch(session, target, console=None, cwd=None):
assert console in (None, "internalConsole", "integratedTerminal", "externalTerminal")
log.info("Launching {0} in {1} using {2!j}.", target, session, console)
log.info("Launching {0} in {1} using {2}.", target, session, json.repr(console))
target.configure(session)
config = session.config
@ -144,8 +144,8 @@ def launch(session, target, console=None, cwd=None):
def _attach_common_config(session, target, cwd):
assert target.code is None or "debuggee.setup()" in target.code, fmt(
"{0} must invoke debuggee.setup().", target.filename
assert target.code is None or "debuggee.setup()" in target.code, (
f"{target.filename} must invoke debuggee.setup()."
)
target.configure(session)
@ -239,8 +239,7 @@ debugpy.listen(({host!r}, {port!r}))
if {wait!r}:
debugpy.wait_for_client()
"""
debuggee_setup = fmt(
debuggee_setup,
debuggee_setup = debuggee_setup.format(
host=host,
port=port,
wait=wait,
@ -293,16 +292,13 @@ def attach_listen(session, target, method, cwd=None, log_dir=None):
elif method == "api":
args = []
api_config = {k: v for k, v in config.items() if k in {"subProcess"}}
debuggee_setup = """
debuggee_setup = f"""
import debugpy
if {log_dir!r}:
debugpy.log_to({log_dir!r})
debugpy.configure({api_config!r})
debugpy.connect({address!r})
debugpy.connect({(host, port)!r})
"""
debuggee_setup = fmt(
debuggee_setup, address=(host, port), log_dir=log_dir, api_config=api_config
)
else:
raise ValueError
args += target.cli(session.spawn_debuggee.env)

View file

@ -12,7 +12,7 @@ import sys
import time
import debugpy.adapter
from debugpy.common import compat, fmt, json, log, messaging, sockets, util
from debugpy.common import compat, json, log, messaging, sockets, util
from debugpy.common.compat import unicode
import tests
from tests import code, timeline, watchdog
@ -203,15 +203,15 @@ class Session(object):
self.spawn_debuggee.env = util.Env()
def __str__(self):
return fmt("Session[{0}]", self.id)
return f"Session[{self.id}]"
@property
def adapter_id(self):
return fmt("Adapter[{0}]", self.id)
return f"Adapter[{self.id}]"
@property
def debuggee_id(self):
return fmt("Debuggee[{0}]", self.id)
return f"Debuggee[{self.id}]"
def __enter__(self):
return self
@ -294,7 +294,7 @@ class Session(object):
if self.log_dir is None:
return False
log.info("Logs for {0} will be in {1!j}", self, self.log_dir)
log.info("Logs for {0} will be in {1}", self, json.repr(self.log_dir))
try:
self.log_dir.remove()
except Exception:
@ -358,13 +358,13 @@ class Session(object):
log.info(
"Spawning {0}:\n\n"
"Current directory: {1!j}\n\n"
"Command line: {2!j}\n\n"
"Environment variables: {3!j}\n\n",
"Current directory: {1}\n\n"
"Command line: {2}\n\n"
"Environment variables: {3}\n\n",
self.debuggee_id,
cwd,
args,
env,
json.repr(cwd),
json.repr(args),
json.repr(env),
)
popen_fds = {}
@ -405,11 +405,11 @@ class Session(object):
log.info(
"Spawning {0}:\n\n"
"Command line: {1!j}\n\n"
"Environment variables: {2!j}\n\n",
"Command line: {1}\n\n"
"Environment variables: {2}\n\n",
self.adapter_id,
args,
env,
json.repr(args),
json.repr(env),
)
self.adapter = psutil.Popen(
args,
@ -446,7 +446,7 @@ class Session(object):
return self.request_attach()
else:
raise ValueError(
fmt('Unsupported "request":{0!j} in session.config', request)
f'Unsupported "request":{json.repr(request)} in session.config'
)
def request(self, *args, **kwargs):
@ -485,7 +485,7 @@ class Session(object):
self.observe(occ)
pid = event("subProcessId", int)
watchdog.register_spawn(
pid, fmt("{0}-subprocess-{1}", self.debuggee_id, pid)
pid, f"{self.debuggee_id}-subprocess-{pid}"
)
def run_in_terminal(self, args, cwd, env):
@ -662,7 +662,7 @@ class Session(object):
else:
marker = line
line = get_marked_line_numbers()[marker]
descr = fmt("{0} (@{1})", line, marker)
descr = f"{line} (@{marker})"
bp_log.append((line, descr))
return {"line": line}

View file

@ -5,7 +5,7 @@
import py
import os
from debugpy.common import fmt, compat
from debugpy.common import compat, json
from tests.patterns import some
@ -108,13 +108,9 @@ class Program(Target):
def __repr__(self):
if self._cwd:
return fmt(
"program (relative) {0!j} / {1!j}",
self._cwd,
self._get_relative_program(),
)
return f"program (relative) {json.repr(self._cwd)} / {json.repr(self._get_relative_program())}"
else:
return fmt("program {0!j}", compat.filename(self.filename.strpath))
return f"program {json.repr(compat.filename(self.filename.strpath))}"
def configure(self, session):
if self._cwd:
@ -147,7 +143,7 @@ class Module(Target):
self.name = name if name is not None else self.filename.purebasename
def __repr__(self):
return fmt("module {0}", self.name)
return f"module {self.name}"
def configure(self, session):
session.config["module"] = self.name
@ -175,7 +171,7 @@ class Code(Target):
def __repr__(self):
lines = self.code.split("\n")
return fmt("code: {0!j}", lines)
return f"code: {json.repr(lines)}"
def configure(self, session):
session.config["code"] = self.code

View file

@ -7,7 +7,6 @@
import collections
import functools
import json
import io
import pytest
import random
@ -16,7 +15,7 @@ import socket
import threading
import time
from debugpy.common import log, messaging
from debugpy.common import json, log, messaging
from tests.patterns import some
@ -45,9 +44,9 @@ class JsonMemoryStream(object):
def _log_message(self, dir, data):
format_string = "{0} {1} " + (
"{2!j:indent=None}" if isinstance(data, list) else "{2!j}"
"{2:indent=None}" if isinstance(data, list) else "{2}"
)
return log.debug(format_string, self.name, dir, data)
return log.debug(format_string, self.name, dir, json.repr(data))
def read_json(self, decoder=None):
decoder = decoder if decoder is not None else self.json_decoder_factory()

View file

@ -7,7 +7,6 @@ import pytest
import re
import sys
from debugpy.common import fmt
import tests
from tests import debug, test_data
from tests.debug import runners, targets
@ -229,10 +228,10 @@ def test_log_point(pyfile, target, run, condition):
assert not session.captured_stdout()
expected_stdout = "".join(
(fmt(r"{0}\r?\n", re.escape(str(i))) for i in range(0, 10))
(r"{0}\r?\n".format(re.escape(str(i))) for i in range(0, 10))
)
expected_stderr = "".join(
(fmt(r"{0}\r?\n", re.escape(str(i * 10))) for i in range(0, 10))
(r"{0}\r?\n".format(re.escape(str(i * 10))) for i in range(0, 10))
)
assert session.output("stdout") == some.str.matching(expected_stdout)
assert session.output("stderr") == some.str.matching(expected_stderr)
@ -286,7 +285,7 @@ def test_add_and_remove_breakpoint(pyfile, target, run):
)
session.request_continue()
expected_stdout = "".join((fmt("{0}\n", i) for i in range(0, 10)))
expected_stdout = "".join(f"{i}\n" for i in range(0, 10))
assert session.output("stdout") == expected_stdout

View file

@ -4,6 +4,8 @@
import pytest
from debugpy.common import json
import tests
from tests import code, debug, log, test_data
from tests.debug import targets
@ -48,7 +50,7 @@ def test_exceptions_and_exclude_rules(pyfile, target, run, scenario, exc_type):
rules = [{"path": code_to_debug.dirname, "include": False}]
else:
pytest.fail(scenario)
log.info("Rules: {0!j}", rules)
log.info("Rules: {0}", json.repr(rules))
with debug.Session() as session:
session.expected_exit_code = some.int
@ -94,7 +96,7 @@ def test_exceptions_and_partial_exclude_rules(pyfile, target, run, scenario):
rules = [{"path": call_me_back_dir, "include": False}]
else:
pytest.fail(scenario)
log.info("Rules: {0!j}", rules)
log.info("Rules: {0}", json.repr(rules))
with debug.Session() as session:
session.expected_exit_code = some.int

View file

@ -7,13 +7,13 @@ import os
import pytest_timeout
import sys
from debugpy.common import log
from debugpy.common import json, log
def dump():
if log.log_dir is None:
return
log.info("Dumping logs from {0!j}", log.log_dir)
log.info("Dumping logs from {0}", json.repr(log.log_dir))
for dirpath, dirnames, filenames in os.walk(log.log_dir):
for name in sorted(filenames):

View file

@ -12,7 +12,7 @@ import socket
import threading
import time
from debugpy.common import compat, fmt, log
from debugpy.common import compat, log
from tests.patterns import some
@ -115,13 +115,13 @@ class WebRequest(object):
func = getattr(requests, method)
self._worker_thread = threading.Thread(
target=lambda: self._worker(func, *args, **kwargs),
name=fmt("WebRequest({0})", self),
name=f"WebRequest({self})",
)
self._worker_thread.daemon = True
self._worker_thread.start()
def __str__(self):
return fmt("HTTP {0} {1}", self.method.upper(), self.url)
return f"HTTP {self.method.upper()} {self.url}"
def _worker(self, func, *args, **kwargs):
try:
@ -158,7 +158,7 @@ class WebServer(object):
def __init__(self, port):
self.port = port
self.url = fmt("http://localhost:{0}", port)
self.url = f"http://localhost:{port}"
def __enter__(self):
"""Blocks until the server starts listening on self.port.

View file

@ -12,7 +12,7 @@ import py.path
import re
import sys
from debugpy.common import compat, fmt
from debugpy.common import compat
from debugpy.common.compat import unicode, xrange
import pydevd_file_utils
@ -90,7 +90,7 @@ class Not(Some):
self.pattern = pattern
def __repr__(self):
return fmt("~{0!r}", self.pattern)
return f"~{self.pattern!r}"
def matches(self, value):
return value != self.pattern
@ -108,7 +108,7 @@ class Either(Some):
try:
return self.name
except AttributeError:
return fmt("({0})", " | ".join(repr(pat) for pat in self.patterns))
return "({0})".format(" | ".join(repr(pat) for pat in self.patterns))
def matches(self, value):
return any(pattern == value for pattern in self.patterns)
@ -156,7 +156,7 @@ class InstanceOf(Some):
name = self.name
else:
name = " | ".join(cls.__name__ for cls in self.classinfo)
return fmt("<{0}>", name)
return f"<{name}>"
def matches(self, value):
return isinstance(value, self.classinfo)
@ -180,7 +180,7 @@ class Path(Some):
self.path = path
def __repr__(self):
return fmt("path({0!r})", self.path)
return "path({self.path!r})"
def __str__(self):
return compat.filename_str(self.path)
@ -218,7 +218,7 @@ class ListContaining(Some):
if not self.items:
return "[...]"
s = repr(list(self.items))
return fmt("[..., {0}, ...]", s[1:-1])
return f"[..., {s[1:-1]}, ...]"
def __getstate__(self):
items = ["\002...\003"]
@ -302,7 +302,7 @@ class SuchThat(Also):
try:
return self.name
except AttributeError:
return fmt("({0!r} if {1})", self.pattern, compat.nameof(self.condition))
return f"({self.pattern!r} if {compat.nameof(self.condition)})"
def _also(self, value):
return self.condition(value)
@ -321,7 +321,7 @@ class InRange(Also):
try:
return self.name
except AttributeError:
return fmt("({0!r} <= {1!r} < {2!r})", self.start, self.pattern, self.stop)
return f"({self.start!r} <= {self.pattern!r} < {self.stop!r})"
def _also(self, value):
return self.start <= value < self.stop
@ -360,7 +360,7 @@ class NotEqualTo(Also):
self.obj = obj
def __repr__(self):
return fmt("<!={0!r}>", self.obj)
return f"<!={self.obj!r}>"
def _also(self, value):
return self.obj != value
@ -375,7 +375,7 @@ class SameAs(Also):
self.obj = obj
def __repr__(self):
return fmt("<is {0!r}>", self.obj)
return f"<is {self.obj!r}>"
def _also(self, value):
return self.obj is value

View file

@ -10,7 +10,7 @@ import sys
import threading
import types
from debugpy.common import compat, fmt, log, timestamp
from debugpy.common import compat, log, timestamp
import tests
from tests import code, logs
from tests.debug import runners, session, targets
@ -57,7 +57,7 @@ def test_wrapper(request, long_tmpdir):
log_subdir = request.node.nodeid
log_subdir = log_subdir.replace("::", "/")
for ch in r":?*|<>":
log_subdir = log_subdir.replace(ch, fmt("&#{0};", ord(ch)))
log_subdir = log_subdir.replace(ch, f"&#{ord(ch)};")
log.log_dir += "/" + log_subdir
try:

View file

@ -7,7 +7,7 @@ import pytest
import pytest_timeout
import sys
from debugpy.common import fmt, log
from debugpy.common import log
import tests
from tests import logs
@ -30,13 +30,13 @@ def pytest_configure(config):
log.log_dir = config.option.debugpy_log_dir
else:
bits = 64 if sys.maxsize > 2 ** 32 else 32
ver = fmt("{0}.{1}-{bits}", *sys.version_info, bits=bits)
ver = "{0}.{1}-{bits}".format(*sys.version_info, bits=bits)
log.log_dir = (tests.root / "_logs" / ver).strpath
log.info("debugpy and pydevd logs will be under {0}", log.log_dir)
def pytest_report_header(config):
log.describe_environment(fmt("Test environment for tests-{0}", os.getpid()))
log.describe_environment(f"Test environment for tests-{os.getpid()}")
@pytest.hookimpl(hookwrapper=True, tryfirst=True)

View file

@ -7,7 +7,7 @@ import contextlib
import itertools
import threading
from debugpy.common import compat, fmt, log, messaging, timestamp
from debugpy.common import compat, json, log, messaging, timestamp
from debugpy.common.compat import queue
from tests.patterns import some
@ -18,9 +18,9 @@ SINGLE_LINE_REPR_LIMIT = 120
be formatted to use multiple shorter lines if possible.
"""
# For use by Expectation.__repr__. Uses fmt() to create unique instances.
_INDENT = fmt("{0}", "_INDENT")
_DEDENT = fmt("{0}", "_DEDENT")
# For use by Expectation.__repr__. Uses format() to create unique instances.
_INDENT = "{0}".format("_INDENT")
_DEDENT = "{0}".format("_DEDENT")
class Timeline(object):
@ -36,7 +36,7 @@ class Timeline(object):
self._record_queue = queue.Queue()
self._recorder_thread = threading.Thread(
target=self._recorder_worker, name=fmt("{0} recorder", self)
target=self._recorder_worker, name=f"{self} recorder"
)
self._recorder_thread.daemon = True
self._recorder_thread.start()
@ -275,7 +275,7 @@ class Timeline(object):
assert expectation not in self.new()
def _explain_how_realized(self, expectation, reasons):
message = fmt("Realized {0!r}", expectation)
message = f"Realized {expectation!r}"
# For the breakdown, we want to skip any expectations that were exact occurrences,
# since there's no point explaining that occurrence was realized by itself.
@ -288,14 +288,14 @@ class Timeline(object):
# one, then we have already printed it, so just add the explanation.
reason = reasons[expectation]
if "\n" in message:
message += fmt(" == {0!r}", reason)
message += f" == {reason!r}"
else:
message += fmt("\n == {0!r}", reason)
message += f"\n == {reason!r}"
elif reasons:
# Otherwise, break it down expectation by expectation.
message += ":"
for exp, reason in reasons.items():
message += fmt("\n\n where {0!r}\n == {1!r}", exp, reason)
message += "\n\n where {exp!r}\n == {reason!r}"
else:
message += "."
@ -501,7 +501,7 @@ class DerivativeExpectation(Expectation):
if len(timelines) > 1:
offending_expectations = ""
for tl_id, tl in timelines.items():
offending_expectations += fmt("\n {0}: {1!r}\n", tl_id, tl)
offending_expectations += f"\n {tl_id}: {tl!r}\n"
raise log.error(
"Cannot mix expectations from multiple timelines:\n{0}",
offending_expectations,
@ -753,7 +753,7 @@ class PatternExpectation(Expectation):
rest = repr(self.circumstances[1:])
if rest.endswith(",)"):
rest = rest[:-2] + ")"
return fmt("<{0}{1}>", self.circumstances[0], rest)
return f"<{self.circumstances[0]}{rest}>"
def __repr__(self):
return self.describe()
@ -768,8 +768,8 @@ def _describe_message(message_type, *items):
d = collections.OrderedDict(items)
# Keep it all on one line if it's short enough, but indent longer ones.
for format_string in "{0!j:indent=None}", "{0!j}":
s = fmt(format_string, d)
for format_string in "{0:indent=None}", "{0}":
s = format_string.format(json.repr(d))
s = "{..., " + s[1:]
# Used by some.dict.containing to inject ... as needed.
@ -816,7 +816,7 @@ def Response(request, body=some.object):
# Try to be as specific as possible.
if isinstance(request, Expectation):
if request.circumstances[0] != "request":
exp.describe = lambda: fmt("response to {0!r}", request)
exp.describe = lambda: f"response to {request!r}"
return
else:
items = (("command", request.circumstances[1]),)
@ -951,18 +951,13 @@ class Occurrence(Expectation):
return hash(id(self))
def __repr__(self):
return fmt(
"{2}{0}.{1}",
self.index,
self.describe_circumstances(),
"" if self.observed else "*",
)
return ("" if self.observed else "*") + f"{self.index}.{self.describe_circumstances()}"
def describe_circumstances(self):
rest = repr(self.circumstances[1:])
if rest.endswith(",)"):
rest = rest[:-2] + ")"
return fmt("{0}{1}", self.circumstances[0], rest)
return f"{self.circumstances[0]}{rest}"
class MessageOccurrence(Occurrence):
@ -1019,9 +1014,9 @@ class MessageOccurrence(Occurrence):
id = collections.OrderedDict(self._id)
# Keep it all on one line if it's short enough, but indent longer ones.
s = fmt("{0!j:indent=None}", id)
s = f"{json.repr(id):indent=None}"
if len(s) > SINGLE_LINE_REPR_LIMIT:
s = fmt("{0!j}", id)
s = f"{json.repr(id)}"
return s
# For messages, we don't want to include their index, because they already have

View file

@ -19,13 +19,13 @@ import sys
import threading
import time
from debugpy.common import fmt, log, messaging
from debugpy.common import log, messaging
from tests.watchdog import worker
WATCHDOG_TIMEOUT = 3
_name = fmt("watchdog-{0}", os.getpid())
_name = f"watchdog-{os.getpid()}"
_stream = None
_process = None
_worker_log_filename = None
@ -57,7 +57,7 @@ def start():
def _dump_worker_log(command, problem, exc_info=None):
reason = fmt("{0}.{1}() {2}", _name, command, problem)
reason = f"{_name}.{command}() {problem}"
if _worker_log_filename is None:
reason += ", but there is no log."
else:
@ -65,9 +65,9 @@ def _dump_worker_log(command, problem, exc_info=None):
with open(_worker_log_filename) as f:
worker_log = f.read()
except Exception:
reason += fmt(", but log {0} could not be retrieved.", _worker_log_filename)
reason += f", but log {_worker_log_filename} could not be retrieved."
else:
reason += fmt("; watchdog worker process log:\n\n{0}", worker_log)
reason += f"; watchdog worker process log:\n\n{worker_log}"
if exc_info is None:
log.error("{0}", reason)
@ -91,7 +91,7 @@ def _invoke(command, *args):
try:
_stream.write_json([command] + list(args))
response = _stream.read_json()
assert response == ["ok"], fmt("{0} {1!r}", _name, response)
assert response == ["ok"], f"{_name} {response!r}"
finally:
timeout.occurred = False
except Exception:

View file

@ -24,13 +24,13 @@ def main(tests_pid):
if "" in sys.path:
sys.path.remove("")
from debugpy.common import fmt, log, messaging
from debugpy.common import log, messaging
# log.stderr_levels |= {"info"}
log.timestamp_format = "06.3f"
log_file = log.to_file(prefix="tests.watchdog")
stream = messaging.JsonIOStream.from_stdio(fmt("tests-{0}", tests_pid))
stream = messaging.JsonIOStream.from_stdio(f"tests-{tests_pid}")
log.info("Spawned WatchDog-{0} for tests-{0}", tests_pid)
tests_process = psutil.Process(tests_pid)
stream.write_json(["watchdog", log_file.filename])
@ -87,7 +87,7 @@ def main(tests_pid):
spawned_processes.pop(pid, None)
else:
raise AssertionError(fmt("Unknown watchdog command: {0!r}", command))
raise AssertionError(f"Unknown watchdog command: {command!r}")
stream.write_json(["ok"])