Repository: hhatto/autopep8

Issue:
"for<space><space>" gets changed to "f<space>or<space>"
---

## Python Code
```python
cm_opts = ([1] +
           [d for  d in [3,4]])

```

Command Line
```shell
$ autopep8 --diff --recursive --aggressive --select E27,W504 foo.py

--- original/foo.py
+++ fixed/foo.py
@@ -1,2 +1,2 @@
-cm_opts = ([1] +
-           [d for  d in [3,4]])
+cm_opts = ([1]
+           + [d f or d in [3,4]])
```

## Your Environment
* Python version: 3.11.2
* autopep8 version: autopep8 2.0.2
* pycodestyle: 2.10.0
* Platform: linux and macOSX

I originally observed this here:
https://github.com/LMFDB/lmfdb/commit/ae5ac12892b0a7b14ab8de99d3bf27495f662332#diff-6d8d8530bb938c81789bbc90c06501eddf133bef2d233725681bbb999c2ce90dL1062-R1066

Discussion:
@hhatto: fixed in v2.2.0

https://pypi.org/project/autopep8/2.2.0/

Solution patch:
diff --git a/autopep8.py b/autopep8.py
index e3666bc..437c92f 100755
--- a/autopep8.py
+++ b/autopep8.py
@@ -477,6 +477,7 @@ class FixPEP8(object):
             self.source = sio.readlines()
         self.options = options
         self.indent_word = _get_indentword(''.join(self.source))
+        self.original_source = copy.copy(self.source)
 
         # collect imports line
         self.imports = {}
@@ -528,6 +529,13 @@ class FixPEP8(object):
         self.fix_w292 = self.fix_w291
         self.fix_w293 = self.fix_w291
 
+    def _check_affected_anothers(self, result) -> bool:
+        """Check if the fix affects the number of lines of another remark."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        original_target = self.original_source[line_index]
+        return target != original_target
+
     def _fix_source(self, results):
         try:
             (logical_start, logical_end) = _find_logical(self.source)
@@ -561,8 +569,12 @@ class FixPEP8(object):
                                 completed_lines):
                             continue
 
+                    if self._check_affected_anothers(result):
+                        continue
                     modified_lines = fix(result, logical)
                 else:
+                    if self._check_affected_anothers(result):
+                        continue
                     modified_lines = fix(result)
 
                 if modified_lines is None:


Test patch:
diff --git a/test/test_autopep8.py b/test/test_autopep8.py
index 3d591d5..bf73fa0 100755
--- a/test/test_autopep8.py
+++ b/test/test_autopep8.py
@@ -2256,6 +2256,18 @@ bar[zap[0][0]:zig[0][0], :]
         with autopep8_context(line) as result:
             self.assertEqual(fixed, result)
 
+    def test_e271_and_w504_with_affects_another_result_line(self):
+        line = """\
+cm_opts = ([1] +
+           [d for  d in [3,4]])
+"""
+        fixed = """\
+cm_opts = ([1]
+           + [d for d in [3,4]])
+"""
+        with autopep8_context(line, options=["--select=E271,W504"]) as result:
+            self.assertEqual(fixed, result)
+
     def test_e272(self):
         line = 'True  and False\n'
         fixed = 'True and False\n'