Extract raises IndexError or ModuleSyntaxError instead of RefactoringError for an empty or whitespace-only region

Offen Anfängerfreundlich
#926 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 7 Tagen

@aliassar arbeitet bereits daran.

Seit 03.11.2026.

  • #929 von @aliassar — offen

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
78/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
python

Rechercherichtung

Beginne bei _get_single_expression_body() in rope/refactor/extract.py, wo extracted.lstrip()[0] bei einem leeren String IndexError auslöst. Reproduziere mit dem Skript aus dem Issue, das einen leeren Bereich für ExtractVariable und ExtractMethod sowie einen nur aus Leerzeichen bestehenden Bereich für ExtractMethod abdeckt. Fertig ist es, wenn alle drei Fälle RefactoringError mit einer klaren Meldung auslösen, geprüft in _ExceptionalConditionChecker.base_conditions() oder nach _fix_start() und _fix_end() im Konstruktor.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

ExtractMethod and ExtractVariable raise IndexError for an empty region, and ModuleSyntaxError about a generated wrapper for a region that contains only whitespace. Both are user mistakes, not internal errors, so they should be reported as RefactoringError, as the other bad-region cases are.

This matters for editor integrations. Neovim sends an empty range when the user requests code actions without a selection, so a language server calls extract with an empty region all the time. It has to tell "can't extract here" apart from a real crash it should log.

To Reproduce

import pathlib
import tempfile

from rope.base.project import Project
from rope.refactor import extract

source = "def f(a):\n    b = a + 1\n    return b\n"
root = pathlib.Path(tempfile.mkdtemp())
(root / "m.py").write_text(source)
project = Project(str(root), ropefolder=None)
resource = project.get_resource("m.py")

expr = source.index("a + 1")
indent = source.index("    b =")
for label, cls, start, end in [
    ("extract variable, empty region", extract.ExtractVariable, expr, expr),
    ("extract method, empty region", extract.ExtractMethod, expr, expr),
    ("extract method, whitespace only", extract.ExtractMethod, indent, indent + 4),
]:
    try:
        cls(project, resource, start, end).get_changes("new_name")
    except Exception as e:
        print(f"{label}: {type(e).__name__}: {e}")

Output on master (46ebf37), Python 3.13:

extract variable, empty region: IndexError: string index out of range
extract method, empty region: IndexError: string index out of range
extract method, whitespace only: ModuleSyntaxError: Syntax error in file <string> line <1>: expected an indented block after function definition on line 1

The IndexError comes from _get_single_expression_body(), which indexes extracted.lstrip()[0] on an empty string.

Expected behaviour

RefactoringError, with a message such as "Extracted piece should contain at least one expression or statement". Checking it in _ExceptionalConditionChecker.base_conditions(), or in the constructor after _fix_start() and _fix_end(), would cover both cases.

Editor information

Vorherrschende Sprache
Python
Sterne
2.2k
Forks
197
Ø Merge
2 T. 13 Std.
Gemergte PRs (30 T.)
5

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus python-rope/rope

Alle Issues in python-rope/rope

Ähnliche Issues

Weitere Issues zu Python

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.