mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-06 03:56:54 +00:00
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
This commit is contained in:
parent
72ad6dc953
commit
f4cd1ba0d6
813 changed files with 66015 additions and 58839 deletions
|
|
@ -1,10 +1,9 @@
|
|||
# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
|
||||
# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
|
||||
|
||||
"""Control of and utilities for debugging."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import _thread
|
||||
import atexit
|
||||
import contextlib
|
||||
import functools
|
||||
|
|
@ -17,15 +16,18 @@ import reprlib
|
|||
import sys
|
||||
import traceback
|
||||
import types
|
||||
import _thread
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import IO
|
||||
from typing import Iterable
|
||||
from typing import Iterator
|
||||
from typing import Mapping
|
||||
from typing import overload
|
||||
|
||||
from typing import (
|
||||
overload,
|
||||
Any, Callable, IO, Iterable, Iterator, Mapping,
|
||||
)
|
||||
|
||||
from coverage.misc import human_sorted_items, isolate_module
|
||||
from coverage.types import AnyCallable, TWritable
|
||||
from coverage.misc import human_sorted_items
|
||||
from coverage.misc import isolate_module
|
||||
from coverage.types import AnyCallable
|
||||
from coverage.types import TWritable
|
||||
|
||||
os = isolate_module(os)
|
||||
|
||||
|
|
@ -53,12 +55,12 @@ class DebugControl:
|
|||
self.suppress_callers = False
|
||||
|
||||
filters = []
|
||||
if self.should("process"):
|
||||
if self.should('process'):
|
||||
filters.append(CwdTracker().filter)
|
||||
filters.append(ProcessTracker().filter)
|
||||
if self.should("pytest"):
|
||||
if self.should('pytest'):
|
||||
filters.append(PytestTracker().filter)
|
||||
if self.should("pid"):
|
||||
if self.should('pid'):
|
||||
filters.append(add_pid_and_tid)
|
||||
|
||||
self.output = DebugOutputFile.get_one(
|
||||
|
|
@ -69,11 +71,11 @@ class DebugControl:
|
|||
self.raw_output = self.output.outfile
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<DebugControl options={self.options!r} raw_output={self.raw_output!r}>"
|
||||
return f'<DebugControl options={self.options!r} raw_output={self.raw_output!r}>'
|
||||
|
||||
def should(self, option: str) -> bool:
|
||||
"""Decide whether to output debug information in category `option`."""
|
||||
if option == "callers" and self.suppress_callers:
|
||||
if option == 'callers' and self.suppress_callers:
|
||||
return False
|
||||
return (option in self.options)
|
||||
|
||||
|
|
@ -96,20 +98,21 @@ class DebugControl:
|
|||
after the message.
|
||||
|
||||
"""
|
||||
self.output.write(msg + "\n")
|
||||
self.output.write(msg + '\n')
|
||||
if exc is not None:
|
||||
self.output.write("".join(traceback.format_exception(None, exc, exc.__traceback__)))
|
||||
if self.should("self"):
|
||||
caller_self = inspect.stack()[1][0].f_locals.get("self")
|
||||
self.output.write(''.join(traceback.format_exception(None, exc, exc.__traceback__)))
|
||||
if self.should('self'):
|
||||
caller_self = inspect.stack()[1][0].f_locals.get('self')
|
||||
if caller_self is not None:
|
||||
self.output.write(f"self: {caller_self!r}\n")
|
||||
if self.should("callers"):
|
||||
self.output.write(f'self: {caller_self!r}\n')
|
||||
if self.should('callers'):
|
||||
dump_stack_frames(out=self.output, skip=1)
|
||||
self.output.flush()
|
||||
|
||||
|
||||
class NoDebugging(DebugControl):
|
||||
"""A replacement for DebugControl that will never try to do anything."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
# pylint: disable=super-init-not-called
|
||||
...
|
||||
|
|
@ -120,12 +123,12 @@ class NoDebugging(DebugControl):
|
|||
|
||||
def write(self, msg: str, *, exc: BaseException | None = None) -> None:
|
||||
"""This will never be called."""
|
||||
raise AssertionError("NoDebugging.write should never be called.")
|
||||
raise AssertionError('NoDebugging.write should never be called.')
|
||||
|
||||
|
||||
def info_header(label: str) -> str:
|
||||
"""Make a nice header string."""
|
||||
return "--{:-<60s}".format(" "+label+" ")
|
||||
return '--{:-<60s}'.format(' ' + label + ' ')
|
||||
|
||||
|
||||
def info_formatter(info: Iterable[tuple[str, Any]]) -> Iterator[str]:
|
||||
|
|
@ -142,17 +145,17 @@ def info_formatter(info: Iterable[tuple[str, Any]]) -> Iterator[str]:
|
|||
assert all(len(l) < label_len for l, _ in info)
|
||||
for label, data in info:
|
||||
if data == []:
|
||||
data = "-none-"
|
||||
data = '-none-'
|
||||
if isinstance(data, tuple) and len(repr(tuple(data))) < 30:
|
||||
# Convert to tuple to scrub namedtuples.
|
||||
yield "%*s: %r" % (label_len, label, tuple(data))
|
||||
yield '%*s: %r' % (label_len, label, tuple(data))
|
||||
elif isinstance(data, (list, set, tuple)):
|
||||
prefix = "%*s:" % (label_len, label)
|
||||
prefix = '%*s:' % (label_len, label)
|
||||
for e in data:
|
||||
yield "%*s %s" % (label_len+1, prefix, e)
|
||||
prefix = ""
|
||||
yield '%*s %s' % (label_len + 1, prefix, e)
|
||||
prefix = ''
|
||||
else:
|
||||
yield "%*s: %s" % (label_len, label, data)
|
||||
yield '%*s: %s' % (label_len, label, data)
|
||||
|
||||
|
||||
def write_formatted_info(
|
||||
|
|
@ -170,35 +173,38 @@ def write_formatted_info(
|
|||
"""
|
||||
write(info_header(header))
|
||||
for line in info_formatter(info):
|
||||
write(f" {line}")
|
||||
write(f' {line}')
|
||||
|
||||
|
||||
def exc_one_line(exc: Exception) -> str:
|
||||
"""Get a one-line summary of an exception, including class name and message."""
|
||||
lines = traceback.format_exception_only(type(exc), exc)
|
||||
return "|".join(l.rstrip() for l in lines)
|
||||
return '|'.join(l.rstrip() for l in lines)
|
||||
|
||||
|
||||
_FILENAME_REGEXES: list[tuple[str, str]] = [
|
||||
(r".*[/\\]pytest-of-.*[/\\]pytest-\d+([/\\]popen-gw\d+)?", "tmp:"),
|
||||
(r'.*[/\\]pytest-of-.*[/\\]pytest-\d+([/\\]popen-gw\d+)?', 'tmp:'),
|
||||
]
|
||||
_FILENAME_SUBS: list[tuple[str, str]] = []
|
||||
|
||||
|
||||
@overload
|
||||
def short_filename(filename: str) -> str:
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def short_filename(filename: None) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def short_filename(filename: str | None) -> str | None:
|
||||
"""Shorten a file name. Directories are replaced by prefixes like 'syspath:'"""
|
||||
if not _FILENAME_SUBS:
|
||||
for pathdir in sys.path:
|
||||
_FILENAME_SUBS.append((pathdir, "syspath:"))
|
||||
_FILENAME_SUBS.append((pathdir, 'syspath:'))
|
||||
import coverage
|
||||
_FILENAME_SUBS.append((os.path.dirname(coverage.__file__), "cov:"))
|
||||
_FILENAME_SUBS.append((os.path.dirname(coverage.__file__), 'cov:'))
|
||||
_FILENAME_SUBS.sort(key=(lambda pair: len(pair[0])), reverse=True)
|
||||
if filename is not None:
|
||||
for pat, sub in _FILENAME_REGEXES:
|
||||
|
|
@ -237,9 +243,9 @@ def short_stack(
|
|||
"""
|
||||
# Regexes in initial frames that we don't care about.
|
||||
BORING_PRELUDE = [
|
||||
"<string>", # pytest-xdist has string execution.
|
||||
r"\bigor.py$", # Our test runner.
|
||||
r"\bsite-packages\b", # pytest etc getting to our tests.
|
||||
'<string>', # pytest-xdist has string execution.
|
||||
r'\bigor.py$', # Our test runner.
|
||||
r'\bsite-packages\b', # pytest etc getting to our tests.
|
||||
]
|
||||
|
||||
stack: Iterable[inspect.FrameInfo] = inspect.stack()[:skip:-1]
|
||||
|
|
@ -251,20 +257,20 @@ def short_stack(
|
|||
)
|
||||
lines = []
|
||||
for frame_info in stack:
|
||||
line = f"{frame_info.function:>30s} : "
|
||||
line = f'{frame_info.function:>30s} : '
|
||||
if frame_ids:
|
||||
line += f"{id(frame_info.frame):#x} "
|
||||
line += f'{id(frame_info.frame):#x} '
|
||||
filename = frame_info.filename
|
||||
if short_filenames:
|
||||
filename = short_filename(filename)
|
||||
line += f"{filename}:{frame_info.lineno}"
|
||||
line += f'{filename}:{frame_info.lineno}'
|
||||
lines.append(line)
|
||||
return "\n".join(lines)
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def dump_stack_frames(out: TWritable, skip: int = 0) -> None:
|
||||
"""Print a summary of the stack to `out`."""
|
||||
out.write(short_stack(skip=skip+1) + "\n")
|
||||
out.write(short_stack(skip=skip + 1) + '\n')
|
||||
|
||||
|
||||
def clipped_repr(text: str, numchars: int = 50) -> str:
|
||||
|
|
@ -285,36 +291,37 @@ def short_id(id64: int) -> int:
|
|||
def add_pid_and_tid(text: str) -> str:
|
||||
"""A filter to add pid and tid to debug messages."""
|
||||
# Thread ids are useful, but too long. Make a shorter one.
|
||||
tid = f"{short_id(_thread.get_ident()):04x}"
|
||||
text = f"{os.getpid():5d}.{tid}: {text}"
|
||||
tid = f'{short_id(_thread.get_ident()):04x}'
|
||||
text = f'{os.getpid():5d}.{tid}: {text}'
|
||||
return text
|
||||
|
||||
|
||||
AUTO_REPR_IGNORE = {"$coverage.object_id"}
|
||||
AUTO_REPR_IGNORE = {'$coverage.object_id'}
|
||||
|
||||
|
||||
def auto_repr(self: Any) -> str:
|
||||
"""A function implementing an automatic __repr__ for debugging."""
|
||||
show_attrs = (
|
||||
(k, v) for k, v in self.__dict__.items()
|
||||
if getattr(v, "show_repr_attr", True)
|
||||
and not inspect.ismethod(v)
|
||||
and k not in AUTO_REPR_IGNORE
|
||||
if getattr(v, 'show_repr_attr', True) and
|
||||
not inspect.ismethod(v) and
|
||||
k not in AUTO_REPR_IGNORE
|
||||
)
|
||||
return "<{klass} @{id:#x}{attrs}>".format(
|
||||
return '<{klass} @{id:#x}{attrs}>'.format(
|
||||
klass=self.__class__.__name__,
|
||||
id=id(self),
|
||||
attrs="".join(f" {k}={v!r}" for k, v in show_attrs),
|
||||
attrs=''.join(f' {k}={v!r}' for k, v in show_attrs),
|
||||
)
|
||||
|
||||
|
||||
def simplify(v: Any) -> Any: # pragma: debugging
|
||||
"""Turn things which are nearly dict/list/etc into dict/list/etc."""
|
||||
if isinstance(v, dict):
|
||||
return {k:simplify(vv) for k, vv in v.items()}
|
||||
return {k: simplify(vv) for k, vv in v.items()}
|
||||
elif isinstance(v, (list, tuple)):
|
||||
return type(v)(simplify(vv) for vv in v)
|
||||
elif hasattr(v, "__dict__"):
|
||||
return simplify({"."+k: v for k, v in v.__dict__.items()})
|
||||
elif hasattr(v, '__dict__'):
|
||||
return simplify({'.' + k: v for k, v in v.__dict__.items()})
|
||||
else:
|
||||
return v
|
||||
|
||||
|
|
@ -343,12 +350,13 @@ def filter_text(text: str, filters: Iterable[Callable[[str], str]]) -> str:
|
|||
lines = []
|
||||
for line in text.splitlines():
|
||||
lines.extend(filter_fn(line).splitlines())
|
||||
text = "\n".join(lines)
|
||||
text = '\n'.join(lines)
|
||||
return text + ending
|
||||
|
||||
|
||||
class CwdTracker:
|
||||
"""A class to add cwd info to debug messages."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.cwd: str | None = None
|
||||
|
||||
|
|
@ -356,32 +364,33 @@ class CwdTracker:
|
|||
"""Add a cwd message for each new cwd."""
|
||||
cwd = os.getcwd()
|
||||
if cwd != self.cwd:
|
||||
text = f"cwd is now {cwd!r}\n" + text
|
||||
text = f'cwd is now {cwd!r}\n' + text
|
||||
self.cwd = cwd
|
||||
return text
|
||||
|
||||
|
||||
class ProcessTracker:
|
||||
"""Track process creation for debug logging."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.pid: int = os.getpid()
|
||||
self.did_welcome = False
|
||||
|
||||
def filter(self, text: str) -> str:
|
||||
"""Add a message about how new processes came to be."""
|
||||
welcome = ""
|
||||
welcome = ''
|
||||
pid = os.getpid()
|
||||
if self.pid != pid:
|
||||
welcome = f"New process: forked {self.pid} -> {pid}\n"
|
||||
welcome = f'New process: forked {self.pid} -> {pid}\n'
|
||||
self.pid = pid
|
||||
elif not self.did_welcome:
|
||||
argv = getattr(sys, "argv", None)
|
||||
argv = getattr(sys, 'argv', None)
|
||||
welcome = (
|
||||
f"New process: {pid=}, executable: {sys.executable!r}\n"
|
||||
+ f"New process: cmd: {argv!r}\n"
|
||||
f'New process: {pid=}, executable: {sys.executable!r}\n' +
|
||||
f'New process: cmd: {argv!r}\n'
|
||||
)
|
||||
if hasattr(os, "getppid"):
|
||||
welcome += f"New process parent pid: {os.getppid()!r}\n"
|
||||
if hasattr(os, 'getppid'):
|
||||
welcome += f'New process parent pid: {os.getppid()!r}\n'
|
||||
|
||||
if welcome:
|
||||
self.did_welcome = True
|
||||
|
|
@ -392,20 +401,22 @@ class ProcessTracker:
|
|||
|
||||
class PytestTracker:
|
||||
"""Track the current pytest test name to add to debug messages."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.test_name: str | None = None
|
||||
|
||||
def filter(self, text: str) -> str:
|
||||
"""Add a message when the pytest test changes."""
|
||||
test_name = os.getenv("PYTEST_CURRENT_TEST")
|
||||
test_name = os.getenv('PYTEST_CURRENT_TEST')
|
||||
if test_name != self.test_name:
|
||||
text = f"Pytest context: {test_name}\n" + text
|
||||
text = f'Pytest context: {test_name}\n' + text
|
||||
self.test_name = test_name
|
||||
return text
|
||||
|
||||
|
||||
class DebugOutputFile:
|
||||
"""A file-like object that includes pid and cwd information."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
outfile: IO[str] | None,
|
||||
|
|
@ -444,21 +455,21 @@ class DebugOutputFile:
|
|||
the_one, is_interim = cls._get_singleton_data()
|
||||
if the_one is None or is_interim:
|
||||
if file_name is not None:
|
||||
fileobj = open(file_name, "a", encoding="utf-8")
|
||||
fileobj = open(file_name, 'a', encoding='utf-8')
|
||||
else:
|
||||
# $set_env.py: COVERAGE_DEBUG_FILE - Where to write debug output
|
||||
file_name = os.getenv("COVERAGE_DEBUG_FILE", FORCED_DEBUG_FILE)
|
||||
if file_name in ("stdout", "stderr"):
|
||||
file_name = os.getenv('COVERAGE_DEBUG_FILE', FORCED_DEBUG_FILE)
|
||||
if file_name in ('stdout', 'stderr'):
|
||||
fileobj = getattr(sys, file_name)
|
||||
elif file_name:
|
||||
fileobj = open(file_name, "a", encoding="utf-8")
|
||||
fileobj = open(file_name, 'a', encoding='utf-8')
|
||||
atexit.register(fileobj.close)
|
||||
else:
|
||||
fileobj = sys.stderr
|
||||
the_one = cls(fileobj, filters)
|
||||
cls._set_singleton_data(the_one, interim)
|
||||
|
||||
if not(the_one.filters):
|
||||
if not (the_one.filters):
|
||||
the_one.filters = list(filters)
|
||||
return the_one
|
||||
|
||||
|
|
@ -467,8 +478,8 @@ class DebugOutputFile:
|
|||
# a process-wide singleton. So stash it in sys.modules instead of
|
||||
# on a class attribute. Yes, this is aggressively gross.
|
||||
|
||||
SYS_MOD_NAME = "$coverage.debug.DebugOutputFile.the_one"
|
||||
SINGLETON_ATTR = "the_one_and_is_interim"
|
||||
SYS_MOD_NAME = '$coverage.debug.DebugOutputFile.the_one'
|
||||
SINGLETON_ATTR = 'the_one_and_is_interim'
|
||||
|
||||
@classmethod
|
||||
def _set_singleton_data(cls, the_one: DebugOutputFile, interim: bool) -> None:
|
||||
|
|
@ -504,7 +515,7 @@ class DebugOutputFile:
|
|||
def log(msg: str, stack: bool = False) -> None: # pragma: debugging
|
||||
"""Write a log message as forcefully as possible."""
|
||||
out = DebugOutputFile.get_one(interim=True)
|
||||
out.write(msg+"\n")
|
||||
out.write(msg + '\n')
|
||||
if stack:
|
||||
dump_stack_frames(out=out, skip=1)
|
||||
|
||||
|
|
@ -519,8 +530,8 @@ def decorate_methods(
|
|||
for name, meth in inspect.getmembers(cls, inspect.isroutine):
|
||||
if name not in cls.__dict__:
|
||||
continue
|
||||
if name != "__init__":
|
||||
if not private and name.startswith("_"):
|
||||
if name != '__init__':
|
||||
if not private and name.startswith('_'):
|
||||
continue
|
||||
if name in butnot:
|
||||
continue
|
||||
|
|
@ -542,7 +553,8 @@ def break_in_pudb(func: AnyCallable) -> AnyCallable: # pragma: debugging
|
|||
|
||||
OBJ_IDS = itertools.count()
|
||||
CALLS = itertools.count()
|
||||
OBJ_ID_ATTR = "$coverage.object_id"
|
||||
OBJ_ID_ATTR = '$coverage.object_id'
|
||||
|
||||
|
||||
def show_calls(
|
||||
show_args: bool = True,
|
||||
|
|
@ -555,27 +567,27 @@ def show_calls(
|
|||
def _wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:
|
||||
oid = getattr(self, OBJ_ID_ATTR, None)
|
||||
if oid is None:
|
||||
oid = f"{os.getpid():08d} {next(OBJ_IDS):04d}"
|
||||
oid = f'{os.getpid():08d} {next(OBJ_IDS):04d}'
|
||||
setattr(self, OBJ_ID_ATTR, oid)
|
||||
extra = ""
|
||||
extra = ''
|
||||
if show_args:
|
||||
eargs = ", ".join(map(repr, args))
|
||||
ekwargs = ", ".join("{}={!r}".format(*item) for item in kwargs.items())
|
||||
extra += "("
|
||||
eargs = ', '.join(map(repr, args))
|
||||
ekwargs = ', '.join('{}={!r}'.format(*item) for item in kwargs.items())
|
||||
extra += '('
|
||||
extra += eargs
|
||||
if eargs and ekwargs:
|
||||
extra += ", "
|
||||
extra += ', '
|
||||
extra += ekwargs
|
||||
extra += ")"
|
||||
extra += ')'
|
||||
if show_stack:
|
||||
extra += " @ "
|
||||
extra += "; ".join(short_stack(short_filenames=True).splitlines())
|
||||
extra += ' @ '
|
||||
extra += '; '.join(short_stack(short_filenames=True).splitlines())
|
||||
callid = next(CALLS)
|
||||
msg = f"{oid} {callid:04d} {func.__name__}{extra}\n"
|
||||
msg = f'{oid} {callid:04d} {func.__name__}{extra}\n'
|
||||
DebugOutputFile.get_one(interim=True).write(msg)
|
||||
ret = func(self, *args, **kwargs)
|
||||
if show_return:
|
||||
msg = f"{oid} {callid:04d} {func.__name__} return {ret!r}\n"
|
||||
msg = f'{oid} {callid:04d} {func.__name__} return {ret!r}\n'
|
||||
DebugOutputFile.get_one(interim=True).write(msg)
|
||||
return ret
|
||||
return _wrapper
|
||||
|
|
@ -595,9 +607,9 @@ def relevant_environment_display(env: Mapping[str, str]) -> list[tuple[str, str]
|
|||
A list of pairs (name, value) to show.
|
||||
|
||||
"""
|
||||
slugs = {"COV", "PY"}
|
||||
include = {"HOME", "TEMP", "TMP"}
|
||||
cloak = {"API", "TOKEN", "KEY", "SECRET", "PASS", "SIGNATURE"}
|
||||
slugs = {'COV', 'PY'}
|
||||
include = {'HOME', 'TEMP', 'TMP'}
|
||||
cloak = {'API', 'TOKEN', 'KEY', 'SECRET', 'PASS', 'SIGNATURE'}
|
||||
|
||||
to_show = []
|
||||
for name, val in env.items():
|
||||
|
|
@ -608,6 +620,6 @@ def relevant_environment_display(env: Mapping[str, str]) -> list[tuple[str, str]
|
|||
keep = True
|
||||
if keep:
|
||||
if any(slug in name for slug in cloak):
|
||||
val = re.sub(r"\w", "*", val)
|
||||
val = re.sub(r'\w', '*', val)
|
||||
to_show.append((name, val))
|
||||
return human_sorted_items(to_show)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue