Skip to content

Commit 0d1f4c6

Browse files
Merge pull request #11914 - Activate flake8-bugbear and flake8-pyi
2 parents e28f35c + 3101c02 commit 0d1f4c6

18 files changed

+64
-52
lines changed

pyproject.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,24 @@ ignore = "W009"
128128
src = ["src"]
129129
line-length = 88
130130
select = [
131+
"B", # bugbear
131132
"D", # pydocstyle
132133
"E", # pycodestyle
133134
"F", # pyflakes
134135
"I", # isort
136+
"PYI", # flake8-pyi
135137
"UP", # pyupgrade
136138
"RUF", # ruff
137139
"W", # pycodestyle
138140
]
139141
ignore = [
142+
# bugbear ignore
143+
"B004", # Using `hasattr(x, "__call__")` to test if x is callable is unreliable.
144+
"B007", # Loop control variable `i` not used within loop body
145+
"B009", # Do not call `getattr` with a constant attribute value
146+
"B010", # [*] Do not call `setattr` with a constant attribute value.
147+
"B011", # Do not `assert False` (`python -O` removes these calls)
148+
"B028", # No explicit `stacklevel` keyword argument found
140149
# pycodestyle ignore
141150
# pytest can do weird low-level things, and we usually know
142151
# what we're doing when we use type(..) is ...
@@ -180,4 +189,6 @@ known-local-folder = ["pytest", "_pytest"]
180189
lines-after-imports = 2
181190

182191
[tool.ruff.lint.per-file-ignores]
192+
"src/_pytest/_py/**/*.py" = ["B", "PYI"]
183193
"src/_pytest/_version.py" = ["I001"]
194+
"testing/python/approx.py" = ["B015"]

scripts/prepare-release-pr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def prepare_release_pr(
7979
)
8080
except InvalidFeatureRelease as e:
8181
print(f"{Fore.RED}{e}")
82-
raise SystemExit(1)
82+
raise SystemExit(1) from None
8383

8484
print(f"Version: {Fore.CYAN}{version}")
8585

scripts/update-plugin-list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def main() -> None:
208208
f.write(f"This list contains {len(plugins)} plugins.\n\n")
209209
f.write(".. only:: not latex\n\n")
210210

211-
wcwidth # reference library that must exist for tabulate to work
211+
_ = wcwidth # reference library that must exist for tabulate to work
212212
plugin_table = tabulate.tabulate(plugins, headers="keys", tablefmt="rst")
213213
f.write(indent(plugin_table, " "))
214214
f.write("\n\n")

src/_pytest/_io/terminalwriter.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,17 +232,17 @@ def _highlight(
232232
# which may lead to the previous color being propagated to the
233233
# start of the expression, so reset first.
234234
return "\x1b[0m" + highlighted
235-
except pygments.util.ClassNotFound:
235+
except pygments.util.ClassNotFound as e:
236236
raise UsageError(
237237
"PYTEST_THEME environment variable had an invalid value: '{}'. "
238238
"Only valid pygment styles are allowed.".format(
239239
os.getenv("PYTEST_THEME")
240240
)
241-
)
242-
except pygments.util.OptionError:
241+
) from e
242+
except pygments.util.OptionError as e:
243243
raise UsageError(
244244
"PYTEST_THEME_MODE environment variable had an invalid value: '{}'. "
245245
"The only allowed values are 'dark' and 'light'.".format(
246246
os.getenv("PYTEST_THEME_MODE")
247247
)
248-
)
248+
) from e

src/_pytest/capture.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,8 @@ class CaptureResult(NamedTuple, Generic[AnyStr]):
598598
else:
599599

600600
class CaptureResult(
601-
collections.namedtuple("CaptureResult", ["out", "err"]), Generic[AnyStr]
601+
collections.namedtuple("CaptureResult", ["out", "err"]), # noqa: PYI024
602+
Generic[AnyStr],
602603
):
603604
"""The result of :method:`caplog.readouterr() <pytest.CaptureFixture.readouterr>`."""
604605

src/_pytest/compat.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@
1515
from typing import Callable
1616
from typing import Final
1717
from typing import NoReturn
18-
from typing import TypeVar
19-
20-
21-
_T = TypeVar("_T")
22-
_S = TypeVar("_S")
2318

2419

2520
# fmt: off

