B018 doesn't trigger for useless expressions involving multiple variables
swierh opened this issue · comments
I recently ran into the following bug and was surprised it wasn't flagged by B018:
def some_funcion(a, b, c, d):
result = a * b
+c * d
return result
that should have been
def some_funcion(a, b, c, d):
result = (
a * b
+ c * d
)
return result
It looks like B018 doesn't trigger for expressions containing multiple variables.
Here's some examples:
a * b # doesn't trigger B018
+a * b # doesn't trigger B018
+1 * 2 # doesn't trigger B018
-1 * 2 # doesn't trigger B018
1 * 2 + 3 # doesn't trigger B018
a + 1 # doesn't trigger B018
a # triggers B018
(a, b) # triggers B018
1 # triggers B018
+1 # triggers B018
-1 # triggers B018
Versions I'm using:
python version 3.10.13
flake8 version 7.0.0
flake8-bugbear version 23.12.2
ruff version 0.1.13
Agree this would be nice to add to B018. Thanks for reporting.
"multiple variables" isn't a great description of what's going on here. If you look at the code for B018, it triggers if a statement consists only of an expression that is a set/list/tuple/dict literal or a non-str constant. (The original post claims that B018 triggers for +1
and -1
, but I don't think it does.)
We could expand the rule to some other kinds of nodes:
- UnaryOp, like
+1
,not x
,~3
. I don't know of any code patterns that would trigger false positives. - BinOp, like
1 + 1
or2 << 3
. This is what the OP is asking for. This could have false positives with Airflow code, where you dodag << task
to add a task to a dag. - Compare, like
1 < 2
. Can't think of any problems with this one. - BoolOp, like
a and b
. People could be using this for conditional execution. - GeneratorExp, like
(x for x in y)
. That is definitely useless. - JoinedStr, which is an f-string. Having an f-string in a line by itself doesn't have any use.
So we could definitely expand B018 to a few more kinds of AST nodes, but there's some room for false positives.
I remembered that internally in our codebase we have a similar lint rule. It triggers on these types:
ast.Attribute, ast.Lambda, ast.Dict, ast.Set, ast.Compare, ast.Num, ast.Subscript, ast.List, ast.Tuple, ast.Name
So that's missing a few that I mentioned above. We also flag ast.Call nodes if the called function is one of sorted
, reversed
, map
, and filter
. If you write sorted(x)
on a line by itself, you probably meant x.sort()
.