diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f45f6be1..9eaf1d65b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - #519 dynamic versioning and move pytest to pyproject.toml (@gliptak, @bagel897) - #509 Fix read/write analysis of the left-hand side of an augmented assignment (@lieryan) - #522 Implement patchedast parsing of MatchMapping (@lieryan) +- #514 Fix inlining dictionary with inline comment # Release 1.4.0 diff --git a/rope/refactor/inline.py b/rope/refactor/inline.py index e60c20fbc..1644bb2c0 100644 --- a/rope/refactor/inline.py +++ b/rope/refactor/inline.py @@ -17,10 +17,12 @@ # but it should be 200. import re +from typing import List import rope.base.exceptions import rope.refactor.functionutils from rope.base import ( + ast, pynames, pyobjects, codeanalyze, @@ -353,15 +355,25 @@ def get_kind(self): return "parameter" -def _join_lines(lines): - definition_lines = [] - for unchanged_line in lines: - line = unchanged_line.strip() - if line.endswith("\\"): - line = line[:-1].strip() - definition_lines.append(line) - joined = " ".join(definition_lines) - return joined +def _join_lines(lines: List[str]) -> str: + return "\n".join(lines) + + +class _ComplexExpressionVisitor: + def __init__(self): + self.is_complex_expression = False + + def _Set(self, node): + self.is_complex_expression = True + + def _List(self, node): + self.is_complex_expression = True + + def _Tuple(self, node): + self.is_complex_expression = True + + def _Dict(self, node): + self.is_complex_expression = True class _DefinitionGenerator: @@ -477,7 +489,7 @@ def _replace_returns_with(self, source, returns): self._check_nothing_after_return(source, match.end("return")) beg_idx = match.end("return") returned = _join_lines( - source[beg_idx : len(source)].splitlines() + source[beg_idx : len(source)].lstrip().splitlines(), ) last_changed = len(source) else: @@ -641,7 +653,7 @@ def _getvardef(pymodule, pyname): lines = pymodule.lines start, end = _assigned_lineno(pymodule, pyname) definition_with_assignment = _join_lines( - [lines.get_line(n) for n in range(start, end + 1)] + [lines.get_line(n) for n in range(start, end + 1)], ) if assignment.levels: raise rope.base.exceptions.RefactoringError("Cannot inline tuple assignments.") diff --git a/rope/refactor/sourceutils.py b/rope/refactor/sourceutils.py index 159476595..27116b60a 100644 --- a/rope/refactor/sourceutils.py +++ b/rope/refactor/sourceutils.py @@ -32,7 +32,7 @@ def indent_lines(source_code, amount): return "".join(result) -def fix_indentation(code, new_indents): +def fix_indentation(code: str, new_indents: int) -> str: """Change the indentation of `code` to `new_indents`""" min_indents = find_minimum_indents(code) return indent_lines(code, new_indents - min_indents) diff --git a/ropetest/refactor/inlinetest.py b/ropetest/refactor/inlinetest.py index 1244a9adf..135f7e6b7 100644 --- a/ropetest/refactor/inlinetest.py +++ b/ropetest/refactor/inlinetest.py @@ -58,7 +58,13 @@ def test_explicit_continuation(self): another_var = a_var """) refactored = self._inline(code, code.index("a_var") + 1) - self.assertEqual("another_var = (10 + 10)\n", refactored) + self.assertEqual( + dedent("""\ + another_var = (10 + + 10) + """), + refactored, + ) def test_implicit_continuation(self): code = dedent("""\ @@ -67,7 +73,13 @@ def test_implicit_continuation(self): another_var = a_var """) refactored = self._inline(code, code.index("a_var") + 1) - self.assertEqual("another_var = 10 + 10\n", refactored) + self.assertEqual( + dedent("""\ + another_var = 10 +\\ + 10 + """), + refactored, + ) def test_inlining_at_the_end_of_input(self): code = dedent("""\ @@ -754,7 +766,14 @@ def a_func(): a = a_func() """)) self._inline2(self.mod, self.mod.read().index("a_func") + 1) - self.assertEqual("a = 1 + 2\n", self.mod.read()) + self.assertEqual( + "a = 1\\\n + 2\n", + dedent("""\ + a = 1\\ + + 2 + """), + self.mod.read(), + ) def test_a_function_with_pass_body(self): self.mod.write(dedent("""\ @@ -1392,3 +1411,18 @@ def a_func(param1=1, param2: int = 2): """)) self._inline2(self.mod, self.mod.read().index("a_func") + 1) self.assertEqual("print(1, 3)\n", self.mod.read()) + + def test_dictionary_with_inline_comment(self): + code = dedent("""\ + myvar = { + "key": "value", # noqa + } + print(myvar) + """) + refactored = self._inline(code, code.index("myvar") + 1) + expected = dedent("""\ + print({ + "key": "value", # noqa + }) + """) + self.assertEqual(expected, refactored)