|
1 | 1 | # -*- coding: utf-8 -*- |
2 | 2 |
|
3 | 3 | import ast |
4 | | -from typing import ClassVar, Optional |
| 4 | +from typing import ClassVar, Iterable, Optional |
5 | 5 |
|
6 | 6 | from wemake_python_styleguide import constants |
7 | 7 | from wemake_python_styleguide.types import AnyNodes, final |
8 | 8 | from wemake_python_styleguide.violations.best_practices import ( |
| 9 | + IncorrectUnpackingViolation, |
9 | 10 | MagicNumberViolation, |
10 | 11 | MultipleAssignmentsViolation, |
11 | 12 | ) |
@@ -102,13 +103,54 @@ def _check_assign_targets(self, node: ast.Assign) -> None: |
102 | 103 | if len(node.targets) > 1: |
103 | 104 | self.add_violation(MultipleAssignmentsViolation(node)) |
104 | 105 |
|
| 106 | + def _check_unpacking_targets( |
| 107 | + self, |
| 108 | + node: ast.AST, |
| 109 | + targets: Iterable[ast.AST], |
| 110 | + ) -> None: |
| 111 | + for target in targets: |
| 112 | + if isinstance(target, ast.Starred): |
| 113 | + target = target.value |
| 114 | + if not isinstance(target, ast.Name): |
| 115 | + self.add_violation(IncorrectUnpackingViolation(node)) |
| 116 | + |
| 117 | + def visit_With(self, node: ast.With) -> None: |
| 118 | + """ |
| 119 | + Checks assignments inside context managers to be correct. |
| 120 | +
|
| 121 | + Raises: |
| 122 | + IncorrectUnpackingViolation |
| 123 | +
|
| 124 | + """ |
| 125 | + for withitem in node.items: |
| 126 | + if isinstance(withitem.optional_vars, ast.Tuple): |
| 127 | + self._check_unpacking_targets( |
| 128 | + node, withitem.optional_vars.elts, |
| 129 | + ) |
| 130 | + self.generic_visit(node) |
| 131 | + |
| 132 | + def visit_For(self, node: ast.For) -> None: |
| 133 | + """ |
| 134 | + Checks assignments inside ``for`` loops to be correct. |
| 135 | +
|
| 136 | + Raises: |
| 137 | + IncorrectUnpackingViolation |
| 138 | +
|
| 139 | + """ |
| 140 | + if isinstance(node.target, ast.Tuple): |
| 141 | + self._check_unpacking_targets(node, node.target.elts) |
| 142 | + self.generic_visit(node) |
| 143 | + |
105 | 144 | def visit_Assign(self, node: ast.Assign) -> None: |
106 | 145 | """ |
107 | | - Checks assingments to be correct. |
| 146 | + Checks assignments to be correct. |
108 | 147 |
|
109 | 148 | Raises: |
110 | 149 | MultipleAssignmentsViolation |
| 150 | + IncorrectUnpackingViolation |
111 | 151 |
|
112 | 152 | """ |
113 | 153 | self._check_assign_targets(node) |
| 154 | + if isinstance(node.targets[0], ast.Tuple): |
| 155 | + self._check_unpacking_targets(node, node.targets[0].elts) |
114 | 156 | self.generic_visit(node) |
0 commit comments