Skip to content

Commit

Permalink
SIM119: Adjust when it is triggered
Browse files Browse the repository at this point in the history
Make SIM119 not trigger on complex operations in the constructor, and when async methods are present on a class. (#74)
  • Loading branch information
Danilo Šegan committed Dec 12, 2021
1 parent 31ea767 commit 6eb41c9
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 15 deletions.
47 changes: 32 additions & 15 deletions flake8_simplify.py
Original file line number Diff line number Diff line change
Expand Up @@ -1093,24 +1093,41 @@ def _get_sim119(node: ast.ClassDef) -> List[Tuple[int, int, str]]:
"__repr__",
"__str__",
]
has_only_constructur_function = True
has_only_dataclass_functions = True
has_any_functions = False
for body_el in node.body:
if (
isinstance(body_el, ast.FunctionDef)
and body_el.name not in dataclass_functions
):
has_only_constructur_function = False
break
if isinstance(body_el, (ast.FunctionDef, ast.AsyncFunctionDef)):
has_any_functions = True
if body_el.name == "__init__":
# Ensure constructor only has pure assignments
# without any calculation.
has_complex_statements = False
for el in body_el.body:
if not isinstance(el, ast.Assign):
has_complex_statements = True
break
else:
# It is an assignment, but we only allow
# `self.attribute = name`.
if any(
[
not isinstance(target, ast.Attribute)
for target in el.targets
]
) or not isinstance(el.value, ast.Name):
has_complex_statements = True
break
if body_el.name not in dataclass_functions:
has_only_dataclass_functions = False

if not (
has_only_constructur_function
and sum(1 for el in node.body if isinstance(el, ast.FunctionDef)) > 0
if (
has_any_functions
and has_only_dataclass_functions
and not has_complex_statements
):
return errors

errors.append(
(node.lineno, node.col_offset, SIM119.format(classname=node.name))
)
errors.append(
(node.lineno, node.col_offset, SIM119.format(classname=node.name))
)

return errors

Expand Down
45 changes: 45 additions & 0 deletions tests/test_simplify.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,25 @@ def test_sim118_del_key():
def test_sim119():
results = _results(
"""
class FooBar:
def __init__(self, a, b):
self.a = a
self.b = b
"""
)
assert results == {"2:0 SIM119 Use a dataclass for 'class FooBar'"}


def test_sim119_ignored_dunder_methods():
"""
Dunder methods do not make a class not be a dataclass candidate.
Examples for dunder (double underscore) methods are:
* __str__
* __eq__
* __hash__
"""
results = _results(
"""
class FooBar:
def __init__(self, a, b):
self.a = a
Expand All @@ -488,6 +507,32 @@ def __str__(self):
assert results == {"2:0 SIM119 Use a dataclass for 'class FooBar'"}


def test_sim119_async():
results = _results(
"""
class FooBar:
def __init__(self, a, b):
self.a = a
self.b = b
async def foo(self):
return "FooBar"
"""
)
assert results == set()


def test_sim119_constructor_processing():
results = _results(
"""
class FooBar:
def __init__(self, a):
self.a = a + 5
"""
)
assert results == set()


def test_sim119_pydantic():
results = _results(
"""
Expand Down

0 comments on commit 6eb41c9

Please sign in to comment.