Skip to content

Commit c452048

Browse files
finswimmerTobias Klarecooperlees
authored
Add Option to extend the list of immutable calls (#204)
* add option to extend the list of immutable calls * update README.rst about `extend-immutable-calls` option Co-authored-by: Tobias Klare <[email protected]> Co-authored-by: Cooper Lees <[email protected]>
1 parent c90fa65 commit c452048

File tree

4 files changed

+62
-2
lines changed

4 files changed

+62
-2
lines changed

README.rst

+8
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,14 @@ by default. Those get enabled as soon as there is an ``ignore =`` line
206206
in your configuration. I think this behavior is surprising so Bugbear's
207207
opinionated warnings require explicit selection.
208208

209+
Configuration
210+
-------------
211+
212+
The plugin currently has one setting:
213+
214+
``extend-immutable-calls``: Specify a list of additional immutable calls.
215+
This could be useful, when using other libraries that provide more immutable calls,
216+
beside those already handled by ``flake8-bugbear``. Calls to these method will no longer raise a ``B008`` warning.
209217

210218
Tests
211219
-----

bugbear.py

+23-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,17 @@ class BugBearChecker:
3232
def run(self):
3333
if not self.tree or not self.lines:
3434
self.load_file()
35-
visitor = self.visitor(filename=self.filename, lines=self.lines)
35+
36+
if self.options and hasattr(self.options, "extend_immutable_calls"):
37+
b008_extend_immutable_calls = set(self.options.extend_immutable_calls)
38+
else:
39+
b008_extend_immutable_calls = set()
40+
41+
visitor = self.visitor(
42+
filename=self.filename,
43+
lines=self.lines,
44+
b008_extend_immutable_calls=b008_extend_immutable_calls,
45+
)
3646
visitor.visit(self.tree)
3747
for e in itertools.chain(visitor.errors, self.gen_line_based_checks()):
3848
if self.should_warn(e.message[:4]):
@@ -73,6 +83,13 @@ def load_file(self):
7383
def add_options(optmanager):
7484
"""Informs flake8 to ignore B9xx by default."""
7585
optmanager.extend_default_ignore(disabled_by_default)
86+
optmanager.add_option(
87+
"--extend-immutable-calls",
88+
comma_separated_list=True,
89+
parse_from_config=True,
90+
default=[],
91+
help="Skip B008 test for additional immutable calls.",
92+
)
7693

7794
@lru_cache()
7895
def should_warn(self, code):
@@ -146,6 +163,7 @@ def _typesafe_issubclass(cls, class_or_tuple):
146163
class BugBearVisitor(ast.NodeVisitor):
147164
filename = attr.ib()
148165
lines = attr.ib()
166+
b008_extend_immutable_calls = attr.ib(default=attr.Factory(set))
149167
node_stack = attr.ib(default=attr.Factory(list))
150168
node_window = attr.ib(default=attr.Factory(list))
151169
errors = attr.ib(default=attr.Factory(list))
@@ -338,7 +356,10 @@ def check_for_b006(self, node):
338356
call_path = ".".join(self.compose_call_path(default.func))
339357
if call_path in B006.mutable_calls:
340358
self.errors.append(B006(default.lineno, default.col_offset))
341-
elif call_path not in B008.immutable_calls:
359+
elif (
360+
call_path
361+
not in B008.immutable_calls | self.b008_extend_immutable_calls
362+
):
342363
# Check if function call is actually a float infinity/NaN literal
343364
if call_path == "float" and len(default.args) == 1:
344365
float_arg = default.args[0]

tests/b008_extended.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from typing import List
2+
3+
import fastapi
4+
from fastapi import Query
5+
6+
7+
def this_is_okay_extended(db=fastapi.Depends(get_db)):
8+
...
9+
10+
11+
def this_is_okay_extended_second(data: List[str] = fastapi.Query(None)):
12+
...
13+
14+
15+
def this_is_not_okay_relative_import_not_listed(data: List[str] = Query(None)):
16+
...

tests/test_bugbear.py

+15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import sys
66
import unittest
77
from pathlib import Path
8+
from unittest.mock import Mock
89

910
from hypothesis import HealthCheck, given, settings
1011
from hypothesmith import from_grammar
@@ -125,6 +126,20 @@ def test_b007(self):
125126
),
126127
)
127128

129+
def test_b008_extended(self):
130+
filename = Path(__file__).absolute().parent / "b008_extended.py"
131+
132+
mock_options = Mock()
133+
mock_options.extend_immutable_calls = ["fastapi.Depends", "fastapi.Query"]
134+
135+
bbc = BugBearChecker(filename=str(filename), options=mock_options)
136+
errors = list(bbc.run())
137+
138+
self.assertEqual(
139+
errors,
140+
self.errors(B008(15, 66)),
141+
)
142+
128143
def test_b009_b010(self):
129144
filename = Path(__file__).absolute().parent / "b009_b010.py"
130145
bbc = BugBearChecker(filename=str(filename))

0 commit comments

Comments
 (0)