Skip to content
This repository has been archived by the owner on Oct 6, 2020. It is now read-only.

Commit

Permalink
Also consider 'async' functions in bad name attribute and scoping rules
Browse files Browse the repository at this point in the history
  • Loading branch information
mschwager committed Sep 13, 2019
1 parent b9a85ca commit 7bd249e
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 1 deletion.
3 changes: 3 additions & 0 deletions dlint/linters/helpers/bad_name_attribute_use.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,6 @@ def attribute_use_callback(inner_node):
)
for result in results
])

def visit_AsyncFunctionDef(self, node):
self.visit_FunctionDef(node)
9 changes: 8 additions & 1 deletion dlint/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
)

import ast
import sys


def decorator_name(decorator):
Expand Down Expand Up @@ -84,10 +85,16 @@ def non_empty_return(_return):


def walk_callback_same_scope(node, callback):
is_python_3_5 = sys.version_info >= (3, 5)

# If we change scope, e.g. enter into a new
# class or function definition, then halt iteration
scopes = (ast.ClassDef, ast.FunctionDef)
if is_python_3_5:
scopes += (ast.AsyncFunctionDef,)

def scope_predicate(inner_node):
return not isinstance(inner_node, (ast.ClassDef, ast.FunctionDef))
return not isinstance(inner_node, scopes)

walk_callback(node, callback, predicate=scope_predicate)

Expand Down
67 changes: 67 additions & 0 deletions tests/test_helpers/test_bad_name_attribute_use.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
unicode_literals,
)

import sys
import unittest

import dlint

IS_PYTHON_3_5 = sys.version_info >= (3, 5)


def get_bad_name_attribute_use_implementation(illegal_name_attributes):
class Cls(dlint.linters.helpers.bad_name_attribute_use.BadNameAttributeUseLinter):
Expand Down Expand Up @@ -129,6 +132,40 @@ def inner_func():

assert result == expected

@unittest.skipUnless(IS_PYTHON_3_5, 'async statements introduced in Python 3.5')
def test_bad_name_attributes_async_nested(self):
python_node = self.get_ast_node(
"""
import bar
async def func():
async def inner_func():
obj = bar.Baz()
return obj.foo()
return
"""
)

linter = get_bad_name_attribute_use_implementation(
{
'foo': [
['bar', 'Baz'],
],
}
)
linter.visit(python_node)

result = linter.get_results()
expected = [
dlint.linters.base.Flake8Result(
lineno=7,
col_offset=15,
message=linter._error_tmpl
)
]

assert result == expected

def test_bad_name_attributes_nested_overwrite(self):
python_node = self.get_ast_node(
"""
Expand Down Expand Up @@ -158,6 +195,36 @@ def inner_func():

assert result == expected

@unittest.skipUnless(IS_PYTHON_3_5, 'async statements introduced in Python 3.5')
def test_bad_name_attributes_async_nested_overwrite(self):
python_node = self.get_ast_node(
"""
import bar
def func():
obj = bar.Qux()
async def inner_func():
obj = bar.Baz()
return obj.foo()
"""
)

linter = get_bad_name_attribute_use_implementation(
{
'foo': [
['bar', 'Baz'],
],
}
)
linter.visit(python_node)

result = linter.get_results()
expected = []

assert result == expected

def test_bad_name_attributes_multiple_findings(self):
python_node = self.get_ast_node(
"""
Expand Down

0 comments on commit 7bd249e

Please sign in to comment.