Skip to content

Commit

Permalink
SIM904: Assign values to dictionary directly at initialization (#97)
Browse files Browse the repository at this point in the history
This will be SIM124 once it's stable.

Closes #92
  • Loading branch information
MartinThoma committed Feb 12, 2022
1 parent 06580ba commit b80f0b5
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Python-specific rules:
* [`SIM117`](https://github.com/MartinThoma/flake8-simplify/issues/35): Merge with-statements that use the same scope ([example](#SIM117))
* [`SIM119`](https://github.com/MartinThoma/flake8-simplify/issues/37) ![](https://shields.io/badge/-legacyfix-inactive): Use dataclasses for data containers ([example](#SIM119))
* `SIM120` ![](https://shields.io/badge/-legacyfix-inactive): Use 'class FooBar:' instead of 'class FooBar(object):' ([example](#SIM120))
* `SIM124`: Reserved for SIM904 once it's stable

Simplifying Comparations:

Expand Down Expand Up @@ -92,6 +93,7 @@ the code will change to another number.
Current experimental rules:

* `SIM901`: Use comparisons directly instead of wrapping them in a `bool(...)` call ([example](#SIM901))
* `SIM904`: Assign values to dictionary directly at initialization ([example](#SIM904))

## Disabling Rules

Expand Down Expand Up @@ -545,3 +547,14 @@ bool(a == b)
# Good
a == b
```

### SIM904

```python
# Bad
a = {}
a["b"] = "c"

# Good
a = {"b": "c"}
```
62 changes: 62 additions & 0 deletions flake8_simplify.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def __init__(self, orig: ast.Call) -> None:
"instead of an if-block"
)
SIM901 = "SIM901 Use '{better}' instead of '{current}'"
SIM904 = "SIM904 Initialize dictionary '{dict_name}' directly"

# ast.Constant in Python 3.8, ast.NameConstant in Python 3.6 and 3.7
BOOL_CONST_TYPES = (ast.Constant, ast.NameConstant)
Expand Down Expand Up @@ -1838,10 +1839,71 @@ def _get_sim901(node: ast.Call) -> List[Tuple[int, int, str]]:
return errors


def _get_sim904(node: ast.Assign) -> List[Tuple[int, int, str]]:
"""
Assign values to dictionary directly at initialization.
Example
-------
Code:
# Bad
a = { }
a['b] = 'c'
# Good
a = {'b': 'c'}
Bad AST:
[
Assign(
targets=[Name(id='a', ctx=Store())],
value=Dict(keys=[], values=[]),
type_comment=None,
),
Assign(
targets=[
Subscript(
value=Name(id='a', ctx=Load()),
slice=Constant(value='b', kind=None),
ctx=Store(),
),
],
value=Constant(value='c', kind=None),
type_comment=None,
),
]
"""
errors: List[Tuple[int, int, str]] = []
n2 = node.next_sibling # type: ignore
if not (
isinstance(node.value, ast.Dict)
and isinstance(n2, ast.Assign)
and len(n2.targets) == 1
and len(node.targets) == 1
and isinstance(n2.targets[0], ast.Subscript)
and isinstance(n2.targets[0].value, ast.Name)
and isinstance(node.targets[0], ast.Name)
and n2.targets[0].value.id == node.targets[0].id
):
return errors
dict_name = to_source(node.targets[0])
errors.append(
(
node.lineno,
node.col_offset,
SIM904.format(dict_name=dict_name),
)
)
return errors


class Visitor(ast.NodeVisitor):
def __init__(self) -> None:
self.errors: List[Tuple[int, int, str]] = []

def visit_Assign(self, node: ast.Assign) -> Any:
self.errors += _get_sim904(node)
self.generic_visit(node)

def visit_Call(self, node: ast.Call) -> Any:
self.errors += _get_sim115(Call(node))
self.errors += _get_sim901(node)
Expand Down
8 changes: 8 additions & 0 deletions tests/test_simplify.py
Original file line number Diff line number Diff line change
Expand Up @@ -935,3 +935,11 @@ def test_sim401_positive_msg_check_issue89():
def test_sim901():
results = _results("bool(a == b)")
assert results == {"1:0 SIM901 Use 'a == b' instead of 'bool(a == b)'"}


def test_sim904():
results = _results(
"""a = { }
a['b'] = 'c'"""
)
assert results == {"1:0 SIM904 Initialize dictionary 'a' directly"}

0 comments on commit b80f0b5

Please sign in to comment.