src/_pytest/config/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,13 +1848,13 @@ def parse_warning_filter(
18481848
try:
18491849
action: "warnings._ActionKind" = warnings._getaction(action_) # type: ignore[attr-defined]
18501850
except warnings._OptionError as e:
1851-
raise UsageError(error_template.format(error=str(e)))
1851+
raise UsageError(error_template.format(error=str(e))) from None
18521852
try:
18531853
category: Type[Warning] = _resolve_warning_category(category_)
18541854
except Exception:
18551855
exc_info = ExceptionInfo.from_current()
18561856
exception_text = exc_info.getrepr(style="native")
1857-
raise UsageError(error_template.format(error=exception_text))
1857+
raise UsageError(error_template.format(error=exception_text)) from None
18581858
if message and escape:
18591859
message = re.escape(message)
18601860
if module and escape:
@@ -1867,7 +1867,7 @@ def parse_warning_filter(
18671867
except ValueError as e:
18681868
raise UsageError(
18691869
error_template.format(error=f"invalid lineno {lineno_!r}: {e}")
1870-
)
1870+
) from None
18711871
else:
18721872
lineno = 0
18731873
return action, message, category, module, lineno

src/_pytest/unittest.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,8 @@ def _addexcinfo(self, rawexcinfo: "_SysExcInfoType") -> None:
209209
)
210210
# Invoke the attributes to trigger storing the traceback
211211
# trial causes some issue there.
212-
excinfo.value
213-
excinfo.traceback
212+
_ = excinfo.value
213+
_ = excinfo.traceback
214214
except TypeError:
215215
try:
216216
try:
@@ -361,14 +361,21 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None:
361361

362362

363363
# Twisted trial support.
364+
classImplements_has_run = False
364365

365366

366367
@hookimpl(wrapper=True)
367368
def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
368369
if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules:
369370
ut: Any = sys.modules["twisted.python.failure"]
371+
global classImplements_has_run
370372
Failure__init__ = ut.Failure.__init__
371-
check_testcase_implements_trial_reporter()
373+
if not classImplements_has_run:
374+
from twisted.trial.itrial import IReporter
375+
from zope.interface import classImplements
376+
377+
classImplements(TestCaseFunction, IReporter)
378+
classImplements_has_run = True
372379

373380
def excstore(
374381
self, exc_value=None, exc_type=None, exc_tb=None, captureVars=None
@@ -396,16 +403,6 @@ def excstore(
396403
return res
397404

398405

399-
def check_testcase_implements_trial_reporter(done: List[int] = []) -> None:
400-
if done:
401-
return
402-
from twisted.trial.itrial import IReporter
403-
from zope.interface import classImplements
404-
405-
classImplements(TestCaseFunction, IReporter)
406-
done.append(1)
407-
408-
409406
def _is_skipped(obj) -> bool:
410407
"""Return True if the given object has been marked with @unittest.skip."""
411408
return bool(getattr(obj, "__unittest_skip__", False))

testing/_py/test_local.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,9 +1241,9 @@ class TestWINLocalPath:
12411241

12421242
def test_owner_group_not_implemented(self, path1):
12431243
with pytest.raises(NotImplementedError):
1244-
path1.stat().owner
1244+
_ = path1.stat().owner
12451245
with pytest.raises(NotImplementedError):
1246-
path1.stat().group
1246+
_ = path1.stat().group
12471247

12481248
def test_chmod_simple_int(self, path1):
12491249
mode = path1.stat().mode

testing/code/test_excinfo.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ def test_excinfo_no_python_sourcecode(tmp_path: Path) -> None:
387387
excinfo = pytest.raises(ValueError, template.render, h=h)
388388
for item in excinfo.traceback:
389389
print(item) # XXX: for some reason jinja.Template.render is printed in full
390-
item.source # shouldn't fail
390+
_ = item.source # shouldn't fail
391391
if isinstance(item.path, Path) and item.path.name == "test.txt":
392392
assert str(item.source) == "{{ h()}}:"
393393

@@ -418,7 +418,7 @@ def test_codepath_Queue_example() -> None:
418418

419419
def test_match_succeeds():
420420
with pytest.raises(ZeroDivisionError) as excinfo:
421-
0 // 0
421+
_ = 0 // 0
422422
excinfo.match(r".*zero.*")
423423

424424

@@ -584,7 +584,7 @@ def test_repr_source_excinfo(self) -> None:
584584
try:
585585

586586
def f():
587-
1 / 0
587+
_ = 1 / 0
588588

589589
f()
590590

@@ -601,7 +601,7 @@ def f():
601601
print(line)
602602
assert lines == [
603603
" def f():",
604-
"> 1 / 0",
604+
"> _ = 1 / 0",
605605
"E ZeroDivisionError: division by zero",
606606
]
607607

@@ -638,7 +638,7 @@ def test_repr_source_failing_fullsource(self, monkeypatch) -> None:
638638
pr = FormattedExcinfo()
639639

640640
try:
641-
1 / 0
641+
_ = 1 / 0
642642
except ZeroDivisionError:
643643
excinfo = ExceptionInfo.from_current()
644644

@@ -1582,7 +1582,7 @@ def __getattr__(self, attr):
15821582
return getattr(self, "_" + attr)
15831583

15841584
with pytest.raises(RuntimeError) as excinfo:
1585-
RecursionDepthError().trigger
1585+
_ = RecursionDepthError().trigger
15861586
assert "maximum recursion" in str(excinfo.getrepr())
15871587

15881588

0 commit comments

Comments
 (0)