Skip to content

Commit 91188aa

Browse files
authored
Rename B028 to B907, making it optional/opinionated. (#333)
1 parent 4a0db1a commit 91188aa

File tree

4 files changed

+62
-57
lines changed

4 files changed

+62
-57
lines changed

README.rst

+6-2
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,6 @@ limitations make it difficult.
169169

170170
**B027**: Empty method in abstract base class, but has no abstract decorator. Consider adding @abstractmethod.
171171

172-
**B028**: Consider replacing ``f"'{foo}'"`` with ``f"{foo!r}"`` which is both easier to read and will escape quotes inside ``foo`` if that would appear. The check tries to filter out any format specs that are invalid together with ``!r``. If you're using other conversion flags then e.g. ``f"'{foo!a}'"`` can be replaced with ``f"{ascii(foo)!r}"``. Not currently implemented for python<3.8 or ``str.format()`` calls.
173-
174172
Opinionated warnings
175173
~~~~~~~~~~~~~~~~~~~~
176174

@@ -211,6 +209,8 @@ For more information: https://peps.python.org/pep-0618/
211209
Will only trigger on function names where the part after ``visit_`` is a valid ``ast`` type with a non-empty ``_fields`` attribute.
212210
This is meant to be enabled by developers writing visitors using the ``ast`` module, such as flake8 plugin writers.
213211

212+
**B907**: Consider replacing ``f"'{foo}'"`` with ``f"{foo!r}"`` which is both easier to read and will escape quotes inside ``foo`` if that would appear. The check tries to filter out any format specs that are invalid together with ``!r``. If you're using other conversion flags then e.g. ``f"'{foo!a}'"`` can be replaced with ``f"{ascii(foo)!r}"``. Not currently implemented for python<3.8 or ``str.format()`` calls.
213+
214214
**B950**: Line too long. This is a pragmatic equivalent of
215215
``pycodestyle``'s ``E501``: it considers "max-line-length" but only triggers
216216
when the value has been exceeded by **more than 10%**. You will no
@@ -308,6 +308,10 @@ MIT
308308
Change Log
309309
----------
310310

311+
Future
312+
~~~~~~~~~
313+
* Rename B028 to B907, making it optional/opinionated.
314+
311315
23.1.14
312316
~~~~~~~~~
313317

bugbear.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ def visit_With(self, node):
450450
self.generic_visit(node)
451451

452452
def visit_JoinedStr(self, node):
453-
self.check_for_b028(node)
453+
self.check_for_b907(node)
454454
self.generic_visit(node)
455455

456456
def check_for_b005(self, node):
@@ -1014,7 +1014,7 @@ def check_for_b906(self, node: ast.FunctionDef):
10141014
else:
10151015
self.errors.append(B906(node.lineno, node.col_offset))
10161016

1017-
def check_for_b028(self, node: ast.JoinedStr): # noqa: C901
1017+
def check_for_b907(self, node: ast.JoinedStr): # noqa: C901
10181018
# AST structure of strings in f-strings in 3.7 is different enough this
10191019
# implementation doesn't work
10201020
if sys.version_info <= (3, 7):
@@ -1048,7 +1048,7 @@ def myunparse(node: ast.AST) -> str: # pragma: no cover
10481048
and value.value[0] == current_mark
10491049
):
10501050
self.errors.append(
1051-
B028(
1051+
B907(
10521052
variable.lineno,
10531053
variable.col_offset,
10541054
vars=(myunparse(variable.value),),
@@ -1485,12 +1485,6 @@ def visit_Lambda(self, node):
14851485
" decorator. Consider adding @abstractmethod."
14861486
)
14871487
)
1488-
B028 = Error(
1489-
message=(
1490-
"B028 {!r} is manually surrounded by quotes, consider using the `!r` conversion"
1491-
" flag."
1492-
)
1493-
)
14941488

14951489
# Warnings disabled by default.
14961490
B901 = Error(
@@ -1539,6 +1533,13 @@ def visit_Lambda(self, node):
15391533
)
15401534
)
15411535

