Skip to content

Commit

Permalink
Add error handling for extract of incomplete block
Browse files Browse the repository at this point in the history
  • Loading branch information
raymyers authored and lieryan committed Jan 11, 2024
1 parent 95585e8 commit 7ebf247
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- #719 Allows the in-memory db to be shared across threads (@tkrabel)
- #720 create one sqlite3.Connection per thread using a thread local (@tkrabel)
- #715 change AutoImport's `get_modules` to be case sensitive (@bagel897)
- #734 raise exception when extracting the start of a block without the end

# Release 1.10.0

Expand Down
29 changes: 29 additions & 0 deletions rope/refactor/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,10 @@ def __call__(self, info):
def base_conditions(self, info):
if info.region[1] > info.scope_region[1]:
raise RefactoringError("Bad region selected for extract method")

end_line = info.region_lines[1]
end_scope = info.global_scope.get_inner_scope_for_line(end_line)

if end_scope != info.scope and end_scope.get_end() != end_line:
raise RefactoringError("Bad region selected for extract method")
try:
Expand Down Expand Up @@ -498,6 +500,33 @@ def multi_line_conditions(self, info):
"Extracted piece should contain complete statements."
)

if self._is_region_incomplete_block(info):
raise RefactoringError(
"Extracted piece cannot contain the start of a block without the end"
)

def _is_region_incomplete_block(self, info):
"""
Is end more indented than start, and does that level continue outside the region?
If so, this is an incomplete block that cannot be extracted.
"""

def get_effective_indent(lines, line):
if found_line := sourceutils.find_nonblank_line(lines, line):
return sourceutils.get_indents(info.pymodule.lines, found_line)
return None

start_line = info.region_lines[0]
end_line = info.region_lines[1]
start_indent = get_effective_indent(info.pymodule.lines, start_line)
end_indent = get_effective_indent(info.pymodule.lines, end_line)
end_next_indent = get_effective_indent(info.pymodule.lines, end_line + 1)
return (
end_next_indent is not None
and start_indent < end_indent
and end_next_indent >= end_indent
)

def _is_region_on_a_word(self, info):
if (
info.region[0] > 0
Expand Down
14 changes: 14 additions & 0 deletions rope/refactor/sourceutils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from rope.base import codeanalyze
from typing import Optional


def get_indents(lines, lineno):
Expand Down Expand Up @@ -91,3 +92,16 @@ def get_body_region(defined):

def get_indent(project):
return project.prefs.get("indent_size", 4)


def find_nonblank_line(
lines, start_line: int, skip_comments: bool = True
) -> Optional[int]:
"""Return index of first non-blank line starting with start_line, None if not found"""
next_line = start_line
while next_line < lines.length():
line_code = lines.get_line(next_line).strip()
if line_code and (not skip_comments or not line_code.startswith("#")):
return next_line
next_line = next_line + 1
return None
58 changes: 58 additions & 0 deletions ropetest/refactor/extracttest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,64 @@ def xxx_test_raising_exception_on_function_parens(self):
end = code.rindex(")") + 1
with self.assertRaises(rope.base.exceptions.RefactoringError):
self.do_extract_method(code, start, end, "new_func")

def test_raising_exception_on_incomplete_block(self):
code = dedent("""\
if True:
a = 1
b = 2
""")
start = code.index("if")
end = code.index("1") + 1
with self.assertRaises(rope.base.exceptions.RefactoringError):
self.do_extract_method(code, start, end, "new_func")

def test_raising_exception_on_incomplete_block_2(self):
code = dedent("""\
if True:
a = 1
#
b = 2
""")
start = code.index("if")
end = code.index("1") + 1
with self.assertRaises(rope.base.exceptions.RefactoringError):
self.do_extract_method(code, start, end, "new_func")

def test_raising_exception_on_incomplete_block_3(self):
code = dedent("""\
if True:
a = 1
b = 2
""")
start = code.index("if")
end = code.index("1") + 1
with self.assertRaises(rope.base.exceptions.RefactoringError):
self.do_extract_method(code, start, end, "new_func")

def test_raising_exception_on_incomplete_block_4(self):
code = dedent("""\
#
if True:
a = 1
b = 2
""")
start = code.index("#")
end = code.index("1") + 1
with self.assertRaises(rope.base.exceptions.RefactoringError):
self.do_extract_method(code, start, end, "new_func")

def test_raising_exception_on_incomplete_block_5(self):
code = dedent("""\
if True:
if 0:
a = 1
""")
start = code.index("if")
end = code.index("0:") + 2
with self.assertRaises(rope.base.exceptions.RefactoringError):
self.do_extract_method(code, start, end, "new_func")

def test_extract_method_and_extra_blank_lines(self):
code = dedent("""\
Expand Down

0 comments on commit 7ebf247

Please sign in to comment.