diff --git a/CHANGELOG.md b/CHANGELOG.md index f86fb1100..ba328bd9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - #895 patchedast Starred and keyword now consumes their syntactically expected and ** (@lieryan) - #896 patchedast cleanup and refactoring (@lieryan) - #905 Ignore `node_modules` directories by default when scanning project files and source folders. (@marcoeangeli) +- #926, #929 Raise RefactoringError instead of IndexError/ModuleSyntaxError when extracting an empty or whitespace-only region (@aliassar) - #933 Add type annotations to project.py (@lieryan) - #119, #928 Fix IndexError in rename and find occurrences when a `from` import is the last thing in a module without a trailing newline (@mcepl) - #921 Patch the else suite of try statements that also have a finally (@marlon-costa-dc) diff --git a/rope/refactor/extract.py b/rope/refactor/extract.py index 1b1659fad..ea373613d 100644 --- a/rope/refactor/extract.py +++ b/rope/refactor/extract.py @@ -442,6 +442,10 @@ def __call__(self, info): self.multi_line_conditions(info) def base_conditions(self, info): + if not info.extracted.strip(): + raise RefactoringError( + "Extracted piece should contain at least one expression or statement." + ) if info.region[1] > info.scope_region[1]: raise RefactoringError("Bad region selected for extract method") diff --git a/ropetest/refactor/extracttest.py b/ropetest/refactor/extracttest.py index 4b34d58d3..53a225d6e 100644 --- a/ropetest/refactor/extracttest.py +++ b/ropetest/refactor/extracttest.py @@ -472,6 +472,36 @@ class AClass(object): with self.assertRaises(rope.base.exceptions.RefactoringError): self.do_extract_method(code, start, end, "new_func") + def test_extract_method_empty_region(self): + code = dedent("""\ + def a_func(arg): + var = arg + 1 + return var + """) + start = code.index("arg + 1") + with self.assertRaises(rope.base.exceptions.RefactoringError): + self.do_extract_method(code, start, start, "new_func") + + def test_extract_method_whitespace_only_region(self): + code = dedent("""\ + def a_func(arg): + var = arg + 1 + return var + """) + start = code.index(" var") + with self.assertRaises(rope.base.exceptions.RefactoringError): + self.do_extract_method(code, start, start + 4, "new_func") + + def test_extract_variable_empty_region(self): + code = dedent("""\ + def a_func(arg): + var = arg + 1 + return var + """) + start = code.index("arg + 1") + with self.assertRaises(rope.base.exceptions.RefactoringError): + self.do_extract_variable(code, start, start, "new_var") + def test_extract_method_containing_return(self): code = dedent("""\ def a_func(arg):