1536+
B907 = Error(
1537+
message=(
1538+
"B907 {!r} is manually surrounded by quotes, consider using the `!r` conversion"
1539+
" flag."
1540+
)
1541+
)
1542+
15421543
B950 = Error(message="B950 line too long ({} > {} characters)")
15431544

15441545
disabled_by_default = ["B901", "B902", "B903", "B904", "B905", "B906", "B950"]

tests/b028.py renamed to tests/b907.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def foo():
104104
# alignment specifier invalid for strings
105105
f'"{var:=}"'
106106

107-
# other types and combinations are tested in test_b028_format_specifier_permutations
107+
# other types and combinations are tested in test_b907_format_specifier_permutations
108108

109109
# don't attempt to parse complex format specs
110110
f'"{var:{var}}"'

tests/test_bugbear.py

+45-45
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@
3939
B025,
4040
B026,
4141
B027,
42-
B028,
4342
B901,
4443
B902,
4544
B903,
4645
B904,
4746
B905,
4847
B906,
48+
B907,
4949
B950,
5050
BugBearChecker,
5151
BugBearVisitor,
@@ -432,55 +432,55 @@ def test_b027(self):
432432
self.assertEqual(errors, expected)
433433

434434
@unittest.skipIf(sys.version_info < (3, 8), "not implemented for <3.8")
435-
def test_b028(self):
436-
filename = Path(__file__).absolute().parent / "b028.py"
435+
def test_b907(self):
436+
filename = Path(__file__).absolute().parent / "b907.py"
437437
bbc = BugBearChecker(filename=str(filename))
438438
errors = list(bbc.run())
439439
expected = self.errors(
440-
B028(8, 0, vars=("var",)),
441-
B028(9, 0, vars=("var",)),
442-
B028(10, 0, vars=("var",)),
443-
B028(12, 0, vars=("var",)),
444-
B028(13, 0, vars=("var",)),
445-
B028(14, 0, vars=("var",)),
446-
B028(16, 0, vars=("'hello'",)),
447-
B028(17, 0, vars=("foo()",)),
448-
B028(20, 5, vars=("var",)),
449-
B028(25, 5, vars=("var",)),
450-
B028(31, 0, vars=("var",)),
451-
B028(32, 0, vars=("var",)),
452-
B028(33, 0, vars=("var",)),
453-
B028(33, 0, vars=("var2",)),
454-
B028(34, 0, vars=("var",)),
455-
B028(34, 0, vars=("var2",)),
456-
B028(35, 0, vars=("var",)),
457-
B028(35, 0, vars=("var2",)),
458-
B028(38, 0, vars=("var2",)),
459-
B028(41, 0, vars=("var",)),
460-
B028(42, 0, vars=("var.__str__",)),
461-
B028(43, 0, vars=("var.__str__.__repr__",)),
462-
B028(44, 0, vars=("3 + 5" if sys.version_info >= (3, 9) else "BinOp",)),
463-
B028(45, 0, vars=("foo()",)),
464-
B028(46, 0, vars=("None",)),
465-
B028(47, 0, vars=("..." if sys.version_info >= (3, 9) else "Ellipsis",)),
466-
B028(48, 0, vars=("True",)),
467-
B028(51, 0, vars=("var",)),
468-
B028(52, 0, vars=("var",)),
469-
B028(53, 0, vars=("var",)),
470-
B028(54, 0, vars=("var",)),
471-
B028(57, 0, vars=("var",)),
472-
B028(60, 0, vars=("var",)),
473-
B028(64, 0, vars=("var",)),
474-
B028(66, 0, vars=("var",)),
475-
B028(68, 0, vars=("var",)),
440+
B907(8, 0, vars=("var",)),
441+
B907(9, 0, vars=("var",)),
442+
B907(10, 0, vars=("var",)),
443+
B907(12, 0, vars=("var",)),
444+
B907(13, 0, vars=("var",)),
445+
B907(14, 0, vars=("var",)),
446+
B907(16, 0, vars=("'hello'",)),
447+
B907(17, 0, vars=("foo()",)),
448+
B907(20, 5, vars=("var",)),
449+
B907(25, 5, vars=("var",)),
450+
B907(31, 0, vars=("var",)),
451+
B907(32, 0, vars=("var",)),
452+
B907(33, 0, vars=("var",)),
453+
B907(33, 0, vars=("var2",)),
454+
B907(34, 0, vars=("var",)),
455+
B907(34, 0, vars=("var2",)),
456+
B907(35, 0, vars=("var",)),
457+
B907(35, 0, vars=("var2",)),
458+
B907(38, 0, vars=("var2",)),
459+
B907(41, 0, vars=("var",)),
460+
B907(42, 0, vars=("var.__str__",)),
461+
B907(43, 0, vars=("var.__str__.__repr__",)),
462+
B907(44, 0, vars=("3 + 5" if sys.version_info >= (3, 9) else "BinOp",)),
463+
B907(45, 0, vars=("foo()",)),
464+
B907(46, 0, vars=("None",)),
465+
B907(47, 0, vars=("..." if sys.version_info >= (3, 9) else "Ellipsis",)),
466+
B907(48, 0, vars=("True",)),
467+
B907(51, 0, vars=("var",)),
468+
B907(52, 0, vars=("var",)),
469+
B907(53, 0, vars=("var",)),
470+
B907(54, 0, vars=("var",)),
471+
B907(57, 0, vars=("var",)),
472+
B907(60, 0, vars=("var",)),
473+
B907(64, 0, vars=("var",)),
474+
B907(66, 0, vars=("var",)),
475+
B907(68, 0, vars=("var",)),
476476
)
477477
self.assertEqual(errors, expected)
478478

