Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- #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)
- #937 Preserve non-ASCII argument expressions and default values when changing function signatures (@Jinyong-Li)
- #948, #949 Don't treat string prefixes such as the `f` in `f"..."` as occurrences when renaming a variable named `f`, `b`, `u`, `rf`, etc. (@aliassar)

# Release 1.15.1

Expand Down
6 changes: 5 additions & 1 deletion rope/refactor/occurrences.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,11 @@ def _get_source(self, resource, pymodule):
return pymodule.source_code

def _get_occurrence_pattern(self, name):
occurrence_pattern = _TextualFinder.any("occurrence", ["\\b" + name + "\\b"])
# A name directly followed by a quote is a string prefix, e.g. the
# ``f`` in ``f"..."``, never a reference to the name.
occurrence_pattern = _TextualFinder.any(
"occurrence", ["\\b" + name + "\\b(?![\"'])"]
)
pattern = re.compile(
occurrence_pattern
+ "|"
Expand Down
24 changes: 24 additions & 0 deletions ropetest/refactor/renametest.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,30 @@ def func(obj):
refactored = self._local_rename(code, code.index('abc'), "new_var")
self.assertEqual(expected, refactored)

def test_not_renaming_f_string_prefix(self):
code = dedent("""\
f = open("out.txt", "w")
f.write(f"{f.name}")
""")
expected = dedent("""\
fh = open("out.txt", "w")
fh.write(f"{fh.name}")
""")
refactored = self._local_rename(code, 0, "fh")
self.assertEqual(expected, refactored)

def test_not_renaming_bytes_string_prefix(self):
code = dedent("""\
b = 1
print(b"x", rb"y", b)
""")
expected = dedent("""\
new_b = 1
print(b"x", rb"y", new_b)
""")
refactored = self._local_rename(code, 0, "new_b")
self.assertEqual(expected, refactored)

def test_not_renaming_string_contents_in_f_string(self):
refactored = self._local_rename(
"a_var = 20\na_string=f'{\"a_var\"}'\n", 2, "new_var"
Expand Down
Loading