Skip to content

Commit 3fed74c

Browse files
authored
Merge pull request #1202 from pre-commit/fix-builtin-literal-check
fix nested calls for check-builtin-literals
2 parents 9ba250d + a804ba5 commit 3fed74c

File tree

2 files changed

+22
-23
lines changed

2 files changed

+22
-23
lines changed

pre_commit_hooks/check_builtin_literals.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,37 @@ class Call(NamedTuple):
2626
class Visitor(ast.NodeVisitor):
2727
def __init__(
2828
self,
29-
ignore: Sequence[str] | None = None,
29+
ignore: set[str],
3030
allow_dict_kwargs: bool = True,
3131
) -> None:
3232
self.builtin_type_calls: list[Call] = []
33-
self.ignore = set(ignore) if ignore else set()
3433
self.allow_dict_kwargs = allow_dict_kwargs
34+
self._disallowed = BUILTIN_TYPES.keys() - ignore
3535

3636
def _check_dict_call(self, node: ast.Call) -> bool:
3737
return self.allow_dict_kwargs and bool(node.keywords)
3838

3939
def visit_Call(self, node: ast.Call) -> None:
40-
if not isinstance(node.func, ast.Name):
40+
if (
4141
# Ignore functions that are object attributes (`foo.bar()`).
4242
# Assume that if the user calls `builtins.list()`, they know what
4343
# they're doing.
44-
return
45-
if node.func.id not in set(BUILTIN_TYPES).difference(self.ignore):
46-
return
47-
if node.func.id == 'dict' and self._check_dict_call(node):
48-
return
49-
elif node.args:
50-
return
51-
self.builtin_type_calls.append(
52-
Call(node.func.id, node.lineno, node.col_offset),
53-
)
44+
isinstance(node.func, ast.Name) and
45+
node.func.id in self._disallowed and
46+
(node.func.id != 'dict' or not self._check_dict_call(node)) and
47+
not node.args
48+
):
49+
self.builtin_type_calls.append(
50+
Call(node.func.id, node.lineno, node.col_offset),
51+
)
52+
53+
self.generic_visit(node)
5454

5555

5656
def check_file(
5757
filename: str,
58-
ignore: Sequence[str] | None = None,
58+
*,
59+
ignore: set[str],
5960
allow_dict_kwargs: bool = True,
6061
) -> list[Call]:
6162
with open(filename, 'rb') as f:

tests/check_builtin_literals_test.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,6 @@
3838
'''
3939

4040

41-
@pytest.fixture
42-
def visitor():
43-
return Visitor()
44-
45-
4641
@pytest.mark.parametrize(
4742
('expression', 'calls'),
4843
[
@@ -85,7 +80,8 @@ def visitor():
8580
('builtins.tuple()', []),
8681
],
8782
)
88-
def test_non_dict_exprs(visitor, expression, calls):
83+
def test_non_dict_exprs(expression, calls):
84+
visitor = Visitor(ignore=set())
8985
visitor.visit(ast.parse(expression))
9086
assert visitor.builtin_type_calls == calls
9187

@@ -102,7 +98,8 @@ def test_non_dict_exprs(visitor, expression, calls):
10298
('builtins.dict()', []),
10399
],
104100
)
105-
def test_dict_allow_kwargs_exprs(visitor, expression, calls):
101+
def test_dict_allow_kwargs_exprs(expression, calls):
102+
visitor = Visitor(ignore=set())
106103
visitor.visit(ast.parse(expression))
107104
assert visitor.builtin_type_calls == calls
108105

@@ -114,17 +111,18 @@ def test_dict_allow_kwargs_exprs(visitor, expression, calls):
114111
('dict(a=1, b=2, c=3)', [Call('dict', 1, 0)]),
115112
("dict(**{'a': 1, 'b': 2, 'c': 3})", [Call('dict', 1, 0)]),
116113
('builtins.dict()', []),
114+
pytest.param('f(dict())', [Call('dict', 1, 2)], id='nested'),
117115
],
118116
)
119117
def test_dict_no_allow_kwargs_exprs(expression, calls):
120-
visitor = Visitor(allow_dict_kwargs=False)
118+
visitor = Visitor(ignore=set(), allow_dict_kwargs=False)
121119
visitor.visit(ast.parse(expression))
122120
assert visitor.builtin_type_calls == calls
123121

124122

125123
def test_ignore_constructors():
126124
visitor = Visitor(
127-
ignore=('complex', 'dict', 'float', 'int', 'list', 'str', 'tuple'),
125+
ignore={'complex', 'dict', 'float', 'int', 'list', 'str', 'tuple'},
128126
)
129127
visitor.visit(ast.parse(BUILTIN_CONSTRUCTORS))
130128
assert visitor.builtin_type_calls == []

0 commit comments

Comments
 (0)