Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add b905: require strict= argument to zip() #314

Merged
merged 2 commits into from Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.rst
Expand Up @@ -200,6 +200,8 @@ or ``raise ... from None`` to distinguish them from errors in exception handling
See `the exception chaining tutorial <https://docs.python.org/3/tutorial/errors.html#exception-chaining>`_
for details.

**B905**: `zip()` without an explicit `strict=` parameter. Added with python3.10, so don't enable this flag for code that should work on previous versions. https://peps.python.org/pep-0618/
Zac-HD marked this conversation as resolved.
Show resolved Hide resolved

**B950**: Line too long. This is a pragmatic equivalent of
``pycodestyle``'s ``E501``: it considers "max-line-length" but only triggers
when the value has been exceeded by **more than 10%**. You will no
Expand Down Expand Up @@ -299,7 +301,8 @@ Change Log

Future
~~~~~~~~~
* B027: ignore @overload when typing is import with other names
* B027: ignore @overload when typing is imported with other names
* Add B905: `zip()` without an explicit `strict=` parameter.

22.10.27
~~~~~~~~~
Expand Down
13 changes: 12 additions & 1 deletion bugbear.py
Expand Up @@ -356,6 +356,7 @@ def visit_Call(self, node):

self.check_for_b026(node)

self.check_for_b905(node)
self.generic_visit(node)

def visit_Assign(self, node):
Expand Down Expand Up @@ -960,6 +961,14 @@ def check_for_b025(self, node):
for duplicate in duplicates:
self.errors.append(B025(node.lineno, node.col_offset, vars=(duplicate,)))

def check_for_b905(self, node):
if (
isinstance(node.func, ast.Name)
and node.func.id == "zip"
and not any(kw.arg == "strict" for kw in node.keywords)
):
self.errors.append(B905(node.lineno, node.col_offset))


def compose_call_path(node):
if isinstance(node, ast.Attribute):
Expand Down Expand Up @@ -1360,6 +1369,8 @@ def visit_Lambda(self, node):
)
)

B905 = Error(message="B905 `zip()` without an explicit `strict=` parameter.")

B950 = Error(message="B950 line too long ({} > {} characters)")

disabled_by_default = ["B901", "B902", "B903", "B904", "B950"]
disabled_by_default = ["B901", "B902", "B903", "B904", "B905", "B950"]
10 changes: 10 additions & 0 deletions tests/b905_py310.py
@@ -0,0 +1,10 @@
zip()
zip(range(3))
zip("a", "b")
zip("a", "b", *zip("c"))
zip(zip("a"), strict=False)
zip(zip("a", strict=True))

zip(range(3), strict=True)
zip("a", "b", strict=False)
zip("a", "b", "c", strict=True)
19 changes: 18 additions & 1 deletion tests/test_bugbear.py
Expand Up @@ -42,6 +42,7 @@
B902,
B903,
B904,
B905,
B950,
BugBearChecker,
BugBearVisitor,
Expand Down Expand Up @@ -297,7 +298,7 @@ def test_b019(self):
def test_b020(self):
filename = Path(__file__).absolute().parent / "b020.py"
bbc = BugBearChecker(filename=str(filename))
errors = list(bbc.run())
errors = list(e for e in bbc.run() if e[2][:4] == "B020")
self.assertEqual(
errors,
self.errors(
Expand Down Expand Up @@ -484,6 +485,22 @@ def test_b904(self):
]
self.assertEqual(errors, self.errors(*expected))

@unittest.skipIf(sys.version_info < (3, 10), "requires 3.10+")
def test_b905(self):
filename = Path(__file__).absolute().parent / "b905_py310.py"
bbc = BugBearChecker(filename=str(filename))
errors = list(bbc.run())
expected = [
B905(1, 0),
B905(2, 0),
B905(3, 0),
B905(4, 0),
B905(4, 15),
B905(5, 4),
B905(6, 0),
]
self.assertEqual(errors, self.errors(*expected))

def test_b950(self):
filename = Path(__file__).absolute().parent / "b950.py"
bbc = BugBearChecker(filename=str(filename))
Expand Down