Repository: wemake-services/wemake-python-styleguide

Issue:
Forbid to use `+=` with list arguments
# Rule request

<!-- Thanks for coming up with a proposal! -->

## Thesis

We can detect when people write code like this: 

```python
some_list += [1, 2, 3]
```

What happens here? `+=` works like `append()` method.
But, why do you want to use this `+=` stuff at all? Why not use just `.append()`?
It is inconsistent and should be forbidden.


Discussion:
Hi! Can I try this one?
Sure, @sathachao! Please feel free to ask for help in case you need it.

Resolving patch:
diff --git a/wemake_python_styleguide/violations/consistency.py b/wemake_python_styleguide/violations/consistency.py
--- a/wemake_python_styleguide/violations/consistency.py
+++ b/wemake_python_styleguide/violations/consistency.py
@@ -73,6 +73,7 @@
    MeaninglessNumberOperationViolation
    OperationSignNegationViolation
    VagueImportViolation
+   AdditionAssignmentOnListViolation
 
 Consistency checks
 ------------------
@@ -125,6 +126,7 @@
 .. autoclass:: MeaninglessNumberOperationViolation
 .. autoclass:: OperationSignNegationViolation
 .. autoclass:: VagueImportViolation
+.. autoclass:: AdditionAssignmentOnListViolation
 
 """
 
@@ -1784,3 +1786,28 @@ class VagueImportViolation(ASTViolation):
 
     error_template = 'Found vague import that may cause confusion: {0}'
     code = 347
+
+
+@final
+class AdditionAssignmentOnListViolation(ASTViolation):
+    """
+    Forbids usage of += with list arguments.
+
+    Reasoning:
+        ``+=`` works like ``extend()`` method.
+        Why not just use ``extend()`` instead of ``+=`` to be consistent.
+
+    Example::
+
+        # Correct:
+        some_list.extend([1, 2, 3])
+
+        # Wrong:
+        some_list += [1, 2, 3]
+
+    .. versionadded:: 0.13.0
+
+    """
+
+    error_template = 'Found addition assignment with list argument'
+    code = 348
diff --git a/wemake_python_styleguide/visitors/ast/operators.py b/wemake_python_styleguide/visitors/ast/operators.py
--- a/wemake_python_styleguide/visitors/ast/operators.py
+++ b/wemake_python_styleguide/visitors/ast/operators.py
@@ -177,6 +177,11 @@ def visit_AugAssign(self, node: ast.AugAssign) -> None:
         """
         self._check_negation(node.op, node.value)
         self._check_string_concat(node.value, node.op)
+        self._check_addition_assignment_on_list(
+            node.target,
+            node.op,
+            node.value,
+        )
         self.generic_visit(node)
 
     def _check_negation(self, op: ast.operator, right: ast.AST) -> None:
@@ -219,3 +224,18 @@ def _check_string_concat(
                     consistency.ExplicitStringConcatViolation(node),
                 )
                 return
+
+    def _check_addition_assignment_on_list(
+        self,
+        left: ast.AST,
+        op: ast.operator,
+        right: ast.AST,
+    ):
+        is_addition_assignment_on_list = (
+            isinstance(op, ast.Add) and
+            isinstance(right, ast.List)
+        )
+        if is_addition_assignment_on_list:
+            self.add_violation(
+                consistency.AdditionAssignmentOnListViolation(right),
+            )


Test patch:
diff --git a/tests/fixtures/noqa.py b/tests/fixtures/noqa.py
--- a/tests/fixtures/noqa.py
+++ b/tests/fixtures/noqa.py
@@ -583,6 +583,7 @@ def nested_annotation_return_func() -> Union[str, Union[int, float]]: # noqa: WP
 from some_module import a  # noqa: WPS347
 from text import from_file  # noqa: WPS347
 
+some_list += [1, 2, 3, 4]  # noqa: WPS348
 
 swap_a = swap_b
 swap_b = swap_a  # noqa: WPS448
diff --git a/tests/test_checker/test_noqa.py b/tests/test_checker/test_noqa.py
--- a/tests/test_checker/test_noqa.py
+++ b/tests/test_checker/test_noqa.py
@@ -121,6 +121,7 @@
     'WPS345': 1,
     'WPS346': 1,
     'WPS347': 3,
+    'WPS348': 1,
 
     'WPS400': 0,
     'WPS401': 0,