diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a6236..512d786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- False positive when bad builtin is overwritten by import (#16) ## [0.6.0] - 2019-08-12 ### Added diff --git a/dlint/linters/base.py b/dlint/linters/base.py index 24c2c5c..59da177 100644 --- a/dlint/linters/base.py +++ b/dlint/linters/base.py @@ -10,6 +10,8 @@ import ast import collections +from .. import namespace + Flake8Result = collections.namedtuple( 'Flake8Result', ['lineno', 'col_offset', 'message'] @@ -19,9 +21,19 @@ class BaseLinter(ast.NodeVisitor): def __init__(self, *args, **kwargs): self.results = [] + self.namespace = None super(BaseLinter, self).__init__(*args, **kwargs) def get_results(self): return self.results + + def visit(self, node): + if not self.namespace: + # Assuming that 'visit' is always called the first time with 'node' + # as an ast.Module. If not, we should fail fast with a raised + # exception and investigate. + self.namespace = namespace.Namespace.from_module_node(node) + + super(BaseLinter, self).visit(node) diff --git a/dlint/linters/helpers/bad_builtin_use.py b/dlint/linters/helpers/bad_builtin_use.py index 50d372a..2e0f0cb 100644 --- a/dlint/linters/helpers/bad_builtin_use.py +++ b/dlint/linters/helpers/bad_builtin_use.py @@ -25,7 +25,8 @@ def illegal_builtin(self): """ def visit_Name(self, node): - if node.id == self.illegal_builtin: + if (node.id == self.illegal_builtin + and not self.namespace.name_imported(node.id)): self.results.append( base.Flake8Result( lineno=node.lineno, diff --git a/tests/test_helpers/test_bad_builtin_use.py b/tests/test_helpers/test_bad_builtin_use.py index 67635fc..de50f95 100644 --- a/tests/test_helpers/test_bad_builtin_use.py +++ b/tests/test_helpers/test_bad_builtin_use.py @@ -63,6 +63,23 @@ def test_bad_builtin_usage(self): assert result == expected + def test_bad_builtin_overwritten(self): + python_string = self.get_ast_node( + """ + from foo import bar + + result = bar() + """ + ) + + linter = get_builtin_use_implementation('bar') + linter.visit(python_string) + + result = linter.get_results() + expected = [] + + assert result == expected + def test_no_builtin_usage(self): python_string = self.get_ast_node( """