479479
# manual permutations to save overhead when doing >60k permutations
480480
# see format spec at
481481
# https://docs.python.org/3/library/string.html#format-specification-mini-language
482482
@unittest.skipIf(sys.version_info < (3, 8), "not implemented for <3.8")
483-
def test_b028_format_specifier_permutations(self):
483+
def test_b907_format_specifier_permutations(self):
484484
visitor = BugBearVisitor(filename="", lines="")
485485

486486
for fields in itertools.product(
@@ -509,27 +509,27 @@ def test_b028_format_specifier_permutations(self):
509509
except ValueError:
510510
assert (
511511
visitor.errors == []
512-
), f"b028 raised for {format_spec!r} not valid for string"
512+
), f"b907 raised for {format_spec!r} not valid for string"
513513
continue
514514

515515
new = ("{!r:" + format_spec + "}").format("hello")
516516

517517
# Preceding the width field by 0 in >=3.10 is valid, but does nothing.
518518
# The presence of it means likely numeric variable though.
519-
# A width shorter than the string will look the same, but should not give b028.
519+
# A width shorter than the string will look the same, but should not give b907.
520520
if fields[5] == "0" or fields[6] == "1":
521521
assert (
522522
visitor.errors == []
523-
), f"b028 should not raise on questionable case {format_spec}"
523+
), f"b907 should not raise on questionable case {format_spec}"
524524
elif old == new:
525525
assert visitor.errors, (
526-
f"b028 not raised for {format_spec} that would look identical"
526+
f"b907 not raised for {format_spec} that would look identical"
527527
" with !r"
528528
)
529529
else:
530530
assert (
531531
visitor.errors == []
532-
), f"b028 raised for {format_spec} that would look different with !r"
532+
), f"b907 raised for {format_spec} that would look different with !r"
533533

534534
def test_b901(self):
535535
filename = Path(__file__).absolute().parent / "b901.py"

0 commit comments

Comments
 (0)